/* =========================================================================
   Wourdoboros — landing-page game reels

   Styles for the looping mini-screens that play inside the phone frames in
   index.html's "On your phone" section. reel.js builds the DOM and drives the
   motion; this file is the look.

   ── The 720x1280 rule ──────────────────────────────────────────────────────
   The game's design viewport is 720x1280 (project.godot [display], and every
   scene is authored in that space: scripts/matchmaking.gd's TILE_SIZE 110,
   TypeScale's 22..64, TouchTarget's 46/82/90). So each reel is laid out in a
   fixed 720x1280 box and the whole box is scaled into the phone screen with a
   container-query unit — see .rl below. Every length in this file is therefore
   a px value copied VERBATIM from the scene it replicates, not a value derived
   for the web. If you find yourself converting a number, stop: the point of the
   fixed box is that no conversion is needed, and that a reviewer can diff any
   value here against its source line.

   ── Two palettes, on purpose ───────────────────────────────────────────────
   The game is not one paper colour. The menu flow (main_menu.gd, play_blade.gd)
   uses the WARM tokens this page already ships — paper #F4EFE6 / ink #1F1A14,
   i.e. --paper / --ink from colors_and_type.css. The round flow
   (wourdoboros_round.gd, wourdoboros_results.gd) resolves its neutrals through
   BrickTile/LDraw instead, which lands on a COOL white: PAPER = LDraw WHITE
   #F4F4F4, PAPER_2 #E3E3E3, INK = LDraw BLACK #1B2A34. Both were sampled from
   a live 720x1280 capture of the current build, so don't "fix" the mismatch
   here — it is what the game looks like.
   ========================================================================= */

/* ---- the scale box -------------------------------------------------------
   --rl-k is the frame's width over 720, set by reel.js from a ResizeObserver on
   the .screen. It is not `scale(calc(100cqw / 720))`: cqw is a length and
   scale() takes a unitless number, so that expression is invalid and silently
   leaves the box at 1:1 (i.e. the top-left ninth of the screen, blown up).
   transform-origin 0 0 pins the scaled box to the screen's top-left. */
.rl{
  position:absolute;inset:0;
  width:720px;height:1280px;
  transform-origin:0 0;transform:scale(var(--rl-k,1));
  overflow:hidden;
  font-family:var(--font-body);
  /* Motion vocabulary, transcribed from scripts/motion.gd. NOT the page's
     --dur-* tokens: those are a faster marketing-page set, and a reel paced to
     them stops reading as the game. POP = TRANS_BACK + EASE_OUT (something
     arriving), GLIDE = TRANS_CUBIC + EASE_OUT (something travelling). */
  --r-fast:120ms;--r-quick:180ms;--r-base:260ms;--r-beat:340ms;
  --r-slow:500ms;--r-travel:1000ms;--r-stagger:60ms;
  --r-pop:cubic-bezier(0.34,1.56,0.64,1);
  --r-glide:cubic-bezier(0.22,0.61,0.36,1);
  /* The round/recap cool neutrals (see the header note). */
  --g-paper:#F4F4F4;--g-paper-2:#E3E3E3;--g-paper-3:#D7BA8C;
  --g-ink:#1B2A34;--g-ink-2:#300F06;--g-ink-3:#755945;--g-ink-4:#897D62;
}
.rl,.rl *{box-sizing:border-box}
.rl-layer{position:absolute;inset:0;overflow:hidden}

/* ---- brick tile ---------------------------------------------------------
   BrickTile.make_tile (scripts/brick_tile.gd:194). Flat face, darker bottom
   wall, soft ink drop shadow; the glyph is lifted 8% so it sits centred above
   the wall. Per-tile face/side/ink and the size-derived lengths come in as
   inline custom properties from reel.js's tile(). */
.rl-t{
  position:relative;display:flex;align-items:center;justify-content:center;
  flex:0 0 auto;
  width:var(--t-size);height:var(--t-size);border-radius:var(--t-corner);
  background:var(--t-face);
  box-shadow:0 var(--t-wall) 0 var(--t-side),
             0 var(--t-shadow-y) var(--t-shadow) rgba(27,42,52,.22);
  font-family:var(--font-display);font-weight:400;line-height:1;
  font-size:var(--t-letter);color:var(--t-ink);
  text-transform:uppercase;
}
.rl-t>span{position:relative;top:calc(var(--t-size) * -0.08)}
/* outline_ink: the 4%-of-size ink ring make_tile draws for the "you" tile. */
.rl-t.is-outlined{
  box-shadow:0 0 0 var(--t-outline) var(--g-ink),
             0 var(--t-wall) 0 var(--t-side),
             0 var(--t-shadow-y) var(--t-shadow) rgba(27,42,52,.22);
}
/* The starter seed tile, which the round draws with a dashed ink ring. */
.rl-t.is-seed{outline:3px dashed var(--g-ink);outline-offset:5px}
.rl-d{border-radius:50%}                 /* letter-bearing disc (avatars, medals) */

