/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE MASTHEAD, ONE RHYTHM — 2026-09-12
   CEO live-play feedback #2 (verbatim): "topnav sloppy design and theres no real difference
   between dark and Neon so remove neon and just have light and dark." The Neon half of that note
   is fixed at the source (mvc-os.js PN_THEMES, pn-shell-adopt.js menu, and the retired
   [data-theme="neon"] skins across pn-system-v4/pn-design-0817/pn-final-20260820/pn-shell-adopt).
   This sheet is the "sloppy design" half: the VISIBLE masthead is `.appbar` (pn-shell.js) — the
   legacy `.topbar`/`#tbOverflow` that `pn-cmdbar-v2.css` and half this codebase's comments still
   describe is hidden at every real data-view (pn-shell-adopt.css §1) and was never the bar a
   player sees. Measured, not assumed (getComputedStyle on the live game, week 11 seed):
     .topbar  { display: none }        .appbar { display: flex, height: 58px }

   THE RHYTHM
   · one control height — 40px desktop / 36px mobile (8pt grid) — on every pill/circle in the bar:
     Guide, mail, Store, Desk, the rank chip, League, the burger, and the OPEN/VALUE/BANK cluster.
   · one radius (999px — the pill family already in use), one border weight (1px), one baseline
     (align-items:center on `.appbar`, unchanged).
   · one label typography for the STAT/DATA layer (OPEN · VALUE · BANK, the week ring, the rank
     chip) — the house mono token, one size, one tracking — with tabular numerals on every figure
     so digits never jitter column to column. Button VERBS (Guide/Store/Desk/League) keep the
     house sans (IS) per the existing v4 canon; that is a different, correct, already-consistent
     type role, not an inconsistency to flatten.
   · three quiet groups on the left — identity (crest+name) · clock (the week ring) · money (OPEN/
     VALUE/BANK) — and ONE right-hand actions group: Guide · mail · Store · Desk · rank chip ·
     League · ≡. Consistent gaps within a group, roughly double between groups (UX_RULES-adjacent
     spacing law already standing in this project's design system).

   MOUNT POINTS (why this file, not a rewrite of the controls' own JS)
   The rank chip (pn-floor-chrome.js), the Desk button (pn-floor-chrome.js) and League
   (pn-league.js) used to insert themselves next to the DEAD `#hud`/`.topbar`, so "always visible"
   was never true — they were never visible at all. Each script now mounts into the real `.appbar`
   (see the 2026-09-12 comments in those files); this sheet only shapes what is now actually on
   screen. No scoring/state logic changed in any of the three files.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

:root{ --tb-h:40px; --tb-h-mobile:36px; --tb-r:999px; --tb-bw:1px; }

/* ── 0 · the bar itself: baseline + group rhythm ─────────────────────────────────────────── */
.appbar{
  /* Measured against the real ceiling: `.dev{width:min(100%,1360px)}` means the bar's actual
     content box never exceeds ~980px, at 1440px or 4K alike. 9 fixed-size members (§1) plus the
     identity block leaves no room for a generous 18px rhythm between all nine — 14px is the
     largest gap that holds without the bar spilling past its own device frame (measured). */
  gap:14px;
}
.appbar .agency{ gap:12px; }                 /* within the identity·clock cluster */

/* `.agency` must NOT shrink below its own content, at any width. pn-system-v4.css's own
   `.appbar > *{min-width:0}` (≤980px) let it compress below its rendered size, so the name/ring
   text overflowed the shrunk box straight into the next group — measured as the week ring and the
   money cluster visually overlapping, at BOTH the 1440 desktop box (real ceiling ~980px, from
   `.dev{width:min(100%,1360px)}`) and again at 390 mobile once `.who` is hidden there (§6): a flex
   item with `min-width:0` but flex:none CHILDREN doesn't shrink those children, it just lets the
   box collapse and the children spill into whatever comes next. The fix is the same at every
   width: this box is fixed-size, not elastic — same treatment as the actions/money groups (§1). */
.appbar .agency{
  flex:0 1 auto !important;
  min-width:max-content !important;
}

/* identity · clock as two legible sub-groups inside .agency, not one run-on string */
.appbar .agency .season{
  padding-left:12px;
  border-left:1px solid color-mix(in srgb, var(--label) 14%, transparent);
}

/* the actions group: Guide · mail · Store · Desk · rank chip · League · ≡, one consistent gap */
.appbar > .guide,
.appbar > .mailbtn,
.appbar > .store,
.appbar > .pnfc-act,
.appbar > .burger{ margin-left:0; }
.appbar > .mailbtn{ margin-left:2px; }       /* was carried by the removed `.sep` divider */

/* ── 1 · ONE HEIGHT, ONE RADIUS, ONE BORDER — every pill/circle in the actions + money groups */
.appbar .guide,
.appbar .mailbtn,
.appbar .store,
.appbar .burger,
.appbar #pn-urg,
#pnfcRankChip,
#pnfcDeskBtn.pnfc-act,
#pnlLeagueBtn.pnfc-act{
  height:var(--tb-h) !important;
  min-height:var(--tb-h) !important;
  border-radius:var(--tb-r) !important;
  border:var(--tb-bw) solid color-mix(in srgb, var(--label) 14%, transparent) !important;
  box-sizing:border-box;
  /* pn-system-v4.css sets `.appbar > *{min-width:0}` below 980px so the bar can shed content —
     correct for the identity block, wrong for these: with flex-shrink left at its default (1)
     every pill in this list quietly compressed to ~10px on a real 390px render (measured), well
     before running out of room. These are the FIXED members (UX_RULES-adjacent "the readouts
     never wrap and never shrink below a tap target" law, cmdbar_spec's own §4) — they never
     shrink; the identity block is the one elastic/truncating member. */
  flex:0 0 auto !important;
}
/* circular controls (mail/burger) stay circular at the new height */
.appbar .mailbtn,
.appbar .burger{ width:var(--tb-h) !important; }

/* #pn-urg and .store/.guide already carry their own background (tint/card) — the added border
   above is a hairline on TOP of that fill, not a replacement, matching the rank chip/Desk/League
   pills which had a hairline already. .store's fill obscures a same-tone border almost entirely
   by design (SST accent-tint pill) — intentional, not a missed case. */
.appbar .store{ border-color:color-mix(in srgb, var(--acc) 30%, transparent) !important; }

/* pn-floor-chrome.js's rank-chip/Desk-button CSS predates this file and set its own 32px height,
   pill background and border — override to the shared rhythm rather than editing that file's own
   injected <style>, so its computation stays untouched and this sheet stays the one place the
   masthead's SHAPE is decided. */
#pnfcRankChip{
  background:var(--card) !important;
  color:var(--label2) !important;
  padding:0 14px !important;
  gap:8px !important;
}
#pnfcRankChip:hover{ border-color:var(--acc) !important; background:var(--card-2) !important; }
#pnfcDeskBtn.pnfc-act,
#pnlLeagueBtn.pnfc-act{
  background:var(--card) !important;
  color:var(--label2) !important;
  padding:0 14px !important;
  display:inline-flex !important; align-items:center !important; gap:8px !important;
}
#pnfcDeskBtn.pnfc-act:hover,
#pnlLeagueBtn.pnfc-act:hover{ background:var(--card-2) !important; color:var(--label) !important; }
#pnfcDeskBtn.pnfc-act svg,
#pnlLeagueBtn.pnfc-act svg{ width:16px; height:16px; stroke:currentColor; fill:none; stroke-width:2; flex:none; }
#pnfcDeskBtn.pnfc-act span:not(#pnfcDeskBadge),
#pnlLeagueBtn.pnfc-act span{ font:500 13px/1 IS,ui-sans-serif,system-ui,sans-serif; }
#pnfcDeskBtn.pnfc-act.pnfc-hot{ border-color:var(--acc) !important; color:var(--acc) !important; }

