/* --------------------------------------------------------------------------
   Play area
   -------------------------------------------------------------------------- */
.wf-arena {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--wc-gap);
}

/* --------------------------------------------------------------------------
   Standings beside the board — wide screens only
   -------------------------------------------------------------------------- */
/* The board column keeps its exact width and the rail is given its own track,
   so turning standings on never resizes a tile. Below this width everything
   returns to one column and the rail stacks under the board, where it is the
   compact three-column table rather than the full dashboard. */
/* The rail sits BELOW the board at every width. It briefly lived beside it on
   wide screens; that pulled the eye sideways during a round and made the game
   feel like a spreadsheet with a puzzle attached. Standings belong where you
   look when you have finished, not where you look while you are guessing —
   and at the end of a round they get the popup instead. */

.wf-rail { width: 100%; min-width: 0; }
/* the tinted winner row runs to the edge of the rail, so the points need a
   little air or they sit hard against it */
.wf-rail .wf-table td.c-pts,
.wf-rail .wf-table th.c-num { padding-right: 8px; }
.wf-rail h3 {
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--muted);
  margin: 0 0 8px;
}
/* Stacked under the board on a phone, where the one-screen rule still holds:
   points only, tight rows, and no time column. */
@media (max-width: 61.99rem) {
  .wf-rail { margin-top: 2px; }
  .wf-rail .wf-table td { padding: 5px 8px 5px 0; font-size: 11px; }
}
.wf-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--wc-gap);
  width: 100%;
}

.wf-board {
  display: flex;
  flex-direction: column;
  gap: var(--wc-tgap);
  /* the handoff's width formula, plus a height term so six rows and the
     keyboard still fit a 640px screen */
  --wc-fit: calc(100svh - var(--wc-head) - (3 * var(--wc-key) + 2 * var(--wc-kgap))
                 - var(--wc-actions) - (3 * var(--wc-gap)) - (2 * var(--wc-pad)) - 10px);
  --wc-tile: min(
    60px,
    calc((100vw - 84px) / 5),
    calc((var(--wc-fit) - 5 * var(--wc-tgap)) / 6)
  );
}
.wf-row { display: flex; gap: var(--wc-tgap); }
.tile {
  /* Height is stated outright rather than left to aspect-ratio: a flex item
     will not shrink below its content, so the moment a letter appeared the row
     grew to fit the glyph and the whole board shifted. Size is fixed, and the
     letter is sized from the tile — never from the viewport. */
  width: var(--wc-tile);
  height: var(--wc-tile);
  flex: none;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border: 2px solid var(--tile-bd);
  border-radius: 9px;
  background: transparent;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: calc(var(--wc-tile) * 0.52);
  line-height: 1;
  font-weight: 700;
  transition: transform 0.22s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.tile.t-fill {                       /* a letter typed, not yet judged */
  background: var(--tile-fill);
  border-color: var(--tile-bd-fill);
}
.tile.is-flipped { transform: rotateX(90deg); }
.tile.t-c { background: var(--correct); border-color: var(--correct); color: var(--on-correct); }
.tile.t-p { background: var(--present); border-color: var(--present); color: var(--on-present); }
.tile.t-a { background: var(--absent);  border-color: var(--absent);  color: var(--on-absent); }

/* The cursor: not in the prototype, asked for twice. A ring on the tile that
   takes the next letter, in the accent so it reads at a glance. */
.wf-row.is-active .tile.is-cursor {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.tile.pop { animation: wcpop 0.13s ease; }
@keyframes wcpop {
  0% { transform: scale(1); }
  50% { transform: scale(1.12); }
  100% { transform: scale(1); }
}
.wf-row.shake { animation: wcshake 0.5s ease; }
@keyframes wcshake {
  0%, 100% { transform: translateX(0); }
  15%, 45%, 75% { transform: translateX(-6px); }
  30%, 60%, 90% { transform: translateX(6px); }
}
.wf-row.is-win .tile { animation: wcwin 0.85s ease; }
@keyframes wcwin {
  0%, 100% { transform: translateY(0); }
  30% { transform: translateY(-16px); }
  55% { transform: translateY(2px); }
  75% { transform: translateY(-7px); }
}

/* --------------------------------------------------------------------------
   Toast — sits above the board, sticky for the end of a round
   -------------------------------------------------------------------------- */
/* Under the board, never across it. Sitting on top of the grid it covered the
   very rows it was talking about — you were told the word while the word was
   hidden behind the message. Absolutely positioned still, so appearing and
   disappearing cannot move the board a pixel. */
.wf-boardwrap { position: relative; display: flex; flex-direction: column; align-items: center; }
.wf-toast {
  position: absolute;
  top: calc(100% + 8px);      /* the board's own bottom edge, any tile size */
  left: 50%;
  display: flex;
  justify-content: center;
  white-space: nowrap;
  pointer-events: none;
  z-index: 5;
  margin: 0;
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 0.22s ease, transform 0.22s ease;
}
.wf-toast { transform: translate(-50%, 8px); }
.wf-toast.is-on { opacity: 1; transform: translate(-50%, 0); }
.wf-toast span {
  background: var(--ink);
  color: var(--bg);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  padding: 10px 18px;
  border-radius: 9px;
  box-shadow: var(--shadow-toast);
  text-align: center;
}

/* --------------------------------------------------------------------------
   Keyboard
   -------------------------------------------------------------------------- */
/* The openers this round will not take, on the line directly above the keys.
   Struck through, because that is what the plan asked for and it is the one
   treatment that says "this word, but not now" without a sentence.

   Muted rather than warning-coloured: it is a rule of the round, not something
   going wrong, and the accent belongs to the clock running out. The label
   carries the meaning in words as well, so the strike is never the only
   channel — a strikethrough alone is a shape, and shapes do not survive being
   read aloud. */
.wf-bans {
  display: flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: 0 0 var(--wc-kgap);
  text-align: center;
}
.wf-bans .k {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--muted);
}
/* The line is on each WORD, never on the row. Struck as one string it runs
   through the spaces as well, and three banned words come out looking like a
   single struck sentence — which is not what the row says. */
.wf-bans .v {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 12px;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.wf-bans .w {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}
.wf-kb { width: 100%; display: flex; flex-direction: column; gap: var(--wc-kgap); }
.kb-row { display: flex; gap: var(--wc-kgap); justify-content: center; }
.key {
  flex: 1;
  min-width: 0;
  height: var(--wc-key);
  /* the handoff draws keys with no border; on cream they read as one soft mass,
     so each key gets a measured edge of its own */
  border: 1px solid var(--key-bd);
  border-radius: 8px;
  background: var(--key-bg);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  box-shadow: var(--shadow-key);
  transition: background-color 0.15s ease, filter 0.1s ease;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}
.key.wide { flex: 1.6; font-size: 11px; letter-spacing: 0.06em; }
.key:hover { filter: brightness(0.96); }
.key:active { transform: translateY(1px); box-shadow: none; }
.key.k-c { background: var(--correct); border-color: var(--correct); color: var(--on-correct); }
.key.k-p { background: var(--present); border-color: var(--present); color: var(--on-present); }
.key.k-a { background: var(--absent);  border-color: var(--absent);  color: var(--on-absent); }

/* Five letters are in and the guess can be submitted. The ENTER key fills with
   the accent and breathes once a second — the one place a first-timer looks
   when they have typed a word and nothing has happened. Colour is not the only
   channel: the key also gains a visible ring, and its accessible name changes.
   Sized identically to the resting key so the keyboard never reflows. */
.key.wide.is-armed {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-status);
  box-shadow: var(--shadow-key), 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent);
  animation: wcarm 1.15s ease-in-out infinite;
}
@keyframes wcarm {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.14); }
}