/* ---- shared chrome atoms ------------------------------------------------ */
.rl-row{display:flex;align-items:center}
/* Vector icons (reel.js's glyph(), transcribed from scripts/menu_glyph.gd).
   display:block kills the inline-SVG baseline gap that otherwise pads every row
   holding one. */
.rl-g{display:block;flex:0 0 auto}
.rl-pill{display:flex;align-items:center;border-radius:999px}
.rl-eyebrow{font-family:var(--font-body);font-weight:600;letter-spacing:.06em;text-transform:uppercase}
/* Brick button: BrickTile.make_button_stylebox (brick_tile.gd:253) — 8px bottom
   wall, 14px corners, 10px/4px ink shadow. .is-pressed is the "pressed" state
   from the same function: the wall flattens to 2px, the shadow goes, and the
   face darkens 8% toward black — so the button visibly sinks by 6px. */
.rl-btn{
  position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;
  border-radius:14px;background:var(--b-face);
  box-shadow:0 8px 0 var(--b-side),0 4px 10px rgba(27,42,52,.16);
  transition:transform var(--r-fast) var(--r-glide),box-shadow var(--r-fast) var(--r-glide);
}
.rl-btn.is-pressed{
  transform:translateY(6px);
  box-shadow:0 2px 0 var(--b-side);
  filter:brightness(.92);
}
.rl-ghost{
  display:flex;align-items:center;justify-content:center;
  border-radius:14px;border:2px solid var(--g-ink-3);background:transparent;
}
/* The tap ripple standing in for a finger. Nothing in the game draws this — it
   is the reel's one honest fiction, because a canned press with no pointer
   reads as the UI moving by itself. */
.rl-tap{
  position:absolute;width:96px;height:96px;margin:-48px 0 0 -48px;
  border-radius:50%;background:rgba(31,26,20,.20);
  pointer-events:none;opacity:0;
}

/* =========================================================================
   Screen 1a — main menu (scripts/main_menu.gd)
   ========================================================================= */
.rl-menu{background:var(--paper);color:var(--ink)}
.rl-menu .m-head{position:absolute;left:40px;right:40px;top:52px;height:76px;justify-content:space-between}
.rl-menu .m-avatar{gap:16px;height:76px;padding:0 22px 0 10px;background:var(--paper);
  box-shadow:0 2px 8px rgba(31,26,20,.10),inset 0 0 0 2px var(--paper-2)}
.rl-menu .m-avatar b{font-weight:600;font-size:34px;letter-spacing:.01em}
.rl-menu .m-pencil{color:var(--ink-4)}
.rl-menu .m-gift{position:relative;width:80px;height:82px;border-radius:18px;
  background:var(--brick-orange);box-shadow:0 6px 0 var(--brick-orange-dark),0 6px 12px rgba(31,26,20,.18);
  display:flex;align-items:center;justify-content:center}
.rl-menu .m-gift .m-badge{position:absolute;top:-10px;right:-10px;width:42px;height:42px;border-radius:50%;
  background:var(--brick-red);color:var(--paper);font-weight:700;font-size:26px;
  display:flex;align-items:center;justify-content:center}
.rl-menu .m-coin{gap:12px;height:68px;padding:0 8px 0 14px;background:var(--paper);
  box-shadow:0 2px 8px rgba(31,26,20,.10),inset 0 0 0 2px var(--paper-2);font-weight:600;font-size:34px}
.rl-menu .m-chev{width:44px;height:44px;border-radius:50%;background:var(--brick-green);color:var(--paper);
  display:flex;align-items:center;justify-content:center}