/* ── 2 · TABULAR NUMERALS EVERYWHERE A DIGIT ALIGNS ──────────────────────────────────────── */
.appbar .agency .season b,
.appbar .pn-urg-n,
.appbar .pn-snap-fig b,
.appbar .store b,
#pnfcRankChip .pnfc-pos,
#pnfcRankChip .pnfc-mv,
#pnfcDeskBadge{
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
}

/* ── 3 · ONE LABEL TYPE FOR THE STAT LAYER (OPEN/VALUE/BANK, rank chip) — house mono, one size,
   one tracking. Button verbs (Guide/Store/Desk/League/mail) keep the house sans (IS) — a
   different, correct type role (verb vs. figure), already consistent, left alone. ─────────────── */
.appbar .pn-urg-lbl i,
.appbar .pn-snap-fig i,
#pnfcRankChip .pnfc-near{
  font:700 9px/1 var(--mono);
  letter-spacing:.18em;
  text-transform:uppercase;
}
#pnfcRankChip .pnfc-near{ font-weight:500; letter-spacing:.02em; text-transform:none; opacity:.62; }

/* ── 4 · RANK CHIP IS ALWAYS VISIBLE (Jon: "the rank chip is ALWAYS visible") ────────────────
   pn-floor-chrome.js already hides it with style.display="none" only when there is genuinely no
   league row for the player (no PN_RIVALS data) — that is a data gate, not a width gate, and is
   untouched. This file guarantees the WIDTH never hides it: no `display:none` on #pnfcRankChip or
   .store below this file's own floor (390px), matching the brief exactly. */
