/* ==========================================================================
   3. THE CONSOLE — three rungs on the ground. WF-UI (work/dice/gauntlet/
   UI-CHOICE.md): the A-horizon winner with grafts B1–B4/C1–C2, replacing
   the two-density console (the 520px "wide" stack / 460px "bar" grid) this
   file held before. WHAT THE REWRITE REPLACED, so the history is not lost
   with the rules:

   - THE 520/460 WIDTH LITERALS ARE DEAD, and "one measure" is why: the
     console now sits on #play's OWN width formula, copied verbatim from
     20-stage.css's #play rule — min(var(--playw), 100% - 2*var(--bpad)) —
     so the two objects share their left and right verticals by
     construction and cannot drift a pixel apart. The 460 was solved
     against a 380px frame's 96%; the 520 was candidate A's approved stack
     measure; both described consoles that no longer exist.
   - data-lay ("wide"/"bar") HAS NO READERS LEFT and layout() no longer
     writes it. The zone wrappers .dkMid/.dkFoot left index.html with the
     stack; .dkTop survives as rail 1's row.
   - THE OLD RUNGS ARE DELETED, NOT OVERRIDDEN — a shipped
     #frame[data-lay="wide"] #balzone .k outranks any class this file could
     write, which is exactly how the first cut of this console would have
     rotted.
   - NO !important ANYWHERE IN THIS FILE: 95-motion.css's reduced-motion
     overrides must stay able to win by cascade order.

   The rungs:
     rail 1   BALANCE $x [delta] ················ MANUAL AUTO
     bar      ⊛ BET AMOUNT ····· $ 1.00 ½ 2× MAX ┃ ROLL / $1.00
     rail 2   MAX BET $x [lever] ················ PRESS [SPACE] / Running…

   The depth budget, stated once (UI-CHOICE §3): the COMMIT and the MODE
   THUMB (80-auto.css) are the only money-material objects, the stake WELL
   is the only inset, everything else is flat. */
/* THE CONSOLE IS A CARD NOW — the owner's third ruling this round: "We can
   have centered with the UI organized in a container." The horizon it
   used to stand on is retired (20-stage.css), so the console gets the
   bounded ground the frame's foot used to lend it: BirdCrash's borderless
   panel grammar (its history chip, linear-gradient(180deg, rgba(11,12,16,
   .9), rgba(20,22,29,.72)), r12 — the house precedent for a gradient
   ground with no stroke), on the game's own measure, centred under the
   game, part of the centred unit. The catch-light chamfer (graft B1) rides
   the card's top edge now — the same inset stroke the horizon carried.
   The INTERNALS are the approved wf-ui console, untouched: the card is a
   ground under them, not a redesign. The game above stays on open sky —
   the frame remains the game's one container.
   --floorpad, the token that was the console's standoff from the horizon,
   is the card's padding now — same density rungs, same writer. */
#dock{min-width:0;min-height:0;position:relative;grid-area:dock;
  /* ONE MEASURE — 20-stage.css:102's formula, copied not paraphrased */
  width:min(var(--playw,760px), 100% - 2*var(--bpad,22px));
  justify-self:center;
  display:grid;grid-template-columns:100%;grid-auto-rows:auto;
  gap:calc(9px*var(--scc,1));align-content:start;
  padding:calc(var(--floorpad,20px)*var(--scc,1)) calc(var(--floorpad,20px)*var(--scc,1)*1.1)
          calc(var(--floorpad,20px)*var(--scc,1)*.9);
  background:linear-gradient(180deg, rgba(20,22,29,.78), rgba(11,12,16,.92));
  border:0;border-radius:calc(16px*var(--scc,1));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.045), 0 18px 44px -18px rgba(0,0,0,.75)}
#frame[data-room="short"] #dock,
#frame[data-room="min"] #dock{--floorpad:14px}
/* the narrow dock repays collision 5's two-row bar (refinement round):
   floorpad 5, gap 4 — with the density rungs in 60-density.css this lands
   the dock at ~100px, the winner's own 380x300 budget */
