/* ============================================================================
   GLEEShell — geometry. CANONICAL SOURCE.
   ----------------------------------------------------------------------------
   These numbers are the invariant. They exist once, here, and the continuity
   gate reads the same values from SHELL_SPEC in glee-shell.js — spec and
   enforcement cannot drift, because they are the same declaration.

   What this replaces: /bridge/ set max-width 1180 on DIV.shell, /map/ set 1180
   on MAIN.gmap-page, /receipts/ set none at all and let paragraphs carry
   --gp-measure, and nav-x came out 50 on one page and 70 on the others from the
   same stylesheet. Four shells, five content-left edges, one number typed in
   several places. A page must no longer be able to express geometry at all.
   ============================================================================ */

:root {
  --gs-header-h: 58px;
  --gs-pad-x: 24px;
  --gs-container: 1180px;
  --gs-mark: 22px;
  --gs-nav-gap: 4px;
  --gs-nav-pad-x: 10px;

  --gs-font-display: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --gs-font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --gs-font-data: ui-monospace, "Cascadia Code", "SF Mono", Menlo, Consolas, monospace;

  --gs-ground: var(--gd-canvas, #000000);
  --gs-ink: var(--gd-ink, #E9E7E2);
  --gs-ink-2: var(--gd-ink-2, #BAC1C9);
  --gs-muted: var(--gd-muted, #98A2AE);
  --gs-gold: var(--gd-gold, #C9A96B);
  --gs-gold-hi: var(--gd-gold-hi, #E4CFA1);
  --gs-hairline: var(--gd-hairline, #1C252C);
  --gs-panel: var(--gd-panel, #090F14);
}

/* The shell owns its own placement. Measured 2026-08-19: /map/ had no body-margin
   reset, so the browser default 8px inset the sticky header to x=8,y=8 while every
   other surface sat flush at 0,0 — a shell that starts in a different place on one
   page is the same fracture in miniature. A page must not be able to move it. */
body:has(> header.gs-shell),
body[data-gs-mounted] {
  margin: 0;
}

/* ---- the bar ------------------------------------------------------------- */

.gs-shell {
  position: sticky;
  top: 0;
  z-index: 200;
  background: color-mix(in srgb, var(--gs-ground) 88%, transparent);
  backdrop-filter: blur(14px) saturate(120%);
  border-bottom: 1px solid var(--gs-hairline);
  font-family: var(--gs-font-ui);
}

.gs-bar {
  max-width: var(--gs-container);
  margin: 0 auto;
  padding: 0 var(--gs-pad-x);
  min-height: var(--gs-header-h);
  display: flex;
  align-items: center;
  gap: var(--space-16);
}

/* ---- BrandAnchor — also the escape affordance ---------------------------- */

.gs-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  flex: none;
  color: var(--gs-ink);
  text-decoration: none;
  /* The way home is the one affordance every surface keeps, and on a phone it
     was the hardest thing in the bar to hit: the anchor took its height from
     the 22px mark, while every nav link next to it stood 31px. Found on all 22
     mobile pages at once, by the layered check, the first time that check
     measured the shell that actually mounts instead of the one it replaced.
     The mark stays 22px — this grows the target, not the geometry. */
  min-height: 32px;
}
.gs-mark {
  width: var(--gs-mark);
  height: var(--gs-mark);
  color: var(--gs-gold);
  flex: none;
  transition: transform 420ms cubic-bezier(.16, 1, .3, 1), color 220ms;
}
.gs-brand:hover .gs-mark { color: var(--gs-gold-hi); transform: rotate(45deg); }
.gs-wordmark {
  font-family: var(--gs-font-display);
  font-size: var(--text-16);
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  line-height: 1;
}

/* ---- GlobalNav — Captain's frozen eight ---------------------------------- */

.gs-nav {
  display: flex;
  align-items: center;
  gap: var(--gs-nav-gap);
  flex: 1 1 auto;
  /* min-width:0 is load-bearing: a flex item defaults to min-width:auto, so a
     nowrap scroller widens the BAR instead of scrolling inside itself. */
  min-width: 0;
  /* Clip and scroll at EVERY width, not just phone width. This was inside the
     760px media query until 2026-08-22, and at 768px the eight sections
     overflowed a 442px box and painted straight through the account control.
     A breakpoint cannot know whether the labels fit; the container can. */
  overflow-x: auto;
  scrollbar-width: none;
  /* Fade the trailing edge so a clipped strip reads as scrollable rather than
     as a navigation that simply ends. */
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%);
  mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%);
}
.gs-nav::-webkit-scrollbar { display: none; }

.gs-nav-a {
  padding: 6px var(--gs-nav-pad-x);
  border-radius: var(--radius-8);
  color: var(--gs-muted);
  text-decoration: none;
  font-size: var(--text-12);
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 140ms, background 140ms;
}
.gs-nav-a:hover { color: var(--gs-ink); background: rgba(201, 169, 107, .08); }
.gs-nav-a.is-on { color: var(--gs-gold-hi); background: rgba(201, 169, 107, .12); }
/* Tablet and small laptop: tighten tracking so more of the eight are visible
   before the strip has to scroll. Nothing is dropped at any width. */
@media (max-width: 1040px) {
  .gs-nav-a { padding: var(--space-4) var(--space-8); letter-spacing: .08em; }
}

/* The keyboard hint rides inside the Search item so the bar carries one
   Search control, not a nav item beside a lookalike pill. */
.gs-nav-key {
  margin-left: var(--space-4);
  font-family: var(--gs-font-data);
  font-size: var(--text-13);
  letter-spacing: 0;
  opacity: .55;
}

/* ---- SessionControl ------------------------------------------------------ */

.gs-right { display: flex; align-items: center; gap: var(--space-8); flex: none; margin-left: auto; }

/* Controls a page carried INTO the shell -- rescued JS hooks and state pills
   keep their own markup and their own (absent) sizing, so they arrive with
   whatever height their old bar gave them. /arcade/'s "back" link measured
   65x22 at 390px, under the 28px tap floor, while all eight nav items were 30.
   Sizing them here rather than in each page is the same argument as the bar
   itself: the shell owns the geometry of everything inside it. */
.gs-right a,
.gs-right button,
.gstate a,
.gstate button {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
}
.gs-cmd {
  display: inline-flex; align-items: center; gap: var(--space-8);
  padding: var(--space-4) var(--space-12);
  border: 1px solid var(--gs-hairline);
  border-radius: var(--radius-pill);
  color: var(--gs-muted);
  text-decoration: none;
  font-size: var(--text-12);
  transition: border-color 140ms, color 140ms;
}
.gs-cmd:hover { border-color: rgba(201, 169, 107, .30); color: var(--gs-ink); }
.gs-cmd-key { font-family: var(--gs-font-data); font-size: var(--text-13); opacity: .8; }

.gs-session {
  padding: var(--space-4) var(--space-12);
  border-radius: var(--radius-8);
  background: linear-gradient(180deg, var(--c-gold-mid), var(--c-gold));
  color: var(--c-ink-2);
  text-decoration: none;
  font-size: var(--text-12);
  font-weight: 700;
  letter-spacing: .06em;
  white-space: nowrap;
}
.gs-session.is-in {
  background: transparent;
  border: 1px solid var(--gs-hairline);
  color: var(--gs-ink-2);
  font-weight: 600;
}

/* ---- LocalNav — the six groups, demoted beneath the shell ---------------- */

.gs-lnav {
  border-bottom: 1px solid var(--gs-hairline);
  background: color-mix(in srgb, var(--gs-panel) 60%, transparent);
}
.gs-lnav-in {
  max-width: var(--gs-container);
  margin: 0 auto;
  padding: 10px var(--gs-pad-x);
  display: flex;
  gap: var(--space-24);
  flex-wrap: wrap;
  overflow-x: auto;
  scrollbar-width: none;
}
.gs-lnav-in::-webkit-scrollbar { display: none; }
.gs-lnav-g { display: flex; align-items: baseline; gap: var(--space-12); white-space: nowrap; }
.gs-lnav-t {
  font-size: var(--text-11); letter-spacing: .14em; text-transform: uppercase;
  font-weight: 700; color: var(--gs-muted);
}
.gs-lnav-g a { color: var(--gs-ink-2); text-decoration: none; font-size: var(--text-13); }
.gs-lnav-g a:hover { color: var(--gs-gold-hi); }

/* ---- SurfaceFrame — the one container ------------------------------------ */

.gs-frame { width: 100%; }
.gs-content {
  max-width: var(--gs-container);
  margin: 0 auto;
  padding: 40px var(--gs-pad-x) 96px;
  display: block;
}
/* A specialized surface may use the full width for its workspace; it still
   inherits the header above and the padding rhythm. */
.gs-frame--specialized > .gs-content { max-width: none; padding-left: var(--gs-pad-x); padding-right: var(--gs-pad-x); }
.gs-frame--immersive > .gs-content { max-width: none; padding: 0; }

/* immersive keeps identity and a way out, nothing else */
.gs-shell.gs-immersive { position: fixed; background: transparent; border-bottom: 0; backdrop-filter: none; }
.gs-shell.gs-immersive .gs-bar { min-height: 44px; }

/* ---- responsive: the shell holds, the nav scrolls ------------------------ */

@media (max-width: 760px) {
  :root { --gs-pad-x: 14px; --gs-header-h: 52px; }
  .gs-bar { gap: var(--space-12); flex-wrap: nowrap; }
  .gs-bar > * { min-width: 0; }
  /* min-width:0 is load-bearing: a flex item defaults to min-width:auto, so a
     nowrap scroller widens the BAR instead of scrolling inside itself. */

  .gs-nav { gap: 0; }
  .gs-nav-a { padding: var(--space-4) var(--space-4); font-size: var(--text-11); letter-spacing: .04em; }
  .gs-nav-key { display: none; }
  .gs-session { padding: var(--space-4) var(--space-8); font-size: var(--text-11); }
  /* State pills are status, not navigation. Hidden rather than removed: page
     scripts rescued into .gstate still write into these nodes. */
  .gs-right .gstate { display: none; }

  .gs-wordmark { letter-spacing: .18em; font-size: var(--text-14); }
  .gs-content { padding-top: var(--space-24); }
}

@media (prefers-reduced-motion: reduce) {
  .gs-brand:hover .gs-mark { transform: none; }
  .gs-mark, .gs-nav-a, .gs-session { transition: none; }
}