/* The same news, said where the eye already is: a return glyph beside the row
   that is ready to go. Absolutely positioned, so a full row cannot nudge the
   board — the layout is fixed by the tiles alone. Hidden where there is no
   room beside the board, since the ENTER key carries the message there. */
.wf-row { position: relative; }
.wf-row.is-ready::after {
  content: "\21B5";
  position: absolute;
  left: 100%;
  top: 0;
  height: 100%;
  width: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: calc(var(--wc-tile) * 0.44);
  line-height: 1;
  color: var(--accent-text);
  pointer-events: none;
  animation: wcnudge 1.15s ease-in-out infinite;
}
@keyframes wcnudge {
  0%, 100% { opacity: 0.45; transform: translateX(0); }
  50%      { opacity: 1;    transform: translateX(3px); }
}
@media (max-width: 34rem) {
  .wf-row.is-ready::after { display: none; }
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.wf-actions { display: flex; gap: 12px; justify-content: center; margin-top: 2px; flex-wrap: wrap; }
/* The studio's chamfered button, at this screen's sizes. Everything about the
   edge and the ring comes from site.css: the element's background IS the
   boundary and ::before carries the fill, with `clip-path: inherit` so the
   smaller chamfer set here flows straight through. Only sizes and colours
   belong in this file. */
.page-play .btn {
  padding: 13px 26px;
  border-radius: 0;
  line-height: 1;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: none;
  clip-path: polygon(0 0, calc(100% - 11px) 0, 100% 11px, 100% 100%, 11px 100%, 0 calc(100% - 11px));
  transition: transform 0.12s ease, background 0.15s ease, color 0.15s ease;
}
.page-play .btn-primary {
  background: var(--ink);            /* only ever seen as the focus ring */
  color: var(--on-status);
  box-shadow: none;
}
.page-play .btn-primary::before {
  background: linear-gradient(135deg, var(--accent), var(--accent-dark));
}
.page-play .btn-primary:hover { transform: none; }
.page-play .btn-primary:hover::before { filter: brightness(1.07); }
.page-play .btn-primary:active { transform: translateY(1px); }

/* --btn-edge, not --rule: --rule draws the hairlines between things and has to
   stay faint, while a button needs a boundary you can see from across the
   room — near-black on the cream theme, matching the studio site. */
.page-play .btn-quiet {
  background: var(--btn-edge);
  color: var(--ink);
  box-shadow: none;
}
.page-play .btn-quiet::before {
  inset: 1.5px;
  background: var(--chip);
}
.page-play .btn-quiet:hover {
  color: var(--accent-text);
  background: var(--accent);
  transform: none;
}
.page-play .btn-quiet:hover::before { background: var(--chip); }
.page-play .btn-quiet:active { transform: translateY(1px); }
.page-play .btn:focus-visible { background: var(--accent); box-shadow: none; }
.page-play .btn-primary:focus-visible { background: var(--ink); }
.page-play .btn:focus-visible::before { inset: 3.5px; }
/* programmatic jump targets, not controls — they must not paint a ring */
#wf-game:focus, #wf-game:focus-visible,
#wf-actions:focus, #wf-actions:focus-visible,
#setup-h:focus, #setup-h:focus-visible,
#lobby-instruction:focus, #lobby-instruction:focus-visible { outline: none; }
.page-play .btn[disabled] { opacity: 0.55; cursor: default; }


/* --------------------------------------------------------------------------
   What solving right now would be worth

   Half of paying for speed is being able to watch it go, so the sum and the
   bar under it redraw on the countdown's own tick. Every colour is a token,
   mixed from --accent rather than picked: a literal here would stay the same
   shade when the cream theme moved around it, which is exactly how the support
   board ended up with one alien chip on it.

   The bar is the only thing that animates, and only its width, so a redraw
   four times a second costs the compositor nothing.
   -------------------------------------------------------------------------- */

.wf-preview {
  width: 100%;
  margin-top: 6px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.wf-preview-line {
  margin: 0;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-mono);
  line-height: 1;
}

.wf-preview-label {
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--muted);
}

