/* ── The guided tutorial ─────────────────────────────────────────────────────
   A tour that runs over the REAL gateway and a REAL pre-loaded game, both
   rendered in same-origin iframes, rather than over a slideshow of hand-drawn
   mocks. See the tutorial section in CLAUDE.md for why that shape was chosen —
   the short version is that a sandbox which IS the product cannot drift from
   it, so there is nothing to keep in step and no "update the mock" button.

   Everything here is viewport-space and unit-relative, so it works at any size
   and in either orientation. Nothing assumes landscape. */

.tour-root {
    position: fixed;
    inset: 0;
    z-index: 99000;
    background: #0d1b12;
    font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    /* **ONE DEFINITION OF THE DIM, spent by BOTH of the things that draw it.**
       A spotlight step is dimmed by the ring's own 9999px shadow and a `reveal`
       step by the flat veil, and the two CROSS-FADE at every step change — so
       they have to be the same value or the composite visibly steps on the
       swap. It was 0.62 in two places; lightened to 0.45 by request ("when the
       screen darkens during the tutorial let's not darken it as much"), which
       still clearly de-emphasises the table while leaving it readable.
       iOS's `dimming(hole:)` carries the same number — keep the two in step. */
    --tour-dim: rgba(0, 0, 0, 0.45);
}

.tour-root[hidden] { display: none; }

/* The stage. BOTH frames stay laid out for the whole tour and are swapped by
   opacity, never by `hidden`/`display: none`.
   
   That is load-bearing rather than tidy: a `display: none` iframe is not laid
   out at all, so its buttons report `offsetParent === null` (which is exactly
   what `primeGame()` refuses to click) and its animations do not run. The game
   could therefore only START dealing at the step that first showed it — and the
   tour would then reach "Your hand" mid-deal and ring a one-card fan while
   saying "six cards to start" (measured: a 106px hand where the dealt fan is
   270). Kept live, the table is genuinely ready before the tour arrives, which
   is what the whole sandbox is for. */
.tour-stage {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
    opacity: 0;
    pointer-events: none;
    z-index: 0;
}

.tour-stage--shown {
    opacity: 1;
    pointer-events: auto;
    z-index: 1;
}

/* A full-screen dim for steps with nothing to point at. The spotlight's own
   dimming is a giant `box-shadow` on the ring (below), which is what leaves the
   hole itself untouched and still clickable. */
.tour-veil {
    position: absolute;
    inset: 0;
    background: var(--tour-dim);
    pointer-events: none;
    /* Above the showing stage, which now carries a z-index of its own so the
       two frames can be stacked rather than un-laid-out. */
    z-index: 2;
    /* **THE DIM CROSS-FADES WITH THE RING, AND THAT IS WHY IT IS TRANSITIONED
       AT ALL.** The ring's own 9999px shadow IS the dim for a spotlight step,
       so a ring that fades out takes the dim with it — the whole stage would
       brighten between steps and re-darken, which is a bigger movement than
       the travel this replaced. The veil fades IN as the ring fades out and
       OUT as the next one fades in, so the two dims hand over and the
       composite barely moves (it dips to ~0.52 mid-swap). One duration and one
       symmetric curve, the card's — keep the three in step. */
    transition: opacity 0.4s ease-in-out;
}

.tour-veil--hiding {
    opacity: 0;
    transition: opacity 0.4s ease-in-out;
}

.tour-veil[hidden] { display: none; }

/* THE HOLE. `box-shadow` with a huge spread paints everything OUTSIDE this box
   and nothing inside it, so the highlighted control stays fully legible — and,
   because the ring takes no pointer events, still reachable. */
.tour-ring {
    position: absolute;
    /* Its own, not the host page's: the tour is injected into the gateway and
       into the React app, and `place()` sizes this box to the hole it wants —
       a content-box ring would put its 3px border OUTSIDE that, where a target
       flush against the viewport edge loses it. Keep the width in step with
       RING_BORDER_PX in tour.js. */
    box-sizing: border-box;
    border-radius: 12px;
    border: 3px solid #ffd700;
    box-shadow: 0 0 0 9999px var(--tour-dim), 0 0 18px rgba(255, 215, 0, 0.55);
    pointer-events: none;
    z-index: 3;
    /* **THE RING CROSS-FADES WITH THE CARD; IT NEVER TRAVELS.** It used to glide
       to each new target over 0.28s, which was asked for and then reported as
       exactly the wrong thing: a big gold border sliding across the screen
       between steps draws the eye to the movement rather than to the thing the
       new step is about. The ring and the card are the same kind of thing at a
       step change — each is REPLACED by a different one — so both fade out
       together, the new box is written while nothing is on screen, and both
       fade in where they belong.

       Opacity only. Position and size are written instantly, which is what lets
       the ring FOLLOW its target while a step is up (the hand shrinks as its two
       cards go to the crib) without any of those corrections reading as travel.

       0.4s is CARD_FADE_MS in tour.js, shared with `.tour-card` and
       `.tour-veil` — keep the four in step. */
    transition: opacity 0.4s ease-in-out;
}

