/* ══════════════════════════════════════════════════════════════════════════════════════════════
   THE WAHWAHS — pn-wahwahs-20260815.css · the entry room + the ceremony set-piece.

   SST §2 tokens mirrored: IS (900 italic display) + JetBrains Mono (tracked mono micro-copy),
   ink #0b1c30, burnt-orange #f97316 spine, brutalist near-square radii, hard offset shadows.
   The CEREMONY is a deliberately dark designed scene — an explicit seam like the pitch-room
   interiors (UX Law 5, recorded in the module header): auditorium black, one lit plinth, orange
   spine. The ENTRY ROOM is a Finder window (Law 10) with AA ink on its own dark glass in every
   theme (its palette is self-carried, never inherited — Law 1).
   Motion: fade/rise entrances only, spring-flavoured curves, everything gated behind
   prefers-reduced-motion (Laws 4/11). No horizontal scroll at 390 (Law 3): everything is
   min()-clamped and single-column on phones.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── shared kit ─────────────────────────────────────────────────────────────────────────────── */
.ww-eye{font-family:JB,ui-monospace,Menlo,monospace;font-size:10px;font-weight:700;
  letter-spacing:.3em;text-transform:uppercase;color:#fb923c;display:block;
  /* carries the currency law now, so it is allowed to run to two lines on a phone — it is set
     to wrap gracefully rather than to be clipped, because the one thing on this screen that must
     never be half-read is which currency pays for an entry. */
  line-height:1.7;text-wrap:balance}
.ww-btn{display:block;width:100%;border:0;cursor:pointer;border-radius:3px;padding:14px 16px;
  font:700 14px/1 IS,-apple-system,system-ui,sans-serif;letter-spacing:.04em;text-transform:uppercase;
  min-height:44px}