.rl-menu .m-xp{position:absolute;left:40px;right:40px;top:150px;height:92px}
.rl-menu .m-lvl{width:82px;height:92px;border-radius:16px;background:var(--brick-green);color:var(--paper);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  box-shadow:0 6px 0 var(--brick-green-dark)}
.rl-menu .m-lvl i{font-style:normal;font-size:22px;font-weight:600;letter-spacing:.08em}
.rl-menu .m-lvl b{font-family:var(--font-display);font-weight:400;font-size:40px;line-height:1}
.rl-menu .m-xp-col{flex:1;margin-left:22px}
.rl-menu .m-xp-top{justify-content:space-between;font-size:30px}
.rl-menu .m-xp-top span:first-child{font-weight:600;letter-spacing:.04em;color:var(--ink-2)}
.rl-menu .m-xp-top span:last-child{color:var(--ink-3)}
.rl-menu .m-xp-bar{margin-top:14px;height:22px;border-radius:999px;background:var(--paper-2);overflow:hidden}
.rl-menu .m-xp-fill{height:100%;border-radius:999px;background:var(--brick-lime);width:3%}

/* The tile ring. Same eleven tiles, same colours and same order as the hero
   ring in index.html — the menu draws this ring too, so they must agree. */
.rl-menu .m-ring{position:absolute;left:0;right:0;top:272px;height:230px}
.rl-menu .m-ring .rl-t{position:absolute;margin:calc(var(--t-size) / -2) 0 0 calc(var(--t-size) / -2)}

.rl-menu .m-title{position:absolute;left:0;right:0;top:534px;text-align:center;
  font-family:var(--font-display);font-weight:400;font-size:66px;letter-spacing:.01em}
.rl-menu .m-tag{position:absolute;left:0;right:0;top:612px;text-align:center;font-size:32px;color:var(--ink-2)}