.wf-preview-sum {
  font-size: 15px;
  font-variant-numeric: tabular-nums;   /* so it does not jitter as it drains */
  color: var(--accent-text);
}

.wf-drain {
  width: 100%;
  height: 3px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  overflow: hidden;
}

.wf-drain-fill {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: inherit;
  background: var(--accent);
  /* Follows the tick rather than easing between them: a transition longer than
     the 250ms redraw would always be chasing a value it never reaches. */
  transition: width 200ms linear;
}

/* THE DRAIN, IN FOUR STATES. §1.3 asks for ticks at 75/50/25 and only the last
   was written — as `--accent-2`, which wordcrew.base.css points straight back
   at `--accent` for this page, so the one tick there was repainted the fill the
   colour it already had. A bar that only ever changes width is a bar nobody
   reads while they are thinking about a word.

   The game's own three tile colours, in the order they already mean something
   in: plenty, getting on, nearly gone — then `--accent-dark` for the last
   quarter, which is where the clock's second beep lands, so the bar and the
   sound say one thing rather than two. Real tokens rather than mixes, because
   this bar is three pixels tall and a mix of two oranges at that height is a
   state change nobody can see. No pulse and no animation: the last quarter of
   a Classic round is forty-five seconds, and forty-five seconds of a throbbing
   bar is the hospital drama the countdown beep was rejected for. */
.wf-drain[data-tick="0"] .wf-drain-fill { background: var(--correct); }
.wf-drain[data-tick="1"] .wf-drain-fill { background: var(--present); }
.wf-drain[data-tick="2"] .wf-drain-fill { background: var(--accent); }
.wf-drain[data-tick="3"] .wf-drain-fill { background: var(--accent-dark); }

@media (prefers-reduced-motion: reduce) {
  .wf-drain-fill { transition: none; }
}

/* Who reached the word first. An ordinal rather than a medal emoji: this
   studio does not put emoji in copy, and "1st" is what a screen reader should
   read out anyway. Cosmetic — it ranks the clock and pays nothing. */
.wf-medal {
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.06em;
  vertical-align: middle;
  color: var(--accent-text);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
}
.wf-medal.m1 { background: color-mix(in srgb, var(--accent) 30%, transparent); }

/* WHOSE TURN IT IS, in a relay. Above the keys, where the hand about to type is
   already looking, and carrying the twenty-second countdown after which the row
   opens to the whole team — a rule whose only route to being learned is being
   refused is not a rule anybody can play by.

   Muted when it is somebody else's, accent when it is yours, because "you are
   up" is the one state that has to interrupt a conversation. Tabular digits so
   the countdown does not jiggle the line it sits on. */
.wf-turn {
  margin: 0;
  /* A LOCKED HEIGHT, not a minimum. `min-height` was not enough and measured
     as 2.75px of movement: the taller "your turn" text makes a line box bigger
     than the minimum, so the row grew whenever it had something to say and the
     board slid down with it. Height and line-height are the same fixed number,
     so every state of this row is exactly one line tall and nothing under it
     can move. */
  height: 1.5rem;
  line-height: 1.5rem;
  text-align: center;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
/* Your turn is the one state that has to interrupt a conversation, so it takes
   the accent and a size the corner of an eye can catch. */
.wf-turn.is-yours {
  color: var(--accent-text);
  font-size: 15px;
}