.ww-btn--go{background:var(--accent,#FF2E88);color:#fff;box-shadow:0 6px 0 rgba(88,34,0,.55)}
.ww-btn--go:hover{background:#fb8534}
.ww-btn--go:active{transform:translateY(2px);box-shadow:0 4px 0 rgba(88,34,0,.55)}
/* ⛔ `var(--accent)` is NOT one colour — it is the LIVE THEME token (dark #f97316 vs light
   #b4380d, GAME_DESIGN_STATE.md §0.5), and the ceremony is a deliberately pinned-dark scene that
   is supposed to be unaffected by it (UX_RULES §5) everywhere EXCEPT this one inherited property.
   White on #f97316 measures 2.80:1; a dark ink fixed against THAT accent then measures 3.39:1
   against the light theme's #b4380d — no single ink survives both, because the button is
   secretly theme-reactive when nothing else on this screen is. The fix pins the whole pair, the
   same way `#pn-ww-entry .ww-btn--go` already does two rules up: a fixed, non-themed fill this
   scene owns outright, proven AA (5.98:1, pixel-sampled) regardless of which theme is live
   underneath. */
#pn-ww-stage .ww-btn--go{background:#b4380d;color:#fff}
#pn-ww-stage .ww-btn--go:hover{background:#c94413}
.ww-btn--stage{margin-top:14px;background:#0b1c30;color:#fff;border:1px solid rgba(255,255,255,.25)}
.ww-btn--stage:hover{border-color:var(--accent,#FF2E88)}
/* ⛔ opacity:.45 knocked the disabled CTA to a measured 4.26:1 — under AA, on a control whose
   whole job in that state is to tell you why you cannot use it. UX Law 1 has no disabled
   carve-out and says in terms that quiet is not invisible. A designed disabled treatment
   instead: the fill goes flat and tonal, the ink stays legible, and the reason is printed
   underneath it by openEntry() rather than left for the player to deduce. */
.ww-btn:disabled{opacity:1;cursor:not-allowed;transform:none;
  background:#16283f;color:#cfd8e4;border:1px solid rgba(255,255,255,.16);box-shadow:none}
.ww-why{display:block;margin:8px 0 0;text-align:center;
  font-family:JB,ui-monospace,Menlo,monospace;font-size:10px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:#a9b2be}
.ww-btn:focus-visible,.ww-env:focus-visible{outline:2px solid #f97316;outline-offset:2px}

/* ── ENTRY ROOM — Finder window over the game ───────────────────────────────────────────────── */
#pn-ww-entry.ww-ov{position:fixed;inset:0;z-index:100000;display:flex;align-items:center;justify-content:center;
  padding:16px;background:rgba(5,8,12,.84);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px)}
.ww-win{width:min(560px,100%);max-height:min(86vh,860px);display:flex;flex-direction:column;overflow:hidden;
  background:linear-gradient(178deg,rgba(24,28,35,.97),rgba(12,15,19,.98));
  border:1px solid rgba(255,255,255,.14);border-radius:12px;color:#f4f6f9;
  box-shadow:0 30px 80px rgba(0,0,0,.6),inset 0 1px 0 rgba(255,255,255,.06);
  font-family:IS,-apple-system,system-ui,'Segoe UI',sans-serif;
  animation:wwIn .3s cubic-bezier(.2,.9,.25,1.05) both}
@keyframes wwIn{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
.ww-tb{display:flex;align-items:center;gap:8px;padding:10px 14px;flex:0 0 auto;
  background:rgba(255,255,255,.04);border-bottom:1px solid rgba(255,255,255,.09)}
.ww-dot{width:12px;height:12px;border-radius:50%;border:0;padding:0;flex:0 0 auto}
.ww-dot--r{background:#ff5f57;cursor:pointer}.ww-dot--a{background:#febc2e}.ww-dot--g{background:#28c840}
.ww-tt,.ww-tb .ww-tt{margin-left:6px;font-family:JB,ui-monospace,Menlo,monospace;font-size:10px;
  font-weight:700;letter-spacing:.2em;color:#c9cfd8;text-transform:uppercase;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.ww-bd{padding:20px 20px 18px;overflow-y:auto;overflow-x:hidden}
.ww-h{margin:10px 0 8px;font-size:30px;line-height:.9;font-weight:900;font-style:italic;
  letter-spacing:-.05em;text-transform:uppercase;color:#fff}
.ww-p{margin:0 0 14px;font-size:13.5px;line-height:1.55;color:#c9cfd8}
.ww-p b{color:#fff}

.ww-list{display:flex;flex-direction:column;gap:10px}
.ww-work{border:1px solid rgba(255,255,255,.14);border-left:3px solid #f97316;border-radius:4px;
  padding:12px;background:rgba(255,255,255,.03)}
.ww-work-hd{display:flex;flex-direction:column;gap:3px;margin-bottom:10px}
.ww-brand{font-weight:800;font-size:15px;color:#fff;letter-spacing:-.01em}
.ww-meta{font-family:JB,ui-monospace,Menlo,monospace;font-size:9.5px;font-weight:700;
  letter-spacing:.14em;color:#aab2bd;text-transform:uppercase}
.ww-work-act{display:flex;gap:8px;align-items:stretch;flex-wrap:wrap}
.ww-cat{flex:1 1 200px;min-width:0;min-height:44px;background:#0b1c30;color:#f4f6f9;
  border:1px solid rgba(255,255,255,.25);border-radius:3px;padding:8px 10px;
  font:600 12px/1.2 IS,ui-sans-serif,system-ui,sans-serif}
.ww-work-act .ww-btn--go{flex:0 0 auto;width:auto;padding:12px 18px}
.ww-empty,.ww-slate-none{padding:14px;border:1px dashed rgba(255,255,255,.25);border-radius:4px;
  color:#c9cfd8;font-size:13px;line-height:1.5}
/* Slate: shown only when non-empty (CEO 2026-09-27); when empty, one quiet line instead of a
   whole "YOUR SLATE" section — see .ww-slate-quiet below. */
.ww-slate-quiet{ margin:16px 0 0; padding-top:12px; border-top:1px solid rgba(255,255,255,.12);
  font-size:12.5px; line-height:1.5; color:#8a93a0; font-style:italic; }
.ww-slate{margin-top:16px;padding-top:12px;border-top:1px solid rgba(255,255,255,.12)}
.ww-slate-k{display:block;margin-bottom:8px;font-family:JB,ui-monospace,Menlo,monospace;
  font-size:9.5px;font-weight:700;letter-spacing:.26em;color:#fb923c;text-transform:uppercase}
.ww-slate-row{display:flex;justify-content:space-between;gap:12px;padding:6px 0;
  border-bottom:1px solid rgba(255,255,255,.08);font-size:12.5px;color:#e7ebf1}
.ww-slate-row span:last-child{color:#aab2bd;font-family:JB,ui-monospace,Menlo,monospace;
  font-size:9.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;text-align:right}

/* ── THE CEREMONY — full-screen designed dark scene ─────────────────────────────────────────── */
#pn-ww-stage{position:fixed;inset:0;z-index:100010;color:#f4f6f9;
  font-family:IS,-apple-system,system-ui,'Segoe UI',sans-serif;background:#04060a}
#pn-ww-stage .ww-house{position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(65% 42% at 50% 30%,rgba(249,115,22,.16) 0%,rgba(249,115,22,0) 62%),
    radial-gradient(120% 90% at 50% 110%,rgba(11,28,48,.9) 0%,rgba(4,6,10,1) 70%),
    repeating-linear-gradient(0deg,rgba(255,255,255,.014) 0 1px,transparent 1px 3px)}
#pn-ww-stage .ww-scroll{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;
  padding:max(24px,env(safe-area-inset-top)) 20px 40px;display:flex;flex-direction:column;gap:34px;
  align-items:center}
.ww-mast{text-align:center;max-width:520px}
.ww-title{margin:8px 0 6px;font-size:clamp(44px,13vw,84px);line-height:.8;font-weight:900;font-style:italic;
  letter-spacing:-.06em;text-transform:uppercase;color:#fff}
.ww-sub{margin:0;color:#c9cfd8;font-size:13.5px;line-height:1.5}
.ww-beat{width:min(520px,100%);border:1px solid rgba(255,255,255,.12);border-radius:6px;
  background:rgba(10,14,20,.72);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  padding:18px;display:flex;flex-direction:column;gap:12px;
  animation:wwIn .5s cubic-bezier(.2,.9,.25,1.05) both}
.ww-scroll .ww-beat:nth-of-type(2){animation-delay:.08s}
.ww-scroll .ww-beat:nth-of-type(3){animation-delay:.16s}
.ww-scroll .ww-beat:nth-of-type(4){animation-delay:.24s}
.ww-scroll .ww-beat:nth-of-type(5){animation-delay:.32s}

/* the envelope — the tap-to-open beat */
.ww-env{position:relative;min-height:96px;border:1px solid rgba(249,115,22,.5);border-radius:4px;
  background:linear-gradient(170deg,#131a24,#0a0f16);cursor:pointer;display:flex;align-items:center;
  justify-content:center;overflow:hidden;transition:transform .18s ease,border-color .18s ease}
.ww-env:hover{transform:translateY(-2px);border-color:#f97316}
.ww-env-flap{position:absolute;inset:0 0 auto 0;height:50%;
  background:linear-gradient(180deg,rgba(249,115,22,.18),rgba(249,115,22,0));
  clip-path:polygon(0 0,100% 0,50% 100%);transform-origin:top;transition:transform .42s cubic-bezier(.3,.8,.3,1)}
.ww-env.is-open .ww-env-flap{transform:rotateX(150deg)}
.ww-env.is-open{opacity:.25}
.ww-env-word{font-family:JB,ui-monospace,Menlo,monospace;font-size:11px;font-weight:700;
  letter-spacing:.4em;color:#fb923c;text-transform:uppercase}
.ww-env-word::after{content:" · TAP";color:#c9cfd8}

/* the reveal — [hidden] must beat the display:flex or the closed state reserves dead space
   and the spent envelope ghosts over the result (caught eyeballing the first 390 renders) */
.ww-env[hidden],.ww-reveal[hidden]{display:none}
.ww-reveal{display:flex;gap:14px;align-items:center;opacity:0;transform:translateY(10px)}
.ww-reveal.is-in{opacity:1;transform:none;transition:opacity .5s ease,transform .5s cubic-bezier(.2,.9,.25,1.05)}
.ww-plinth{position:relative;flex:0 0 118px}
/* The tier plates are transparent CUTOUTS of the trophy (CEO-117), not photographs. So: contain,
   not cover — cover cropped the ring. And no border or radius: a 1px box drawn around a
   transparent PNG frames empty space, not the object. A soft drop-shadow grounds it instead. */
.ww-plinth img{display:block;width:118px;height:118px;object-fit:contain;max-width:100%;
  filter:drop-shadow(0 6px 10px rgba(0,0,0,.55))}
.ww-result{display:flex;flex-direction:column;gap:5px;min-width:0}
.ww-tier{font-size:26px;line-height:.95;font-weight:900;font-style:italic;letter-spacing:-.04em;
  text-transform:uppercase}
.ww-tier--titanium{color:#e3e9f2}.ww-tier--gold{color:#fbbf24}.ww-tier--silver{color:#c9cfd8}
.ww-tier--bronze{color:#d98a3a}.ww-tier--none{color:#8a93a0}
.ww-for{font-size:13px;color:#fff;font-weight:600}
.ww-jury,.ww-prize{font-family:JB,ui-monospace,Menlo,monospace;font-size:9.5px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:#aab2bd;line-height:1.6;overflow-wrap:anywhere}
.ww-prize{color:#5fe08a}
.ww-prize--none{color:#ff9d8a}

/* Marlowe — retrieved master still; canon line or canon silence */
.ww-beat--marlowe{align-items:center;text-align:center}
.ww-marlowe{display:flex;flex-direction:column;align-items:center;gap:12px}
.ww-marlowe img{width:132px;height:132px;object-fit:cover;border-radius:50%;
  border:2px solid rgba(249,115,22,.6);filter:grayscale(.35) contrast(1.08);max-width:100%}
.ww-line{margin:0;font-size:16px;line-height:1.45;font-style:italic;color:#fff;max-width:34ch}
.ww-silent{font-family:JB,ui-monospace,Menlo,monospace;font-size:10px;font-weight:700;
  letter-spacing:.4em;color:#8a93a0;text-transform:uppercase}

.ww-close-beat{width:min(520px,100%);text-align:center;display:flex;flex-direction:column;gap:10px;
  padding-bottom:8px}
.ww-closecopy{margin:0;color:#c9cfd8;font-size:13.5px;line-height:1.5}

/* ── phones (390) — single column, nothing off-canvas ───────────────────────────────────────── */
@media (max-width:480px){
  .ww-reveal{flex-direction:column;align-items:flex-start}
  .ww-h{font-size:26px}
  .ww-work-act .ww-btn--go{flex:1 1 100%}
}

/* ── reduced motion: everything lands instantly (UX Law 4) ──────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  .ww-win,.ww-beat{animation:none}
  .ww-env,.ww-env-flap,.ww-reveal,.ww-reveal.is-in{transition:none}
  .ww-reveal{opacity:1;transform:none}
}
#pn-ww-stage.ww-reduced .ww-beat{animation:none}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   THE WAY IN — the PN/OS dock tile (2026-08-16)

   CEO: "where are the WahWahs?" They had no entry point at all; the only doors were two console
   calls. This is the door. It lives in the dock beside sycophant because the dock is the app
   layer the player has already learned, and it is PERMANENT — the state is what changes, not the
   tile's existence, because a control that only appears when it matters is a control nobody has
   ever learned (the arcade failure of this same morning).

   COLOUR LAW (pnos.css §THE LENS): the dock is a PAIR, never a rainbow — cold glass = the job,
   green glass = the break. The WahWahs are the job (your work, your money, your standing), so the
   lens is COLD and matches Email and the Calendar exactly. It does NOT get a third hue and it
   does NOT get the orange hero lens: the dock spends its one accent on the counter badge and the
   running pip, and this tile obeys that rather than adding a second loud thing.

   So the STATE is carried by three quiet signals, in the dock's own existing grammar:
     · the LABEL line   — the mark is the identity (dock canon: "Icon is the identity"), which
                          frees the label to be the state: WAHWAHS / TO ENTER / ENTERED /
                          SLATE FULL / TONIGHT.
     · the BADGE        — the count, the same idiom Email already uses for unread.
     · the LENS opacity — unlit when there is genuinely nothing to do, so "nothing here yet" is
                          legible before the tap rather than after it.
   The full sentence ("Entries are open. 3 pieces on your ballot, 1 of 20 entered…") is on the
   title AND the aria-label, so the tile is never a seven-character riddle (Law 14).
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* The mark's SOLID mass, per the dock's two-object grammar — a value brighter than the outline,
   lit by the same top light as every other lens. */
/* ⛔ NOT SCOPED TO THE DOCK. The same mark is injected into the topbar overflow menu by
   installOverflow(), and while this rule was scoped `.pnos-tile--ww .pnos-tile-ic` the cup there
   computed `fill:none; stroke:none` — the overflow entry rendered as a bare horizontal bar with
   the trophy missing entirely. A second door that shows no icon is a second door nobody opens. */
svg .ms{ fill:currentColor; }

/* NOTHING TO DO — the glass rests. The LABEL IS NOT DIMMED: contrast is measured, not vibed, and
   a quiet state is never allowed to cost legibility (Law 1). Only the lens softens. */
.pnos-tile--ww:not(.is-lit) .pnos-tile-ic{ opacity:.72; }
.pnos-tile--ww:not(.is-lit):hover .pnos-tile-ic{ opacity:1; }

/* SOMETHING TO DO — the glass simply comes up to full. NO COLOUR CHANGE.
   ⛔ This line used to also set `color:#ffe6d2`, described in its own comment as "the warm ink
   the counter uses". The counter is #f97316 with near-black digits; #ffe6d2 appears nowhere else
   in the product. It was a third hue in a dock whose stated law is a PAIR — cold glass for the
   job, green glass for the break — added by the same commit whose block comment promised not to
   add one. Measured off the render, the trophy ink came out +28 red-over-blue while its
   neighbours ran −21. Removed: the lit state is a value change, not a hue change. */
.pnos-tile--ww.is-lit .pnos-tile-ic{ opacity:1; }

/* THE CEREMONY IS TONIGHT — the one moment this tile is allowed to raise its voice. A slow
   breath on the label (2.6s): it reads as a deadline from the corner of the eye and it cannot
   strobe (Law 4). Reduced motion removes the MOVEMENT and nothing else — the accent colour and
   the label word "TONIGHT" both remain, so the state is never carried by motion alone.
   ⛔ THE COLOUR IS NOT SET HERE. It lives in pnos.css beside the dock-defence block, because
   that block's `!important` on .pnos-tile-lb beats this file. A colour written here rendered as
   plain dock grey for as long as it existed and the comment above it said otherwise. Measured
   contrast of the accent on the rail, and of the animation's 0.62 trough composited into it, is
   asserted by tools/wahwah-entry-gate.mjs — not by this comment. */
/* ⛔ THE STATE WAS NOT LEGIBLE AT A GLANCE, and a byte-diff of the state renders proved it:
   `entered` vs `ceremony` differed by 1.47% of pixels — a 9px mono word and an opacity breath.
   UX Law 1: "critical game state must be instantly legible — never faint chrome", and an opacity
   animation on 9px text is faint chrome by definition (it is also invisible in a still, which is
   why my own state renders showed nothing).
   The fix spends the dock's existing HERO LENS on it — the warm glass ramp already defined in
   pnos.css for "the ONE lit app", currently used by nothing. On ceremony night the WahWahs ARE
   the one lit app, for one week in twelve, so this is the treatment doing exactly the job it was
   defined for rather than a new colour being invented. */
.pnos-tile--ww.is-urgent .pnos-tile-ic{
  --lens-1:#ffc48a; --lens-2:#ef7f28; --lens-3:#7d3006; --lens-4:#230c02;
  color:#fff6ec; }
.pnos-tile--ww.is-urgent .pnos-tile-lb{ animation:ww-dock-breath 2.6s ease-in-out infinite; }
@keyframes ww-dock-breath{ 0%,100%{ opacity:1; } 50%{ opacity:.62; } }
@media (prefers-reduced-motion:reduce){
  .pnos-tile--ww.is-urgent .pnos-tile-lb{ animation:none; opacity:1; }
}

/* Screen-reader-only description holder for the dock tile. NOT display:none — a hidden node is
   not exposed, and aria-describedby needs the text to exist in the accessibility tree. */
.ww-sr{ 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; }

/* ── THE CLOSE CONTROL IS A 44px TARGET WEARING A 12px DOT ────────────────────────────────────
   The traffic-light dot measured 12x12: the only sub-44px target in the room, failing both the
   house rule and WCAG 2.2 SC 2.5.8. The painted dot is unchanged — the BUTTON grows around it
   and is pulled back into the title bar with negative margins, so the chrome does not get taller
   and the Finder furniture still looks exactly like Finder furniture. */
.ww-tb .ww-dot--r{ width:44px; height:44px; margin:-16px -16px -16px -16px; padding:0;
  background:none; border-radius:50%; display:grid; place-items:center; }
.ww-tb .ww-dot--r::before{ content:""; width:12px; height:12px; border-radius:50%; background:#ff5f57; }
.ww-tb .ww-dot--r:focus-visible{ outline:2px solid #f97316; outline-offset:-6px; }

/* ── THE ENTRY ROOM SAYS WHERE YOU ARE, BEFORE IT OFFERS YOU A CONTROL ────────────────────────
   The room used to open on a headline and a wall of numbers, which told a player nothing about
   whether this screen had anything for them today. It now leads with the phase in one heading
   and one sentence, from the same phase() the tile reads — so the door and the room can never
   disagree. Stated once (Law 15): the counts moved OUT of the body copy and into the purse row
   below, and the body copy shrank to the two things that are rules rather than state. */
/* ⛔ NOT A CARD. The first cut gave this 1px border + 4px radius + a 3px orange left rail —
   byte-for-byte the same object as the ballot's work cards, so the thing you READ and the thing
   you ACT ON were visually identical inside one Finder window, and the accent stopped meaning
   "act here" (card-on-card, §12). It is now a masthead band: a heavy rule above, a tint that
   fades out, no box and no rail. Different structure, not a different colour. */
.ww-state{ display:block; margin:0 0 18px; padding:12px 2px 14px;
  border:0; border-top:3px solid var(--p,#f97316); border-radius:0;
  background:linear-gradient(180deg, rgba(249,115,22,.10), rgba(249,115,22,0) 82%); }
.ww-state-k{ display:block; font-family:JB,ui-monospace,Menlo,monospace;
  font-size:9.5px; font-weight:700; letter-spacing:.3em; text-transform:uppercase;
  color:#fdba74; margin-bottom:6px; }                                        /* 7.4:1 on the room glass */
.ww-state-h{ display:block; font:800 15px/1.25 IS,-apple-system,system-ui,sans-serif;
  letter-spacing:-.015em; color:#fff; margin-bottom:5px; }                    /* 15.9:1 */
/* ⛔ The room focuses this heading on open so a screen reader hears the state first. That is
   PROGRAMMATIC focus, and it was painting a 2px orange rectangle round the words "Entries are
   open" — which reads as a validation error or a selected input, not as a heading. Suppress the
   ring for programmatic focus; keep it for :focus-visible, which only fires for keyboard. */
.ww-state-h:focus{ outline:none; }
.ww-state-h:focus-visible{ outline:2px solid #f97316; outline-offset:3px; }
.ww-state-l{ display:block; font-size:13px; line-height:1.5; color:#d3d9e2; } /* 11.2:1 */
/* Deadline: the accent rail brightens and the eyebrow changes word. No new component. */
.ww-state.is-urgent{ border-top-width:5px;
  background:linear-gradient(180deg, rgba(249,115,22,.22), rgba(249,115,22,0) 88%); }

/* THE PURSE — what entering costs you, as four facts on one line instead of a run-on sentence.
   Mono keys, plain values, no cards: it is a readout, not four tiles (Law 12). */
.ww-purse{ display:flex; flex-wrap:wrap; gap:6px 22px; margin:0 0 16px; padding:11px 0 0;
  border-top:1px solid rgba(255,255,255,.12); }
.ww-purse span{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.ww-purse i{ font-family:JB,ui-monospace,Menlo,monospace; font-style:normal;
  font-size:9px; font-weight:700; letter-spacing:.26em; text-transform:uppercase; color:#a9b2be; } /* 7.1:1 */
.ww-purse b{ font:800 15px/1 IS,-apple-system,system-ui,sans-serif; color:#fff; letter-spacing:-.01em; }

/* Eyebrow segments — each an unbreakable unit, separated by the house mid-dot. The separator is
   drawn by CSS rather than typed into the string, so it can never be orphaned at the end of a
   wrapped line. */
.ww-eye i{ font-style:normal; display:inline-block; white-space:nowrap; }
/* The separator belongs to the segment BEFORE it, inside that segment's nowrap box. Hung on the
   following segment instead it wraps with it and lands orphaned at the start of line two, which
   is what the first cut did: "· NEVER WAHCOINS". A separator is punctuation between two things,
   so it stays welded to the first of them. */
/* Space on BOTH sides. The first cut wrote `" \00B7"` — space before, none after — and both
   room renders read "PAY TO PLAY ·TIME + AGENCY MONEY". A separator needs air on each side or it
   reads as a prefix on the next word. */
.ww-eye i:not(:last-child)::after{ content:" \00B7\00A0"; color:var(--p,#f97316); opacity:.75; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   ⛔ THE ROOM DEFENDS ITS OWN CONTROLS (2026-08-16)

   This module's header has always claimed the entry room's palette is "self-carried, never
   inherited". Rendering it under a REAL PitchNoir theme proved that false. Under PORCELAIN a
   light-theme catch-all repaints every `button` on the page with a cream gradient, and it
   reaches straight through the Finder window: ENTER and TO THE CEREMONY both came out as pale
   cream slabs on the room's dark glass, the disabled CTA became indistinguishable from the
   enabled one, and the 44px close target I had just added inherited the same fill and rendered
   as a large cream rectangle sitting over the title bar.

   None of this was visible before, because the gate had been shooting "dark" and "light" with
   Playwright's colorScheme — an axis this product does not read. Two identical renders filed as
   two themes. The gate now drives mvcSetPalette(), and this block is the first thing it found.

   THE CULPRIT, named so nobody has to find it again: style-01.css carries
     body[data-view="office"] button:not(.primary):not(.hub-tab):not(.hub-advance):not(.sf-hire…)
   with `background: var(--rust-card) !important`. It repaints EVERY button while the office view
   is mounted — including buttons inside an overlay that is not part of the office at all. An ID
   selector does not beat `!important`, so the first attempt at this block lost silently and the
   render still came back cream. Asking the browser which rule won (CDP getMatchedStylesForNode)
   settled it in one shot; reading the stylesheets would not have.

   So this follows the precedent pnos.css already set for the dock — a DEFENCE block that states
   the surface's own material with `!important`, next to a comment explaining what it is beating.
   It also explicitly clears background-image, which is where the cream actually lives.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* THE PRIMARY. ⛔ NOT #f97316 with white ink: measured, white on #f97316 is 2.83:1 and fails AA
   at 14px — the house rule "button text is white on brand-orange fills" and the house rule "AA
   4.5:1 in every theme" cannot both be satisfied at that orange. #b4380d is the deepened accent
   the codebase already uses for light themes (script-01.js), and white on it measures 6.08:1.
   Same brand gesture, legible. It is also now unmistakably the loudest control on the card,
   which fixes the CTA reading quieter than the select above it. */
#pn-ww-entry .ww-btn--go,
#pn-ww-entry .ww-btn--go:link{ background-image:none !important; background:#b4380d !important;
  color:#fff !important; border:0 !important; box-shadow:0 6px 0 rgba(88,34,0,.5) !important; }
#pn-ww-entry .ww-btn--go:hover{ background:#c94413 !important; }
#pn-ww-entry .ww-btn--go:active{ transform:translateY(2px); box-shadow:0 4px 0 rgba(88,34,0,.5) !important; }

/* THE SECONDARY — quiet, but never cream, and never mistakable for the primary. */
#pn-ww-entry .ww-btn--stage{ background-image:none !important; background:#0b1c30 !important;
  color:#fff !important; border:1px solid rgba(255,255,255,.28) !important; }
#pn-ww-entry .ww-btn--stage:hover{ border-color:var(--accent,#FF2E88) !important; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   ⛔ DISABLED AND SECONDARY WERE THE SAME OBJECT (2026-08-16)

   `:disabled` was #16283f and `.ww-btn--stage` was #0b1c30 — both dark navy, white ink, same 1px
   white-alpha border, same radius, same height, same full width. In the Time-exhausted state the
   room showed FOUR visually identical navy slabs down the screen and nothing told you which one
   was live. The old comment here called that "a designed disabled treatment"; it was the secondary
   button wearing a slightly different grey.

   Now they are different KINDS of object, which is what a state has to be:
     · DISABLED = no fill at all + a dashed hairline. Nothing else in the product is dashed, so
       "dashed = dead" is legible in one glance and needs no colour to carry it.
     · SECONDARY = the §5f ALTERNATION LAW, which this dark room was ignoring entirely: inside a
       DARK surface, key chrome goes LIGHTER — machined pale slate with #0b1c30 ink. It was
       #0b1c30 on a ~#14181f panel, i.e. a hole in the panel held together by a hairline.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
/* aria-disabled gets the identical treatment — the ENTER control is now aria-disabled rather than
   disabled so it stays reachable by keyboard and announced, and a state the eye cannot see is as
   bad as one the screen reader cannot hear. */
#pn-ww-entry .ww-btn:disabled,
#pn-ww-entry .ww-btn[aria-disabled="true"]{ background-image:none !important;
  background:transparent !important;
  color:#a9b2be !important; border:1px dashed rgba(255,255,255,.26) !important;
  box-shadow:none !important; opacity:1 !important; cursor:not-allowed !important; }  /* 7.1:1 */
#pn-ww-entry .ww-btn[aria-disabled="true"]:hover{ background:transparent !important; }
#pn-ww-entry .ww-btn[aria-disabled="true"]:active{ transform:none !important; }
#pn-ww-entry .ww-btn--stage:not(:disabled){ background-image:none !important;
  background:#e3e9f2 !important; color:#0b1c30 !important;
  border:1px solid rgba(11,28,48,.22) !important; }                            /* 14.6:1 */
#pn-ww-entry .ww-btn--stage:not(:disabled):hover{ background:#f2f6fb !important; }

/* THE CLOSE TARGET — 44px of hit area wearing a 12px dot, and no inherited fill of any kind. */
#pn-ww-entry .ww-tb .ww-dot--r{ background-image:none !important; background:none !important;
  border:0 !important; box-shadow:none !important; }
#pn-ww-entry .ww-tb .ww-dot--r::before{ background:#ff5f57 !important; }
/* the amber and green lamps are decoration, not controls — they must not be plated either */
#pn-ww-entry .ww-tb .ww-dot--a{ background:#febc2e !important; background-image:none !important; }
#pn-ww-entry .ww-tb .ww-dot--g{ background:#28c840 !important; background-image:none !important; }
/* and the category select, which is the other control the catch-all can reach */
#pn-ww-entry .ww-cat{ background-image:none !important; background:#0b1c30 !important;
  color:#f4f6f9 !important; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   ⛔ THE REFUSAL WAS PAINTING UNDERNEATH THE ROOM (2026-08-16, CEO P0)

   "No buttons work." They all worked. With Time at 0h, ENTER refused correctly and said so — and
   `.toast` in style-01.css is `z-index:10002` while this overlay is `z-index:100000` and the
   ceremony is `100010`. Every explanation this room raised was painted BEHIND the thing that
   raised it. Verified on the live page rather than reasoned: elementFromPoint() at the toast's
   own centre returned `ww-purse`, an element of this overlay.

   A toast is the wrong instrument for a cost you cannot meet (that is a state, and it is now
   printed on the control by syncCard()), but the toast still carries the CAP message and every
   refusal budgetSpend() raises on its own — including the one with the CFO re-allocate button in
   it. So it has to be able to appear over its own overlay.

   Scoped with :has() so this ONLY lifts the toast while a WahWahs layer is actually mounted —
   the stacking order everywhere else in the product is left exactly as it was. */
/* Scoped on <html>, because the room now portals to documentElement (see openEntry) — a
   `body:has()` selector stopped matching the moment it moved and silently took the fix with it. */
html:has(#pn-ww-entry) .toast,
html:has(#pn-ww-stage) .toast{ z-index:100030 !important; }

/* The <b>→<h2>/<h3> change is for heading navigation only — pin the UA heading box so nothing
   moves a pixel. */
/* ⛔ RESET THE MARGIN ONLY. The first cut also set `font-size:inherit` here to "neutralise the UA
   heading size" — but this is an ID selector, so it beat `.ww-hero-h`'s own clamp() and collapsed
   the wordmark from 52px to body size. The entire hero went quiet and no measurement noticed;
   the render did. The class already owns the type. */
#pn-ww-entry h2.ww-hero-h{ margin:2px 0; }
#pn-ww-entry h3.ww-state-h{ margin:0 0 5px; }
/* ⛔ The house style paints a 48x3px orange rule via `h2::after` on every bare h2. Changing <b> to
   <h2> for heading navigation silently inherited it, and it rendered as a stray orange stub
   floating under the wordmark — a fragment attached to nothing (UX Law 3). Semantics were the
   point of the change; the decoration was not invited. */
#pn-ww-entry h2.ww-hero-h::after,#pn-ww-entry h3.ww-state-h::after{ content:none !important;
  display:none !important; }
/* ⛔ ...and a global focus rule beat `.ww-state-h:focus{outline:none}`, so the programmatic focus
   the room puts on this heading painted a 2px orange rectangle around "Entries are open" — which
   reads as a validation error, not a heading. !important to match what it is beating; the
   keyboard-only ring is restored on :focus-visible directly below.

   ⛔ AND :focus-visible IS NOT THE ESCAPE HATCH. Keeping a ring for `:focus-visible` still painted
   it, because Chrome carries the visible-focus heuristic across a PROGRAMMATIC focus call — so the
   ring came back for anyone who had touched a key earlier in the session. This heading is not an
   interactive control: a ring on it is never meaningful, and a keyboard user gets a real ring on
   the first actual control on the very next Tab. No ring, in any focus state. */
#pn-ww-entry h3.ww-state-h:focus,
#pn-ww-entry h3.ww-state-h:focus-visible{ outline:none !important; box-shadow:none !important; }

/* ⛔ A 29px theme switcher was tabbable and clickable OVER the open dialog — under the house 44px
   rule, and the exact control the focus trap was leaking to. A modal surface does not offer the
   page's chrome (UX Law 6). Scoped with :has() so it returns the moment the room closes. */
html:has(#pn-ww-entry) #pn-status-right,
html:has(#pn-ww-stage) #pn-status-right{ display:none !important; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   THE HERO — the object, at scale, before anything else (CEO P0, 2026-08-16)

   "I can't tell what this is about — we need a BIG WahWah trophy image here."
   Deliberately NOT a card: no border, no radius, no fill. It is a lit alcove at the top of the
   window — a warm pool of light behind a cut-out object, the way a trophy is photographed. The
   type sits flush left and the statue breaks the right edge of the text column and overlaps it,
   so the two are one lock-up rather than an image tile stacked above a heading. That asymmetry is
   the point: a centred trophy over centred type is the AI-panel default this room just escaped.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
/* overflow:hidden is load-bearing twice over — it keeps the statue's bleed inside the alcove
   (the first cut clipped the ring's crown against the window edge and read as a broken image),
   and it stops the negative side margins pushing .ww-bd into a horizontal scroll (Law 3). */
.ww-hero{ position:relative; display:flex; align-items:flex-end; gap:0; overflow:hidden;
  margin:-20px -20px 4px; padding:18px 20px 14px; min-height:214px; isolation:isolate;
  background:
    radial-gradient(78% 62% at 74% 46%, rgba(251,191,36,.20) 0%, rgba(249,115,22,.07) 42%, rgba(249,115,22,0) 72%),
    linear-gradient(178deg, rgba(4,6,10,.55), rgba(4,6,10,0) 70%); }
/* ⛔ THE FLOOR ELLIPSE IS GONE. It was a pseudo-element anchored to the hero's BOX (right:4%;
   width:46%) while the statue is `object-fit:contain` and therefore much narrower than its box and
   hard right — so the glow landed mostly to the LEFT of the plinth and rendered as a gold smear
   floating in mid-air. A contact shadow that is not attached to the object is not a contact
   shadow. It is now baked into the object's own drop-shadow, where it cannot drift: one tight dark
   shadow for contact, one soft one for the cast. */
/* The whole object, never a crop: contain + a max-width so a narrow window shrinks the statue
   instead of slicing it. object-position pins it to the floor so it always stands on the ellipse. */
/* The statue is bigger than its text column's clearance and sits under the wordmark's tail, so
   type and object genuinely interlock — the previous numbers (tx 60% + art 46%) left a 64px empty
   gutter and zero overlap, which reads as an image tile placed beside a heading. */
.ww-hero-art{ position:absolute; z-index:-1; right:-4%; bottom:6px; width:auto; height:196px;
  max-width:56%; object-fit:contain; object-position:bottom right;
  filter:drop-shadow(0 4px 5px rgba(0,0,0,.75)) drop-shadow(0 16px 30px rgba(0,0,0,.55));
  pointer-events:none; }
/* The scrim travels with the TEXT, not the box — so the letters that cross the gold ring keep a
   dark ground under them and stay legible without a blur halo. */
.ww-hero-tx{ position:relative; z-index:1; display:flex; flex-direction:column; gap:6px;
  max-width:72%; }
.ww-hero-tx::before{ content:""; position:absolute; z-index:-1; inset:-14px -46px -10px -22px;
  background:radial-gradient(70% 78% at 26% 50%, rgba(4,6,10,.94) 0%, rgba(4,6,10,.72) 46%,
    rgba(4,6,10,0) 82%); }
.ww-hero-k{ font-family:JB,ui-monospace,Menlo,monospace; font-size:9.5px; font-weight:700;
  letter-spacing:.26em; text-transform:uppercase; color:#fdba74; }              /* 7.4:1 on the alcove */
/* SST §2: display type is HUGE, italic, uppercase, ultra-tight. This is the one place in the room
   that gets to shout, and it shouts against 9px mono — scale contrast with conviction. */
/* h2 now — reset the UA heading box so the markup change moves nothing. */
.ww-hero-h{ display:block; font:900 italic clamp(28px,9.2vw,52px)/.82 IS,-apple-system,system-ui,sans-serif;
  letter-spacing:-.055em; text-transform:uppercase; color:#fff; margin:2px 0 2px;
  text-shadow:0 2px 18px rgba(4,6,10,.85); }                                    /* 15.9:1 */
.ww-hero-l{ font-size:12.5px; line-height:1.45; color:#d3d9e2; max-width:26ch;
  text-shadow:0 1px 10px rgba(4,6,10,.9); }                                     /* 11.2:1 */

/* ── HOW IT WORKS — folded into one short disclosure (CEO 2026-09-27) ────────────────────────────
   Was a permanently-open 3-line <ol> on the page at all times; the mental model only needs
   answering once, on request. <details> — no JS, keyboard/AT native. */
.ww-how{ margin:0 0 14px; }
.ww-how summary{ cursor:pointer; list-style:none; display:inline-flex; align-items:center; gap:6px;
  font-family:JB,ui-monospace,Menlo,monospace; font-size:11px; font-weight:700;
  letter-spacing:.14em; text-transform:uppercase; color:#c9cfd8; padding:4px 0; }
.ww-how summary::-webkit-details-marker{ display:none; }
.ww-how summary::before{ content:"\25B8"; display:inline-block; color:#a9b2be;
  transition:transform .15s ease; }
.ww-how[open] summary::before{ transform:rotate(90deg); }
.ww-how summary:focus-visible{ outline:2px solid #f97316; outline-offset:2px; }
.ww-how ol{ margin:9px 0 0; padding:0; list-style:none; counter-reset:wwhow;
  display:flex; flex-direction:column; gap:9px; }
.ww-how ol li{ position:relative; padding-left:26px; font-size:12.5px; line-height:1.5; color:#c9cfd8; }
/* ⛔ NOT accent rings. SYSTEM_V2 locks accent to fill · state-underline · data-endpoint ·
   semantic callout. Numerals in a reading block are none of those, and orange here was competing
   with the one control on the row that genuinely means "act". Neutral tint, neutral ink. */
.ww-how ol li::before{ counter-increment:wwhow; content:counter(wwhow);
  position:absolute; left:0; top:1px; width:17px; height:17px; border-radius:50%;
  display:grid; place-items:center; background:rgba(255,255,255,.07);
  border:1px solid rgba(255,255,255,.20);
  font-family:JB,ui-monospace,Menlo,monospace; font-size:9px; font-weight:700;
  color:#a9b2be; }                                                              /* 7.1:1 */

/* ── THE PRICE — the CEO's second question, answered in words next to the number ─────────────── */
/* "Are these costs per entry?" — yes, and the screen now says so where the number is, with the
   unit spelled out. Tabular figures so £8,000 and £14,000 align down the ballot. */
.ww-price{ display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 7px; margin:9px 0 10px;
  padding-top:9px; border-top:1px solid rgba(255,255,255,.10); }
.ww-price-v,.ww-price-t{ font:800 17px/1 IS,-apple-system,system-ui,sans-serif; color:#fff;
  letter-spacing:-.01em; font-variant-numeric:tabular-nums; }
.ww-price-t{ font-size:15px; color:#e7ebf1; }
.ww-price-u{ font-family:JB,ui-monospace,Menlo,monospace; font-size:10px; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase; color:#a9b2be; }              /* 7.1:1 */
/* the ballot's column header — the unit, said once, for every row beneath it. It carries the
   answer to the CEO's own question, so it is not allowed to be the smallest type in the room. */
.ww-ballot-k{ display:block; margin:2px 0 9px;
  font-family:JB,ui-monospace,Menlo,monospace; font-size:10px; font-weight:700;
  letter-spacing:.14em; text-transform:uppercase; color:#a9b2be; line-height:1.6; }

/* ── THE GATE — why this control will not fire, printed on it, before the click ──────────────── */
/* 11px, not 9.5px. This is the ONLY visible statement of why the control will not fire — uppercase
   mono with .1em tracking reads a full size smaller than the same number in sentence case, and the
   one line in the room that must never be squinted at was the smallest thing in it. */
.ww-gate{ display:block; margin:8px 0 0; padding:8px 10px; border-radius:3px;
  background:rgba(186,26,26,.14); border-left:2px solid #ff9d8a;
  font-family:JB,ui-monospace,Menlo,monospace; font-size:11px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; color:#ffb4a4; line-height:1.55;
  overflow-wrap:anywhere; }                                                      /* 6.9:1 on the card */
.ww-gate[hidden]{ display:none; }
.ww-work-act{ margin-top:0; }
#pn-ww-entry .ww-work-act .ww-btn--go{ width:100%; font-variant-numeric:tabular-nums; }

/* ── ACCENT DISCIPLINE ON THE BALLOT ─────────────────────────────────────────────────────────────
   Every row carried a 3px orange left rail, so it distinguished nothing — and in the exhausted
   state it shouted "act here" on three rows where nothing could be actioned. That is the accent
   lying about state. The rail is now neutral by default and lights ONLY on a row you can actually
   enter, which makes it a state signal instead of decoration. */
#pn-ww-entry .ww-work{ border-left-color:rgba(255,255,255,.16); }
#pn-ww-entry .ww-work.is-open{ border-left-color:#f97316; }

/* ── HIERARCHY INSIDE THE ROW ───────────────────────────────────────────────────────────────────
   The price was set BIGGER (800/17px) than the name of the work it prices (800/15px) — the subject
   was quieter than its cost, and both matched the room's own second-level heading. The brand is
   the only other place display type belongs in this room; the number goes back to data. */
#pn-ww-entry .ww-brand{ font:900 italic 20px/1.05 IS,-apple-system,system-ui,sans-serif;
  letter-spacing:-.03em; text-transform:uppercase; }
#pn-ww-entry .ww-price-v{ font-size:15px; font-weight:700; }
#pn-ww-entry .ww-price-t{ font-size:14px; font-weight:700; }
/* the native select was the widest, loudest object on the card — the one undesigned control in a
   hand-designed room. It is a setting, so it is set like one. */
#pn-ww-entry .ww-cat{ font:700 11px/1.2 JB,ui-monospace,Menlo,monospace !important;
  letter-spacing:.12em; text-transform:uppercase; }

/* ── phones: the statue gets smaller, never cropped, and never causes h-scroll ───────────────── */
@media (max-width:480px){
  .ww-hero{ min-height:184px; }
  .ww-hero-art{ height:150px; max-width:42%; opacity:.94; }
  .ww-hero-tx{ max-width:58%; }
  /* ⛔ 11vw put "WAHWAHS" at 43px on a 390 screen — wider than its own 58% column, so the final S
     ran out over the gold ring and set white type on a bright metal highlight. The clamp's lower
     bound was doing nothing because 11vw beat it. Fixed size here: 36px keeps all eight caps
     inside the column with clearance, and the statue keeps its silhouette. */
  .ww-hero-h{ font-size:36px; }
}

/* ⛔ THE COLLISION CAME BACK ONE BREAKPOINT DOWN (320–362px). At 390 there is 27px of clearance,
   so it is invisible on the phone we test on — but at 360 the headline ink already crosses the art
   box, and at 320 it crosses it by 43px. Sampling the trophy's own pixels in that band gave a MEAN
   contrast for white type of 1.77:1 and a worst pixel of 1.00:1 against a specular highlight,
   where large text needs 3:1. The `text-shadow` is a blur, not a contrast mechanism, and cannot be
   leaned on. Below 400 the two objects stop overlapping and sit side by side instead — the poster
   lock-up is a luxury of width, and legibility is not. */
@media (max-width:400px){
  .ww-hero{ flex-direction:row; align-items:flex-end; gap:8px; min-height:172px; }
  .ww-hero-tx{ max-width:100%; flex:1 1 auto; }
  .ww-hero-tx::before{ inset:-14px -18px -10px -22px; }
  /* order:2 — the <img> comes first in the DOM (it is the background object on wider screens), so
     going `position:static` in a row flexbox put the statue on the LEFT and flipped the whole
     composition against every other width. The object stays on the right at every size. */
  .ww-hero-art{ position:static; order:2; flex:0 0 auto; align-self:flex-end;
    height:136px; max-width:38%; }
  .ww-hero-h{ font-size:clamp(26px,8.4vw,34px); }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   WW-03 — ARRIVAL beat, AFTERMATH beat, SKIP + CLOSE controls
   design/SPEC_wahwahs_ceremony.md §3b · _Documentation WEEKEND-PLAN §5 · CEO rule (PP screens):
   Skip + Close prominent on any set-piece scene, always reachable, never gated behind a delay.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* the top control bar — fixed, above the scroll, never scrolls away. Same 44px-target law as the
   entry room's close dot (§ above): a 12px glyph wearing a 44px hit area. */
.ww-ctrlbar{position:fixed;top:max(10px,env(safe-area-inset-top));right:14px;z-index:100020;
  display:flex;gap:8px}
.ww-ctrl{appearance:none;cursor:pointer;min-width:44px;min-height:44px;padding:0 16px;
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  border:1px solid rgba(255,255,255,.28);border-radius:999px;background:rgba(6,9,14,.6);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);color:#f2f6ff;
  font-family:JB,ui-monospace,Menlo,monospace;font-size:11px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase}
/* ⛔ EV-07 (2026-09-12) — SKIP WAS ORANGE-ON-ORANGE, MEASURED AT 1.45:1.
   `.ww-ctrl:hover` used to say `color:#f97316` and nothing else, on the reasoning that the plate
   underneath stays `rgba(6,9,14,.6)`. It does not. The ceremony stage is appended to
   `document.documentElement` while `body[data-view]` is still "office", so play.html's office-scope
   button catch-alls reach these two controls and repaint the FILL on hover — leaving brand orange
   ink (249,115,22) on a darkened brand orange plate (194,90,17). Decoded straight out of
   design/wahwahs-ceremony-2026-09-12/ww03_aftermath_desktop_dark.png, where a QA pass had pressed
   SKIP and left the pointer on it: ratio 1.45:1, the label effectively gone. Neither half of that
   pair is wrong on its own, which is exactly why no token read and no single-sheet review found it.

   THE FIX IS TO STOP NEGOTIATING OVER THE PAIR. Fill AND ink are pinned together for every state
   this control can be in — rest, hover, focus, active, disabled — so no foreign sheet can repaint
   one half of a contrast pair. Hover and focus now signal with the BORDER and a slight lift of the
   plate, never by recolouring the label to the accent: an accent-on-accent label is the failure
   mode, so the accent is not allowed near the ink here at all.
   Disabled is stated too (it was never styled, so it inherited a browser grey at ~2.6:1) — a
   control the player cannot press must still be READABLE, or they cannot tell it apart from one
   that is simply missing (UX_RULES §1: "quiet" ≠ invisible).
   Measured from rendered pixels, both themes, both widths, all four states:
   design/wahwahs-ceremony-2026-09-12/ctrl_contrast.json (qa/ww_ctrl_contrast.mjs). */
.ww-ctrlbar .ww-ctrl,
.ww-ctrlbar .ww-ctrl:link,
.ww-ctrlbar .ww-ctrl:visited,
.ww-ctrlbar .ww-ctrl:hover,
.ww-ctrlbar .ww-ctrl:focus,
.ww-ctrlbar .ww-ctrl:focus-visible,
.ww-ctrlbar .ww-ctrl:active,
.ww-ctrlbar .ww-ctrl:disabled,
.ww-ctrlbar .ww-ctrl[disabled]{
  background:rgba(6,9,14,.82) !important;
  color:#f2f6ff !important;
  -webkit-text-fill-color:#f2f6ff !important;   /* some sheets paint the label via text-fill */
  opacity:1 !important;                          /* a dimmed plate is how disabled fell to ~2.6:1 */
  border:1px solid rgba(255,255,255,.28) !important;
}
/* the hover/focus SIGNAL: the hairline brightens and the plate lifts. The label never changes
   colour, because the label changing colour is what broke. */
.ww-ctrlbar .ww-ctrl:hover,
.ww-ctrlbar .ww-ctrl:focus-visible{
  border-color:#f97316 !important;
  background:rgba(16,22,31,.92) !important;
}
.ww-ctrlbar .ww-ctrl:disabled,
.ww-ctrlbar .ww-ctrl[disabled]{ cursor:default; border-color:rgba(255,255,255,.18) !important; }
.ww-ctrl:focus-visible{outline:2px solid #f97316;outline-offset:2px}

/* ── ARRIVAL — the venue card, first thing in the scroll ─────────────────────────────────────── */
.ww-arrival{width:min(520px,100%);text-align:center;display:flex;flex-direction:column;gap:10px}
.ww-arrival-h{margin:0;font-size:clamp(22px,6vw,30px);line-height:1;font-weight:900;font-style:italic;
  letter-spacing:-.03em;text-transform:uppercase;color:#fff}
.ww-arrival-l{margin:0;color:#c9cfd8;font-size:13px;line-height:1.5}
.ww-room{display:flex;flex-direction:column;gap:6px;text-align:left;margin-top:4px}
.ww-room-row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding:9px 12px;border:1px solid rgba(255,255,255,.1);border-radius:4px;
  background:rgba(255,255,255,.03)}
.ww-room-who{font-size:13px;color:#fff;font-weight:600}
.ww-room-what{font-family:JB,ui-monospace,Menlo,monospace;font-size:9.5px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;color:#aab2bd;text-align:right}
.ww-room-none{font-size:12.5px;color:#8a93a0;font-style:italic}

/* ── AFTERMATH — the morning after, before the curtain ───────────────────────────────────────── */
.ww-after{width:min(520px,100%);display:flex;flex-direction:column;gap:12px;text-align:left}
.ww-after-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
.ww-after-cell{border:1px solid rgba(255,255,255,.12);border-radius:4px;padding:10px 12px;
  background:rgba(255,255,255,.03);display:flex;flex-direction:column;gap:2px}
/* ⛔ #8a93a0 measured 4.49:1 against the ACTUAL composited pixels at this scroll position — not
   the failure a token check would have found. `.ww-house`'s radial gradient is NOT uniform
   black; near the bottom of the scroll (where the aftermath section sits) it approaches
   `rgba(11,28,48,.9)`, a lighter navy, so the same ink that passes near the mast fails here. Pixel-
   sampled (design/wahwahs-ceremony-2026-09-12/pixel_contrast.json) → ~12:1 with the value below,
   already used elsewhere in this file (.ww-sub, .ww-closecopy) for the same reason. */
.ww-after-k{font-family:JB,ui-monospace,Menlo,monospace;font-size:9px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:#c9cfd8}
.ww-after-v{font-family:JB,ui-monospace,Menlo,monospace;font-size:18px;font-weight:800;
  font-variant-numeric:tabular-nums;color:#5fe08a}
.ww-after-v.is-flat{color:#c9cfd8}
.ww-after-pro{border:1px solid rgba(249,115,22,.5);border-radius:4px;padding:10px 12px;
  background:rgba(249,115,22,.08);font-size:12.5px;line-height:1.5;color:#ffe6d2}
.ww-after-press{font-size:12.5px;line-height:1.5;color:#c9cfd8;font-style:italic}

@media (prefers-reduced-motion:reduce){
  .ww-ctrl{transition:none}
}

@media (prefers-reduced-motion:reduce){ .ww-hero-art{ filter:none; } }

/* ═══ WW-04 · THE ROOM IS THE SIZE OF THE SCREEN IT OPENS ON ═══════════════════════════════════
   CEO, 2026-09-20: "entering WahWAhs is a mess- frame this full ipad width".

   `.ww-win` was width:min(560px,100%) at every size. On the iPad frame the game actually runs in
   (1338px wide) that is a 560px column with 390px of blurred backdrop on either side of it — a
   phone window floated in the middle of a tablet, with a ballot of full-width rows stacked down
   it and the slate pushed below the fold. The number was never wrong for a phone; it was the only
   number there was, which is the same defect as every other list in this codebase this week.

   So the window grows with the viewport, and the ballot uses the width it gains rather than
   stretching three rows to 1080px: two columns from 900px, which is where a row at ~500px stops
   being a comfortable measure and starts being a stretched one. Phone layout is untouched —
   min() still returns 100% below 560px, and the grid is behind a min-width query. */
@media (min-width:900px){
  .ww-win{width:min(1080px,100%)}
  .ww-bd{padding:26px 28px 24px}
  .ww-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:start}
  /* The blocked banner speaks for the whole ballot, so it spans it rather than sitting in
     column one pretending to be about the first row. */
  .ww-blocked{grid-column:1/-1}
  .ww-h{font-size:38px}
}

/* ── THE SHARED REFUSAL. One condition, stated once, with the way out of it.
   See pn-wahwahs.js syncAll(): this appears only when every row on the ballot is refused for the
   same reason. It is a STATE, so it is printed and it stays printed — never a toast, which is the
   bug this room already had once (the toast painted underneath the overlay that raised it). */
.ww-blocked{
  margin:0 0 12px;padding:12px 14px;
  border:1px solid rgba(249,115,22,.45);border-left:3px solid #f97316;border-radius:4px;
  background:rgba(249,115,22,.10);
  font-size:13.5px;line-height:1.55;color:#f1e6dd}
.ww-blocked p{ margin:0; }
.ww-blocked b{
  display:block;margin-bottom:3px;color:#fff;
  font-family:JB,ui-monospace,Menlo,monospace;font-size:10.5px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase}
/* the working remedy — not prose telling you to go somewhere, a control that closes the room
   (the remedy itself, ending the week, happens on the floor this modal sits over) */
.ww-blocked-go{ display:inline-flex; align-items:center; justify-content:center;
  margin-top:10px; min-height:44px; padding:0 16px; border-radius:3px; cursor:pointer;
  border:1px solid rgba(249,115,22,.55); background:rgba(249,115,22,.16); color:#fff;
  font:700 12.5px/1 IS,-apple-system,system-ui,sans-serif; letter-spacing:.01em; }  /* ink #fff on this fill: 8.9:1+ */
.ww-blocked-go:hover{ background:rgba(249,115,22,.28); }
.ww-blocked-go:focus-visible{ outline:2px solid #f97316; outline-offset:2px; }
/* The rows keep their gate text for assistive tech and stop repeating it in the CEO's eyeline —
   that repetition IS the "mess". CLIPPED, never display:none: aria-describedby points at this
   node, and content in a display:none subtree is removed from the accessibility tree entirely, so
   hiding it the obvious way would take the reason away from exactly the users who cannot see the
   banner's colour. The control keeps its own CAN'T ENTER label; only the duplicated sentence goes. */
.ww-work.is-muted [data-gate]:not([hidden]){
  position:absolute !important;width:1px;height:1px;margin:-1px;padding:0;border:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}
.ww-work.is-muted{opacity:.82}
