/* Card themes — the look of a playing card.
 *
 * Shipping stylesheet, not a harness one: players choose a theme from the cog
 * beside their hand, and the choice is stored per browser (see
 * public/card-theme.js). A theme is a `cardtheme-*` class on <html>; with no
 * class the card renders exactly as it always has.
 *
 * How a theme can override anything at all: views/card.jsx sets the card's face
 * colour and art as the custom properties --card-face and --card-art rather
 * than inline `background` declarations, and public/cards.css consumes them.
 * Because nothing declares background-color / background-image inline any more,
 * a rule here simply wins.
 *
 * Composition is identical in every theme — action top-left, cost middle-left,
 * name bottom. Only the frame and the way values sit on the card change.
 */

/* ═══════════════════════════════════════════════════════════════════════════
   THREE PROPOSED CARD LOOKS

   Composition is deliberately unchanged in all three: action top-left, cost
   middle-left, name bottom. What changes is the frame and how the values sit
   on the card.

   Sizing is deliberately unchanged too — icons stay 16px, values 14px, names
   16px, exactly as in game, including at the 70x140 landscape card size. That
   is the honest test: a look that only works when the chrome is rescaled is
   not a look you can ship without also rescaling the chrome.

   Shared fixes in all three:
     - the drop shadow is symmetric (the shipping one is `-5px 0`, so in a row
       every card shadows onto its left neighbour)
     - (a min-width on the value rows was tried and dropped: they already
       share a left edge, so it aligned nothing and only padded out the
       icon-only chips into empty space)
     - the top-right multi-select caret is chrome, not data, and stops
       competing with the action value until you hover it
   ═════════════════════════════════════════════════════════════════════════ */


.cardtheme-engraved .card-top-right,
.cardtheme-glass .card-top-right,
.cardtheme-stock .card-top-right,
.cardtheme-edge .card-top-right,
.cardtheme-orb .card-top-right {
  background-color: transparent;
  padding: 2px;
  /* The caret is a Font Awesome glyph at the inherited 16px, which next to a
     compact bead reads as the loudest thing on the card. It is chrome. */
  font-size: 11px;
  opacity: 0.45;
  text-shadow: 0 1px 2px #000;
  transition: opacity 0.15s ease;
}

.cardtheme-engraved .card-container:hover .card-top-right,
.cardtheme-glass .card-container:hover .card-top-right,
.cardtheme-stock .card-container:hover .card-top-right,
.cardtheme-edge .card-container:hover .card-top-right,
.cardtheme-orb .card-container:hover .card-top-right {
  opacity: 1;
}

/* ── A · Engraved ───────────────────────────────────────────────────────────
   No containers at all. The numerals carry their own shadow, and a soft
   radial darkening bleeds into the art where they sit instead of cutting a
   rectangle out of it. The frame is a bevel: dark outer edge, light inner
   hairline, art very slightly recessed. */

.cardtheme-engraved .card {
  border-width: 4px;
  border-radius: 5px;
  /* No border-color here on purpose — .card-type-* keeps supplying it. */
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.26),
    inset 0 8px 20px rgba(0, 0, 0, 0.34),
    inset 0 -8px 18px rgba(0, 0, 0, 0.22),
    0 3px 9px rgba(0, 0, 0, 0.55);
}

/* The shipping border texture is masked to a 5px ring; at 4px it would spill
   over the art, and this frame does not want it anyway. */
.cardtheme-engraved .card::before {
  display: none;
}

/* Two soft pools of shade, under the action and under the costs. A radial
   gradient has no edge, so it darkens the art without sitting on top of it. */
.cardtheme-engraved .card::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(38px 30px at 20px 18px, rgba(0, 0, 0, 0.62), transparent 70%),
    radial-gradient(40px 34px at 20px 50%, rgba(0, 0, 0, 0.58), transparent 72%);
}

.cardtheme-engraved .card-top-left,
.cardtheme-engraved .card-cost,
.cardtheme-engraved .card-name {
  background-color: transparent;
  border-radius: 0;
  padding: 0;
}

/* z-index on the containers, not on .card-cost. .card-cost is a static flex
   child of .card-costs, so z-index does nothing on it — and the
   `position: absolute` that would have made it work took every cost row out of
   the column and stacked them all on the same spot. Cards with two costs
   (Dragon, Curse, the Bribe cards) printed one row on top of the other. */