/* the card keeps its box at the docked minimum but not its full radius —
   16 on a ~110px card reads pill-cornered; 10 is BirdCrash's own small-
   panel step. Padding rides the same --floorpad rung (5px). */
#frame[data-narrow] #dock{--floorpad:5px;gap:4px;border-radius:10px}

/* ---- one caption face for every rail text (UI-CHOICE §3) ----------------
   All rail captions — balance, max bet, press-space, the running readout —
   wear one face, so the three rungs read as one instrument, not three
   opinions about what a label is. --off is #7E8498, the spec's own hex. */
#balzone .k,#capline,.hzSpace,.hzRun{
  font:600 calc(9.5px*var(--scc,1))/1 var(--ui);letter-spacing:.18em;
  text-transform:uppercase;color:var(--off)}

/* ---- rail 1: BALANCE ... MANUAL AUTO ------------------------------------ */
.dkTop{display:flex;align-items:baseline;justify-content:space-between;
  gap:14px;min-height:16px}
#frame[data-narrow] .dkTop{min-height:0}
#balzone{display:flex;align-items:baseline;gap:8px;min-width:0}
#balrow{display:flex;align-items:baseline;gap:8px;min-width:0}
/* 16px: the stake (22px) stays the console's largest figure — the number
   being RISKED outranks the number being held */
#bal{font:700 calc(16px*var(--scc,1))/1.1 var(--fig);font-variant-numeric:tabular-nums;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#dl{font:700 calc(11.5px*var(--scc,1))/1 var(--fig);font-variant-numeric:tabular-nums;opacity:0;
  transition:opacity .2s;white-space:nowrap}
#dl[data-s="up"]{color:var(--win);opacity:1}
#dl[data-s="dn"]{color:var(--loss);opacity:1}
/* R1 item 2 (producer VERDICT): the delta is SUPPRESSED while a roll is in
   flight — settle() is #dl's one writer, so mid-flight the only thing a
   prior round's chip could do here is sit, tenseless, beside a live
   balance. data-rolling leaves on the same synchronous frame settle()
   writes the new delta, so the settle frame brings it back with fresh
   text. (Carried through the wf-ui rewrite verbatim.) */
#frame[data-rolling] #dl{opacity:0}

/* THE TABS ARE WORDS, NOT A PILL — app-mode never wears the money material
   (UI-CHOICE §3): bare uppercase words, the active one white with a 2px
   red underline that springs in. The red segmented pill on the board is a
   BET parameter and keeps its fill; these switch the console's mode and
   stay flat. */
#tabs{display:flex;gap:calc(18px*var(--scc,1));align-self:baseline;
  background:none;border:0;padding:0}
#tabs button{position:relative;padding:0 0 5px;border-radius:0;
  font:700 calc(10.5px*var(--scc,1))/1 var(--ui);letter-spacing:.14em;text-transform:uppercase;
  color:#767C90;transition:color .16s}
#tabs button::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;
  border-radius:2px;background:var(--cp-red);box-shadow:0 0 8px rgba(192,24,12,.55);
  transform:scaleX(0);transform-origin:left;
  transition:transform .22s cubic-bezier(.3,1.35,.4,1)}
#tabs button:hover{color:#C8CDDA}
#tabs button[data-on]{color:#fff}
#tabs button[data-on]::after{transform:scaleX(1)}

/* ---- the bar: the well and the commit, ONE welded object ----------------
   Two cells, both PINNED (graft B4 — B's iter1 lost its CTA to an implicit
   row through a stray grid-area). The field carries no right border and
   the commit squares its left corners: the seam is the weld. The bar's
   own numbers (--barh/--stakefs/--qbw/--ctafs) are declared here at the
   designed size; 60-density.css steps them per data-room (height) and
   data-tiny/data-narrow (width) — never conflated. */