/* Faded out between steps — see `fadeRingOut`. `hidden` is applied at the END
   of the fade rather than transitioned, because the ring's giant shadow is the
   dim and a transparent one has to stop painting eventually. */
/* **THE GOLD BORDER AND THE GLOW, AND NO DIM** — worn by BOTH rings whenever a
   step has two boxes, and it is one rule because it is one statement: this ring
   does not own the dim.

   A `box-shadow` dim has exactly ONE rectangular hole, so two of them leave both
   holes dimmed and everything else twice as dark, which is the opposite of a
   spotlight. The second ring has therefore never cast one; the PRIMARY drops its
   own (`--nodim`) because `.tour-joined` below is the dim on a two-box step and
   it punches a hole per box. Until Sep 2026 it did not, and the second target sat
   inside the dim wearing a border — reported on the game log's header button as a
   ring round something dark. iOS has lit both all along (`dimming(holes:)`).

   The JOINED rule below comes AFTER this and so beats it, which is what lets a
   joined step mute the border as well. */
.tour-ring--extra,
.tour-ring--nodim {
    box-shadow: 0 0 18px rgba(255, 215, 0, 0.55);
}

/* **A STEP WHOSE TWO BOXES TOUCH IS DRAWN AS ONE OUTLINE INSTEAD**, by the
   layer below. The two rings keep every bit of the fade choreography — the same
   clock, the same `hidden`, the same classes, so nothing about the TIMING
   branches on a joined step — and simply stop painting. `border-color` rather
   than `border: none`, or the box would change size and the ring would move. */
.tour-ring--joined {
    border-color: transparent;
    box-shadow: none;
}

.tour-ring--hiding { opacity: 0; }

.tour-ring[hidden] { display: none; }

/* ── the two-box layer ──────────────────────────────────────────────────────
   The dim with A HOLE PER BOX, and — on a JOINED step only — one continuous
   border as well. Drawn as SVG because neither can be expressed as a box on an
   element: a `box-shadow` dim has exactly one rectangular hole, and two stroked
   boxes break at the seam. See `spotlightSvg`.

   **IT IS FIRST IN THE DOM, so the rings paint over it**: all three carry
   `z-index: 3`, so source order decides, and on a `separate` step the rings
   really do draw their borders — which a dim above them would grey out.

   It fades on the RING's own class and clock, so the three layers cannot come
   apart. Keep the transition in step with `.tour-ring` above. */
.tour-joined {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 3;
    transition: opacity 0.4s ease-in-out;
}

.tour-joined[hidden] { display: none; }

/* ONE DEFINITION OF THE DIM, shared with `.tour-ring`'s shadow and the flat
   veil — the three cross-fade at every step change, so a value of its own here
   would step visibly on the swap. */
.tour-joined-dim { fill: var(--tour-dim); }