.cardtheme-engraved .card-top-left,
.cardtheme-engraved .card-costs,
.cardtheme-engraved .card-name {
  z-index: 1;
}

.cardtheme-engraved .card-value {
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.95),
    0 0 5px rgba(0, 0, 0, 0.85),
    0 0 1px rgba(0, 0, 0, 1);
}

.cardtheme-engraved .card-icon {
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.95));
}

/* Full-width fade rather than a floating pill: the text lands on a gradient
   that belongs to the art. */
.cardtheme-engraved .card-name {
  left: 0;
  right: 0;
  bottom: 0;
  transform: none;
  max-width: none;
  padding: 16px 4px 5px;
  background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.88) 62%);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.95);
}

/* ── B · Inlaid glass ──────────────────────────────────────────────────────
   The containers stay, but stop being flat black slabs: frosted, tinted by
   the card's own type colour, lit along the top edge so they read as inlays
   pressed into the card rather than stickers on it. */

.cardtheme-glass .card {
  border-width: 3px;
  border-radius: 4px;
  box-shadow:
    inset 0 0 0 2px var(--card-face, #888),
    inset 0 0 0 3px rgba(0, 0, 0, 0.55),
    inset 0 0 22px rgba(0, 0, 0, 0.3),
    0 3px 9px rgba(0, 0, 0, 0.5);
}

.cardtheme-glass .card::before {
  display: none;
}

.cardtheme-glass .card-top-left,
.cardtheme-glass .card-cost,
.cardtheme-glass .card-name {
  background-color: rgba(12, 10, 8, 0.42);
  -webkit-backdrop-filter: blur(4px) saturate(1.2);
  backdrop-filter: blur(4px) saturate(1.2);
  border: 1px solid var(--card-face, rgba(255, 255, 255, 0.3));
  border-radius: 5px;
  padding: 2px 5px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.34),
    inset 0 -1px 0 rgba(0, 0, 0, 0.35),
    0 1px 3px rgba(0, 0, 0, 0.45);
}

.cardtheme-glass .card-value {
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}

.cardtheme-glass .card-name {
  left: 4px;
  right: 4px;
  bottom: 5px;
  transform: none;
  max-width: none;
  padding: 3px 4px;
}

/* ── C · Card stock ────────────────────────────────────────────────────────
   The art stops bleeding to the edge and becomes a window mounted on stock.
   Chrome never sits on the art edge-to-edge, and the name gets its own band
   below the picture — the printed-card arrangement. */

.cardtheme-stock .card {
  border-width: 3px;
  border-radius: 4px;
  /* The art moves into ::after; the card face becomes the stock. */
  background-image: none;
  background-color: #241d18;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.1),
    0 3px 9px rgba(0, 0, 0, 0.5);
}

.cardtheme-stock .card::before {
  display: none;
}

/* The picture window. Sits above the stock but below the chrome, which is why
   both carry an explicit z-index. */
.cardtheme-stock .card::after {
  content: "";
  position: absolute;
  left: 5px;
  right: 5px;
  top: 5px;
  bottom: 34px;
  z-index: 0;
  background-image: var(--card-art-v2, var(--card-art, none));
  background-size: cover;
  background-position: center;
  background-color: var(--card-face, #333);
  border-radius: 2px;
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, 0.55),
    0 1px 3px rgba(0, 0, 0, 0.5);
}

.cardtheme-stock .card-top-left,
.cardtheme-stock .card-costs,
.cardtheme-stock .card-name,
.cardtheme-stock .card-top-right {
  z-index: 1;
}

.cardtheme-stock .card-top-left,
.cardtheme-stock .card-cost {
  background-color: rgba(20, 16, 13, 0.72);
  border-radius: 3px;
  padding: 1px 4px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}

/* The name sits on the stock below the window, with a type-coloured rule
   separating picture from plate. */