.hzBar{display:grid;grid-template-columns:minmax(0,1fr) clamp(112px,36%,300px);
  height:var(--barh,60px);
  --barh:calc(60px*var(--scc,1));--stakefs:calc(22px*var(--scc,1));--qbw:calc(44px*var(--scc,1));--ctafs:calc(17px*var(--scc,1))}

/* THE FIELD — graft B2, the inset well: "a slot you put money in". The two
   blacks are tokens (--well-hi/--well-lo, 00-tokens.css); background-color
   backs the gradient so the surface never reads transparent to a probe or
   a slow first paint. */
.hzField{grid-column:1;grid-row:1;display:flex;align-items:center;gap:10px;
  min-width:0;height:100%;
  background-color:var(--well-hi);
  background-image:linear-gradient(180deg,var(--well-hi),var(--well-lo));
  border:1px solid var(--hair);border-right:0;
  border-radius:calc(14px*var(--scc,1)) 0 0 calc(14px*var(--scc,1));
  box-shadow:inset 0 2px 6px rgba(0,0,0,.55);
  padding:0 10px 0 14px}
.hzField:focus-within{border-color:#3A3F50}
/* the mark: the house glyph in the house red, the field's identity — and
   at data-narrow, where the caption sheds, its ONLY identity */
.hzMk{width:calc(18px*var(--scc,1));height:calc(18px*var(--scc,1));flex:none;color:var(--cp-red);
  filter:drop-shadow(0 0 6px rgba(192,24,12,.5))}
/* the slack lives in the CAPTION (flex:1), so the figure sits hard against
   the keys; ellipsis is a safety net the shed rung should always beat —
   never render "B" (A's iter1 lesson: shed whole, don't ellipsize) */
.hzCap{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;
  font:600 calc(9.5px*var(--scc,1))/1 var(--ui);letter-spacing:.18em;
  text-transform:uppercase;color:var(--off)}
.hzMoney{display:flex;align-items:baseline;gap:4px;flex:none;min-width:0}
.hzMoney .pfx{font:600 calc(var(--stakefs,22px)*.68)/1 var(--fig);color:#767C90;flex:none}
/* the input's width is the ghost span's (game.js sizeStake) — value-sized,
   so the well's dead space is all in the caption's cell */
#betInput{background:none;border:0;padding:0;min-width:0;text-align:right;
  font:700 var(--stakefs,22px)/1 var(--fig);
  font-variant-numeric:tabular-nums;color:var(--ink)}
#betInput:focus{outline:none;color:#fff}

/* quick keys: HAIRLINE, no fills — VERDICT Round 3 ruling ("three more
   filled keys next to a filled field is four slabs"); B's relief keys were
   rejected with B's own pre-authorised fallback */
.hzKeys{display:flex;gap:5px;flex:none;margin-left:8px}
.qb{flex:none;height:calc(28px*var(--scc,1));min-width:var(--qbw,44px);padding:0 8px;
  border-radius:9px;background:none;border:1px solid #262B37;
  font:600 calc(11px*var(--scc,1))/1 var(--ui);color:#98A0B4;
  transition:background .14s,color .14s}
.qb:hover{background:rgba(255,255,255,.08);color:#fff}
/* MAX AT THE DOCKED MINIMUM IS AN OWNER RULING — the key is present at
   every width; what sheds at data-narrow is the caption, never a key
   (60-density.css). */

/* THE COMMIT — v1's money material re-tokened (UI-CHOICE §3): the accent
   gradient, an ACCENT bloom (never black — a black shadow under the only
   red mass reads as a hole in the ground), 1px sink + Plinko's release
   spring. Material and type live on #cta ITSELF so 95-motion.css's
   reduced-motion override (#cta{transition:none}) still outranks the
   transition by cascade order; only the weld geometry needs the .hzBar
   scope. */
#cta{position:relative;height:100%;min-height:0;overflow:visible;
  /* solid accent UNDER the gradient — the slab never reads transparent to
     a slow first paint or a background-color probe (§15's material check) */
  background-color:var(--acc);
  background-image:linear-gradient(180deg,var(--acc),var(--acc2));
  box-shadow:0 8px 24px color-mix(in srgb, var(--acc) 30%, transparent);
  display:grid;justify-items:center;align-content:center;gap:2px;
  transition:transform .19s cubic-bezier(.34,1.56,.64,1), filter .15s}
.hzBar #cta{grid-column:2;grid-row:1;
  border-radius:0 calc(14px*var(--scc,1)) calc(14px*var(--scc,1)) 0}