.tour-joined-band { fill: #ffd700; }

/* The ring's own glow. `box-shadow`'s blur radius is about twice a filter's
   standard deviation, so 18px there is 9px here. */
.tour-joined-glow { filter: drop-shadow(0 0 9px rgba(255, 215, 0, 0.55)); }

/* ── the coach card ─────────────────────────────────────────────────────── */

.tour-card {
    position: absolute;
    width: min(420px, calc(100vw - 24px));
    box-sizing: border-box;
    padding: 16px 18px 14px;
    border-radius: 14px;
    border: 2px solid #ffd700;
    background: #e7dcc3;
    color: #1a1a1a;
    box-shadow: 0 18px 42px rgba(0, 0, 0, 0.55);
    /* Above the ring's 9999px shadow, which would otherwise dim the card too. */
    z-index: 4;
    /* The backstop the placement's clamp relies on: a card that cannot outgrow
       the viewport can always be put somewhere with its buttons on screen, and
       those buttons are the only way forward. */
    max-height: calc(100vh - 24px);
    overflow-y: auto;
    /* **THE CARD CROSS-FADES; IT DOES NOT TRAVEL.** It used to glide with the
       ring, which meant the new step's words appeared on the OLD card and then
       slid across the screen while being read — reported as exactly that, and
       the reason is that the two halves of a step change are not the same kind
       of thing: the ring MOVES to a new target, and the card is REPLACED by a
       different one. So the old card fades out, the new position and wording
       are written while nothing is on screen, and the new card fades in where
       it belongs. Opacity only: animating a size that changes with every step's
       wording makes the text reflow visibly on the way.

       **THE TWO DIRECTIONS ARE ONE DURATION AND ONE SYMMETRIC CURVE.** They
       were both 0.28s and both `ease` — which is cubic-bezier(.25,.1,.25,1),
       an asymmetric curve, so the out and the in were mirror images of each
       OTHER rather than of themselves and the pair did not read as one
       movement (reported as the fade out not matching the fade in).
       `ease-in-out` is its own mirror, so out and back are the same shape.
       The 0.4s is CARD_FADE_MS in tour.js — keep the three values in step. */
    transition: opacity 0.4s ease-in-out;
}

/* Faded out between steps — see `fadeCardOut`. `visibility` goes with the
   opacity so a card nobody can see cannot be clicked or tabbed into either,
   and it is transitioned to nothing so it snaps at the END of the fade. */
.tour-card--hiding {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.4s ease-in-out, visibility 0s linear 0.4s;
}

.tour-card-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 6px;
}

.tour-card h3 {
    flex: 1 1 auto;
    margin: 0;
    font-size: 1.05rem;
    font-weight: 800;
    color: #2c5234;
}

/* **A WORD, NOT A GLYPH.** It was a 28px "×" square; "Exit" says what it does
   without the reader having to know that a cross closes a tutorial, and it is a
   far bigger target. `nowrap` + `flex: 0 0 auto` is what keeps it one line when
   the head is squeezed by a long title — the same rule the social rows follow. */
/* **A DARK-BROWN OUTLINE AT NEXT'S OWN WEIGHT.** Exit was the one control on
   the card with no edge at all — a tinted pill that read as a label beside two
   bordered buttons — so it takes `.tour-btn`'s 1.5px. The colour is the wood
   brown this tutorial already spends (`#6b4423`, the offer card's own header
   gradient and the gateway's themed-modal band), which is what separates it
   from Next's goldenrod without introducing a hue.

   **`border-box` IS LOAD-BEARING**: `tour.css` has no `*` reset, so a border on
   a content-box element grows it by 3px in each axis and Exit would stand
   taller than the title beside it. */
.tour-exit {
    flex: 0 0 auto;
    box-sizing: border-box;
    height: 28px;
    padding: 0 10px;
    margin: -4px -4px 0 0;
    /* An EDGE, not an emphasis: solid #6b4423 at 1.5px read as the loudest
       thing on the card, next to the gold Next it is meant to sit quietly
       beside. 45% of the same wood brown at 1px says where the pill ends
       and no more. Kept in step with iOS's `exitButton`. */
    border: 1px solid rgba(107, 68, 35, 0.45);
    border-radius: 8px;
    background: rgba(44, 82, 52, 0.12);
    color: #2c5234;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
}

.tour-exit:hover { background: rgba(44, 82, 52, 0.22); }

/* **SHOW ME PRESSED: THE CARD IS ITS BUTTONS.** The set piece IS the content of
   those five steps, and this is a large parchment panel sitting on the table the
   player has just asked to watch — so the words come off and Back/Next stay. The
   SAME background and the SAME gold border, shrink-wrapped (`width: auto`) with
   the card's own padding still round them, so it reads as the same object rather
   than as a new control. Cleared at the step change — see `go()`. */
/* **AND IT OUTRANKS EVERY WIDTH A STEP CAN ASK FOR — hence `.tour-card` as
   well, which is (0,2,0) against their (0,1,0).** `--wide` and `--narrow` set
   the same property from further down this file, and the short-screen media
   query sets it further down still, so source order alone put the collapsed
   card back at the step's full width: measured on "Play It Out", the one
   `wide` step, a button row 560px across with ~380px of it bare parchment
   (reported as exactly that). A media query adds no specificity, so (0,2,0)
   beats all three wherever they sit. This is not tidiness — `--bare` is a
   statement of a different KIND from those two ("this is no longer a card of
   words, it is a button row"), so it has to win outright rather than for as
   long as nobody adds a later width rule. */
.tour-card.tour-card--bare {
    width: auto;
    /* A ROW, so the bar reads as one control strip: Exit, then Back and Next.
       The head is a flex item here rather than a block above the foot, which
       is what keeps the collapsed card one line high. */
    display: flex;
    align-items: center;
    gap: 8px;
}