@media (min-width:390px){
  #pnfcRankChip, .appbar .store{ display:inline-flex !important; }
}

/* ── 5 · SHEDDING ORDER — Guide + mail fold into the burger's overflow FIRST, UNCONDITIONALLY.
   Measured, not guessed: `.dev{width:min(100%,1360px)}` caps the whole device frame, so the
   masthead's real content box tops out around 980px at EVERY viewport ≥ ~1400px — "desktop 1440"
   never buys the bar more room than "desktop 1920" does. Nine controls plus two quiet stat groups
   never fit that box with Guide+mail inline, at any width, so there is no threshold to tune here:
   they fold ALWAYS. Both have a real menu entry now (pn-shell-adopt.js menuHTML: "Guide", "Mail /
   THE WIRE"), so neither becomes unreachable — only the inline pill goes. Store, Desk, rank chip
   and League stay inline at every width down to 390px per the brief; their labels shed first,
   below, before anything is hidden. ─────────────────────────────────────────────────────────── */
.appbar .guide,
.appbar .mailbtn{ display:none !important; }

/* rank chip: the inline chip is the glance (P10 + trend); "who's above you" is exactly the extra
   context the tap-to-open league book already exists to carry (title= already states the full
   sentence for a11y/hover) — repeating it inline was the single biggest thing standing between
   this bar and fitting its own device frame. Noise Test §1: said once, not twice. */
#pnfcRankChip .pnfc-near{ display:none; }

/* below 900px the action pills lose their word too (icon + figure survive) */
@media (max-width:900px){
  #pnfcDeskBtn.pnfc-act span:not(#pnfcDeskBadge),
  #pnlLeagueBtn.pnfc-act span{ display:none; }
  #pnfcDeskBtn.pnfc-act,
  #pnlLeagueBtn.pnfc-act{ width:var(--tb-h); padding:0; justify-content:center; }
}

/* ── 6 · MOBILE (390px) — 36px controls, money cluster collapses to BANK only ────────────────
   "on mobile the money cluster collapses to BANK only" — OPEN (the urgency ring+label) and VALUE
   drop; BANK is the one figure that answers "can I pay the wages" at a glance, on the narrowest
   frame this game supports (UX_RULES §3: no horizontal scroll at 390px, ever). */
@media (max-width:430px){
  :root{ --tb-h:var(--tb-h-mobile); }
  .appbar{ padding:0 10px; gap:6px; }
  .appbar .agency{ gap:6px; }                   /* stays fixed-size (§0) — just smaller content */
  .appbar .agency .who{ display:none; }         /* the crest still identifies the agency; the
    NAME is restated on The Floor headline one line below (Noise Test Law §1 — said once) */
  .appbar .agency .season{ padding-left:0; border-left:0; }
  .appbar .agency .season svg{ width:20px; height:20px; }
  .appbar .agency .season b{ font-size:11px; }
  /* Store's word (icon already dropped ≤640px by pn-system-v4.css) is the last thing this pill
     can shed before the figure itself would have to go — the font-size:0/reset-on-child trick is
     the same one pn-system-v4.css already uses for `.guide` at this exact breakpoint. */
  .appbar .store{ font-size:0 !important; padding:0 12px !important; gap:0 !important; }
  .appbar .store b{ font-size:14px !important; }
  /* style-01.css hides the whole `.pn-snap-rail` (VALUE+BANK) below 900px — correct for a bar
     that had no room at all, wrong now that the ring/label/VALUE are already gone: BANK is the
     one figure that answers "can I pay the wages" at a glance and the brief keeps it. */
  .appbar .pn-snap-rail{ display:flex !important; margin-left:0; padding-left:0; border-left:0; }
  .appbar .pn-urg-ring,
  .appbar .pn-urg-lbl,
  .appbar .pn-snap-fig[data-k="value"]{ display:none !important; }
  .appbar #pn-urg{ padding:0 10px !important; gap:0; }
  .appbar .pn-snap-fig[data-k="cash"] i{ display:none; }     /* the ring's gone; BANK reads alone */
  .appbar .pn-snap-fig[data-k="cash"] b{ font-size:14px; }
  #pnfcRankChip{ padding:0 10px !important; }
  /* Desk + League fold into the burger's overflow on the narrowest frame — the same shedding
     order as Guide/mail, one step later. UX_RULES §3 ("no horizontal scroll at 390px, ever") outranks
     keeping every action pill inline; Store and the rank chip are the two the brief protects by
     name and both stay. Neither becomes unreachable — the burger menu carries both (pn-shell-adopt.js). */
  #pnfcDeskBtn.pnfc-act,
  #pnlLeagueBtn.pnfc-act{ display:none !important; }
}