#cta .t{font:800 var(--ctafs,17px)/1 var(--ui);letter-spacing:.12em;
  text-transform:uppercase;color:var(--icoin)}
/* #FFD9D5, NOT rgba(255,255,255,.72) — Mines measured the translucent white
   at 3.75:1 on this red, under the floor, on the line that states the
   price. (Carried from the pre-wf console verbatim.) */
#cta .s{font:700 calc(11px*var(--scc,1))/1 var(--fig);font-variant-numeric:tabular-nums;
  color:#FFD9D5;margin-top:0}
#cta:hover{filter:brightness(1.06)}
/* the acknowledged click: a 1px sink, and the spring above plays the
   release — §4's first 150ms is this plus the balance moving */
#cta[data-press],#cta:active{transform:translateY(1px)}
/* DISABLED, not merely styled (the CTA's own rule since round 1): the
   control is really disabled while rolling; the look is drained saturation
   over the SAME material, bloom off — a dead light, not a different lamp */
#cta:disabled{filter:saturate(.4) brightness(.6);cursor:not-allowed;box-shadow:none}
/* data-stop (a live STOP during an autobet run) wears the SAME money
   material — the approved auto-running render shows the red slab reading
   STOP / $1.00. The old hollow --e3 treatment died with the rewrite: a
   run's one live control should be the loudest object on the console, not
   the quietest. */

/* ---- the R1 MONEY LOCK (VERDICT R1 item 1 / UI-CHOICE graft C1) ---------
   Carried through the rewrite with its selector contract intact: the
   functional half is real `disabled` attributes written by paint(); this
   is the visible half, keyed on the same data-money attribute paint()
   writes, so lock and dim can never disagree about when money is live.
   .45 — one rung dimmer than the mode rail's .55: the rail is aim, this
   is money. #stakefld is the well itself now; the dim covers the mark,
   caption, figure and keys in one stroke. */
#stakefld,#tabs{transition:opacity .18s ease}
#app[data-money="live"] #stakefld,
#app[data-money="live"] #tabs{opacity:.45;pointer-events:none}

/* ---- rail 2: MAX BET [lever] ... PRESS SPACE / Running ------------------ */
.hzRail2{display:flex;align-items:baseline;justify-content:space-between;
  gap:14px;min-height:calc(12px*var(--scc,1))}
/* with the capline resting hidden, the hint (and the running readout that
   takes its slot) holds the rail's right edge on its own */
.hzSpace,.hzRun{margin-left:auto}
/* the cap line — §3 of the spec: the ceiling is PRINTED, the stake is
   CLAMPED, the payout is never truncated; at the ceiling the line adds
   Shuffle's exact lever. The lever keeps its sentence case inside the
   uppercase rail: it is a sentence, not a caption. */
/* ITEM 5 — owner: "Max bet can be removed from here." The LINE leaves the
   rail at rest; the CLAMP it printed is untouched (setStake still clamps,
   diag-dice-math's ceiling assertions still hold) and the truth still
   surfaces where it matters: paint()'s existing data-at write brings the
   line back — ceiling figure and Shuffle's lever — for exactly as long
   as the player is ON the ceiling. At rest, rail 2 is the SPACE hint
   alone, kept to the right edge it always held. */