/* **EXIT SURVIVES THE COLLAPSE.** It used to go with the head, on the
   reasoning that Next is right there and brings the whole card back — but the
   set piece it starts runs for seconds, and the one control a player might
   want during it is the way out. The TITLE is what goes; the button beside it
   stays. */
.tour-card--bare h3,
.tour-card--bare p,
.tour-card--bare .tour-count {
    display: none;
}

.tour-card--bare .tour-card-head {
    margin-bottom: 0;
}

/* The head's own negative margin pulls Exit up and right against the card's
   padding, which is right under a title and wrong in a centred one-line bar. */
.tour-card--bare .tour-exit {
    margin: 0;
}

.tour-card p {
    margin: 0 0 12px;
    font-size: 0.92rem;
    line-height: 1.45;
}

.tour-foot {
    display: flex;
    align-items: center;
    gap: 8px;
}

.tour-count {
    flex: 1 1 auto;
    min-width: 0;
    color: #5c6670;
    font-size: 0.78rem;
    font-weight: 600;
}

.tour-btn {
    flex: 0 0 auto;
    padding: 7px 14px;
    border-radius: 9px;
    border: 1.5px solid rgba(44, 82, 52, 0.35);
    background: rgba(255, 255, 255, 0.75);
    color: #2c5234;
    font-family: inherit;
    font-size: 0.86rem;
    font-weight: 700;
    cursor: pointer;
}

