/* ============================================================================
   FeltOdds — styles.css (v2)

   ─────────────────────────────────────────────────────────────────────────
   DESIGN PLAN  (frontend-design skill: plan → review → build → critique)
   ─────────────────────────────────────────────────────────────────────────
   Subject, audience, job. A Texas Hold'em odds calculator. The subject's own
   materials are baize, a brass-trimmed wooden rail and clay chips; the
   audience is poker players, not designers; the job is one question answered
   fast — "what is my equity, and is this call +EV?" — first on a phone held
   one-handed, then on a desktop used for study.

   Colour (4 named families, fixed by the spec and kept):
     ground   #07080b dark / #eef0f4 light   — everything off the felt
     felt     #1a8250 -> #0d5633             — the only textured surface
     rail     #6b4e2c / #42301d / #1f1509    — the wood that frames it
     brass    #e8b84b                        — hero, dealer button, chip edge
     verdict  #2fd48a positive / #ff5f5a negative, plus an HSL equity ramp
   Hue is never decoration: on this page a colour always encodes either a
   seat's identity or how good a number is.

   Type. Two families, clearly distinct in weight and width.
     Sora 800  — wordmark, the verdict figure, panel titles. Nothing else.
     Manrope 400–800 — every label, number and sentence, tabular-nums on all
     numerals, zero tracking. JetBrains Mono is gone from the UI entirely.
   Scale: 34/28 verdict · 17/15 titles · 13 body · 12 numbers · 11 captions.
   Lines stay under 80 characters; panel prose is capped at 62ch.

   Layout. ONE flat column that recomposes, never two presentations fighting
   for the same space. The stage is a CSS grid whose areas change with the
   measured mode; nothing is re-parented, so state survives every switch.

     Stage / Compact / Pocket          Hands
     +-----------------------+         +-----------------------+
     |  table (oval, seats)  |         |  board row            |
     +-----------------------+         +-----------------------+
     |  VERDICT              |         |  VERDICT              |
     +-----------------------+         +-----------------------+
     |  editor (Stage only)  |         |  one row per seat     |
     +-----------------------+         +-----------------------+
     |  panels 3 / 2 columns |         |  52-card grid         |
     +-----------------------+         |  panels (tab rail)    |
                                       +-----------------------+
   Alignment: the table is centred because an oval has no other reading;
   everything else is left-aligned, including the verdict figure, so the eye
   returns to one edge. Ultrawide gets outer margins, never a stretched table.

   Principles.
     1  The felt is the only textured, shadowed surface. Off it, everything is
        flat and opaque. The contrast between the two IS the design.
     2  Spend the boldness once: the verdict figure. Everything else is quiet.
     3  Structure encodes information — the oval, the rail band, the identity
        chips, the dealer button, the chip stack all mean something.
     4  Radius is information: 0 on panel cells, 6–10px on things that are
        physically objects (cards, chips, buttons), 50% on the oval and discs.
     5  One orchestrated motion: the deal. Nothing else animates unprompted.

   ─────────────────────────────────────────────────────────────────────────
   PLAN REVIEWED AGAINST THE GENERIC-DEFAULT LIST — three things changed
   ─────────────────────────────────────────────────────────────────────────
   · Trait 4, "the SaaS-card kit", described v1 exactly: five panels as
     identical rounded cards, one radius on everything, the same soft shadow
     and the same backdrop-blur under each. CHANGED — panels are now flat
     cells of a single grid separated by hairlines, with no shadow and no
     blur; shadow is reserved for objects that genuinely sit above the felt
     (cards, pods, the action bar). Radius is assigned by what a thing is.
   · Trait 5, "template chrome": v1 carried a tracked ALL-CAPS eyebrow over
     every panel and every felt caption, and set every number in a monospace
     face. CHANGED — sentence-case Manrope titles, no tracking, no mono, no
     middle-dot meta strings except the verdict's two facts (which the brief's
     own copy rules allow because they are facts, not chrome).
   · Trait 2, "near-black plus one bright accent", is a near-miss: the ground
     IS near-black. KEPT, because the accents are the subject's own materials
     (baize green, brass, clay-chip red and blue) rather than one arbitrary
     acid hue, and because the brief pins the palette. Where the brief pins a
     direction, the brief wins.
   Deliberate omission (Chanel's rule): the v1 guide card is gone. Each panel
   now explains itself in one line of its own empty state.

   Section map: 1 reset · 2 tokens · 3 palettes · 4 motion · 5 header ·
   6 stage grid · 7 table & seats · 8 cards · 9 verdict · 10 hands view ·
   11 editor · 12 panels · 13 bottom bar · 14 sheets · 15 toast ·
   16 responsive · 17 SEO content
   ========================================================================== */

/* ── 1. reset ────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-bottom: calc(var(--bar-h, 0px) + 20px);
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: Manrope, system-ui, -apple-system, sans-serif;
  font-size: 13px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overscroll-behavior-y: none;
  -webkit-tap-highlight-color: transparent;
}
/* F7 (verifier): `100vh` is the LARGE viewport on mobile — a browser chrome's
   worth too tall while the URL bar is showing, which is exactly the overshoot
   that puts a phone's last row under the address bar. `100dvh` tracks the
   viewport that is actually visible; the `vh` declaration above stays as the
   fallback for engines without dynamic viewport units. */
@supports (min-height: 100dvh) {
  body { min-height: 100dvh; }
}

h1, h2, h3, p { margin: 0; }

button {
  font: inherit;
  color: inherit;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

input { font: inherit; touch-action: manipulation; }

[hidden] { display: none !important; }

:focus-visible {
  outline: 3px solid var(--info);
  outline-offset: 1px;
  box-shadow: 0 0 0 3px var(--info);
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 400;
  padding: 12px 16px;
  border-radius: 0 0 12px 0;
  background: var(--surface2);
  color: var(--text);
  font: 700 13px/1 var(--font-u);
  text-decoration: none;
}
.skip:focus { left: 0; }

/* Reads the safe-area insets so layout.js never has to guess them. */
.safeprobe {
  position: fixed;
  left: 0; top: 0;
  width: 0; height: 0;
  visibility: hidden;
  pointer-events: none;
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

/* ── 2. tokens ───────────────────────────────────────────────────────────── */

:root {
  --bg: #07080b;
  --surface: rgba(255,255,255,.05);
  --surface2: rgba(255,255,255,.095);
  --panel: #0d0f14;
  --glass2: rgba(12,14,19,.965);
  --line: rgba(255,255,255,.09);
  --line2: rgba(255,255,255,.2);
  --slot: rgba(255,255,255,.44);
  --text: #f2f4f8;
  --text2: #99a2b1;
  --text3: #616978;
  --gold: #e8b84b;
  --pos: #2fd48a;
  --neg: #ff5f5a;
  --info: #5b8cff;
  --pod: #13161d;
  --podbest: #241c08;
  --switch: rgba(255,255,255,.14);
  --carda: #fff;
  --cardb: #eaeef5;
  --cardline: rgba(9,12,20,.16);
  --sh1: 0 1px 2px rgba(0,0,0,.4), 0 14px 36px rgba(0,0,0,.42);
  --shc: 0 1px 1px rgba(0,0,0,.34), 0 6px 16px rgba(0,0,0,.38);

  /* felt & rail — the felt is always dark, in both themes */
  --felta: #1a8250;
  --feltb: #0d5633;
  --raila: #42301d;
  --railb: #6b4e2c;
  --railc: #1f1509;

  /* suit colours — the classic deck is the default */
  --suit0: #101826; --suit1: #dc2626; --suit2: #dc2626; --suit3: #101826;
  --badge0: #94a3b8; --badge1: #ef4444; --badge2: #ef4444; --badge3: #94a3b8;

  --font-d: Sora, system-ui, -apple-system, sans-serif;
  --font-u: Manrope, system-ui, -apple-system, sans-serif;

  --e-in: cubic-bezier(.16,.9,.25,1);
  --e-out: cubic-bezier(.2,.8,.2,1);

  --gap: clamp(10px, 1.1vw, 16px);
  --bar-h: 0px;
  --hdr-h: 64px;

  /* set by app.js from the resolved layout geometry */
  --box-w: 0px; --box-h: 0px;
  --ov-w: 0px; --ov-h: 0px; --ov-x: 0px; --ov-y: 0px;
  --card-h: 48px; --card-w: 34px;
  --bcard-h: 55px; --bcard-w: 39px;
  --tok: 44px; --pgap: 4px;
  --pill-f: 13px; --name-f: 11px; --chip-f: 11px;
}

/* light tokens — applied on the system preference until the user chooses */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #eef0f4;
    --surface: rgba(255,255,255,.75);
    --surface2: #ffffff;
    --panel: #ffffff;
    --glass2: rgba(255,255,255,.975);
    --line: rgba(12,17,29,.1);
    --line2: rgba(12,17,29,.22);
    --slot: rgba(12,17,29,.46);
    --text: #0e1320;
    --text2: #5a6273;
    --text3: #8a91a0;
    --gold: #6f4e07;
    --pos: #0b7c4c;
    --neg: #c22e29;
    --info: #2454c8;
    --pod: #ffffff;
    --podbest: #fff6e2;
    --switch: rgba(12,17,29,.16);
    --raila: #6d5132;
    --railb: #a37c48;
    --railc: #3d2b16;
    --sh1: 0 1px 2px rgba(16,24,40,.06), 0 12px 30px rgba(16,24,40,.1);
    --shc: 0 1px 1px rgba(16,24,40,.12), 0 6px 14px rgba(16,24,40,.14);
  }
}

/* …and once the user has chosen, the stored choice wins in both directions */
:root[data-theme="light"] {
  --bg: #eef0f4;
  --surface: rgba(255,255,255,.75);
  --surface2: #ffffff;
  --panel: #ffffff;
  --glass2: rgba(255,255,255,.975);
  --line: rgba(12,17,29,.1);
  --line2: rgba(12,17,29,.22);
  --slot: rgba(12,17,29,.46);
  --text: #0e1320;
  --text2: #5a6273;
  --text3: #8a91a0;
  --gold: #6f4e07;
  --pos: #0b7c4c;
  --neg: #c22e29;
  --info: #2454c8;
  --pod: #ffffff;
  --podbest: #fff6e2;
  --switch: rgba(12,17,29,.16);
  --raila: #6d5132;
  --railb: #a37c48;
  --railc: #3d2b16;
  --sh1: 0 1px 2px rgba(16,24,40,.06), 0 12px 30px rgba(16,24,40,.1);
  --shc: 0 1px 1px rgba(16,24,40,.12), 0 6px 14px rgba(16,24,40,.14);
}