#capline{display:none}
#capline[data-at]{display:flex;align-items:baseline;gap:12px;min-width:0}
#capline b{font:700 calc(11px*var(--scc,1))/1 var(--fig);font-variant-numeric:tabular-nums;
  color:#8A91A4;margin-left:4px}
#capline[data-at]{color:var(--acc2)}
#capline[data-at] b{color:var(--acc)}
#caplever{display:none;text-transform:none;letter-spacing:.02em;
  font-weight:500;color:#8A91A4;
  overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
#capline[data-at] #caplever{display:inline}
/* the SPACE hint left the commit's own face for this rail (the welded cell
   centres its two lines; a pinned kbd landed on them) — out of the red,
   where a hint belongs */
.hzSpace{flex:none;display:flex;align-items:baseline;gap:6px}
/* the kbd chip's padded box must NOT set rail 2's height: negative
   vertical margins collapse its outer box back to the text line, so the
   rail is the same height with the hint (idle), with the running readout
   (auto), and with neither (mid-roll) — the dock-height-constant gate
   measures exactly this */
.hzSpace kbd{font:600 calc(9px*var(--scc,1))/1 var(--ui);letter-spacing:.08em;color:#98A0B4;
  padding:2px 5px;margin:-3px 0;border:1px solid #2A2F3B;border-radius:4px}
/* .hzRun (the running readout) is 80-auto.css's — it swaps in over
   .hzSpace only while a run is live, and that file owns the run states */

#betMsg{margin:0;min-height:0;font:600 10.5px/1.35 var(--ui);color:var(--cp-red-hi)}
/* an empty status line still cost a grid gap at the docked minimum
   (refinement round) — the row leaves when it has nothing to say */
#betMsg:empty{display:none}

/* ==========================================================================
   TOUCH, WHEREVER THE POINTER IS COARSE (mobile round, 2026-08-27) — the
   landscape phone and the tablet, which data-port does not cover. Only
   what is FREE: 844x390 has ~10px of vertical slack and every pixel spent
   there comes straight off a 34px result figure, so nothing here may make
   a row taller. The quick keys grow INSIDE the 52px bar they already sit
   in. */
#frame[data-touch] .qb{height:44px;min-width:44px}
/* THERE IS NO KEYBOARD IN THE PLAYER'S HAND: "PRESS SPACE" is a claim
   about hardware, gated on the pointer that proves otherwise — the same
   gate the Settings Hotkeys row takes in game.js's openDoor('set'). */
#frame[data-touch] .hzSpace{display:none}

/* PORTRAIT — THE CONSOLE IS THE THUMB BAR. Everything below the waterline
   (20-stage.css) reaches the 44px floor; the faces ride --scp (type and
   air follow the frame's height, the touch floors never do — 44px is a
   property of the hand, not of the window). Portrait phones are
   data-narrow/data-tiny by width, so these rules sit after 60-density's
   rungs in the cascade (later file) and win by order at equal
   specificity. */
#frame[data-port] #dock{--floorpad:12px;gap:calc(10px*var(--scp,1));border-radius:18px}
/* RAIL 1 IS SOLVED, NOT GUESSED. At 390x844 the dock's inner measure is
   315.6px (playw 342 less 2x13.2 of floorpad). v2 put 164 of balance
   beside 153 of tabs with a 10px gap = 327, and #bal's own
   overflow:hidden/text-overflow:ellipsis ate it silently: the render read
   "BALANCE $1,000...." and on a settled win "BALANCE $1,... +$1.14". The
   budget below is 6 + 85 (balance) + 52 (delta) + 10 + 132 (tabs) = 285
   against 315.6. */
#frame[data-port] .dkTop{gap:10px;min-height:44px;align-items:center}
/* THE BALANCE CAPTION IS BACK, STACKED — the owner, on the live phone
   build (2026-08-28 mobile polish): "it doesn't say balance." The mobile
   round shed the word on overflow arithmetic (66 BALANCE + 6 + 80 + 8 +
   52 + 10 + 145 = 367 against 315.6 of dock measure, eaten silently by
   #bal's ellipsis), and that arithmetic was true of the SINGLE-LINE rail;
   the restoration changes the geometry instead of re-entering the sum.
   BET AMOUNT's own caption grammar, turned vertical: the caption sits
   ABOVE the figure, and the DELTA rides the caption line (the audit's own
   named escape — #dl out of the figure's row), so the figure line carries
   the balance alone:
       BALANCE  -$1.00          MANUAL  AUTO
       $99,999.99
   Worst case is now max(caption row, figure) beside 132 of tabs — the
   $99,999.99-class figure (~105px at 18px) fits the 360x640 floor's
   ~285px measure with ~40px spare, where the single-line sum lost 10.
   CSS only, one DOM: #balrow lifts its children into the zone's grid
   (display:contents), the caption and the delta share row 1, the figure
   spans row 2. Costs NO dock height — the stack (~33px) sits inside the
   44px .dkTop cell the tab targets already hold open. check-dice §27e
   asserts the caption PRESENT and #bal's zero overflow with the delta up
   at the $99,999.99-class worst case. */
#frame[data-port] #balzone{display:grid;grid-template-columns:auto 1fr;
  gap:3px 8px;align-items:baseline}
