/* ============================================================================
   app-shell/shell.css — the ONE cross-door navigation fragment.
   Stamped into /, /ops/ and /health/ by scripts/assemble-app-deploy.sh.
   Contract: docs/plans/2026-07-23-app-shell-review-workbench-design/design.md
             section 2 + mock-01-shell-switchboard.html
   Locks:    PGM-app-shell-fragment (one buildless fragment; no framework, no
             client router, no URL moves, NO THIRD VISUAL LANGUAGE)
             PGM-health-door-attribution (door vocabulary + tokens reused verbatim)

   THE IDEA: the bar is a theme-neutral deep-ink strip whose bottom edge IS the
   B2-d gold thread, and the ACTIVE DOOR IS A LIT BEAD SITTING ON THAT THREAD --
   the brand mark doing navigation work. Deep ink (#0D1226) is chosen to read
   correctly over BOTH grounds: it deepens Command's Luxury-Midnight navy
   (#0A0F1F) and reads as the ledger's spine over Ops/Engine-Room paper
   (#FAF7F0). No third palette is introduced.

   TWO HARD INTEGRATION RULES, both measured rather than assumed:
   1. EVERY selector and custom property is `zg-`/`--zg-` prefixed. health-ui
      ALREADY OWNS `.door`, `.door-command`, `.door-ops`, `.door-platform` for
      its legend and map chips -- unprefixed names from the mock would collide
      on that exact door.
   2. Tokens are scoped to `.zg-shell` / `.zg-switchboard`, NOT `:root`. All
      three hosts define `--gold`, `--ink`, `--panel`, `--line` etc. on `:root`;
      a `:root` block here could silently reshade a host app.
   ========================================================================== */

/* Single source of truth for the bar height. Declared on the fragment's OWN body
   class (never :root -- all three hosts own :root tokens), so both the bar and the
   host-compensation rules below read one value. */
body.zg-shelled { --zg-bar-h: 52px; }

.zg-shell {
  /* --- shell tokens (theme-neutral; mock-01 values verbatim) --- */
  --zg-ink: #0D1226;
  --zg-ink-edge: #1B2340;
  --zg-thread: #C9A227;
  --zg-thread-lit: #F3E6B4;
  --zg-text: #B9BECF;
  --zg-text-dim: #6E7488;
  --zg-gold-light: #E8D48B;
  --zg-gold-muted: #C9B97A;
  /* --- door vocabulary: health-ui/styles.css:19-20 dark set, VERBATIM.
         Platform deliberately has NO token -- health-ui/styles.css:125 records
         "keeps the ghost base style -- shared hull, recedes". Two of three doors
         are tokenised by design; Platform is a no-token state, not a colour. --- */
  --zg-cmd-ink: #E8D48B;  --zg-cmd-line: rgba(201, 162, 39, .55);  --zg-cmd-bg: rgba(201, 162, 39, .13);
  --zg-ops-ink: #6fb9cf;  --zg-ops-line: rgba(111, 185, 207, .5);  --zg-ops-bg: rgba(111, 185, 207, .12);
  --zg-plat-ink: #8B90A3; --zg-plat-line: rgba(139, 144, 163, .4); --zg-plat-bg: rgba(139, 144, 163, .08);
  --zg-mono: "Spline Sans Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --zg-sans: Inter, "Segoe UI", system-ui, sans-serif;

  /* z-index 35 is measured, not guessed:
       ABOVE health-ui .topbar (20) and dashboard's bottom-anchored 20/30
       BELOW health-ui .scrim (40) / .drawer (41) so a modal correctly covers it
       BELOW both skip-links (health 50, ops 100) so keyboard skip stays reachable */
  position: sticky;
  top: 0;
  z-index: 35;
  display: flex;
  align-items: stretch;
  height: var(--zg-bar-h, 52px);
  flex: none;
  background: var(--zg-ink);
  font-family: var(--zg-sans);
  font-weight: 300;
  /* the host grounds differ; the bar must never inherit their text colour */
  color: var(--zg-text);
  -webkit-font-smoothing: antialiased;
}

/* THE THREAD — the bar's true bottom edge, not a border */
.zg-shell::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg,
    rgba(201, 162, 39, 0) 0%,
    rgba(201, 162, 39, .65) 12%,
    rgba(201, 162, 39, .65) 88%,
    rgba(201, 162, 39, 0) 100%);
  pointer-events: none;
}