/* 4-colour deck — an explicit colour-blind toggle, never the default */
:root[data-deck="four"] {
  --suit0: #1e293b; --suit1: #dc2626; --suit2: #2563eb; --suit3: #16a34a;
  --badge0: #94a3b8; --badge1: #ef4444; --badge2: #3b82f6; --badge3: #22c55e;
}

/* ── 3. palettes ─────────────────────────────────────────────────────────── */

/* seat identity — one colour per seat, in the chip, the panel row and the graph */
.idn1  { --idn: #c08a12; --idn-fg: #1a1200; --idn-line: #f0c75f; }
.idn2  { --idn: #1668c4; --idn-fg: #ffffff; --idn-line: #4fa8ff; }
.idn3  { --idn: #10894b; --idn-fg: #ffffff; --idn-line: #2fd48a; }
.idn4  { --idn: #c9491c; --idn-fg: #ffffff; --idn-line: #ff8a4c; }
.idn5  { --idn: #7b3bc4; --idn-fg: #ffffff; --idn-line: #b47bf5; }
.idn6  { --idn: #be2278; --idn-fg: #ffffff; --idn-line: #ff5fb0; }
.idn7  { --idn: #0e7d8a; --idn-fg: #ffffff; --idn-line: #38d6d4; }
.idn8  { --idn: #b0182a; --idn-fg: #ffffff; --idn-line: #ff6b6b; }
.idn9  { --idn: #5e7a12; --idn-fg: #ffffff; --idn-line: #b5e04a; }
.idn10 { --idn: #4442c4; --idn-fg: #ffffff; --idn-line: #8c9bff; }

/* hand tiers — five distinct hues, always solid chips, never coloured text.
   --tier-muted is the "no live cards" fill: same hue, blended toward black
   for the white-text tiers (darkening only ever helps a light label) and
   toward white for the one dark-text tier (marginal) — so the label's own
   contrast against the muted fill clears 4.5:1 by a wide margin in both
   cases (verified: premium 16:1, strong 14.6:1, playable 14.4:1, weak
   14:1, marginal 13.7:1 — see grid.spec.mjs). */
.tier--premium  { --tier: #b0182a; --tier-fg: #ffffff; --tier-muted: #4f0b13; }
.tier--strong   { --tier: #177a40; --tier-fg: #ffffff; --tier-muted: #0a371d; }
.tier--playable { --tier: #2563eb; --tier-fg: #ffffff; --tier-muted: #112d6a; }
.tier--marginal { --tier: #e4b511; --tier-fg: #1a1400; --tier-muted: #f3de94; }
.tier--weak     { --tier: #6b7280; --tier-fg: #ffffff; --tier-muted: #30333a; }

/* hand categories 0→8, for the stacked distribution bar */
.cat0 { background: #6b7280; }
.cat1 { background: #8296c0; }
.cat2 { background: #4f8ef7; }
.cat3 { background: #2fd48a; }
.cat4 { background: #e8b84b; }
.cat5 { background: #f2803b; }
.cat6 { background: #e8574a; }
.cat7 { background: #c74bd6; }
.cat8 { background: #ff3fa4; }

.sw { width: 8px; height: 8px; border-radius: 2px; flex: 0 0 auto; display: inline-block; }
.sw.tier--premium, .sw.tier--strong, .sw.tier--playable,
.sw.tier--marginal, .sw.tier--weak { background: var(--tier); }

.gold { color: var(--gold); }

/* ── 4. motion ───────────────────────────────────────────────────────────── */

@keyframes pkDeal {
  0%   { opacity: 0; transform: translateY(-14px) rotateX(56deg) scale(.9); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: none; }
}
@keyframes pkRise  { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes pkSheet { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }
@keyframes pkToast { from { opacity: 0; transform: translate(-50%,14px); } to { opacity: 1; transform: translate(-50%,0); } }
@keyframes pkSpin  { to { transform: rotate(360deg); } }
@keyframes pkPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(232,184,75,.65); } 50% { box-shadow: 0 0 0 7px rgba(232,184,75,0); } }
@keyframes pkWash  { from { opacity: 0; transform: scale(.94); } to { opacity: 1; transform: none; } }

/* The one orchestrated moment (SPEC v2 §9): the deal itself is driven from
   app.js with the Web Animations API — transform + opacity only, 380 ms,
   60 ms stagger, on this curve. A flying card drops its own entrance
   animation so the two never fight over `transform`. */
.card.is-flying { animation: none !important; }

/* Reduced motion, from the system AND from the in-app toggle. Both land on the
   same declarations so there is exactly one code path to reason about. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before,
:root[data-motion="reduce"] *::after {
  animation-duration: .001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .001ms !important;
  scroll-behavior: auto !important;
}

.bgwash {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 120% 70% at 50% -12%, rgba(91,140,255,.08), transparent 62%),
    radial-gradient(ellipse 80% 60% at 94% 110%, rgba(232,184,75,.055), transparent 62%);
}

/* ── 5. header ───────────────────────────────────────────────────────────── */

.hdr {
  position: sticky;
  top: 0;
  z-index: 60;
  background: var(--glass2);
  border-bottom: 1px solid var(--line);
  padding-top: env(safe-area-inset-top);
}

.hdr__row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px clamp(12px, 2vw, 22px);
  padding-left: max(clamp(12px, 2vw, 22px), env(safe-area-inset-left));
  padding-right: max(clamp(12px, 2vw, 22px), env(safe-area-inset-right));
}

.hdr__spacer { flex: 1 1 10px; }

.brand { display: flex; align-items: center; gap: 9px; min-width: 0; }
.brand__tile {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex: 0 0 auto;
  border-radius: 9px;
  background: linear-gradient(150deg, var(--surface2), var(--surface));
  border: 1px solid var(--line);
  font-size: 16px;
  color: var(--gold);
}
.brand__name {
  font: 800 16px/1 var(--font-d);
  letter-spacing: -.02em;
  color: var(--text);
  white-space: nowrap;
}
.brand__thin { color: var(--gold); }

.stepper {
  display: flex;
  align-items: center;
  height: 40px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  overflow: hidden;
  flex: 0 0 auto;
}
.stepper__btn {
  width: 38px;
  height: 100%;
  border: 0;
  background: transparent;
  color: var(--text2);
  font: 600 18px/1 var(--font-u);
  cursor: pointer;
  transition: background .14s, color .14s;
}
.stepper__val {
  min-width: 70px;
  text-align: center;
  font: 700 13px/1 var(--font-u);
  font-variant-numeric: tabular-nums;
}

.viewseg {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  flex: 0 0 auto;
}
.viewseg__btn {
  min-height: 34px;
  padding: 0 11px;
  border: 1px solid transparent;
  border-radius: 7px;
  background: transparent;
  color: var(--text3);
  font: 700 12px/1 var(--font-u);
  cursor: pointer;
  white-space: nowrap;
  transition: background .14s, color .14s;
}
.viewseg__btn[aria-pressed="true"] { background: var(--surface2); border-color: var(--line2); color: var(--text); }
/* BRIEF W: shown vs preference. `aria-pressed` above is the PREFERENCE; this
   marks the segment naming the presentation actually on screen, so an Auto
   that resolved to Table is visible as well as announced. The rule is written
   for the unpressed case only — a segment that is both the preference and what
   is shown needs no second mark. */
.viewseg__btn[data-shown="1"][aria-pressed="false"]::after {
  content: "";
  display: block;
  height: 2px;
  margin: 3px auto 0;
  width: 14px;
  border-radius: 2px;
  background: var(--gold);
}

/* BRIEF W (council round 10, remedy A): the phone's two-segment view control
   — Table | Hands, 48x44 each — replacing round 9's cycling button, which
   named the preference instead of the choice. Hidden above 400px, where the
   3-segment control keeps running. See the ≤400px rule in §16 for the swap. */
/* The group carries NO padding or border of its own: the segments are 44px
   tall and the header row must stay ≤64px including its 8px padding (R2), so
   every pixel of chrome around them would come out of that budget. */
.viewpick {
  display: none;
  gap: 0;
  padding: 0;
  border: 0;
  border-radius: 11px;
  background: var(--surface);
  overflow: hidden;
  flex: 0 0 auto;
}
.viewpick__btn {
  min-width: 48px;
  min-height: 44px;
  padding: 0 4px;
  border: 1px solid transparent;
  border-radius: 11px;
  background: transparent;
  color: var(--text3);
  font: 700 12px/1 var(--font-u);
  cursor: pointer;
  white-space: nowrap;
  transition: background .14s, color .14s;
}
.viewpick__btn[aria-checked="true"] {
  background: var(--surface2);
  border-color: var(--line2);
  color: var(--text);
}

.btn {
  height: 40px;
  padding: 0 13px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex: 0 0 auto;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: 700 13px/1 var(--font-u);
  cursor: pointer;
  transition: background .14s, border-color .14s, color .14s, transform .14s var(--e-out);
}
.btn--quiet { color: var(--text2); }
.btn--icon { width: 40px; padding: 0; font-size: 15px; color: var(--text2); }
.btn--gold {
  padding: 0 16px;
  border-color: rgba(232,184,75,.5);
  background: linear-gradient(170deg, #f0c75f, #d09a2c);
  color: #221704;
  font-weight: 800;
  box-shadow: 0 1px 0 rgba(255,255,255,.35) inset;
}
.btn--sm { height: 36px; padding: 0 12px; font-size: 12.5px; }
.btn--danger { color: var(--neg); }

.dots { display: inline-flex; gap: 2.5px; }
.dots i { width: 3.5px; height: 3.5px; border-radius: 50%; background: var(--text2); }

/* Coarse pointer: EVERY header control is a 44px target (SPEC v2 §4 / layout.js
   MIN.touch), not just the wide action buttons. The 40px `.btn`/`.btn--icon`
   height, the 38-40px stepper buttons and the 34px view segments all sat under
   the floor on a touch device (layout.spec.mjs:56, round 1). `min-*` is used
   throughout so it also beats the narrow-viewport `width` overrides further
   down, whatever their specificity or order. */
@media (any-pointer: coarse) {
  .hdr__row .btn { min-height: 44px; min-width: 44px; }
  .hdr__row .stepper { height: 44px; }
  .hdr__row .stepper__btn { min-width: 44px; min-height: 44px; }
  .hdr__row .viewseg__btn { min-height: 44px; min-width: 44px; }
  .bottombar .barbtn { min-height: 44px; min-width: 44px; }
  /* F2 (verifier), round 3: the rest of the chrome, wherever it is mounted —
     the editor's "Make hero" / "Clear seat" (36px), the Timeline's "Copy
     link" (36px), the picker's segments and presets, the accordion headers
     and the drawer's own controls. The 13x13 range grid is the ONE
     documented exception (council ruling: WCAG AA's 24px minimum governs that
     dense matrix), so `.rangecell` is deliberately absent and stays at 26px. */
  .btn--sm { min-height: 44px; min-width: 44px; }
  .linkbtn { min-height: 44px; min-width: 44px; }
  .iconbtn { min-width: 44px; min-height: 44px; }
  .seg__btn { min-height: 44px; min-width: 44px; }
  .preset { min-height: 44px; min-width: 44px; }
  .acc__btn { min-height: 44px; }
  .drawer__act { min-height: 44px; min-width: 44px; }
  .tab { min-height: 44px; min-width: 44px; }
}

.progress { height: 3px; background: var(--line); overflow: hidden; }
.progress__fill {
  height: 100%;
  width: var(--w, 0%);
  background: linear-gradient(90deg, var(--gold), #f0c75f);
  transition: width .2s linear;
}

/* ── 6. stage grid ───────────────────────────────────────────────────────── */

.main {
  position: relative;
  z-index: 1;
  padding: var(--gap);
  padding-left: max(var(--gap), env(safe-area-inset-left));
  padding-right: max(var(--gap), env(safe-area-inset-right));
  padding-bottom: calc(var(--bar-h, 0px) + 20px);
}

.stage {
  display: grid;
  gap: var(--gap);
  /* Ultrawide gets outer margins, never a stretched table: the TABLE is capped
     at 1100 by the layout engine, while the panel grid is allowed the width it
     needs for three columns (SPEC v2 §2 wants both). */
  max-width: 1760px;
  margin: 0 auto;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "table" "verdict" "editor" "panels";
}
#viewTable  { grid-area: table; }
#viewBoard  { grid-area: table; }
#verdict    { grid-area: verdict; }
#viewHands  { grid-area: hands; }
#editorHost { grid-area: editor; }
#panels     { grid-area: panels; }
#drawer     { grid-area: drawer; }

/* Stage with the Game view drawer open: the drawer is the right column and
   spans the table and the verdict rows, so it is exactly as tall as the table
   column (amendment A1). The 1680 side-dock is withdrawn — the editor lives in
   this drawer at every Stage width. */
.stage[data-drawer="dock"][data-dopen="1"] {
  grid-template-columns: minmax(0, 1fr) var(--drawer-w, 400px);
  grid-template-areas:
    "table   drawer"
    "verdict drawer";
}
/* Hands: board, the answer, the hands, the grid, the analysis. */
.stage[data-mode="hands"] {
  grid-template-areas: "table" "verdict" "hands" "editor" "panels";
}

.stage[data-mode="hands"] #viewTable { display: none; }
.stage:not([data-mode="hands"]) #viewBoard { display: none; }
.stage:not([data-mode="hands"]) #viewHands { display: none; }
/* The inline editor host is Hands only now: Stage and Compact put the editor
   in the drawer, Pocket keeps the modal sheet. */
.stage:not([data-mode="hands"]) #editorHost { display: none; }
/* The panel GRID belongs to Pocket and Hands (the tab rail). Stage and Compact
   moved these very sections into the drawer accordion, so the empty shell must
   not take a grid row — SPEC v2 amendment A1, "below the calculator shell only
   the SEO/about section remains". */
.stage[data-drawer="dock"] #panels,
.stage[data-drawer="over"] #panels { display: none; }

/* ── 7. table & seats ────────────────────────────────────────────────────── */

.tablewrap { display: flex; justify-content: center; }

.table {
  position: relative;
  width: var(--box-w);
  height: var(--box-h);
  max-width: 100%;
  animation: pkRise .45s var(--e-in) both;
}
.table__box { position: absolute; inset: 0; }

.oval {
  position: absolute;
  left: var(--ov-x); top: var(--ov-y);
  width: var(--ov-w); height: var(--ov-h);
  border-radius: 50%;
  background: linear-gradient(170deg, var(--railb), var(--raila) 46%, var(--railc));
  box-shadow: 0 2px 0 rgba(255,255,255,.1) inset, 0 -3px 10px rgba(0,0,0,.4) inset, 0 26px 60px rgba(0,0,0,.5);
}
.oval__grain {
  position: absolute; inset: 0;
  border-radius: 50%;
  background: repeating-linear-gradient(97deg, rgba(255,255,255,.05) 0 2px, transparent 2px 7px);
  pointer-events: none;
}
.felt {
  position: absolute;
  inset: clamp(8px, 2.6%, 18px);
  border-radius: 50%;
  overflow: hidden;
  background:
    radial-gradient(ellipse 70% 62% at 38% 24%, rgba(255,255,255,.11), transparent 62%),
    radial-gradient(ellipse 100% 100% at 50% 46%, var(--felta), var(--feltb) 60%),
    var(--feltb);
  box-shadow: 0 0 0 2px rgba(0,0,0,.35) inset, 0 10px 44px rgba(0,0,0,.5) inset, 0 0 120px rgba(0,0,0,.3) inset;
}
.felt__weave {
  position: absolute; inset: 0; pointer-events: none;
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,.014) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(-45deg, rgba(0,0,0,.028) 0 1px, transparent 1px 3px);
}
.felt__betline {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 86%; height: 74%;
  border: 1px dashed rgba(255,255,255,.13);
  border-radius: 50%;
  pointer-events: none;
}
/* the watermark spade: an inline SVG path, so it is the same shape on every
   platform (a glyph here becomes a colour emoji on Windows) */
.felt__mark {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: calc(var(--ov-h) * .42);
  height: calc(var(--ov-h) * .42);
  fill: rgba(255,255,255,.05);
  pointer-events: none;
}

/* pot + board, centred on the felt */
.center {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--pgap) * 2);
}
.pot { display: flex; align-items: center; gap: 9px; pointer-events: none; }
.pot__fig {
  font: 800 calc(var(--pill-f) * 1.15)/1 var(--font-u);
  font-variant-numeric: tabular-nums;
  color: #ffe9b0;
  text-shadow: 0 1px 6px rgba(0,0,0,.55);
}

/* The pot chip stack: FOUR clay discs with a gold edge, drawn in CSS. Never an
   emoji — an emoji is a different typeface at a fixed size, renders differently
   on every platform, and cannot pick up the felt's light. The stack scales off
   --chip-w, so it grows with the table the layout engine produced. */
.chipstack {
  --chip-w: calc(var(--pill-f) * 2.1);
  --chip-h: calc(var(--chip-w) * .30);
  --chip-lift: calc(var(--chip-h) * .52);
  position: relative;
  flex: 0 0 auto;
  width: var(--chip-w);
  height: calc(var(--chip-h) + var(--chip-lift) * 3);
}
.chipstack i {
  position: absolute;
  left: 0;
  width: var(--chip-w);
  height: var(--chip-h);
  border-radius: 50%;
  /* the alternating edge spots of a casino chip, plus the gold rim */
  background:
    radial-gradient(ellipse 52% 62% at 50% 42%, #f6dc9a 0 62%, transparent 63%),
    repeating-conic-gradient(from 0deg, #e8b84b 0 22.5deg, #2a1e07 22.5deg 45deg);
  box-shadow:
    0 0 0 1px rgba(255, 233, 176, .75) inset,
    0 1px 2px rgba(0, 0, 0, .6);
}
.chipstack i:nth-child(1) { bottom: calc(var(--chip-lift) * 3); }
.chipstack i:nth-child(2) { bottom: calc(var(--chip-lift) * 2); filter: brightness(.95); }
.chipstack i:nth-child(3) { bottom: var(--chip-lift); filter: brightness(.88); }
.chipstack i:nth-child(4) { bottom: 0; filter: brightness(.8); }
.chipstack--sm { --chip-w: 22px; }

.board { display: flex; gap: var(--pgap); perspective: 900px; }
.board--felt .card, .board--felt .slot { width: var(--bcard-w); }

/* seats -------------------------------------------------------------------- */

.seats { position: absolute; inset: 0; z-index: 5; pointer-events: none; }

.seat {
  position: absolute;
  left: var(--px);
  top: var(--py);
  width: max-content;
  max-width: var(--pw);
  z-index: var(--z, 5);
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: auto;
}

/* empty seat = ONE target: a card-back pair, the identity chip and a "+" */
.seat__add {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: var(--tok);
  min-height: var(--tok);
  padding: 2px;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.backs { position: relative; display: block; width: calc(var(--card-w) * 1.35); height: var(--card-h); margin-top: -2px; }
/* The empty-seat token is a pair of card BACKS: dark felt green, a woven
   diagonal pattern and a thin gold edge — the same material as the table, so an
   empty seat reads as "no cards here", not as a broken card. */
.backs i {
  position: absolute;
  top: 0;
  width: var(--card-w);
  height: var(--card-h);
  border-radius: 6px;
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,.07) 0 1px, transparent 1px 5px),
    repeating-linear-gradient(-45deg, rgba(0,0,0,.22) 0 1px, transparent 1px 5px),
    linear-gradient(158deg, #17754b, #0a3f27);
  border: 1px solid rgba(232,184,75,.55);
  box-shadow:
    inset 0 0 0 1px rgba(232,184,75,.22),
    inset 0 0 12px rgba(0,0,0,.45),
    var(--shc);
}
.backs i:nth-child(1) { left: 0; transform: rotate(-7deg); }
.backs i:nth-child(2) { right: 0; transform: rotate(6deg); }
.seat__plus {
  position: absolute;
  left: 50%; top: 46%;
  transform: translate(-50%, -50%);
  font: 700 20px/1 var(--font-u);
  color: rgba(255,255,255,.94);
  text-shadow: 0 1px 5px rgba(0,0,0,.75);
  pointer-events: none;
}

.seat__filled { display: flex; flex-direction: column; align-items: center; width: 100%; }

.seat__chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 2px 8px;
  border-radius: 6px;
  border: 1px solid rgba(0,0,0,.35);
  background: var(--idn);
  color: var(--idn-fg);
  font: 800 var(--chip-f)/1.5 var(--font-u);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  z-index: 4;
  white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0,0,0,.4);
}
/* the hit box grows UPWARD and sideways only, so it can never cover the cards */
.seat__chip::before {
  content: '';
  position: absolute;
  inset: -18px -10px 0 -10px;
  border-radius: 12px 12px 4px 4px;
}
.seat.is-hero .seat__chip {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px var(--pod), 0 0 0 3px var(--gold);
}
.seat__add .seat__chip { cursor: inherit; }
.seat__add .seat__chip::before { content: none; }

.seat__mini {
  position: absolute;
  top: 0; right: 0;
  width: 17px; height: 17px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 5px;
  border: 1px solid var(--line);
  background: var(--pod);
  color: var(--text3);
  font: 700 10px/1 var(--font-u);
  cursor: pointer;
  z-index: 5;
}
/* The hit box grows UP and RIGHT only: never down over the cards.
   F2 (verifier): 32x32 for a fine pointer, 44x44 for a coarse one — the same
   two floors SPEC v2 §4 sets everywhere else. Growing up and to the right
   keeps it off this pod's own cards and off the diagonal neighbour below,
   which is the pair the expanded-target cross-talk test in hit.spec samples. */
.seat__mini::before { content: ''; position: absolute; inset: -15px -15px 0 0; }
@media (any-pointer: coarse) {
  .seat__mini::before { inset: -27px -27px 0 0; }
}

/* No negative top margin: pulling the pair up under the identity chip put the
   cards' top 2 px inside the chip's own box, so the top corner of card 1 hit
   the chip instead of the card (council §11 hit testing). layout.js's podSize
   already budgets the 2 px gap. */
.seat__cards { display: flex; gap: var(--pgap); perspective: 900px; margin-top: 0; }
.seat__cards .card, .seat__cards .slot { width: var(--card-w); }
/* the hero's pod renders 1.1x — the same factor the layout engine reserves */
.seat.is-hero .seat__cards .card { width: calc(var(--card-w) * 1.1); font-size: calc(var(--card-h) * 1.1); }
.seat.is-hero .seat__cards .slot { width: calc(var(--card-w) * 1.1); }
.seat.is-hero .backs { width: calc(var(--card-w) * 1.49); height: calc(var(--card-h) * 1.1); }
.seat.is-hero .backs i { width: calc(var(--card-w) * 1.1); height: calc(var(--card-h) * 1.1); }

.seat__pill {
  /* The pill and the hand name deliberately overlap the cards' lower edge, so
     they must be transparent to the pointer: otherwise they eat the bottom of a
     44 px card target (council §11 hit testing). Neither is interactive. */
  pointer-events: none;
  margin-top: -6px;
  padding: 2px 7px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--pod);
  box-shadow: var(--sh1);
  z-index: 4;
  white-space: nowrap;
  font: 800 var(--pill-f)/1.45 var(--font-u);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  color: var(--eq, var(--text3));
}
.seat.is-best .seat__pill { background: var(--podbest); border-color: rgba(232,184,75,.5); color: var(--gold); }

.seat__name {
  pointer-events: none;
  max-width: 100%;
  margin-top: 3px;
  font: 700 var(--name-f)/1.35 var(--font-u);
  color: #fff;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-shadow: 0 1px 4px rgba(0,0,0,.85);
}
.seat__name.is-tier {
  color: var(--tier-fg);
  background: var(--tier);
  border-radius: 5px;
  padding: 1px 7px;
  text-shadow: none;
}

.seat__dealer {
  position: absolute;
  /* outside the pod's own box, so it never lands on the cards or the name */
  right: calc(100% - 4px); bottom: 26%;
  width: 21px; height: 21px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: linear-gradient(170deg, #fff, #d8dbe2);
  color: #1b1405;
  border: 1px solid rgba(0,0,0,.35);
  font: 800 11px/1 var(--font-u);
  box-shadow: 0 2px 5px rgba(0,0,0,.5);
  z-index: 5;
  pointer-events: none;
}

/* states: empty · dealt · hero · editing · winner (SPEC v2 §5) */

/* hero: the gold ring is carried by the chip (with its ★) and repeated around
   the card pair, so the hero reads at a glance without a second colour */
.seat.is-hero .seat__cards {
  border-radius: 9px;
  box-shadow: 0 0 0 2px rgba(232,184,75,.75), 0 0 16px rgba(232,184,75,.25);
}

/* editing: a 900 ms ring while the picker is targeting this seat. The keyframe
   animates box-shadow only — no transform, nothing that moves the pod — and
   both reduced-motion paths flatten it to a static ring. */
.seat.is-editing .seat__cards,
.seat.is-editing .backs { animation: pkPulse .9s ease-in-out infinite; border-radius: 9px; }
@media (prefers-reduced-motion: reduce) {
  .seat.is-editing .seat__cards,
  .seat.is-editing .backs { box-shadow: 0 0 0 3px rgba(232,184,75,.65); }
}
:root[data-motion="reduce"] .seat.is-editing .seat__cards,
:root[data-motion="reduce"] .seat.is-editing .backs { box-shadow: 0 0 0 3px rgba(232,184,75,.65); }

/* winner: a gold wash behind the whole pod, not just a coloured number */
.seat.is-winner::before {
  content: '';
  position: absolute;
  inset: -10px -12px -8px -12px;
  border-radius: 16px;
  background: radial-gradient(ellipse 80% 70% at 50% 55%, rgba(232,184,75,.28), rgba(232,184,75,0) 72%);
  animation: pkWash .5s var(--e-in) both;
  pointer-events: none;
  z-index: 0;
}
.seat.is-winner .seat__pill {
  background: linear-gradient(170deg, #f0c75f, #d09a2c);
  border-color: #f0c75f;
  color: #221704;
}
.seat.is-winner .seat__cards { box-shadow: 0 0 0 2px rgba(232,184,75,.85), 0 0 22px rgba(232,184,75,.35); border-radius: 9px; }

/* The compact pod drops the hand-name line and overlaps chip and pill onto
   the cards: below ~140px of oval a name cannot be set legibly on the felt. */
.stage[data-pod="compact"] .seat__name { display: none; }
.stage[data-pod="compact"] .seat__chip { margin-bottom: 1px; }
.stage[data-pod="compact"] .seat__pill { margin-top: -9px; }

/* ── 8. cards & slots ────────────────────────────────────────────────────── */

.card {
  position: relative;
  aspect-ratio: 5/7;
  border-radius: 6px;
  background: linear-gradient(158deg, var(--carda), var(--cardb));
  border: 1px solid var(--cardline);
  box-shadow: var(--shc);
  overflow: hidden;
  padding: 0;
  display: block;
  cursor: pointer;
  animation: pkDeal .46s var(--e-in) both;
  transition: transform .16s var(--e-out), box-shadow .16s;
  color: var(--suit0);
  /* card type is set in em of the card's own height, so a card is legible at
     every size the layout engine produces (ISSUE C5) */
  font-size: var(--card-h);
}
.card[data-suit="0"] { color: var(--suit0); }
.card[data-suit="1"] { color: var(--suit1); }
.card[data-suit="2"] { color: var(--suit2); }
.card[data-suit="3"] { color: var(--suit3); }
.board--felt .card { font-size: var(--bcard-h); }

.card__idx {
  position: absolute;
  top: 5%; left: 7%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: .92;
  pointer-events: none;
}
.card__rank { font: 800 .33em/1 var(--font-u); letter-spacing: -.04em; }
/* Suits are inline SVG paths, never font glyphs: a glyph is a different
   typeface at every size and on Windows it renders as a colour emoji, which
   destroys the 4-colour deck and the corner index at 38 px (SPEC v2 §9). */
.card__suit { display: block; width: .17em; height: .17em; margin: .03em 0 0 .02em; }
.card__pip {
  position: absolute;
  left: 58%; top: 62%;
  transform: translate(-50%, -50%);
  width: .42em;
  height: .42em;
  pointer-events: none;
  opacity: .94;
}
.card__suit svg, .card__pip svg { display: block; width: 100%; height: 100%; fill: currentColor; }

.slot {
  position: relative;
  aspect-ratio: 5/7;
  border-radius: 6px;
  border: 1.5px dashed var(--slot);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text2);
  font: 600 16px/1 var(--font-u);
  cursor: pointer;
  background: var(--surface);
  padding: 0;
  transition: border-color .16s, color .16s, background .16s, transform .16s;
}
.slot::before { content: ''; position: absolute; inset: -8px -2px; border-radius: 12px; }
.board--felt .slot {
  border-color: rgba(255,255,255,.58);
  color: rgba(255,255,255,.86);
  background: rgba(0,0,0,.2);
}
.slot.is-target { border-color: var(--gold); border-style: solid; color: var(--gold); box-shadow: 0 0 0 2px rgba(232,184,75,.35); }
.card.is-target { box-shadow: 0 0 0 2px var(--gold), var(--shc); }

@media (hover: hover) {
  .stepper__btn:hover { background: var(--surface2); color: var(--text); }
  .btn:hover { background: var(--surface2); border-color: var(--line2); }
  .btn--gold:hover { transform: translateY(-1px); background: linear-gradient(170deg, #f3ce6c, #d9a531); }
  .btn--icon:hover { color: var(--gold); }
  .viewseg__btn:hover { color: var(--text); }
  .seat__mini:hover { color: var(--gold); border-color: var(--gold); }
  .card:hover { transform: translateY(-5px) scale(1.06); }
  .slot:hover { border-color: var(--gold); color: var(--gold); }
  .cardcell:hover { transform: translateY(-4px) scale(1.07); border-color: #e8b84b; }
  .rangecell:hover { transform: scale(1.14); z-index: 2; }
  .preset:hover { background: var(--surface2); border-color: var(--gold); color: var(--gold); }
  .histrow:hover { border-color: var(--line2); }
  .hrow:hover { border-color: var(--line2); }
  .tab:hover { color: var(--text); }
  .about__foot a:hover { text-decoration: underline; }
}

/* ── 9. verdict strip — the loudest element after the cards ──────────────── */

.verdict {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px 18px;
  padding: 14px 16px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel);
  /* The strip's height is RESERVED, never content-driven (SPEC v2 §8: the
     answer updates in place). layout.js sizes the table from the MEASURED
     strip height (app.js measuredVerdictH), so a strip that grew when the
     facts line appeared or when the CTA gave way to the pot/to-call inputs
     would resize the table under the user. Each varying row below carries the
     height of its own largest state; the terms are the type sizes themselves,
     so they cannot drift from the rendered text. */
  --v-fig-size: clamp(28px, min(5vw, 7vh), 34px);
  --v-fig-h: calc(var(--v-fig-size) * 1.08);          /* the figure line */
  --v-sub-h: calc(5px + 14px * 1.4);                  /* margin + facts line */
  --v-odds-h: calc(11px + 3px + 44px);                /* label + gap + input */
}
.verdict__answer {
  grid-column: 1;
  min-width: 0;
  /* figure line + facts line, whether or not the facts line is rendered */
  min-height: calc(var(--v-fig-h) + var(--v-sub-h));
}
.verdict__fig {
  font: 800 var(--v-fig-size)/1.08 var(--font-d);
  letter-spacing: -.025em;
  font-variant-numeric: tabular-nums;
  color: var(--eq, var(--text));
}
.verdict.is-empty .verdict__fig {
  font-size: clamp(16px, 2.4vw, 20px);
  color: var(--text2);
  letter-spacing: -.005em;
  font-weight: 700;
}
.verdict__sub {
  margin-top: 5px;
  font: 700 14px/1.4 var(--font-u);
  font-variant-numeric: tabular-nums;
  color: var(--text2);
}
/* "+EV call" and "−EV fold" are different strings in different colours; a
   fixed-width box keeps the facts line from re-wrapping when the verdict
   flips (SPEC v2 §8). */
.v-ev {
  font-weight: 800;
  display: inline-block;
  min-width: 8.5ch;
  text-align: left;
}
.v-ev.is-pos { color: var(--pos); }
.v-ev.is-neg { color: var(--neg); }

/* the CTA stands in for the pot/to-call fields, so it reserves their height */
.verdict__cta { grid-column: 2; min-height: var(--v-odds-h); }
.verdict:not(.is-empty) .verdict__cta { display: none; }
.verdict.is-empty .verdict__odds { display: none; }

.verdict__odds { grid-column: 2; display: flex; gap: 10px; }
.field { display: flex; flex-direction: column; gap: 3px; }
.field__lbl { font: 600 11px/1 var(--font-u); color: var(--text2); }
.field__in {
  width: 88px;
  height: 44px;
  padding: 0 10px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: 700 16px/1 var(--font-u);   /* 16px keeps iOS from zooming on focus */
  text-align: right;
  font-variant-numeric: tabular-nums;
  /* The bottom bar is already reserved once, on the scroll container
     (`html { scroll-padding-bottom: var(--bar-h) + 20px }`). Reserving it a
     second time here — plus 120 px of guessed on-screen keyboard — meant every
     tap into pot/to-call scrolled the page even when the field was nowhere
     near the fold (verdict.spec.mjs:37). The keyboard is the browser's to
     handle; this keeps only a hairline of breathing room. */
  scroll-margin-bottom: 8px;
}
.field__in:focus { outline: none; border-color: var(--info); box-shadow: 0 0 0 3px var(--info); }

.metarow {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
.streetrail { display: flex; align-items: center; flex: 1 1 200px; min-width: 0; gap: 4px; }
.streetrail__item { flex: 1; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.streetrail__bar { height: 3px; border-radius: 2px; background: var(--line); transition: background .3s; }
.streetrail__lbl {
  font: 600 11.5px/1 var(--font-u);
  color: var(--text3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.streetrail__item.is-past .streetrail__bar { background: var(--gold); }
.streetrail__item.is-past .streetrail__lbl { color: var(--text2); }
.streetrail__item.is-now .streetrail__bar { background: var(--gold); }
.streetrail__item.is-now .streetrail__lbl { color: var(--gold); font-weight: 700; }

.enginebadge {
  display: flex;
  align-items: center;
  gap: 7px;
  font: 600 11.5px/1 var(--font-u);
  font-variant-numeric: tabular-nums;
  color: var(--text3);
}
.enginebadge__txt.is-exact { color: var(--pos); }
.enginebadge__txt.is-fail { color: var(--neg); }
.spin {
  width: 11px; height: 11px;
  border-radius: 50%;
  border: 1.5px solid var(--line2);
  border-top-color: var(--gold);
  animation: pkSpin .7s linear infinite;
  display: inline-block;
  flex: 0 0 auto;
}

/* ── 10. Hands view ──────────────────────────────────────────────────────── */

.hboard {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel);
}
.hboard__cap { font: 700 12.5px/1 var(--font-u); color: var(--text2); flex: 0 0 auto; }
.pot--row { margin-left: auto; gap: 7px; }
.hboard__pot {
  font: 800 14px/1 var(--font-u);
  font-variant-numeric: tabular-nums;
  color: var(--gold);
  flex: 0 0 auto;
}
.board--row { flex: 0 1 auto; gap: 6px; }
.board--row .card { width: 44px; min-width: 44px; font-size: 62px; }
.board--row .slot { width: 44px; min-width: 44px; height: 62px; }

.hlist { display: flex; flex-direction: column; gap: 6px; }
.hrow {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  grid-template-areas: "chip cards name eq";
  align-items: center;
  column-gap: 12px;
  row-gap: 4px;
  padding: 8px 12px 8px 8px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--panel);
}
.hrow.is-hero { border-color: rgba(232,184,75,.5); background: var(--podbest); }
.hrow.is-best .hrow__eq { color: var(--gold); }
.hrow__chip {
  grid-area: chip;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px;
  padding: 0 8px;
  border-radius: 9px;
  border: 1px solid rgba(0,0,0,.35);
  background: var(--idn);
  color: var(--idn-fg);
  font: 800 13px/1 var(--font-u);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.hrow.is-hero .hrow__chip { box-shadow: 0 0 0 2px var(--gold); }
.hrow__cards { grid-area: cards; display: flex; gap: 5px; }
.hrow__cards .card { width: 48px; min-width: 48px; font-size: 67px; }
.hrow__cards .slot { width: 48px; min-width: 48px; height: 67px; }
.hrow__name {
  grid-area: name;
  min-width: 0;
  font: 700 13px/1.35 var(--font-u);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hrow__name.is-tier {
  justify-self: start;
  color: var(--tier-fg);
  background: var(--tier);
  border-radius: 5px;
  padding: 2px 8px;
}
.hrow__name.is-quiet { color: var(--text3); font-weight: 600; }
.hrow__num { grid-area: eq; text-align: right; }
.hrow__eq {
  display: block;
  font: 800 19px/1.15 var(--font-u);
  font-variant-numeric: tabular-nums;
  /* F8 (verifier / council §5): equity figures are set at zero letter-spacing.
     The negative tracking closed 3/8 and 6/9 into each other at the minimum
     size. Only the Sora verdict figure — display type — keeps its own. */
  letter-spacing: 0;
  color: var(--eq, var(--text3));
}
.hrow__wt {
  display: block;
  font: 600 11.5px/1.3 var(--font-u);
  font-variant-numeric: tabular-nums;
  color: var(--text2);
  white-space: nowrap;
}

/* ── 11. inline card editor ──────────────────────────────────────────────── */

.editor {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 16px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel);
}
/* (the >= 1680 side-dock is withdrawn — amendment A1) */
.editor__head { display: flex; flex-direction: column; gap: 2px; }
.editor__title { font: 700 15px/1.3 var(--font-d); letter-spacing: -.012em; color: var(--text); }
.editor__hint { font: 600 12px/1.4 var(--font-u); color: var(--text3); }
.pickbody { display: flex; flex-direction: column; gap: 12px; }

/* ── 11b. Game view drawer (SPEC v2 amendment A1) ────────────────────────── */

.drawer {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel);
  /* ONE internal scrollbar: the aside itself never scrolls, `.drawer__scroll`
     does, and nothing inside it is allowed to scroll vertically. */
  overflow: hidden;
}
/* Docked (Stage). `--drawer-h` is written by app.js as table box + row gap +
   the MEASURED verdict strip, so the column has a DEFINITE height and the flex
   scroller below it resolves — a grid item sized by its own content would grow
   the row instead and put the page back into document scroll. */
.stage[data-drawer="dock"] .drawer {
  height: var(--drawer-h, auto);
  max-height: var(--drawer-h, none);
  transition: width .22s var(--e-out);
}
.drawer__head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
}
.drawer__title { font: 800 15px/1.25 var(--font-d); letter-spacing: -.015em; color: var(--text); }
.drawer__title:focus-visible, .drawer__edtitle:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
/* the close control is the slide-over's; the dock uses the header toggle */
.stage[data-drawer="dock"] #drawerClose { display: none; }

.drawer__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  padding: 10px;
}
/* No nested vertical scrollbars anywhere inside the drawer. The two grids keep
   their HORIZONTAL scroller (the 13x13 matrix is wider than 380px at 26px
   cells), and `overflow-x: auto` alone would silently make overflow-y `auto`
   too — hence the explicit hidden. */
.drawer .gridscroll { overflow-y: hidden; }
.drawer .presets { overflow-y: hidden; }
/* the Timeline's own 240px scroller becomes part of the drawer's one scroll */
.drawer .histlist { max-height: none; overflow-y: visible; }
.drawer .panels, .drawer .tabbar { overflow: visible; }

/* accordion ---------------------------------------------------------------- */
.acc { display: flex; flex-direction: column; gap: 8px; }
.acc__sec { border: 1px solid var(--line); border-radius: 12px; background: var(--surface); overflow: hidden; }
.acc__h { margin: 0; }
.acc__btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 42px;
  padding: 9px 12px;
  border: 0;
  background: transparent;
  color: var(--text);
  font: 700 13.5px/1.3 var(--font-d);
  letter-spacing: -.01em;
  text-align: left;
  cursor: pointer;
}
.acc__btn::after {
  content: '';
  flex: 0 0 auto;
  width: 8px; height: 8px;
  border-right: 2px solid var(--text3);
  border-bottom: 2px solid var(--text3);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .16s var(--e-out);
}
.acc__btn[aria-expanded="true"] { color: var(--text); }
.acc__btn[aria-expanded="true"]::after { transform: rotate(-135deg) translate(-2px, -2px); }
.acc__body[hidden] { display: none; }
.acc__body > .panel { background: transparent; padding: 0 12px 12px; }
/* the accordion header IS the section heading here — the panel's own <h2>
   would be a second copy of the same words */
.acc__body .panel__h { display: none; }
.acc__body .panel__top { justify-content: flex-end; }
.acc__body .panel--hist .panel__top { justify-content: flex-start; }

/* editor state — it REPLACES the accordion, never stacks above it */
.drawer__editor { display: flex; flex-direction: column; gap: 10px; }
.drawer__edhead { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.drawer__edtitle { font: 700 14px/1.3 var(--font-d); letter-spacing: -.012em; color: var(--text); }
.drawer__act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 12px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text2);
  font: 700 12.5px/1 var(--font-u);
  cursor: pointer;
}
.drawer__back { color: var(--info); }

/* The 52-card grid wraps each suit into 7 + 6 cells — eight grouped rows, and
   every cell at least 44px wide inside a 380-440px column (amendment A1). */
.drawer .cardgrid {
  grid-template-columns: 20px repeat(7, minmax(44px, 1fr));
  min-width: 0;
  gap: 4px;
  row-gap: 5px;
}
.drawer .cardgrid > * { grid-row: var(--sg-r); grid-column: var(--sg-c, 1); }
.drawer .cardgrid__lbl { grid-row: var(--sg-r) / span 2; grid-column: 1; }
.drawer .cardcell { min-height: 44px; font-size: 48px; }
/* the 13x13 matrix keeps its 26px cells and scrolls sideways (council ruling) */
.drawer .rangegrid { min-width: 360px; }

/* Compact: a MODAL slide-over from the right. */
.drawer__scrim {
  position: fixed;
  inset: 0;
  z-index: 79;
  background: rgba(0, 0, 0, .55);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
.stage[data-drawer="over"] .drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: min(440px, 88vw);
  max-width: 88vw;
  z-index: 80;
  border-radius: 0;
  border-top: 0; border-right: 0; border-bottom: 0;
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  box-shadow: -18px 0 50px rgba(0, 0, 0, .5);
  animation: pkSlideIn .2s var(--e-out) both;
}
@keyframes pkSlideIn { from { transform: translateX(14px); opacity: .4; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .stage[data-drawer="over"] .drawer { animation: none; }
  .stage[data-drawer="dock"] .drawer { transition: none; }
}
[data-motion="reduce"] .stage[data-drawer="over"] .drawer { animation: none; }
[data-motion="reduce"] .stage[data-drawer="dock"] .drawer { transition: none; }

/* `hidden` must win over the flex display above — that is the whole collapsed
   contract (hidden + inert, out of the tab order). */
.drawer[hidden], .drawer__scrim[hidden], .drawer__editor[hidden] { display: none !important; }

/* The toggle and the bar button only exist where a drawer does. The header is
   outside `.stage`, so the presentation is mirrored onto <body>. */
.hdr__drawer { display: none; }
body[data-drawer="dock"] .hdr__drawer { display: inline-flex; }
#barDrawer { display: none; }
body[data-drawer="over"] #barDrawer { display: inline-flex; }
.hdr__drawer[aria-expanded="true"] { border-color: var(--line2); background: var(--surface2); }
.hdr__drawer[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
.barbtn--game { flex: 2 1 104px; }

/* ── 12. panels ──────────────────────────────────────────────────────────── */

.panels {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
}
.stage[data-pcols="3"] .panels { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.stage[data-pcols="1"] .panels {
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  background: none;
  border: 0;
  border-radius: 0;
  overflow: visible;
}

.tabbar { display: none; }
.stage[data-pcols="1"] .tabbar {
  display: flex;
  gap: 4px;
  padding: 4px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--panel);
  overflow-x: auto;
  scrollbar-width: thin;
}
.tab {
  flex: 1 0 auto;
  height: 44px;
  padding: 0 14px;
  border-radius: 9px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text3);
  font: 700 13px/1 var(--font-u);
  cursor: pointer;
  white-space: nowrap;
  transition: background .16s, color .16s, border-color .16s;
}
.tab[aria-selected="true"] { background: var(--surface2); border-color: var(--line2); color: var(--text); }

.panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  background: var(--panel);
}
.stage[data-pcols="1"] .panel { border: 1px solid var(--line); border-radius: 14px; }
.stage[data-pcols="3"] .panel--equity,
.stage[data-pcols="2"] .panel--equity { grid-column: span 2; }

.panel__top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.panel__h {
  font: 700 15px/1.25 var(--font-d);
  letter-spacing: -.012em;
  color: var(--text);
}
.panel__note { font: 600 12px/1.3 var(--font-u); color: var(--text3); }
.panel__note--band { font-weight: 700; color: var(--tex, var(--text3)); }
.panel__body { font: 500 13px/1.6 var(--font-u); color: var(--text2); max-width: 62ch; }
.empty { font: 500 13px/1.6 var(--font-u); color: var(--text2); max-width: 62ch; }

.iconbtn {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text2);
  font-size: 15px;
  cursor: pointer;
}
.linkbtn {
  min-height: 36px;
  padding: 0 12px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--info);
  font: 700 12px/1 var(--font-u);
  cursor: pointer;
}

/* equity rows */
.eqrows { display: flex; flex-direction: column; gap: 8px; }
.eqrow {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.eqrow.is-best { background: var(--podbest); border-color: rgba(232,184,75,.4); }
.eqrow__top { display: flex; align-items: center; gap: 9px; }
.eqrow__tag {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px;
  padding: 3px 7px;
  border-radius: 6px;
  background: var(--idn);
  color: var(--idn-fg);
  font: 800 12.5px/1.3 var(--font-u);
  font-variant-numeric: tabular-nums;
}
.eqrow.is-hero .eqrow__tag { box-shadow: 0 0 0 2px var(--gold); }
.eqrow__cards { display: flex; gap: 5px; font: 800 13.5px/1 var(--font-u); min-width: 56px; }
.badge[data-suit="0"] { color: var(--badge0); }
.badge[data-suit="1"] { color: var(--badge1); }
.badge[data-suit="2"] { color: var(--badge2); }
.badge[data-suit="3"] { color: var(--badge3); }
.badge.is-empty { color: var(--text3); }
.eqrow__notewrap { flex: 1; min-width: 0; display: flex; }
.eqrow__note {
  font: 700 12.5px/1.45 var(--font-u);
  color: var(--text);
  border-radius: 5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.eqrow__note.is-tier { color: var(--tier-fg); background: var(--tier); padding: 2px 8px; }
.eqrow__eq {
  font: 800 17px/1 var(--font-u);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;   /* F8: see .hrow__eq */
  color: var(--eq, var(--text));
}
.eqrow.is-best .eqrow__eq { color: var(--gold); }
.eqrow__mid { display: flex; align-items: center; gap: 9px; }
.eqrow__wt { font: 600 11.5px/1 var(--font-u); font-variant-numeric: tabular-nums; color: var(--text2); white-space: nowrap; }

.bar { flex: 1; height: 5px; border-radius: 3px; background: var(--line); overflow: hidden; }
.bar--tex { height: 7px; border-radius: 4px; }
.bar__fill {
  height: 100%;
  border-radius: inherit;
  width: var(--w, 0%);
  background: var(--eq, var(--text3));
  transition: width .45s var(--e-out), background .3s;
}
.bar__fill--tex { background: linear-gradient(90deg, var(--pos), var(--gold) 55%, var(--neg)); }

.dist { display: flex; height: 6px; border-radius: 3px; overflow: hidden; background: var(--line); }
.dist > i { width: var(--w, 0%); transition: width .45s var(--e-out); }

.catlegend, .tierlegend { display: flex; flex-wrap: wrap; gap: 5px 12px; padding-top: 2px; }
.catlegend__i, .tierlegend__i {
  display: inline-flex; align-items: center; gap: 5px;
  font: 600 11px/1 var(--font-u);
  color: var(--text3);
}

/* outs */
.outs { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.outs__big { display: flex; align-items: baseline; gap: 6px; }
.outs__count {
  font: 800 34px/1 var(--font-d);
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  color: var(--pos);
}
.outs__count.is-against { color: var(--neg); }
.outs__unit { font: 700 12px/1 var(--font-u); color: var(--text3); }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-flex;
  align-items: center;
  padding: 5px 10px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--surface);
  font: 700 12px/1 var(--font-u);
  color: var(--text);
}
.chip--quiet { color: var(--text2); font-weight: 600; }

.stat { display: flex; flex-direction: column; gap: 3px; }
.stat__cap { font: 600 11px/1 var(--font-u); color: var(--text3); }
.stat__val { font: 800 16px/1 var(--font-u); font-variant-numeric: tabular-nums; color: var(--text); }

.texbar { display: flex; align-items: center; gap: 10px; }
.texbar__score {
  font: 700 13px/1 var(--font-u);
  font-variant-numeric: tabular-nums;
  color: var(--text2);
  min-width: 34px;
  text-align: right;
}

/* streets chart — council round 8 §3 ("unprofessional lines") and §4's minimum:
   stable aspect ratio, real plot margins, hero dominant, opponents quiet, and
   isolation that works from pointer, touch and keyboard. Geometry lives in one
   place only: app.js `GEO` (l34 / b26 / r12 / t12 inside a 360x200 box). */
.graph { position: relative; }
.graph__svg {
  display: block;
  width: 100%;
  aspect-ratio: 360 / 200;
  min-height: 190px;
  overflow: visible;
  touch-action: manipulation;
}
.graph__grid line { stroke: var(--line); stroke-width: 1; }
.graph__grid line.is-base { stroke: var(--text3); opacity: .55; }
.graph__axis text {
  font: 600 11px/1 var(--font-u);
  font-variant-numeric: tabular-nums;
  fill: var(--text2);
}
.graph__axis text.is-now { fill: var(--gold); font-weight: 800; }
.graph__empty {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  margin: 0; padding: 0 18px;
  text-align: center;
  font: 600 13px/1.45 var(--font-u);
  color: var(--text3);
}
.graph.has-data .graph__empty { display: none; }

/* one group per seat — isolation dims the whole group, so the hero's own
   opacity hierarchy inside it never has to be recomputed */
.gs { transition: opacity 180ms ease; }
.gline {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke-dashoffset 500ms cubic-bezier(.22,.61,.36,1);
}
.garea { stroke: none; }
.gdot { cursor: pointer; }
.gdot__hit { fill: transparent; stroke: none; }
.gdot:hover .gdot__pt { stroke: var(--info); }
.gdot:focus-visible { outline: none; }
.gdot:focus-visible .gdot__pt { stroke: var(--info); stroke-width: 2.5; }
.graph__readbox { fill: var(--bg); fill-opacity: .94; stroke: var(--line); stroke-width: 1; }
.graph__readtxt {
  font: 700 10.5px/1 var(--font-u);
  font-variant-numeric: tabular-nums;
  fill: var(--text);
}

.glegend { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.glegend__i {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px 3px 4px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: var(--surface);
  font: inherit;
  cursor: pointer;
  transition: opacity 160ms ease, border-color 160ms ease;
}
.glegend__i[aria-pressed="true"] { border-color: var(--idn-line); }
.glegend__i.is-dim { opacity: .35; }
.glegend__tag {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 30px;
  padding: 2px 5px;
  border-radius: 5px;
  background: var(--idn);
  color: var(--idn-fg);
  font: 800 11.5px/1.3 var(--font-u);
  font-variant-numeric: tabular-nums;
}
.glegend__line { width: 16px; height: 3px; border-radius: 2px; background: var(--idn-line); }

/* timeline */
.histlist { display: flex; flex-direction: column; gap: 5px; max-height: 240px; overflow-y: auto; scrollbar-width: thin; }
.histrow {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px;
  padding: 8px 10px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  transition: border-color .14s;
}
.histrow.is-new { border-color: rgba(232,184,75,.35); background: rgba(232,184,75,.06); }
.histrow__t { font: 600 11px/1 var(--font-u); font-variant-numeric: tabular-nums; color: var(--text3); min-width: 40px; }
.histrow__l { flex: 1; font: 700 12.5px/1.3 var(--font-u); color: var(--text2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.histrow.is-new .histrow__l { color: var(--text); }
.histrow__s { font: 600 11px/1 var(--font-u); color: var(--text3); }

/* ── 13. bottom bar ──────────────────────────────────────────────────────── */

.bottombar {
  display: none;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 70;
  align-items: center;
  gap: 8px;
  padding: 10px max(12px, env(safe-area-inset-left)) calc(10px + env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-right));
  background: var(--glass2);
  border-top: 1px solid var(--line);
}
body[data-bar="1"] .bottombar { display: flex; }
/* F1 (verifier): the bar and the header's wide actions are the SAME actions in
   two places, and council §11 forbids duplicating a control. The width-only
   rule in §16 hid the header copy below 1100 px, which left both mounted
   wherever the bar appears on a WIDE window — manual Hands at 1440x900, and
   auto-Hands at H0 < 560 (1440x450). The bar's presence is the real condition,
   so it is the one that hides them. */
body[data-bar="1"] .hdr__wide { display: none; }
.barbtn {
  height: 54px;
  min-height: 54px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: 13px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: 700 13px/1 var(--font-u);
  cursor: pointer;
  flex: 2 1 104px;
}
.barbtn--gold {
  flex: 3 1 150px;
  border-color: rgba(232,184,75,.5);
  background: linear-gradient(170deg, #f0c75f, #d09a2c);
  color: #221704;
  font: 800 15px/1 var(--font-u);
  box-shadow: 0 1px 0 rgba(255,255,255,.35) inset;
}
.barbtn--icon { flex: 0 0 60px; flex-direction: column; gap: 2px; color: var(--text2); }
.barbtn__glyph { font-size: 16px; line-height: 1; }
.barbtn__cap { font: 700 10px/1 var(--font-u); }
.barbtn:active { transform: translateY(1px); }

/* ── 14. sheets ──────────────────────────────────────────────────────────── */

.sheetwrap {
  border: 0;
  padding: 0;
  margin: 0;
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  background: transparent;
  color: var(--text);
  overflow: hidden;
}
.sheetwrap:not([open]) { display: none; }
.sheetwrap[open] {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.sheetwrap::backdrop { background: rgba(0,0,0,.66); }
.sheetwrap.is-fallback { position: fixed; background: rgba(0,0,0,.66); }

.sheet {
  width: 100%;
  max-width: 720px;
  max-height: 92vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  gap: 12px;
  border-radius: 20px 20px 0 0;
  border: 1px solid var(--line);
  border-bottom: 0;
  background: var(--bg);
  box-shadow: 0 -20px 60px rgba(0,0,0,.6);
  animation: pkSheet .28s var(--e-in) both;
  padding: 10px clamp(12px, 3vw, 22px) calc(18px + env(safe-area-inset-bottom));
  scrollbar-width: thin;
}
@supports (max-height: 100dvh) {
  .sheet { max-height: min(92dvh, calc(100dvh - env(safe-area-inset-top))); }
}
.sheet__handle { width: 42px; height: 4px; border-radius: 2px; background: var(--line2); margin: 4px auto 0; flex: 0 0 auto; }
.sheet__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.sheet__title { font: 800 16px/1.25 var(--font-d); letter-spacing: -.015em; color: var(--text); }
.sheet__hint { font: 600 12px/1.4 var(--font-u); color: var(--text3); margin-top: 3px; }
.sheet__sub { margin-top: 6px; }
.sheet__foot { font: 500 12px/1.5 var(--font-u); color: var(--text3); }

.seatctl { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.seg {
  display: flex;
  gap: 5px;
  padding: 4px;
  border-radius: 11px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.seg--slots { flex: 1 1 180px; }
.seg--iters, .seg--view { flex: 0 0 auto; padding: 3px; gap: 3px; }
.seg__btn {
  flex: 1;
  min-height: 44px;
  padding: 0 12px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text3);
  font: 700 12.5px/1 var(--font-u);
  cursor: pointer;
  white-space: nowrap;
}
.seg--iters .seg__btn,
.seg--view .seg__btn { min-height: 44px; min-width: 44px; padding: 0 9px; font-size: 12px; }
.seg__btn.is-on { background: var(--surface2); border-color: var(--line2); color: var(--text); }

.presets { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 6px; scrollbar-width: thin; }
.preset {
  flex: 0 0 auto;
  height: 44px;
  padding: 0 14px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: 700 12.5px/1 var(--font-u);
  cursor: pointer;
  transition: background .14s, border-color .14s, color .14s;
}

.gridscroll { overflow-x: auto; padding-bottom: 6px; scrollbar-width: thin; }
.gridscroll::-webkit-scrollbar { height: 5px; }
.gridscroll::-webkit-scrollbar-thumb { background: var(--line2); border-radius: 3px; }

.cardgrid {
  display: grid;
  grid-template-columns: 22px repeat(13, minmax(40px, 1fr));
  gap: clamp(3px, .6vw, 6px);
  align-items: center;
  min-width: 590px;
}
.cardgrid__lbl { font-size: 17px; line-height: 1; text-align: center; }
.cardgrid__lbl[data-suit="0"] { color: var(--badge0); }
.cardgrid__lbl[data-suit="1"] { color: var(--badge1); }
.cardgrid__lbl[data-suit="2"] { color: var(--badge2); }
.cardgrid__lbl[data-suit="3"] { color: var(--badge3); }

.cardcell {
  position: relative;
  aspect-ratio: 5/7;
  min-height: 56px;
  border-radius: 7px;
  background: linear-gradient(158deg, var(--carda), var(--cardb));
  border: 1.5px solid transparent;
  box-shadow: var(--shc);
  cursor: pointer;
  overflow: hidden;
  padding: 0;
  font-size: 56px;
  transition: transform .14s var(--e-out), border-color .14s, opacity .14s;
}
.cardcell[data-suit="0"] { color: var(--suit0); }
.cardcell[data-suit="1"] { color: var(--suit1); }
.cardcell[data-suit="2"] { color: var(--suit2); }
.cardcell[data-suit="3"] { color: var(--suit3); }
.cardcell.is-used { opacity: .14; pointer-events: none; }

.rangewrap { display: flex; flex-direction: column; gap: 9px; }
.rangegrid { display: grid; grid-template-columns: repeat(13, minmax(26px, 1fr)); gap: 2px; min-width: 360px; }
.rangecell {
  aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
  border-radius: 4px;
  border: 1px solid color-mix(in srgb, var(--tier) 70%, black 20%);
  background-color: var(--tier);
  color: var(--tier-fg);
  font: 700 clamp(8px, 1.1vw, 11px)/1 var(--font-u);
  cursor: pointer;
  padding: 0;
  position: relative;
  transition: transform .12s, box-shadow .12s;
}
@supports not (background: color-mix(in srgb, red 18%, transparent)) {
  .rangecell { border-color: var(--tier); }
}
/* unavailable: solid muted fill (own custom property, not an alpha wash so
   the label keeps its normal opaque tier-fg colour on top) plus a diagonal
   hatch image layered above it — background-color stays a plain solid so a
   contrast check against it (grid.spec.mjs) reads one real colour. */
.rangecell.is-dead {
  background-color: var(--tier-muted);
  background-image: repeating-linear-gradient(45deg, transparent 0 4px, rgba(0,0,0,.35) 4px 5px);
  border-color: color-mix(in srgb, var(--tier-muted) 70%, black 20%);
  pointer-events: none;
  cursor: default;
}
/* selected combo: gold ring, a dark keyline just inside it (separates the
   ring from the cell's own fill on Marginal yellow / Weak grey) and, in
   light theme only, a further 1px light line outside the ring (separates
   the ring from the light page background). */
.rangecell.is-selected {
  box-shadow: inset 0 0 0 1px #07080b, 0 0 0 2px #e8b84b;
  z-index: 1;
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .rangecell.is-selected {
    box-shadow: inset 0 0 0 1px #07080b, 0 0 0 2px #e8b84b, 0 0 0 3px #ffffff;
  }
}
:root[data-theme="light"] .rangecell.is-selected {
  box-shadow: inset 0 0 0 1px #07080b, 0 0 0 2px #e8b84b, 0 0 0 3px #ffffff;
}

.setrows { display: flex; flex-direction: column; gap: 10px; }
.setrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 58px;
  padding: 10px 14px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: 700 13.5px/1.3 var(--font-u);
  cursor: pointer;
  text-align: left;
}
.setrow--static { cursor: default; flex-wrap: wrap; }
.setrow--slim { min-height: 50px; }
.setrow--danger { color: var(--neg); }
.setrow__text { display: flex; flex-direction: column; gap: 3px; }
.setrow__title { font: 700 13.5px/1.3 var(--font-u); }
.setrow__sub { font: 500 12px/1.4 var(--font-u); color: var(--text2); }

.switch {
  flex: 0 0 auto;
  width: 46px; height: 27px;
  border-radius: 14px;
  background: var(--switch);
  display: flex; align-items: center; justify-content: flex-start;
  padding: 3px;
  transition: background .18s;
}
.switch__knob { width: 21px; height: 21px; border-radius: 50%; background: var(--pod); box-shadow: 0 1px 3px rgba(0,0,0,.35); transition: transform .18s var(--e-out); }
.setrow[aria-pressed="true"] .switch { background: linear-gradient(170deg, #f2cb63, #cf9829); }
.setrow[aria-pressed="true"] .switch__knob { transform: translateX(19px); background: #fff; }

.pills { flex: 0 0 auto; display: flex; gap: 3px; padding: 3px; border-radius: 10px; background: var(--switch); }
.pills__p { width: 26px; height: 22px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--text3); }
.pills__p.is-on { background: var(--pod); color: var(--gold); }

.keys { display: flex; flex-direction: column; gap: 6px; }
.keys__row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 11px;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--surface);
  font: 600 12.5px/1.4 var(--font-u);
  color: var(--text2);
}
.kbd {
  font: 700 11px/1 var(--font-u);
  padding: 5px 8px;
  border-radius: 5px;
  background: var(--surface2);
  border: 1px solid var(--line);
  color: var(--text);
  min-width: 36px;
  text-align: center;
  flex: 0 0 auto;
}

/* ── 15. toast ───────────────────────────────────────────────────────────── */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(24px + var(--bar-h, 0px) + env(safe-area-inset-bottom));
  z-index: 300;
  transform: translateX(-50%);
  max-width: min(92vw, 420px);
  padding: 11px 18px;
  border-radius: 11px;
  border: 1px solid var(--line);
  background: var(--glass2);
  box-shadow: var(--sh1);
  font: 700 13px/1.35 var(--font-u);
  color: var(--text);
  text-align: center;
  animation: pkToast .26s var(--e-in) both;
}

/* ── 16. responsive ──────────────────────────────────────────────────────── */

/* The mode is measured, never guessed — these rules only handle chrome that
   the layout engine does not own.
   F1 fix (blind verifier, round 3): `.hdr__wide` used to be hidden by this
   WIDTH breakpoint, which is exactly the width-not-measurement bug F1 was
   about — Stage can legitimately resolve below 1100px (BRIEF P's accepted
   deviation: the Stage box's ~1010px cap is a derived cap, not a target), and
   in that band `data-bar` is still "0" (BAR_MODES has no "stage"), so this
   rule and the fixed bar's absence left NO Deal control mounted anywhere at
   1024x768 Stage. The single, measured rule at line ~1735
   (`body[data-bar="1"] .hdr__wide`) is what F1 actually asks for; this stale
   duplicate is removed rather than reconciled, since keeping both is what
   caused the gap. */
@media (max-width: 760px) {
  .hdr__row { padding: 8px 10px; gap: 7px; }
  .hdr__spacer { flex: 1 1 0px; min-width: 0; }
  .brand__name { font-size: 15px; }
  .stepper__val { min-width: 54px; font-size: 12.5px; }
  .viewseg__btn { padding: 0 9px; font-size: 11.5px; }
  .verdict { --v-fig-size: clamp(28px, min(8vw, 7vh), 34px); }
  .verdict { grid-template-columns: minmax(0, 1fr); padding: 12px 14px; }
  .verdict__answer, .verdict__cta, .verdict__odds { grid-column: 1; }
  .verdict__odds { justify-content: flex-start; }
  .field__in { width: 104px; }
  .hrow {
    grid-template-columns: auto auto minmax(0, 1fr);
    grid-template-areas:
      "chip cards eq"
      "chip name  name";
    column-gap: 10px;
  }
  .hboard { flex-wrap: wrap; }
}
/* One row at 390 px, with every target still 44 px (ISSUE C6). The wordmark
   is the only thing that can go: the h1 stays in the DOM and in the
   accessibility tree, it just stops taking horizontal space. */
@media (max-width: 560px) {
  .hdr__row { flex-wrap: nowrap; gap: 6px; }
  .brand {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .hdr__spacer { display: none; }
  .stepper__u { display: none; }
  .stepper__val { min-width: 26px; }
  .stepper__btn { width: 40px; }
  .viewseg { padding: 2px; }
  .viewseg__btn { padding: 0 6px; font-size: 11px; }
  .btn--icon { width: 40px; }
}
/* BRIEF S / council round 9, R2 — real-device failure (S25, 360x641): the
   3-segment view control plus the stepper and two icon buttons needed ~378px
   of run at 44px targets, so the row below 380px used to WRAP to two rows.
   A wrapped header measured ~118px, which pushed H0 under the SEAM.safeH
   floor before Pocket was even considered (council round 9 diagnosis) — the
   real bug was never Pocket's geometry, it was a two-row header stealing the
   height budget. The fix: below 400px the 3-segment control is replaced by a
   narrower control in ONE slot (round 9's cycling button, superseded by brief
   W's two-segment `#viewPick` below) — so the row now holds stepper + view
   control + theme + "..." on ONE row with room to spare, and the wrap rule
   that used to rescue it is gone. The 3-segment control is unchanged above
   400px (session ruling R2 / brief S). */
/* BRIEF W (round 10, remedy A) replaces round 9's cycling button with the
   two-segment Table | Hands control at the same single header slot: 48x44 per
   segment still fits the one-row budget at 360px (stepper ~114 + segments 96
   + theme 40 + "..." 40 + gaps ≈ 320 of the 340 available), and it names the
   CHOICE instead of the state, which is what the owner could not find. */
@media (max-width: 400px) {
  .viewseg { display: none; }
  .viewpick { display: flex; }
}
/* Below ~340px (the 320px class the round-9 matrix carries) the two segments'
   48px costs more run than the row has: the segments give back the 4px each
   that is decoration, never the 44px target floor, and the row's gap tightens
   by 1px. Measured at 320px: everything inside the viewport, no horizontal
   overflow (narrow.spec "320x568"). */
@media (max-width: 340px) {
  .hdr__row { gap: 5px; }
  .viewpick__btn { min-width: 44px; padding: 0 2px; font-size: 11.5px; }
}

/* BRIEF U: header About button. Text label at ≥440px CSS width; below that
   the row needs the space back, so 400-440px swaps to an icon-only button
   (aria-label carries the name); below 400px both are hidden and "About" is
   reached from the "..." settings sheet (its first row) or the footer link,
   same as the header disappearing at that width for other wide controls. */
.hdr__aboutIcon { display: none; }
@media (max-width: 440px) {
  .hdr__about { display: none; }
  .hdr__aboutIcon { display: inline-flex; }
}
@media (max-width: 400px) {
  .hdr__aboutIcon { display: none; }
}

@media print {
  .hdr, .bottombar, .tabbar, .sheetwrap, .toast, .bgwash { display: none; }
  .panel { break-inside: avoid; }
}

/* ── 17. About dialog (council round 8 §2: the SEO copy moved off the
   calculator's own flow into a sheet reached from the header/"..." menu and
   the footer — README §7.3/DEPLOY unaffected, `.about` still names the
   typographic content, just as a dialog body instead of a page section). */

.about {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 2px 0 4px;
}
.about h2,
.about h3 {
  font-family: var(--font-d);
  color: var(--text);
  margin: 0;
}
.about h2 { font-size: clamp(21px, 4vw, 27px); font-weight: 800; line-height: 1.28; }
.about h3 { font-size: 17px; font-weight: 700; line-height: 1.32; margin-top: 6px; }
.about p {
  font-family: var(--font-u);
  font-weight: 500;
  font-size: 16px;
  line-height: 1.65;
  color: var(--text2);
}
.about b.gold { color: var(--gold); font-weight: 700; }

.about__steps {
  margin: 0;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-family: var(--font-u);
  font-weight: 500;
  font-size: 16px;
  line-height: 1.6;
  color: var(--text2);
}
.about__steps li { padding-left: 2px; }

.about__faq { display: flex; flex-direction: column; gap: 8px; }
.about__faq details {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  overflow: hidden;
}
.about__faq summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 12px 16px;
  font-family: var(--font-u);
  font-weight: 700;
  font-size: 15px;
  line-height: 1.4;
  color: var(--text);
}
.about__faq summary::-webkit-details-marker { display: none; }
.about__faq summary::after {
  content: '+';
  margin-left: auto;
  flex: 0 0 auto;
  font-size: 19px;
  line-height: 1;
  color: var(--text3);
}
.about__faq details[open] summary::after { content: '\2212'; }
.about__faq summary:focus-visible { outline-offset: -3px; }
.about__faq p {
  margin: 0;
  padding: 0 16px 16px;
  font-family: var(--font-u);
  font-weight: 500;
  font-size: 15px;
  line-height: 1.6;
  color: var(--text2);
}

.about__foot {
  margin: 4px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-family: var(--font-u);
  font-weight: 700;
  font-size: 13px;
  text-align: center;
  color: var(--text3);
}

.appfoot {
  max-width: 760px;
  margin: 28px auto 0;
  padding: 14px 20px calc(20px + env(safe-area-inset-bottom));
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-u);
  font-weight: 600;
  font-size: 12.5px;
  color: var(--text3);
  text-align: center;
}
.appfoot__link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--info);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.appfoot__link:hover, .appfoot__link:focus-visible { text-decoration: underline; }
.appfoot__dot { color: var(--text3); }

@media (max-width: 480px) {
  .about h3 { font-size: 16px; }
}

/* ── 18. send-feedback sheet (council round 8 §2, "with a smart menu") ──── */

.feedback { display: flex; flex-direction: column; gap: 16px; padding: 2px 0 4px; }
.feedback__group { display: flex; flex-direction: column; gap: 8px; }
.feedback__h {
  font-family: var(--font-u);
  font-weight: 700;
  font-size: 13.5px;
  color: var(--text);
  margin: 0;
}
.fbchip {
  height: 40px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text2);
  font: 700 12.5px/1 var(--font-u);
  cursor: pointer;
  transition: background .14s, border-color .14s, color .14s;
}
.fbchip[aria-pressed="true"] {
  border-color: transparent;
  background: linear-gradient(170deg, #f2cb63, #cf9829);
  color: #1a1400;
}
@media (any-pointer: coarse) { .fbchip { min-height: 44px; min-width: 44px; } }

.feedback__field { display: flex; flex-direction: column; gap: 6px; }
.feedback__text {
  width: 100%;
  resize: vertical;
  min-height: 84px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: 500 14px/1.5 var(--font-u);
}
.feedback__text:focus-visible { outline-offset: 1px; }
.feedback__count {
  align-self: flex-end;
  font: 600 11px/1 var(--font-u);
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}
.feedback__actions { display: flex; gap: 10px; }
.feedback__actions .btn { flex: 1 1 0; }
.feedback__note { margin: 0; font: 500 12px/1.4 var(--font-u); color: var(--text3); }
.feedback__fallback {
  width: 100%;
  min-height: 90px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--line2);
  background: var(--surface2);
  color: var(--text);
  font: 500 13px/1.5 var(--font-u);
}