#frame[data-port] #balzone .k{display:block;grid-row:1;grid-column:1}
#frame[data-port] #balrow{display:contents}
#frame[data-port] #bal{font-size:18px;grid-row:2;grid-column:1/-1}
#frame[data-port] #dl{font-size:12px;grid-row:1;grid-column:2;justify-self:start}
#frame[data-port] #tabs{gap:2px;align-self:stretch}
/* the tab is a 44px CELL with a 12px word centred in it — padding cannot
   reach 44 without pushing the underline eight pixels off the word.
   12px/8px, not 12.5/10: at 360x800 with the delta up, 146.1 of tabs
   squeezed #bal by a measured 9px (balScroll 9). 132 of tabs clears it
   by 16. */
#frame[data-port] #tabs button{font-size:12px;padding:0 8px;letter-spacing:.10em;
  min-height:44px;display:grid;place-items:center}
#frame[data-port] #tabs button::after{bottom:9px}
/* the welded bar at thumb size: the phone frames are all data-narrow, so
   the commit is already its own full-width row (60-density's collision-5
   rung) — these steps size that two-row form; the 768-class tablet is
   not narrow and keeps the one-row weld, whose cells fill their 60px row
   (height:100%), so the two height rules below gate on data-narrow to
   leave the weld's geometry alone. */
#frame[data-port] .hzBar{--stakefs:26px;--qbw:48px;--ctafs:19px;--barh:60px}
/* the 10px gap belongs to the TWO-ROW bar only (every portrait phone is
   data-narrow): on the tablet's one-row weld a gap is a slit between two
   square edges — rendered at 768x1024 and scoped the same day */
#frame[data-port][data-narrow] .hzBar{gap:10px}
#frame[data-port][data-narrow] .hzField{height:60px;border-radius:14px}
#frame[data-port] .hzKeys{gap:8px}
#frame[data-port] .qb{height:48px;min-width:48px;padding:0 8px;font-size:13.5px;border-radius:12px}
#frame[data-port][data-narrow] .hzBar #cta{height:56px;border-radius:14px}
#frame[data-port] .hzBar #cta .s{font-size:12.5px}
#frame[data-port] #capline{font-size:10.5px}
/* the port half of the keyboard-copy deletion: data-port does not imply a
   coarse pointer (a tall desktop window can trip the gate with a mouse),
   but the portrait composition has no rail-2 slot budgeted for the badge
   either way */
#frame[data-port] .hzSpace{display:none}