.rl-menu .m-cta{position:absolute;left:40px;right:40px;top:668px;height:180px;gap:20px}
.rl-menu .m-cta .rl-btn{flex:1;height:100%;gap:6px}
.rl-menu .m-cta .m-glyph{font-size:44px;line-height:1}
.rl-menu .m-cta b{font-family:var(--font-display);font-weight:400;font-size:46px;line-height:1}
.rl-menu .m-cta i{font-style:normal;font-weight:600;font-size:26px;letter-spacing:.04em}
.rl-menu .m-play{--b-face:var(--brick-green);--b-side:var(--brick-green-dark);color:var(--paper)}
.rl-menu .m-practice{--b-face:#7396C8;--b-side:#1C58A7;color:var(--g-ink)}

/* Bottom of the card is pinned above the footer rather than left to grow: with
   the board populated (the empty "No players yet!" state is what a fresh local
   DB shows, not what a visitor meets) three rows would otherwise run under the
   footer row. */
.rl-menu .m-card{position:absolute;left:40px;right:40px;top:866px;bottom:156px;padding:22px 30px;
  border-radius:28px;background:var(--paper);box-shadow:0 8px 24px rgba(31,26,20,.10)}
.rl-menu .m-card-head{justify-content:space-between;margin-bottom:12px}
.rl-menu .m-card-head b{font-family:var(--font-display);font-weight:400;font-size:36px}
.rl-menu .m-card-head>span{display:flex;align-items:center;gap:4px;font-weight:600;font-size:30px;
  color:var(--brick-violet-dark)}
.rl-menu .m-lb-row{gap:18px;height:56px;font-size:30px}
.rl-menu .m-lb-row .m-rank{width:26px;color:var(--ink-3)}
.rl-menu .m-lb-row .m-name{flex:1;font-weight:600}
.rl-menu .m-lb-row .m-wins{color:var(--ink-2);font-weight:600}

.rl-menu .m-foot{position:absolute;left:40px;right:40px;bottom:44px;height:88px;gap:20px}
.rl-menu .m-soon{flex:1;height:100%;border-radius:20px;background:var(--paper-2);color:var(--ink-3);
  display:flex;align-items:center;justify-content:center;gap:14px;font-weight:600;font-size:32px}
.rl-menu .m-gear{width:88px;height:88px;border-radius:20px;border:3px solid var(--ink);
  display:flex;align-items:center;justify-content:center}

/* =========================================================================
   Screen 1b — the play blade (scripts/play_blade.gd)
   ========================================================================= */
.rl-blade{pointer-events:none}
/* Scrim: ink at 0.52, faded in over Motion.QUICK (play_blade.gd:47-56). */
.rl-blade .b-scrim{position:absolute;inset:0;background:rgba(31,26,20,.52);opacity:0}
/* Sheet: 40px top corners, 30px side padding, -8px/30px shadow (play_blade.gd:78-89).
   It rises from below over Motion.BASE with POP easing. */
.rl-blade .b-sheet{position:absolute;left:0;right:0;bottom:0;
  padding:16px 30px 56px;border-radius:40px 40px 0 0;background:var(--paper);
  box-shadow:0 -8px 30px rgba(31,26,20,.28);transform:translateY(100%)}
.rl-blade .b-grab{width:54px;height:6px;border-radius:999px;background:var(--paper-3);margin:0 auto 18px}
.rl-blade .b-eyebrow{font-size:26px;font-weight:600;letter-spacing:.06em;color:var(--brick-green-dark)}
.rl-blade .b-title{font-family:var(--font-display);font-weight:400;font-size:48px;margin:8px 0 0}
/* pre-line: the sub-heading is two authored lines in play_blade.gd, not a wrap. */
.rl-blade .b-sub{font-size:28px;line-height:1.35;color:var(--ink-3);margin:10px 0 0;white-space:pre-line}
.rl-blade .b-close{position:absolute;right:30px;top:52px;width:52px;height:52px;border-radius:50%;
  background:var(--paper-2);color:var(--ink-2);display:flex;align-items:center;justify-content:center;font-size:30px}
.rl-blade .b-rows{margin-top:22px}
/* Row geometry is set so the widest meta line — Gold's "Free-for-all · 4P · 45s
   · 5 words" — holds ONE line, as it does in the live blade. If it wraps, the
   row grows past its height and the rows visibly collide, so the gaps and the
   medal/token/chevron widths below are load-bearing, not decoration. */
.rl-blade .b-row{position:relative;gap:16px;height:145px;margin-top:14px;padding:0 16px;
  border-radius:24px;background:var(--paper-2);
  transition:transform var(--r-fast) var(--r-glide)}
.rl-blade .b-row.is-pressed{transform:scale(.985)}
.rl-blade .b-medal{width:70px;height:70px;border-radius:50%;display:flex;align-items:center;justify-content:center}
.rl-blade .b-txt{flex:1;min-width:0}
.rl-blade .b-txt b{display:block;font-family:var(--font-display);font-weight:400;font-size:34px}
.rl-blade .b-txt span{display:block;margin-top:4px;font-size:28px;color:var(--ink-3);white-space:nowrap}
.rl-blade .b-txt i{display:flex;align-items:center;gap:8px;margin-top:4px;font-style:normal;font-size:28px;
  color:var(--ink-2);font-weight:600}
.rl-blade .b-token{gap:6px;height:48px;padding:0 12px;border-radius:999px;background:var(--paper);
  font-size:26px;color:var(--ink-3)}
.rl-blade .b-go{width:58px;height:58px;border-radius:50%;background:var(--brick-green);color:var(--paper);
  display:flex;align-items:center;justify-content:center}
/* Bronze's tilted "Free!" luggage tag — the row's only free signal, so it leads
   the row rather than sitting quietly beside it (play_blade.gd:14-28). */
.rl-blade .b-free{width:120px;height:83px;transform:rotate(-24deg);
  display:flex;align-items:center;justify-content:flex-end;padding-right:14px;
  border-radius:12px 42px 42px 12px;background:var(--brick-green-light);
  color:#14351F;font-family:var(--font-display);font-size:30px;
  box-shadow:0 4px 0 var(--brick-green),0 6px 10px rgba(31,26,20,.18)}
.rl-blade .b-free::before{content:"";position:absolute;left:14px;width:14px;height:14px;border-radius:50%;
  background:var(--paper)}

/* =========================================================================
   Screen 1c — matchmaking (scripts/matchmaking.gd)
   ========================================================================= */
/* Background is the league's pale leaderboard band tint (_set_league_background);
   reel.js sets --mm-bg per league. Platinum's is #E6F0F3. */
.rl-mm{background:var(--mm-bg);color:var(--ink)}
.rl-mm .mm-top{position:absolute;left:40px;right:40px;top:52px;height:44px;justify-content:space-between}
.rl-mm .mm-cancel{font-size:32px;color:var(--brick-violet)}
.rl-mm .mm-league{font-family:var(--font-display);font-weight:400;font-size:36px}
.rl-mm .mm-dots{font-size:30px;color:var(--ink-4);letter-spacing:.1em}
.rl-mm .mm-h1{position:absolute;left:34px;top:126px;width:420px;
  font-family:var(--font-display);font-weight:400;font-size:54px;line-height:1.3}
.rl-mm .mm-count{position:absolute;right:40px;top:186px;font-size:30px;color:var(--ink-3);letter-spacing:.04em}
.rl-mm .mm-count b{font-family:var(--font-display);font-weight:400;font-size:38px;color:var(--ink)}
/* The ring: RING_DIAMETER 440, TILE_SIZE 110, LETTER_FONT 76 (matchmaking.gd:28-32). */
.rl-mm .mm-ring{position:absolute;left:0;right:0;top:340px;height:640px}
.rl-mm .mm-slot{position:absolute;display:flex;flex-direction:column;align-items:center;gap:10px;
  transform:translate(-50%,-50%) scale(0);opacity:0}
.rl-mm .mm-slot .mm-name{padding:4px 16px;border-radius:999px;background:var(--g-paper);
  font-size:26px;color:var(--ink-2);white-space:nowrap}
.rl-mm .mm-slot.is-you .mm-name{background:var(--ink);color:var(--paper)}
/* Lifted above dead-centre so "EVERYONE'S IN" clears the name pills of the two
   avatars flanking the bottom of the ring. */
.rl-mm .mm-hub{position:absolute;left:50%;top:50%;transform:translate(-50%,-62%);text-align:center}
.rl-mm .mm-hub b{display:block;font-family:var(--font-display);font-weight:400;font-size:96px;line-height:1;
  color:var(--g-ink)}
.rl-mm .mm-hub span{display:block;margin-top:6px;font-size:30px;color:var(--ink-3)}
.rl-mm .mm-hub i{display:block;margin-top:2px;font-style:normal;font-size:28px;font-weight:600;
  letter-spacing:.04em;color:var(--ink-2);opacity:0}
.rl-mm .mm-strip{position:absolute;left:34px;right:34px;top:996px;height:120px;
  border-radius:18px;background:var(--g-paper-2);overflow:hidden}
/* Column widths are the ones measured off the live 720-wide screen (195/122/168/
   168 across the strip's 652px interior), not four equal quarters: equal columns
   wrap "STARTER WORD" and clip "STACK ORDER"/"WORD LIMIT". */
.rl-mm .mm-col{flex:0 0 auto;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:6px;padding:0 8px;box-shadow:1px 0 0 rgba(27,42,52,.10)}
.rl-mm .mm-col:nth-child(1){width:195px}
.rl-mm .mm-col:nth-child(2){width:122px}
.rl-mm .mm-col:nth-child(3){width:168px}
.rl-mm .mm-col:nth-child(4){width:168px}
.rl-mm .mm-col:last-child{box-shadow:none}
.rl-mm .mm-col span{font-size:24px;letter-spacing:.05em;color:var(--ink-3);text-transform:uppercase;white-space:nowrap}
.rl-mm .mm-col b{white-space:nowrap}
.rl-mm .mm-col b{font-family:var(--font-display);font-weight:400;font-size:36px}
.rl-mm .mm-col.is-num b{font-family:var(--font-body);font-weight:600;font-size:34px}
.rl-mm .mm-start{position:absolute;left:34px;right:34px;bottom:52px;height:104px;
  --b-face:var(--brick-green);--b-side:var(--brick-green-dark);color:var(--paper)}
.rl-mm .mm-start b{font-family:var(--font-display);font-weight:400;font-size:40px}

/* =========================================================================
   Screen 2 — the round (scenes/wourdoboros_round.tscn, wourdoboros_round.gd)

   Cool neutrals here, not the warm menu paper: this screen resolves its
   background through BrickTile.PAPER = LDraw WHITE. See the header note.
   ========================================================================= */
.rl-round{background:var(--g-paper);color:var(--g-ink)}
.rl-round .r-phase{position:absolute;left:20px;right:20px;top:38px;height:76px;justify-content:space-between}
.rl-round .r-title{font-family:var(--font-display);font-weight:400;font-size:56px;line-height:1}
.rl-round .r-right{gap:22px}
.rl-round .r-time{font-size:52px;color:var(--g-ink);font-variant-numeric:tabular-nums}
.rl-round .r-cog{width:62px;height:62px;border-radius:16px;border:3px solid var(--g-ink);
  display:flex;align-items:center;justify-content:center}
/* TimerStrip + TimerFill: a flat green bar draining left to right. */
.rl-round .r-strip{position:absolute;left:20px;right:20px;top:124px;height:14px;border-radius:4px;
  background:#E3E4E5;overflow:hidden}
.rl-round .r-fill{height:100%;background:var(--brick-green);width:100%;transform-origin:0 50%}
.rl-round .r-meta{position:absolute;left:20px;right:20px;top:152px;height:40px;justify-content:space-between}
.rl-round .r-players{font-size:30px;color:var(--g-ink-3)}
/* The legend: one dot per player, and the sonar ripple for a submission pings
   from the dot of whoever submitted (SonarEffect, project-overview.md:609). */
.rl-round .r-legend{gap:12px}
.rl-round .r-dot{position:relative;width:16px;height:16px;border-radius:50%}
.rl-round .r-sonar{position:absolute;left:50%;top:50%;width:16px;height:16px;margin:-8px 0 0 -8px;
  border-radius:50%;border:3px solid currentColor;opacity:0;pointer-events:none}
.rl-round .r-starter{position:absolute;left:20px;right:20px;top:204px;text-align:center}
.rl-round .r-eyebrow{font-size:26px;letter-spacing:.14em;color:var(--g-ink-3);text-transform:uppercase}
.rl-round .r-band{justify-content:center;gap:10px;margin-top:16px}
/* Body: SUBS rail | word card + pool + actions | STACK rail. */
.rl-round .r-body{position:absolute;left:20px;right:20px;top:326px;bottom:30px;align-items:stretch;gap:8px}
/* Rail width 128 and pool tiles at 92 are the measured live widths (LeftRail
   x14..142, pool tiles 92 on a 96 pitch): the three columns have to add up to
   720, so shrinking a rail silently shrinks the pool. */
/* A flex column so the lists below can take the leftover height and clip their
   own tails — the clip belongs to the list, not the rail: on the rail it also
   ate the count badge, which deliberately overhangs the rail's edge. */
.rl-round .r-rail{width:128px;flex:0 0 auto;border-radius:14px;background:var(--g-paper-2);padding:14px 10px;
  display:flex;flex-direction:column}
.rl-round .r-rail-head{gap:8px;align-items:center}
.rl-round .r-rail-head span{font-size:28px;color:var(--g-ink-3)}
.rl-round .r-count{min-width:44px;height:44px;padding:0 8px;border-radius:999px;background:var(--g-ink);
  color:var(--g-paper);font-size:26px;font-weight:600;justify-content:center}
.rl-round .r-subs{flex-direction:column;gap:4px;margin-top:16px;align-items:center;
  flex:1;min-height:0;overflow:hidden}
.rl-round .r-sub-word{font-size:26px;color:var(--g-ink);letter-spacing:.02em}
.rl-round .r-sub-score{font-size:24px;color:var(--brick-green-dark);font-weight:600}
.rl-round .r-center{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center}
.rl-round .r-card{align-self:stretch;border-radius:20px;background:var(--g-paper);padding:18px 22px 22px;
  box-shadow:0 4px 14px rgba(27,42,52,.08)}
.rl-round .r-slots{justify-content:center;gap:3px;margin-top:14px}
.rl-round .r-slot{width:44px;height:52px;border-radius:10px;background:#EBECEC}
.rl-round .r-pool{display:grid;grid-template-columns:repeat(4,92px);gap:6px;margin-top:24px}
/* Pool tiles sit at 96% brightness while unspent — sampled #CEB286 against the
   starter band's #D7BA8C. A pressed tile sinks onto its own side wall like the
   buttons do; while its letter is in the word it drops out of the pool. */
.rl-round .r-pool .rl-t{filter:brightness(.96);
  transition:opacity var(--r-fast) linear,filter var(--r-fast) linear,
             transform var(--r-fast) var(--r-glide)}
.rl-round .r-pool .rl-t.is-pressed{transform:translateY(calc(var(--t-wall) * 0.6))}
.rl-round .r-pool .rl-t.is-spent{opacity:.28;filter:none}
.rl-round .r-actions{align-self:stretch;gap:16px;margin-top:26px}
.rl-round .r-clear{width:78px;height:78px;flex:0 0 auto}
.rl-round .r-submit{flex:1;height:78px;--b-face:var(--brick-yellow);--b-side:var(--brick-yellow-dark);
  color:var(--g-ink-2);font-size:34px}
.rl-round .r-left{margin-top:18px;font-size:28px;color:var(--g-ink-3)}
/* The stack's tail is clipped here so a deep stack never spills over the rest of
   the screen (project-overview.md, "Stack rail"). */
.rl-round .r-stack{flex-direction:column;gap:10px;margin-top:16px;align-items:stretch;
  flex:1;min-height:0;overflow:hidden}
/* A stack entry is BrickTile.make_tile("", colour, 54) stretched by its VBox, so
   it reads as a squat disc rather than a square tile. */
.rl-round .r-stack .rl-t{width:auto;--t-size:54px;height:54px}

/* =========================================================================
   Screen 3 — the chain recap (scenes/wourdoboros_results.tscn,
   wourdoboros_results.gd). Same cool neutrals as the round.
   ========================================================================= */
.rl-recap{background:var(--g-paper);color:var(--g-ink)}
.rl-recap .c-head{position:absolute;left:22px;right:22px;top:88px;align-items:flex-end;
  justify-content:space-between}
.rl-recap .c-eyebrow{font-size:26px;letter-spacing:.06em;color:var(--g-ink-3);text-transform:uppercase}
.rl-recap .c-title{font-family:var(--font-display);font-weight:400;font-size:44px;margin-top:6px}
.rl-recap .c-standing{gap:10px;font-size:30px;color:var(--g-ink-3)}
.rl-recap .c-standing b{font-family:var(--font-display);font-weight:400;font-size:32px;color:var(--g-ink)}
.rl-recap .c-chip{width:18px;height:18px;border-radius:50%}
/* Racetrack: the strip the popped players travel along, one avatar dot per
   remaining stack entry, with the chequered finish at the right end. */
.rl-recap .c-track{position:absolute;left:22px;right:22px;top:194px;height:36px;border-radius:8px;
  background:var(--g-paper-2)}
.rl-recap .c-track i{position:absolute;left:48px;top:8px;width:3px;height:20px;background:var(--g-ink-4);
  font-style:normal}
.rl-recap .c-flag{position:absolute;right:0;top:0;width:36px;height:36px;border-radius:0 8px 8px 0;
  background-image:linear-gradient(45deg,var(--g-ink-4) 25%,transparent 25%,transparent 75%,var(--g-ink-4) 75%),
                   linear-gradient(45deg,var(--g-ink-4) 25%,transparent 25%,transparent 75%,var(--g-ink-4) 75%);
  background-size:12px 12px;background-position:0 0,6px 6px;opacity:.55}
.rl-recap .c-runner{position:absolute;top:4px;width:28px;height:28px;border-radius:50%;
  box-shadow:0 0 0 3px var(--g-paper)}
/* Sits under the racetrack (top 194 + height 36), pointing at the local
   player's runner — not floating up by the header. */
.rl-recap .c-you{position:absolute;top:236px;left:196px;padding:4px 14px;border-radius:8px;
  background:var(--g-ink);color:var(--g-paper);font-size:26px;font-weight:600;z-index:2}
.rl-recap .c-chain{position:absolute;left:22px;right:22px;top:240px}
.rl-recap .c-chain-eyebrow{justify-content:center;gap:12px;font-size:26px;letter-spacing:.1em;
  color:var(--g-ink-3);text-transform:uppercase}
.rl-recap .c-band{justify-content:center;gap:8px;margin-top:14px}
/* Stage + StackRail. The stage is the camera's world: SCAN/MATCH zoom it onto a
   card by translating and scaling this element, so the cards themselves never
   move relative to each other. */
.rl-recap .c-body{position:absolute;left:22px;right:22px;top:352px;bottom:196px;align-items:stretch;gap:8px}
.rl-recap .c-stage{position:relative;flex:1;min-width:0;border-radius:18px;background:var(--g-paper-2);
  overflow:hidden}
.rl-recap .c-world{position:absolute;inset:0;transform-origin:50% 50%}
.rl-recap .c-card{position:absolute;width:340px;padding:18px 20px 20px;border-radius:20px;
  background:var(--g-paper);box-shadow:0 10px 26px rgba(27,42,52,.16);
  transition:filter var(--r-base) linear,opacity var(--r-base) linear}
/* Everything the camera is not looking at goes soft — the recap's own
   depth-of-field, which is what makes a zoom read as a camera move. */
.rl-recap .c-card.is-far{filter:blur(3px);opacity:.55}
.rl-recap .c-card-head{gap:14px}
.rl-recap .c-card-head .c-who{flex:1;min-width:0}
.rl-recap .c-card-head b{display:block;font-family:var(--font-display);font-weight:400;font-size:32px}
.rl-recap .c-card-head span{display:block;font-size:26px;color:var(--g-ink-3);letter-spacing:.04em}
.rl-recap .c-score{text-align:right}
.rl-recap .c-score b{display:block;font-size:30px;font-weight:600}
.rl-recap .c-score span{display:block;font-size:24px;color:var(--g-ink-3);letter-spacing:.06em}
/* A word row: _apply_row_state (wourdoboros_results.gd:2338) — default PAPER_2,
   "match" LDraw LIGHT_GREEN with a 4px WOURDO_GREEN border and a PLAYS flag,
   "used" faded to 40% with a USED flag. */
.rl-recap .c-word{position:relative;gap:6px;margin-top:10px;padding:8px 10px;border-radius:12px;
  background:var(--g-paper-2);border:4px solid transparent;
  transition:background var(--r-base) linear,border-color var(--r-base) linear,opacity var(--r-base) linear}
.rl-recap .c-word.is-match{background:#ADDDA8;border-color:var(--brick-green)}
.rl-recap .c-word.is-used{opacity:.4}
/* In flow and pushed right, not absolutely positioned: the flag is ~80px wide
   at this size, so any hand-reserved padding is a number that goes wrong the
   moment the text changes ("PLAYS" -> "USED") and the row overlaps it. */
.rl-recap .c-flagtxt{margin-left:auto;padding-left:8px;font-size:22px;font-weight:700;letter-spacing:.08em;
  color:var(--brick-green-dark);opacity:0;white-space:nowrap}
.rl-recap .c-word.is-match .c-flagtxt{opacity:1}
.rl-recap .c-word.is-used .c-flagtxt{opacity:1;color:var(--g-ink-4)}
/* "No matches!" toast — the PASS scene's whole event (_flash_no_match_toast). */
.rl-recap .c-toast{position:absolute;left:50%;top:-18px;transform:translate(-50%,0);
  padding:8px 20px;border-radius:12px;background:var(--g-ink);color:var(--g-paper);
  font-size:26px;font-weight:600;white-space:nowrap;opacity:0}
.rl-recap .c-rail{width:112px;flex:0 0 auto;border-radius:18px;background:var(--g-paper-2);
  padding:14px 10px;display:flex;flex-direction:column;align-items:stretch;gap:10px;overflow:hidden}
.rl-recap .c-rail-head{flex-direction:column;gap:8px;align-items:center}
.rl-recap .c-rail-head span{font-family:var(--font-display);font-weight:400;font-size:30px;color:var(--g-ink-3)}
.rl-recap .c-count{min-width:52px;height:52px;border-radius:999px;background:var(--g-ink);color:var(--g-paper);
  font-size:28px;font-weight:600;justify-content:center}
.rl-recap .c-discs{flex-direction:column;gap:10px;align-items:stretch}
.rl-recap .c-discs .rl-t{width:auto;--t-size:54px;height:54px}
/* The disc the replay is on right now takes the highlight ring
   (_add_highlight_ring). */
.rl-recap .c-discs .rl-t.is-current{outline:4px solid var(--g-ink);outline-offset:3px}
.rl-recap .c-banner{position:absolute;left:22px;right:22px;bottom:118px;height:66px;gap:16px;
  padding:0 24px;border-radius:14px;background:#E5E6E7}
.rl-recap .c-banner .c-chip{width:20px;height:20px}
.rl-recap .c-banner span{font-size:30px;color:var(--g-ink)}
.rl-recap .c-controls{position:absolute;left:22px;right:22px;bottom:30px;height:72px;gap:14px}
.rl-recap .c-ctl{width:72px;height:72px;flex:0 0 auto}
.rl-recap .c-ctl.is-play{--b-face:var(--brick-yellow);--b-side:var(--brick-yellow-dark);
  border-radius:14px;color:var(--g-ink-2)}
.rl-recap .c-scrub{flex:1;height:10px;border-radius:999px;background:var(--g-ink-4);opacity:.5;position:relative}
.rl-recap .c-scrub i{position:absolute;top:-7px;width:24px;height:24px;border-radius:50%;
  background:var(--g-paper);box-shadow:0 0 0 3px var(--g-ink-4);font-style:normal}