/* ── brand lockup ─────────────────────────────────────────────────────────── */
.zg-brand { display: flex; align-items: center; gap: 10px; padding: 0 18px 0 20px; }
.zg-brand svg { width: 24px; height: 24px; display: block; flex: none; }
.zg-brand .zg-wm {
  font-size: 13px; letter-spacing: 6px; font-weight: 300; color: var(--zg-gold-muted);
  white-space: nowrap;
}
.zg-brand .zg-wm b { font-weight: 500; color: var(--zg-gold-light); }

/* ── door tabs = beads on the thread ──────────────────────────────────────── */
.zg-doors { display: flex; align-items: stretch; margin-left: 14px; min-width: 0; }

.zg-door {
  position: relative;
  display: flex; align-items: center; gap: 8px;
  padding: 0 16px;
  color: var(--zg-text-dim);
  text-decoration: none;
  font-size: 12.5px;
  letter-spacing: .06em;
  white-space: nowrap;
  transition: color .15s ease;
}
.zg-door:hover { color: var(--zg-text); }
.zg-door:focus-visible {
  outline: 1px solid var(--zg-gold-light);
  outline-offset: -3px;
  border-radius: 3px;
  color: var(--zg-text);
}
.zg-door[aria-current="page"] { color: #fff; cursor: default; }

/* THE BEAD — sits ON the thread beneath the active door */
.zg-door[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 50%; bottom: -5px;
  width: 9px; height: 9px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(circle at 40% 34%, #FBF3D6, #E8D48B 55%, #C9A227);
  box-shadow: 0 0 10px 2px rgba(232, 212, 139, .45);
}

/* door chips — Spline Sans Mono, health-ui .door metrics verbatim */
.zg-chip {
  flex: none;
  font-family: var(--zg-mono);
  font-size: 8px; font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .09em;
  line-height: 1;
  padding: 3px 5px;
  border-radius: 4px;
  border: 1px solid;
}
.zg-chip-command  { color: var(--zg-cmd-ink);  border-color: var(--zg-cmd-line);  background: var(--zg-cmd-bg); }
.zg-chip-ops      { color: var(--zg-ops-ink);  border-color: var(--zg-ops-line);  background: var(--zg-ops-bg); }
.zg-chip-platform { color: var(--zg-plat-ink); border-color: var(--zg-plat-line); background: var(--zg-plat-bg); }

/* the honest queue badge — rendered ONLY when a host supplies a real number.
   No host-supplied count => no element at all. Never a fabricated or stale 0. */
.zg-badge {
  font-family: var(--zg-mono);
  font-size: 10px;
  color: var(--zg-gold-light);
  background: rgba(201, 162, 39, .12);
  border: 1px solid rgba(201, 162, 39, .3);
  border-radius: 9px;
  padding: 1px 7px;
}

/* ── right side: org · exec · ONE sign-out ────────────────────────────────── */
.zg-right {
  margin-left: auto;
  display: flex; align-items: center; gap: 18px;
  padding-right: 20px;
  min-width: 0;
}
.zg-org {
  font-size: 11px; letter-spacing: 2px; text-transform: uppercase;
  color: var(--zg-text-dim); white-space: nowrap;
}
.zg-who {
  font-size: 11px; color: var(--zg-text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 22ch;
}
.zg-signout {
  background: none; border: none; padding: 0;
  font: inherit; font-size: 11px; letter-spacing: 1px;
  color: var(--zg-text-dim); cursor: pointer;
  transition: color .15s ease;
  white-space: nowrap;
}
.zg-signout:hover { color: var(--zg-gold-muted); }
.zg-signout:focus-visible { outline: 1px solid var(--zg-gold-light); outline-offset: 2px; border-radius: 2px; }

/* ── host compensation — the fragment adjusts the HOSTS, so no host
      stylesheet is edited (keeps dashboard/styles.css touched only by the
      ACT_SURFACE flag, per the cycle-200 authorisation scope). ───────────── */

/* health-ui's .topbar is position:sticky;top:0;z-index:20 -- it would slide
   UNDER this bar on scroll. Re-seat it below the bar. ops-ui's .topbar is not
   sticky, so `top` is inert there; harmless. */
body.zg-shelled .topbar { top: var(--zg-bar-h, 52px); }

/* ── viewport-height compensation: the bar is 52px of REAL layout, so any host
      rule pinned to 100vh overflows by exactly the bar's height and leaves a
      permanent phantom scrollbar. Measured: 52px of overflow on both doors that
      do this. Two rules, both verified against the hosts:
        dashboard/styles.css:36  body { min-height: 100vh }
        ops-ui/styles.css:54     .app { min-height: 100vh }
      The two .signin-wrap:100vh rules are deliberately NOT compensated -- the bar
      is hidden pre-auth, so it occupies no space and the sign-in card must stay
      centred in the FULL viewport. health-ui's .drawer:100vh is position:fixed and
      is meant to span the whole viewport (it covers the bar at z-index 41). --- */
body.zg-shelled { min-height: calc(100vh - var(--zg-bar-h, 52px)); }
body.zg-shelled #app { min-height: calc(100vh - var(--zg-bar-h, 52px)); }

/* ── retiring the per-app header duplicates (design section 2) ──────────────
   "Right side: org name · signed-in exec · ONE sign-out (global ... the per-app
   header duplicates retire)." Before this, each app restated brand/org/sign-out
   independently -- three headers, which is the very thing the shell exists to fix.

   ⚠️ EVERYTHING HERE HIDES; NOTHING IS REMOVED. Two reasons, both measured:
     · dashboard/app.js:39 binds `$("sign-out")` with NO optional chaining and
       :44 writes `$("org-name").textContent` -- removing either node throws at
       load. The nodes must exist.
     · This bar's single sign-out DELEGATES to the host button by click, so each
       app keeps its own supabase client and auth path.
   All of it is keyed on `body.zg-shelled`, so if the fragment ever fails to load
   the host headers come back intact -- graceful degradation, not a broken page. */

/* Command: .app-header carries ONLY brand + org + exec identity + sign-out --
   every one of which the bar now owns. The whole header retires. */
body.zg-shelled #app > .app-header { display: none; }

/* Ops + Engine Room: .topbar also carries FUNCTIONAL controls that must survive
   (Ops: the viewer-block "whose eyes" line; Engine Room: Map/Flow toggle, overall
   status, run-at, theme, refresh). Retire only the duplicated brand/org/sign-out. */
body.zg-shelled #app > .topbar > .brand-lockup,
body.zg-shelled #app > .topbar > .wordmark,
body.zg-shelled #app > .topbar > #org-name,
body.zg-shelled #app > .topbar > #sign-out { display: none; }

/* ==========================================================================
   THE SWITCHBOARD — Command root only (Anne's 1-3-1 (A) = option 2: the bar
   everywhere + this header ABOVE the existing panels; no URL moved).
   Lives here rather than in dashboard/styles.css so the shell owns its own
   presentation and the host stylesheet stays out of scope.
   ========================================================================== */
.zg-switchboard {
  --zg-mono: "Spline Sans Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --zg-gold-light: #E8D48B;
  --zg-gold-muted: #C9B97A;
  --zg-ice: #CADCFC;
  --zg-warm-gray: #9CA3AF;
  --zg-panel: rgba(10, 15, 31, .6);
  --zg-panel-border: rgba(201, 185, 122, .18);
  --zg-ops-ink: #6fb9cf;
  --zg-plat-ink: #8B90A3;
  display: block;
  margin-bottom: 34px;
  /* The Command host mounts this inside <main id="panels">, which is a
     `repeat(auto-fit, minmax(min(100%,380px),1fr))` grid (dashboard/styles.css:83).
     Span every column, the same way .panel.wide does at :89 -- otherwise the
     switchboard would sit in a single 380px track beside a panel. */
  grid-column: 1 / -1;
}

/* today-strip: greeting · date + briefing time · queue pulse */
.zg-today {
  display: flex; align-items: baseline; gap: 26px; flex-wrap: wrap;
  padding-bottom: 20px; margin-bottom: 30px;
  border-bottom: 1px solid var(--zg-panel-border);
  animation: zg-rise .5s ease .05s both;
}
.zg-today h1 {
  font-family: Fraunces, Georgia, serif; font-weight: 500;
  font-size: clamp(22px, 3vw, 30px); color: #fff; letter-spacing: .3px;
  margin: 0;
}
.zg-today .zg-date { font-family: var(--zg-mono); font-size: 12px; color: var(--zg-warm-gray); }
.zg-today .zg-pulse { margin-left: auto; font-size: 12.5px; color: var(--zg-ice); }
.zg-today .zg-pulse b { font-family: var(--zg-mono); font-weight: 600; color: var(--zg-gold-light); }

/* three door cards, door-coloured left edges */
.zg-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 20px;
}
.zg-card {
  position: relative; display: block; text-decoration: none; color: inherit;
  background: var(--zg-panel);
  border: 1px solid var(--zg-panel-border);
  border-radius: 6px;
  padding: 24px 24px 20px;
  overflow: hidden;
  backdrop-filter: blur(8px);
  transition: transform .18s ease, border-color .18s ease;
  animation: zg-rise .5s ease both;
}
.zg-card:nth-child(1) { animation-delay: .12s; }
.zg-card:nth-child(2) { animation-delay: .20s; }
.zg-card:nth-child(3) { animation-delay: .28s; }
.zg-card:hover { transform: translateY(-3px); border-color: rgba(201, 185, 122, .4); }
.zg-card:focus-visible { outline: 1px solid var(--zg-gold-light); outline-offset: 2px; }

.zg-card::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; }
.zg-card-command::before  { background: linear-gradient(180deg, #E8D48B, #C9A227); }
.zg-card-ops::before      { background: linear-gradient(180deg, #6fb9cf, #20707f); }
.zg-card-platform::before { background: linear-gradient(180deg, rgba(139, 144, 163, .7), rgba(139, 144, 163, .25)); }

.zg-card h2 {
  font-size: 15px; font-weight: 400; letter-spacing: 3px; text-transform: uppercase;
  color: var(--zg-gold-muted);
  display: flex; align-items: center; gap: 10px;
  margin: 0;
}
.zg-card-ops h2 { color: var(--zg-ops-ink); }
.zg-card-platform h2 { color: var(--zg-plat-ink); }
.zg-card .zg-desc { font-size: 12.5px; color: var(--zg-warm-gray); margin-top: 6px; min-height: 34px; }

.zg-stat { display: flex; align-items: baseline; gap: 10px; margin-top: 16px; }
.zg-stat .zg-n { font-family: var(--zg-mono); font-size: 30px; font-weight: 600; color: #fff; }
.zg-stat .zg-n.zg-n-gold { color: var(--zg-gold-light); }
.zg-stat .zg-lbl { font-size: 12px; color: var(--zg-warm-gray); }

.zg-rows { margin-top: 14px; border-top: 1px solid rgba(255, 255, 255, .07); }
.zg-rows .zg-r {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 8px 0; border-bottom: 1px solid rgba(255, 255, 255, .05);
  font-size: 12.5px; color: var(--zg-ice);
}
.zg-rows .zg-r:last-child { border-bottom: none; }
.zg-rows .zg-r .zg-v { font-family: var(--zg-mono); color: var(--zg-warm-gray); text-align: right; }
.zg-rows .zg-r .zg-v.zg-warn { color: #E8C46B; }
.zg-rows .zg-r .zg-v.zg-ok { color: #7FB59B; }

.zg-go { margin-top: 14px; font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--zg-gold-muted); }
.zg-card-ops .zg-go { color: var(--zg-ops-ink); }
.zg-card-platform .zg-go { color: var(--zg-plat-ink); }

/* Reserved Think-layer slot (design section 6): the last-24h state-change feed
   that (3)SYNTHESIZE feeds via intel_events. Renders as an honest empty state;
   NOTHING here gates the v1 build and no count is invented. */
.zg-feed { margin-top: 26px; animation: zg-rise .5s ease .34s both; }
.zg-feed h3 {
  font-size: 11px; letter-spacing: 2.5px; text-transform: uppercase;
  color: var(--zg-warm-gray); font-weight: 400; margin: 0 0 12px;
}
.zg-feed .zg-empty {
  padding: 14px 18px;
  border: 1px dashed var(--zg-panel-border);
  border-radius: 6px;
  font-size: 12px; color: var(--zg-warm-gray);
}

@keyframes zg-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ── responsive: the bar sheds words before it sheds doors ────────────────── */
@media (max-width: 860px) {
  .zg-brand .zg-wm { display: none; }
  .zg-org { display: none; }
}
@media (max-width: 720px) {
  .zg-door-label { display: none; }        /* chips alone still name the door */
  .zg-door { padding: 0 11px; }
  .zg-right { gap: 12px; }
}
@media (max-width: 520px) {
  .zg-who { display: none; }
  .zg-doors { margin-left: 4px; }
  .zg-brand { padding: 0 8px 0 12px; }
}

/* ── accessibility ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .zg-today, .zg-card, .zg-feed { animation: none; }
  .zg-card:hover { transform: none; }
  .zg-door, .zg-signout, .zg-card { transition: none; }
}
@media (prefers-contrast: more) {
  .zg-shell { --zg-text-dim: #9BA1B5; }
  .zg-door[aria-current="page"]::after { box-shadow: 0 0 0 1px #fff, 0 0 10px 2px rgba(232, 212, 139, .6); }
}