.tour-btn:hover:not(:disabled) { background: #fff; }
.tour-btn:disabled { opacity: 0.4; cursor: default; }

.tour-btn--primary {
    border-color: #b8860b;
    background: #ffd700;
    color: #2c5234;
}

.tour-btn--primary:hover { background: #ffe34d; }

/* **SHOW ME — the button that starts a step's set piece.**

   Dressed as neither of the other two: Next is the gold primary and carries
   the tour forward, Back is the plain secondary, and this one does something
   to the TABLE rather than to the tour. A green fill against the parchment
   card puts it in the felt's own colour, which is where the thing it starts
   happens.

   `hidden` is honoured explicitly: `.tour-foot` is a flex row, and a flex
   parent gives every child a `display` — which beats the UA stylesheet's
   `[hidden] { display: none }` however low its specificity. Same trap the
   gateway's own `[hidden]` rows record. */
.tour-btn--show {
    border-color: #1c3b24;
    background: #2c5234;
    color: #ffd700;
}

.tour-btn--show:hover:not(:disabled) { background: #37663f; }

.tour-btn--show[hidden] { display: none; }

/* **A WIDER CARD FOR A STEP WHOSE SUBJECT IS BELOW IT.** "Play it out" runs
   for ~25 seconds of pegging with the cards going down in the middle of the
   table, so the card is moved to the top-right (see `placeCard`) and widened:
   the same paragraph in 560px is three lines shorter, which is height the
   table gets back. `min()` keeps the viewport clamp the base rule has. */
.tour-card--wide {
    width: min(560px, calc(100vw - 24px));
}

/* **AND A NARROWER, TALLER ONE FOR A CARD THAT HAS BEEN PUT IN THE CORNER
   BECAUSE NOTHING WOULD CLEAR ITS RING** — see `placeCard`'s `fallback`. The
   trade is the exact reverse of `--wide`: there the card had a whole empty
   half of the table to spread into and height was what the step needed back,
   here it is sharing the screen with the thing it is describing and WIDTH is
   what that thing needs back.

   280px is derived rather than picked: the Create Game dialog is a fixed
   500px wide whatever the window, so a card in the bottom-left corner clears
   it outright while `12 + width <= (100vw - 500) / 2`, which at 280 holds down
   to a 1084px window. Below that it covers a share of the dialog that shrinks
   with the width — measured against the ring's area, 3.5% at 980px against the
   full card's 7.5%, and 9.4% at 800 against 12.0%.

   AFTER `--wide`, which sets the same property at the same specificity, so a
   step that somehow asked for both would get this one — the narrower of the two
   is the safe way to lose that argument. */
.tour-card--narrow {
    width: min(280px, calc(100vw - 24px));
}

/* A short screen (mobile-web landscape is ~390px tall) has to keep the card
   from covering the very thing it is pointing at, so it tightens rather than
   scrolling — the buttons must never be the part below the fold. */
@media (max-height: 460px) {
    .tour-card {
        width: min(360px, calc(100vw - 24px));
        padding: 11px 13px 10px;
    }
    /* Still the wider of the two, and still clamped to the viewport: a short
       screen is exactly where trading width for height pays best. */
    .tour-card--wide { width: min(460px, calc(100vw - 24px)); }
    /* **AND THE NARROW CARD IS NOT NARROWED HERE — it keeps the short screen's
       own width.** Narrowing buys horizontal room by spending vertical, and a
       390px-tall landscape phone has none to spend: past the viewport the card
       scrolls, and its buttons are the only way forward. This whole media query
       exists to stop that happening, so it stays in charge. */
    .tour-card--narrow { width: min(360px, calc(100vw - 24px)); }
    .tour-card h3 { font-size: 0.95rem; }
    .tour-card p { margin-bottom: 8px; font-size: 0.82rem; line-height: 1.35; }
    .tour-btn { padding: 5px 11px; font-size: 0.8rem; }
}

/* ── the opt-in offer ───────────────────────────────────────────────────────
   The tour is OFFERED, never forced: the old tutorial launched itself in front
   of a player who had only asked to create a game. */

.tour-offer {
    position: fixed;
    inset: 0;
    z-index: 99500;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(0, 0, 0, 0.6);
}

.tour-offer[hidden] { display: none; }

.tour-offer-card {
    width: min(430px, 100%);
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    box-sizing: border-box;
    border-radius: 14px;
    border: 2px solid #ffd700;
    background: #e7dcc3;
    color: #1a1a1a;
    box-shadow: 0 18px 42px rgba(0, 0, 0, 0.55);
}

.tour-offer-card h3 {
    margin: 0;
    padding: 13px 20px;
    border-radius: 11px 11px 0 0;
    background: linear-gradient(135deg, #2c5234, #6b4423);
    color: #fff;
    font-size: 1.05rem;
    font-weight: 800;
}

.tour-offer-body { padding: 16px 20px 6px; }
.tour-offer-body p { margin: 0 0 12px; font-size: 0.94rem; line-height: 1.5; }

.tour-offer-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 4px 20px 18px;
}


/* The ring is drawn in the PARENT document, so it is the PARENT's preference
   that governs it — not the sandbox frame's, which is where the tour used to
   ask. A viewer who has asked for less motion gets the ring placed rather than
   glided; the scroll behind it is instant for everybody now (see `needsScroll`
   in tour.js), so this is the only travel left to suppress. */
@media (prefers-reduced-motion: reduce) {
    /* The cross-fade goes too — `fadeCardOut` / `fadeRingOut` skip their own
       waits under the same query, so all three layers are simply replaced. */
    .tour-ring, .tour-ring--hiding, .tour-joined { transition: none; }
    .tour-veil, .tour-veil--hiding { transition: none; }
    .tour-card, .tour-card--hiding { transition: none; }
}

/* ── The tutorial's own loading screen ───────────────────────────────────────
   Both stages are loaded from the start now, so the tour has a wait of its own
   at the front rather than the app's "Setting the table" splash appearing
   fourteen seconds into the first table step. See LOADING_MIN_MS in tour.js.

   Above everything the tour draws (the card is z 4) and inside `.tour-root`, so
   it covers the stages and nothing else on the page. */
.tour-loading {
    position: absolute;
    inset: 0;
    z-index: 6;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #0d1b12;
    opacity: 1;
    transition: opacity 400ms ease;
}

/* Faded out rather than removed on the spot, so the gateway behind it is not
   revealed with a cut. The element is taken out of the DOM after the fade. */
.tour-loading--gone {
    opacity: 0;
    pointer-events: none;
}

/* The tour's own card dress, so the wait reads as part of the tutorial rather
   than as the page failing to load. */
.tour-loading-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 22px 28px;
    border-radius: 14px;
    border: 2px solid #ffd700;
    background: #e7dcc3;
    color: #1a1a1a;
    box-shadow: 0 18px 42px rgba(0, 0, 0, 0.55);
    max-width: min(340px, calc(100vw - 32px));
    text-align: center;
}

.tour-loading-card p {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
}

.tour-loading-spinner {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: 3px solid rgba(44, 82, 52, 0.25);
    border-top-color: #2c5234;
    animation: tour-loading-spin 900ms linear infinite;
}

@keyframes tour-loading-spin { to { transform: rotate(360deg); } }

/* A spinner that never stops is the one thing here that can be a problem for a
   reader who has asked for less movement; the card still says what is going on. */
@media (prefers-reduced-motion: reduce) {
    .tour-loading-spinner { animation: none; }
    .tour-loading { transition: none; }
}