/* ── 7 · LIGHT-THEME LEGIBILITY FIX (measured, UX_RULES Law 1) ───────────────────────────────
   `#pn-urg`'s ink (style-01.css) was authored once, for the dark ground, and never re-pinned for
   light: the figures printed near-white (#F6F3FF) and the "OPEN"/"1 to watch" labels printed a
   pale lilac/sage — both effectively invisible on the light theme's cream `.appbar`. Measured,
   not eyeballed: 1.13:1 and 1.37:1 against WCAG AA's 4.5:1 floor. Re-pinned to the same house
   tokens every other light-theme surface in this file already uses (SST-locked, already AA). */
html[data-theme="light"] .appbar #pn-urg,
html[data-theme="light"] .appbar .pn-urg-n,
html[data-theme="light"] .appbar .pn-snap-fig b,
html[data-theme="light"] .appbar .pn-urg-lbl em{
  color:var(--label) !important;
}
html[data-theme="light"] .appbar .pn-urg-lbl i,
html[data-theme="light"] .appbar .pn-snap-fig i{
  color:var(--label3) !important;
}
html[data-theme="light"] .appbar #pn-urg{
  background:var(--card) !important;
}
html[data-theme="light"] .appbar .pn-urg-trk{ stroke:color-mix(in srgb, var(--label) 16%, transparent) !important; }

/* the Store figure ("120"/coin balance) was pinned to `var(--acc)` (pn-shell-adopt.css item 4) on
   the pill's `--card-2` fill — measured 3.73:1 in dark, below AA's 4.5:1 floor for 13px bold text
   (UX_RULES Law 1, "quiet ≠ invisible"). The pill's own ink (`--label`) is already the AA-correct
   colour on this exact background (every other figure in the pill uses it); the figure now matches. */
.appbar .store b{ color:var(--label) !important; }

/* ── 8 · BASKET OCCLUSION (feedback #7, _Documentation/2026-09-12_CEO-PLAY-FEEDBACK.md) ──────
   "INTERNAL WIRE … added to your basket" is `.toast` (style-01.css, z-index:10002); the open
   Basket/Vault window is `#vv-ov`/`.vv-ov` (z-index:9200) — the toast painted OVER an open vv
   window it was reporting on (UX_RULES Law 2, occlusion). This is the z-index/stacking fix the
   masthead pass was asked to take if the cause lived there — it does: one number, no logic moved.
   The toast drops below any open vv-window instead of racing it for the top of the stack. */
body:has(.vv-ov) .toast{ z-index:9150 !important; }

@media (prefers-reduced-motion:reduce){
  #pnfcRankChip, #pnfcDeskBtn.pnfc-act, #pnlLeagueBtn.pnfc-act{ transition:none !important; }
}

/* ── 9 · FIX #1 · INSTANT THEME REPAINT — no illegible mid-transition frame ──────────────────
   Companion to the `pn-theme-swap` class added in mvc-os.js `setPal()`. Root cause (proven by a
   REAL screenshot taken at realistic timing, not by getComputedStyle after a wait): `.side a`
   (pn-system-v4.css) and every appbar pill/tab below carry a hover `transition` on background/
   colour that ALSO animates the dark<->light swap, so for ~160ms the rail's active item, the
   Store/Desk/League/rank-chip pills, the REPORT tab and the theme toggle paint a BLEND of the two
   themes' colours — measured as dark-ink-on-dark-navy for one frame in Light. This rule kills
   every transition for exactly that frame so the swap is instant; hover/focus transitions are
   untouched (the class is removed two frames later, in mvc-os.js). */
html.pn-theme-swap,
html.pn-theme-swap *,
html.pn-theme-swap *::before,
html.pn-theme-swap *::after{
  transition:none !important;
  animation-duration:0s !important;
}