.cardtheme-stock .card-name {
  left: 5px;
  right: 5px;
  bottom: 5px;
  transform: none;
  max-width: none;
  background-color: transparent;
  border-radius: 0;
  padding: 2px 0 0;
  border-top: 2px solid var(--card-face, #888);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}

/* ── D · Edge-blended ──────────────────────────────────────────────────────
   The values stop being objects sitting on the art and become part of the
   frame: the same colour as the card's border, flush against it, square on
   the outside and rounded only on the side that meets the picture. Nothing is
   blurred, nothing is a dark slab — the chip and the frame read as one piece
   of furniture with the art mounted inside it.

   The frame colours live on .card-type-* as border-color, which children
   cannot read, so they are mirrored here as --card-edge. Keep the two lists in
   step: if a type's border-color changes in cards.css, change it here too.

   These are the *border* colours, not --card-face. The face colours are pale
   (bisque, lightblue) and would not carry white text; the border colours are
   all mid-to-dark and do. */
.cardtheme-edge .card-type-offense { --card-edge: #8b3030; }
.cardtheme-edge .card-type-magic { --card-edge: #4a7f9e; }
.cardtheme-edge .card-type-defense { --card-edge: #6b3a1a; }
.cardtheme-edge .card-type-special { --card-edge: #5a5a5a; }
.cardtheme-edge .card-type-resource { --card-edge: #a8763f; }

.cardtheme-edge .card {
  border-width: 4px;
  border-radius: 6px;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.18),
    0 3px 9px rgba(0, 0, 0, 0.5);
}

.cardtheme-edge .card::before {
  display: none;
}

/* One material for every chip: the edge colour, with a top-down sheen so it
   catches light like the frame rather than looking like flat paint. */
.cardtheme-edge .card-top-left,
.cardtheme-edge .card-cost,
.cardtheme-edge .card-name {
  background-color: var(--card-edge, #5a5a5a);
  background-image: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.24),
    rgba(255, 255, 255, 0.04) 45%,
    rgba(0, 0, 0, 0.18)
  );
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
}

/* Corner tab: hard into the corner, opening out into the art. The 2px on the
   outer corner matches the frame's inner radius (6px radius less the 4px
   border) so it does not poke past the curve. */
.cardtheme-edge .card-top-left {
  top: 0;
  left: 0;
  padding: 3px 8px 4px 5px;
  border-radius: 2px 0 10px 0;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.28),
    2px 2px 4px rgba(0, 0, 0, 0.4);
}

/* Cost tabs grow out of the left edge, square where they meet it. */
.cardtheme-edge .card-costs {
  left: 0;
  gap: 3px;
}

.cardtheme-edge .card-cost {
  padding: 2px 8px 2px 5px;
  border-radius: 0 9px 9px 0;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.26),
    2px 2px 4px rgba(0, 0, 0, 0.38);
}

/* Nameplate: the bottom rail of the frame, not a pill floating above it. */
.cardtheme-edge .card-name {
  left: 0;
  right: 0;
  bottom: 0;
  transform: none;
  max-width: none;
  border-radius: 0 0 2px 2px;
  padding: 3px 4px 4px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.26),
    0 -2px 6px rgba(0, 0, 0, 0.4);
}

/* ── E · Orb ───────────────────────────────────────────────────────────────
   Compact, radial, and anchored to the card rather than floating on it. Each
   bead is centred ON an edge and clipped by it, so it reads as part of the
   card's boundary instead of a sticker:

     top-left   centre on the corner  -> bottom-right quarter shows
     costs      centre on the left edge -> right half shows
     name       hangs off the bottom  -> top half shows

   The clipping is `overflow: hidden` on .card, which cuts at the padding box —
   i.e. the inside of the frame — so the frame itself stays unbroken and the
   beads appear to be set into it.

   Sizes are the three variables below. They are large because the visible
   sliver has to hold the content: a quarter of a disc only offers a usable box
   of about r/2 square once the arc is accounted for, so the disc has to be
   roughly four times the size of what sits in it. */
.cardtheme-orb {
  /* How much of each cost bead is buried off the left edge. */
  --orb-cost-bury: 15px;
  /* How far the nameplate hangs below the card. */
  --orb-name-drop: 11px;
}

.cardtheme-orb .card-type-offense { --card-edge: #8b3030; }
.cardtheme-orb .card-type-magic { --card-edge: #4a7f9e; }
.cardtheme-orb .card-type-defense { --card-edge: #6b3a1a; }
.cardtheme-orb .card-type-special { --card-edge: #5a5a5a; }
.cardtheme-orb .card-type-resource { --card-edge: #a8763f; }

.cardtheme-orb .card {
  border-width: 3px;
  /* Nearly square: a large corner radius would take a bite out of the corner
     medallion and the two curves would fight. */
  border-radius: 5px;
  overflow: hidden;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.2),
    0 3px 9px rgba(0, 0, 0, 0.5);
}

.cardtheme-orb .card::before {
  display: none;
}

.cardtheme-orb .card-top-left,
.cardtheme-orb .card-cost,
.cardtheme-orb .card-name {
  border-radius: 999px;
  background-color: var(--card-edge, #5a5a5a);
  background-image:
    radial-gradient(circle at 34% 26%, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0) 58%),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.26));
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  box-sizing: border-box;
  /* Only the inner edge is lit — the outer edge is buried in the card. */
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28);
}

.cardtheme-orb .card-icon {
  width: 10px;
  height: 10px;
}

.cardtheme-orb .card-value {
  font-size: 11px;
  line-height: 1;
}

/* Corner medallion: flush into the corner, rounded only where it meets the
   art, so it reads as a disc whose centre is the card's corner.
   
   It is a rounded box rather than a real circle offset by half its diameter.
   A true quarter-disc has to be about four times the size of its content to
   keep it inside the arc, and the widest indicators in the deck are three
   icons plus a value (Thief, All Weapons, Wane) — those need a ~100px disc on
   a 100px card, and at anything smaller the icons spill straight through the
   curve onto the art. A fixed 19px bottom-right radius keeps the same corner on
   every card — a clamped 999px would track the box's shorter side and change
   shape whenever an indicator ran wide or tall — and a wide indicator simply
   extends along the top edge. Same motif, no overflow. */
.cardtheme-orb .card-top-left {
  top: 0;
  left: 0;
  min-width: 26px;
  min-height: 23px;
  max-width: calc(100% - 22px);
  padding: 3px 10px 5px 4px;
  border-radius: 0 0 19px 0;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 2px;
}

/* Half-beads set into the left edge. */
.cardtheme-orb .card-costs {
  left: 0;
  gap: 5px;
}

/* Half-capsules rather than half-discs: a true semicircle wide enough to hold
   "icon 20" would have to be ~48px tall, and two of those stacked take a
   quarter of the card. The rounded right end keeps the radial read; the left
   end is buried off the edge and clipped flat by it. */
.cardtheme-orb .card-cost {
  height: 20px;
  margin-left: calc(var(--orb-cost-bury) * -1);
  padding: 0 8px 0 calc(var(--orb-cost-bury) + 4px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  white-space: nowrap;
}

/* The nameplate hangs off the bottom: the extra padding-bottom is the part
   that gets cut, so the text keeps sitting where it already sat. */
.cardtheme-orb .card-name {
  left: 50%;
  bottom: calc(var(--orb-name-drop) * -1);
  transform: translateX(-50%);
  max-width: 86px;
  font-size: 12px;
  line-height: 1.15;
  /* Fixed 9px rather than the shared stadium radius — the plate is half buried,
     so only its top corners ever show. */
  border-radius: 9px;
  padding: 2px 9px calc(var(--orb-name-drop) + 2px);
}

/* Cards with no top-left indicator would otherwise show a bare corner blob. */
.cardtheme-orb .card-top-left:not(:has(.card-icon)):not(:has(.card-value)):not(:has(i)) {
  display: none;
}

/* Randomize / defaults controls in the frame's meta row. */
.cps-deal {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.cps-deal-btn {
  padding: 3px 9px;
  border-radius: 6px;
  border: 1px solid rgba(127, 127, 127, 0.45);
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 0.8rem;
  cursor: pointer;
}

.cps-deal-btn:hover {
  background: rgba(127, 127, 127, 0.22);
}

/* The dealt hand, so a card that breaks a look can be found again. */
.cps-deal-list {
  opacity: 0.7;
  font-size: 0.75rem;
}

/* ── The settings cog and its modal ────────────────────────────────────────
   A cog at the top-right of the player's hand, opening a small modal for the
   two things worth changing without leaving the game: how the cards look, and
   whether card help text is shown. Shared with the playground stage so the
   control is styled and behaves the same in both places.

   Its left/top are set by card-theme.js against the hand's bounding box —
   fixed rather than anchored to a screen corner, because it belongs with the
   cards, and the hand moves with the layout. Visibility is a class rather than
   a :hover rule for the same reason: the cog is not a descendant of the hand,
   and it has to linger for a moment after the pointer leaves. */
.cwl-card-cog {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 60;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.24);
  background: rgba(12, 18, 26, 0.78);
  color: #e8eef5;
  font-size: 14px;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, background-color 0.18s ease;
}

.cwl-card-cog.is-visible {
  opacity: 1;
  pointer-events: auto;
}

/* Only exists where there are cards to restyle. */
body:not(:has(.hand)) .cwl-card-cog {
  display: none;
}

/* Guided play is scripted and already busy telling the player what to do; a
   settings cog is one more thing to poke at mid-lesson. */
body:has(#game-state-data[data-is-guided="true"]) .cwl-card-cog {
  display: none;
}

.cwl-card-cog:hover {
  background: rgba(30, 44, 60, 0.94);
}

.cwl-card-cog:focus-visible {
  opacity: 1;
  pointer-events: auto;
  outline: 2px solid rgba(255, 255, 255, 0.7);
  outline-offset: 2px;
}

.cwl-card-settings[hidden] {
  display: none;
}

.cwl-card-settings {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.cwl-card-settings-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
}

.cwl-card-settings-panel {
  position: relative;
  width: min(340px, 100%);
  box-sizing: border-box;
  padding: 16px 18px 18px;
  border-radius: 12px;
  background: #16212e;
  color: #e8eef5;
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.cwl-card-settings-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

.cwl-card-settings-head h3 {
  margin: 0;
  font-size: 1rem;
}

.cwl-card-settings-x {
  background: none;
  border: 0;
  color: inherit;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
  padding: 0 4px;
}

.cwl-card-settings-x:hover {
  opacity: 1;
}

.cwl-card-settings-row {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-bottom: 14px;
  font-size: 0.86rem;
}

.cwl-card-settings-row select {
  flex: 1;
  padding: 6px 8px;
  border-radius: 6px;
}

.cwl-card-settings-check {
  align-items: flex-start;
}

.cwl-card-settings-check input {
  width: 16px;
  height: 16px;
  margin-top: 2px;
  flex: none;
  cursor: pointer;
}

.cwl-card-settings-label {
  display: block;
  font-weight: 600;
}

.cwl-card-settings-hint {
  display: block;
  margin-top: 3px;
  opacity: 0.65;
  font-size: 0.78rem;
  line-height: 1.4;
}

/* ── Card size ─────────────────────────────────────────────────────────────
   How large the cards in hand are drawn, chosen from the settings cog.

   The whole row is scaled with one transform rather than resizing each part.
   The card carries a lot of sized pieces — icons, values, the name, and
   whatever the active theme adds — so resizing them individually would need a
   rule per theme per size, and a new theme could silently miss out. The row's
   width also comes from three nested elements (.hands > .hand-container >
   #red-hand > .hand), so growing only the cards just makes them overlap until
   the names are unreadable. Scaling the row keeps the fan exactly as it is,
   only bigger.

   A transform does not affect layout, so the row keeps its original footprint
   and paints outside it — anchored at the bottom, so it grows up into the
   board's empty middle and everything below it stays put.

   Each size has its own minimum viewport, matching minWidth in
   misc/cardThemes.js, which also decides whether the option is offered.
   Below it the cards would not fit, and phones and landscape have their own
   tuned sizes in mobile.css / landscape-mobile.css. */
@media (min-width: 1024px) {
  .cardsize-large {
    --card-scale: 1.25;
  }
}

@media (min-width: 1280px) {
  .cardsize-xl {
    --card-scale: 1.5;
  }
}

.cardsize-large .hand,
.cardsize-xl .hand {
  transform: scale(var(--card-scale, 1));
  transform-origin: bottom center;
}

/* The one thing directly above the hand is the turn indicator, which sits with
   barely any clearance and would end up behind the enlarged cards. It is plain
   text with no backing, so raising its stacking order would just put it on top
   of the art; instead it is nudged up by exactly what the row grows. Visual
   only — nothing else in the column moves. */
.cardsize-large .current-turn,
.cardsize-xl .current-turn {
  position: relative;
  top: calc(-220px * (var(--card-scale, 1) - 1));
}

/* ── Rules text on the larger cards ────────────────────────────────────────
   MTG style: the title doubles as a drawer handle, and the card's description
   pulls up from behind it.

   Only on the larger sizes. views/card.jsx renders the text on every card, but
   at the default size there is nowhere to put it, so it stays hidden. It also
   respects the card-help preference — this is a card description, which is
   exactly what that setting governs.

   Sizes here are in the card's own unscaled units; the row's transform paints
   them 1.25x or 1.5x larger. */
.card-description {
  display: none;
}

.cardsize-large .hand .card,
.cardsize-xl .hand .card {
  /* So the parked drawer is clipped away rather than hanging below the card. */
  overflow: hidden;
}

.cardsize-large .hand .card-description,
.cardsize-xl .hand .card-description {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 26px;
  height: 118px;
  box-sizing: border-box;
  padding: 6px 7px;
  overflow: auto;
  background: #efe4c8;
  color: #241c10;
  font-size: 8px;
  line-height: 1.35;
  text-align: left;
  text-shadow: none;
  z-index: 1;
  box-shadow: 0 -3px 8px rgba(0, 0, 0, 0.45);
  transform: translateY(calc(100% + 26px));
  transition: transform 0.24s cubic-bezier(0.22, 0.8, 0.3, 1);
}

/* Stacking, from the back: the card's own chips, then the drawer, then the
   title. .card-costs comes after .card-description in the markup, so without
   this the cost pills would paint on top of the rules text; and the title has
   to stay on top so the drawer slides out from behind it rather than across
   it. */
.cardsize-large .hand .card-top-left,
.cardsize-xl .hand .card-top-left,
.cardsize-large .hand .card-top-right,
.cardsize-xl .hand .card-top-right,
.cardsize-large .hand .card-costs,
.cardsize-xl .hand .card-costs {
  z-index: 0;
}

.cardsize-large .hand .card-name,
.cardsize-xl .hand .card-name {
  z-index: 2;
  cursor: help;
}

/* The missing-cost highlight lives outside .card so it can escape the greyscale
   filter, which also puts it above the drawer. While the rules text is open it
   is covering the very cost being pointed at, so it steps aside. */
.cardsize-large .card-container:has(.card-name:hover) .missing-cost-layer,
.cardsize-xl .card-container:has(.card-name:hover) .missing-cost-layer {
  opacity: 0;
}

/* Note the order: the size class is on <html> and the card-help class on
   <body>, so cardsize has to come first. Focus as well as hover, so the drawer
   is reachable by tap and by keyboard.

   The title, and only the title. The panel used to hold itself open while the
   pointer was over it — but the panel covers the card, so once it opened the
   pointer was on it, and the only way back to the art was to leave the card
   entirely and come back. */
.cardsize-large .cwl-help-on .hand .card-name:hover + .card-description,
.cardsize-xl .cwl-help-on .hand .card-name:hover + .card-description,
.cardsize-large .cwl-help-on .hand .card-container:focus-within .card-description,
.cardsize-xl .cwl-help-on .hand .card-container:focus-within .card-description {
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .cardsize-large .hand .card-description,
  .cardsize-xl .hand .card-description {
    transition: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   The lesson's cards
   ═══════════════════════════════════════════════════════════════════════════
   From 1024px wide (about half of players — the 1024+ bands are ~48% of the
   production sample) onboarding draws bigger cards that carry their own rules
   text, sits them at the bottom of the screen, and drops the help bar under the
   hand: the same information, on the card it describes, instead of in a strip
   the player has to look away to read. Narrower screens keep the bar and the
   normal cards, where there is no room to do better.

   The scale grows with the screen AND shrinks with the hand — see the two
   ladders below. It does not stop when the lesson does: `room.onboarding` is
   never cleared, so #game keeps .onboarding-active for the rest of that game,
   and a player who has just been taught with big readable cards should not have
   them shrink back the moment the last step is over.

   Three things here are deliberately NOT the way the player-facing card size
   works:

   1. The scale is on each .card, not on the row. A transform on an ancestor of
      the cards creates a stacking context, and the lesson lifts a highlighted
      .card-container above the z-index:9000 spotlight overlay — from inside a
      transformed ancestor it cannot escape, and the card being pointed at ends
      up under the dim. Margin makes the room the scale needs instead, and any
      row-scale from the player's own card size is switched off so the two
      cannot compound.
   2. The rules text is part of the deal, not a separate card size the player
      has to find. It behaves like the shipping drawer — parked behind the title
      until the title is hovered or the card is focused.
   3. The row's max-width is lifted. The ordinary hand is capped at 650px and
      lets seven cards share it; at these sizes that made them overlap by 38px
      and cover each other's text. */

/* ── How big ──────────────────────────────────────────────────────────────
   Two ladders, because the binding constraint is the row's width: a teaching
   hand of two to five cards can be much larger than the seven-card hand the
   game settles into. `--ob-card-gap` is half the card's growth plus a little
   air, since a transform takes no layout space. */
@media (min-width: 1024px) {
  #game.onboarding-active #red-hand {
    --ob-card-scale: 1.25;
    --ob-card-gap: 14px;
    /* What the card grows to while its help is open — an absolute readable
       size rather than a multiple of the size above, so the text is the same
       size to read on every screen. */
    --ob-card-pop: 2.4;
  }
  #game.onboarding-active #red-hand:has(.card-container:nth-child(6)) {
    --ob-card-scale: 1.1;
    --ob-card-gap: 9px;
  }
}

@media (min-width: 1280px) {
  #game.onboarding-active #red-hand {
    --ob-card-scale: 1.5;
    --ob-card-gap: 26px;
    --ob-card-pop: 2.6;
  }
  #game.onboarding-active #red-hand:has(.card-container:nth-child(6)) {
    --ob-card-scale: 1.4;
    --ob-card-gap: 22px;
  }
}

@media (min-width: 1600px) {
  #game.onboarding-active #red-hand {
    --ob-card-scale: 1.75;
    --ob-card-gap: 39px;
    --ob-card-pop: 2.8;
  }
  #game.onboarding-active #red-hand:has(.card-container:nth-child(6)) {
    --ob-card-scale: 1.5;
    --ob-card-gap: 26px;
  }
}

/* Five cards at 2x is a 400px card, which needs the height to sit above the
   hand without meeting the board furniture. */
@media (min-width: 1920px) and (min-height: 900px) {
  #game.onboarding-active #red-hand {
    --ob-card-scale: 2;
    --ob-card-gap: 52px;
    --ob-card-pop: 3;
  }
  #game.onboarding-active #red-hand:has(.card-container:nth-child(6)) {
    --ob-card-scale: 1.6;
    --ob-card-gap: 32px;
  }
}