/* ── 9b · "End the week" ghost CTA — legible over the busy hero photo, both themes ───────────
   MEASURED (pixel-sampled from a real render, design/masthead-fix-2026-09-12/light_mobile.png):
   `body.mvc-light … .perf-hero-cta .lg-btn--ghost{color:#241f1b}` (style-01.css) sets a flat dark
   ink with no scrim, directly over `THE KNIVES ARE OUT.`'s brick photograph — the same photo the
   headline sits on, but the headline has its own legibility treatment and this ghost label never
   did. Sampled ratio against a LIGHT brick patch: 3.87:1, below AA. A flat colour can never
   guarantee AA over a photograph (the pixel underneath varies); the fix used everywhere else this
   problem exists (the headline itself) is a halo in the OPPOSITE tone, so the label reads against
   both the photo's light and dark patches. A text-shadow halo alone was tried first and still
   measured 3.55:1 against a light mortar patch — a soft blur cannot beat a genuinely busy photo,
   pixel for pixel. The pattern this codebase already uses for exactly this problem (`.s2-cli-open`,
   pn-button-unify-20260819.css §B5, "a LOW-KEY legibility scrim … so white passes AA on any banner
   in every theme") is a translucent backing PLATE, not just a shadow — contrast is then computed
   against a near-solid fill, not an uncontrolled photo pixel. Same technique, same negative-margin
   trick so the visible padding/position doesn't shift. */
/* ⛔ AND THE PLATE MUST FOLLOW THE BUTTON, NOT ONE HUB TAB (audit, 2026-09-20).
   Everything above is right and stays. What was wrong is the SCOPE: it was keyed to
   `.hub-view[data-view="v-perf"]`, but `.perf-hero-cta` is the hero's own CTA slot and the hero
   rides EVERY hub view. So "End the week" carried its legibility plate on one tab and went bare
   on the rest - measured at 390px in light theme on the default tab, ink rgb(34,28,22) on a bed
   of rgb(19,14,14): 1.14:1. Not dim. Gone. On a phone, which is what a tester picks up.
   The qualifier is dropped so the treatment lands wherever the element it was written for
   actually renders. Nothing else about it changes - same plate, same tones, same negative-margin
   trick so nothing shifts. */
/* ⛔ AND THE PLATE IS A FLAT COLOUR, BECAUSE A GRADIENT IS A background-image (2026-09-20).
   This is why the plate above was written, reviewed, shipped - and never appeared. Read off the
   live cascade with CDP getMatchedStylesForNode: THREE separate pn-ds.css rules set
   `background-image: none !important` on every button, at id-level specificity. A gradient IS a
   background-image, so the plate was erased on arrival while its padding, margin and radius all
   landed - which is exactly what the element looked like: plate-shaped, and not there.
   A flat translucent background-COLOR cannot be wiped by a background-image rule, and the
   gradient was never doing the work anyway: contrast is computed against the fill, and a 46%-62%
   vertical ramp only varies what you measure against. One value, stated once, unkillable. */
body[data-view="office"] .perf-hero-cta .lg-btn--ghost{
  background-color:rgba(6,8,12,.72) !important;
  padding:8px 14px !important; margin:-8px -14px !important; border-radius:8px !important;
  text-shadow:0 1px 2px rgba(0,0,0,.7) !important;
}
body.mvc-light[data-view="office"] .perf-hero-cta .lg-btn--ghost{
  background-color:rgba(250,248,245,.92) !important;
  text-shadow:none !important;
}

/* ── 10 · FIX #2 · MOBILE HERO CTA ARROW — unbounded raw <svg> ───────────────────────────────
   `script-01.js`'s `ARROW` constant is a bare `<svg viewBox="0 0 24 24">` with no width/height
   attribute and no CSS rule ever sized it (only `.lg-g`/`.lg-btn--icon svg` are sized — this arrow
   matches neither). Per the CSS default-object-size algorithm an unsized replaced element with
   only an intrinsic ratio (1:1, from the viewBox) resolves against its flex context: at a fixed
   desktop button width it collapsed to ~0; at mobile, where `.perf-hero-cta .lg-btn` is width:100%
   (style-01.css §v-perf), it instead resolved to a max-content box ≈equal to the button's own
   height (measured 100.578px square in a 278px-wide button) — the "giant arrow" defect, confirmed
   by decoding the actual PNG (design/masthead-2026-09-12/*_mobile.png), not asserted. Same button
   markup is used for BOTH "Win your first pitch" and "End the week" (script-01.js `winCta` /
   `advanceHero`), so both are covered by one rule. Sized to the house icon convention (pn-system.css
   `.pn-btn svg{width:1.15em}`) — text-relative, so it stays "arrow at text size" at any button
   font-size, never unbounded again. */
.lg-btn > svg{
  width:1.15em !important;
  height:1.15em !important;
  flex:none !important;
  display:block !important;
}