@media (min-width: 1024px) {
  /* ── Where ──────────────────────────────────────────────────────────────
     Down at the bottom edge. The lesson's board leaves a deep band of empty
     ground below the hand — the taller the cards, the more they grew up into
     the middle of the screen instead of into that space. A flex column with an
     auto top margin on the hand puts them where a hand belongs. */
  #game.onboarding-active .game-board {
    display: flex;
    flex-direction: column;
    min-height: calc(100vh - 96px);
  }

  #game.onboarding-active .hands {
    margin-top: auto;
  }

  /* A row-scale from the player's own card size would compound with the card
     scale below and trap the spotlighted card under the overlay — see (1). */
  #game.onboarding-active .hand,
  #game.onboarding-active .onboarding-hand {
    transform: none;
  }

  /* The 650px cap is what made seven enlarged cards overlap — see (3). Lifting
     it alone is not enough: the containers flex-grow to share whatever width
     they are given, so four cards spread across the whole screen. Size the row
     to its content and let the cards keep their own width. */
  #game.onboarding-active #red-hand .hand {
    max-width: none;
    width: max-content;
    margin-left: auto;
    margin-right: auto;
    justify-content: center;
  }

  #game.onboarding-active #red-hand .card-container {
    flex-grow: 0;
    width: 100px;
  }

  #game.onboarding-active #red-hand .card {
    transform: scale(var(--ob-card-scale, 1.25));
    transform-origin: bottom center;
    /* So the parked rules text is clipped to the card. */
    overflow: hidden;
    transition: transform 0.2s ease;
  }

  /* ── Popped out ─────────────────────────────────────────────────────────
     Reading the rules is a deliberate act — the title says so with a help
     cursor — so the card answers by growing to a size the text can actually be
     read at, and shrinks back the moment the pointer leaves the title. Only the
     title: the panel covers the card, so a panel that held itself open left no
     way back to the art short of leaving the card altogether.

     The dim is not escaped with z-index: `.hands` carries z-index 5, which caps
     everything inside it far below the overlay's 9000. main.js cuts the popped
     card its own hole in the dim instead — see __obSpotlightHover. */
  #game.onboarding-active #red-hand .card:has(.card-name:hover),
  #game.onboarding-active #red-hand .card-container:focus-within .card {
    transform: scale(var(--ob-card-pop, 2.4));
  }

  /* Above its neighbours in the row. */
  #game.onboarding-active #red-hand .card-container:has(.card-name:hover),
  #game.onboarding-active #red-hand .card-container:focus-within {
    z-index: 20;
  }


  #game.onboarding-active #red-hand .card-container {
    margin-left: var(--ob-card-gap, 14px);
    margin-right: var(--ob-card-gap, 14px);
  }

  /* ── The rules text ─────────────────────────────────────────────────────
     Same drawer the large card sizes ship: parked below the card, pulled up by
     the title. Sized against the longest card the lesson plants (Builder, 115
     characters), with room to spare; the random cards dealt from stage 4 on can
     run to ~260 and scroll inside the panel rather than being cut off. */
  #game.onboarding-active #red-hand .card-description {
    display: block;
    position: absolute;
    left: 0;
    right: 0;
    bottom: 24px;
    height: 126px;
    box-sizing: border-box;
    padding: 6px 7px;
    overflow: auto;
    background: #efe4c8;
    color: #241c10;
    font-size: 8px;
    line-height: 1.35;
    text-align: left;
    text-shadow: none;
    z-index: 1;
    box-shadow: 0 -3px 8px rgba(0, 0, 0, 0.45);
    transform: translateY(calc(100% + 24px));
    transition: transform 0.24s cubic-bezier(0.22, 0.8, 0.3, 1);
  }

  /* Hover, and focus so it is reachable by tap and by keyboard. The card-help
     preference governs it, exactly as it governs the shipping drawer. */
  .cwl-help-on #game.onboarding-active #red-hand .card-name:hover + .card-description,
  .cwl-help-on #game.onboarding-active #red-hand .card-container:focus-within .card-description {
    transform: translateY(0);
  }

  /* Same stacking fix as the shipping drawer: .card-costs comes after the
     description in the markup and would paint its pills over the text. */
  #game.onboarding-active #red-hand .card-top-left,
  #game.onboarding-active #red-hand .card-top-right,
  #game.onboarding-active #red-hand .card-costs {
    z-index: 0;
  }

  #game.onboarding-active #red-hand .card-name {
    z-index: 2;
    cursor: help;
  }

  /* The bar the cards replace. !important because main.js's initCardHelp writes
     display straight onto the element's style attribute. */
  #game.onboarding-active #cardhelptextdiv {
    display: none !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  #game.onboarding-active #red-hand .card-description {
    transition: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   CARD ART SET — which painting goes on the face

   Orthogonal to the themes above: a theme is the frame, this is the picture
   inside it. views/card.jsx puts BOTH paintings on every card, as --card-art
   (the original deck) and --card-art-v2 (the repaint under
   public/assets/cards/cards_v2/), so switching sets is a class flip on <html>
   with nothing to fetch and nothing to re-render.

   The repaint is what ships, so it needs no class at all: every rule that
   paints a card reads `var(--card-art-v2, var(--card-art, none))` directly.
   That fallback is also what covers a card the repaint never reached — Destroy
   Crystals has no v2 painting, so it keeps its original art instead of showing
   a bare face — and it means a player still gets the shipping art if
   card-theme.js fails to load.

   Only the opt-out is a class. `cardart-classic` points those same rules back
   at the original deck, and every place that paints a card needs a twin here.
   There are five: the card face (public/cards.css), the Card stock theme's
   picture window above, the browsing grids on /cards (public/style.css), the
   deck builder's tiles (public/deck-builder.css) and the fixed-deck shop
   modal's contents thumbnails (public/deck-shop.css). A sixth consumer has to
   add itself to the list below — a list rather than one blanket rule because an
   inline --card-art cannot be re-pointed from a stylesheet without !important,
   and a silent !important is worse than a list that is easy to grep for
   (`cardart-classic`).
   ═════════════════════════════════════════════════════════════════════════ */

:root.cardart-classic .card,
:root.cardart-classic.cardtheme-stock .card::after,
:root.cardart-classic .card-grid-image,
:root.cardart-classic .deck-builder-card-image,
:root.cardart-classic .deck-shop-comp-thumb {
  background-image: var(--card-art, none);
}

/* The reward reveals paint with <img>, not a background, so they opt out by
   swapping which of the two images is displayed (public/daily-bonus.css sets
   the default). Same class, same choice. */
:root.cardart-classic .card-reveal-art-v2 {
  display: none;
}

:root.cardart-classic .card-reveal-front .card-reveal-art-classic {
  display: block;
}
