/* ============================================================
   AMBER PHOSPHOR — base
   Reset, type, focus, links, tables, motion policy.
   Component styles live in components.css (card T2).
   ============================================================ */


/* --- fonts ---------------------------------------------------
   Self-hosted, woff2 only, latin subset only. Never the Google Fonts CDN:
   an extra connection, and cache partitioning killed the shared-cache argument.
   woff2 alone because nothing in 2026 needs the woff fallback, and the two legacy
   files cost 26KB against the P10 budget for bytes no browser requests.
   Blocks below are DESIGN-SYSTEM.md 4.2 verbatim. The fallback overrides are
   measured off the shipped woff2 files, not guessed: IBM Plex Mono is
   unitsPerEm 1000, hhea asc 1025, desc -275, gap 0, advance 600.

   Departure Mono (display) has no @font-face here because the file is not in
   public/fonts/: acquiring it needs a network fetch card T1 was not permitted to
   make. --display therefore resolves through to var(--mono), which is correct and
   costs nothing. See dev/web/HANDOFF-T1-fonts.md.
   Spec: docs/website/DESIGN-SYSTEM.md section 4, PERFORMANCE-SPEC.md 2.1 and 4.3. */

/* ---------- IBM Plex Mono 400: body, tables, UI ---------- */
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/ibm-plex-mono-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122,
                 U+2190-2193, U+2212, U+2215,
                 U+2500-257F,      /* box drawing */
                 U+2580-259F,      /* block elements, for pips and bars */
                 U+25A0-25FF,      /* geometric shapes */
                 U+FEFF, U+FFFD;
}

/* ---------- IBM Plex Mono 600: table headers, buttons, emphasis ---------- */
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/fonts/ibm-plex-mono-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122,
                 U+2190-2193, U+2212, U+2215,
                 U+2500-257F, U+2580-259F, U+25A0-25FF, U+FEFF, U+FFFD;
}

/* ---------- metric-matched fallback (zero CLS on swap) ----------
   One family name, "IBM Plex Mono Fallback", because that is the name
   the committed --mono stack already lists. Three declarations of the
   same name, each with a local()-only src: the platform that lacks the
   named face resolves nothing and the declaration drops out, so exactly
   one wins per OS and the size-adjust that wins is the right one. */
@font-face {
  font-family: "IBM Plex Mono Fallback";
  src: local("SF Mono"), local("Menlo"), local("Monaco");
  ascent-override: 102.5%; descent-override: 27.5%; line-gap-override: 0%;
  size-adjust: 99.66%;      /* Menlo advance 1233/2048 = .60205 vs .600 */
}
@font-face {
  font-family: "IBM Plex Mono Fallback";
  src: local("Cascadia Mono"), local("Consolas");
  ascent-override: 102.5%; descent-override: 27.5%; line-gap-override: 0%;
  size-adjust: 109.13%;     /* Consolas advance 1126/2048 = .54980 vs .600 */
}
@font-face {
  font-family: "IBM Plex Mono Fallback";
  src: local("Roboto Mono"), local("Droid Sans Mono");
  ascent-override: 102.5%; descent-override: 27.5%; line-gap-override: 0%;
  size-adjust: 99.98%;      /* Roboto Mono advance 1229/2048 = .60010 vs .600 */
}

/* The two stacks are declared once, in tokens.css. Not redeclared here. */

/* --- reset ---------------------------------------------------
   --radius is 0 and is not overridable. Declaring it globally means no
   component ever has to remember it, and a stray `border-radius: 6px`
   from a copied snippet is the only way a round corner can appear. */
*, *::before, *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  border-radius: var(--radius);
}

html {
  -webkit-text-size-adjust: 100%;
  scrollbar-color: var(--eye) var(--night2);
}

body {
  font-family: var(--mono);
  font-feature-settings: "zero" 1;   /* slashed zero. Free terminal correctness. */
  font-variant-numeric: tabular-nums;
  /* A synthesised bold has different metrics than the real 600 and reintroduces the
     shift the metric-matched fallback exists to remove. PERFORMANCE-SPEC.md 4.3. */
  font-synthesis-weight: none;
  font-size: var(--fs);
  line-height: var(--lh);
  color: var(--cream);
  background: var(--night);
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  text-rendering: optimizeLegibility;
}

main { flex: 1 0 auto; }

/* --- type ---------------------------------------------------- */
/* Type scale: DESIGN-SYSTEM.md 4.5, implemented.
   The display face is pixel-derived: never below 22px, and every size is a
   multiple of 11 so it stays pixel-aligned. It sets H1 and H2 and nothing
   else. H3 and H4 are panel titles and sub-labels, which are Plex 600 with
   letter-spacing, because a pixel face at 13px is mush. Line heights on the
   display roles are in px on purpose: that pins the line box independent of
   font metrics, which is the whole CLS exposure of a display swap. */
h1, h2 {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: 0;
  text-wrap: balance;
}
h1 { font-size: 33px; line-height: 36px; color: var(--cream); }
h2 { font-size: 22px; line-height: 24px; color: var(--eye); }

h3, h4 {
  font-family: var(--mono);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-wrap: balance;
}
h3 { font-size: 16px; color: var(--cream); }
h4 { font-size: 14px; color: var(--violet); }

@media (min-width: 1024px) and (pointer: fine) {
  h1 { font-size: 44px; line-height: 48px; }
  h2 { font-size: 33px; line-height: 36px; }
  h3 { font-size: 13px; }
  h4 { font-size: 12px; }
}

p { max-width: var(--measure); text-wrap: pretty; }
p + p { margin-top: var(--s3); }

small, .quiet { color: var(--muted); font-size: max(13px, 0.85em); }

/* Error text specifically. --ember is 6.96:1 and fails AAA over a long
   string; --bad-text clears 8.99:1, which is why the token exists.
   Errors say what broke and then what to do (VOICE-GUIDE-WEB.md 3). */
.err { color: var(--bad-text); font-weight: 600; }

.label {
  font-size: max(12px, 0.75em);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--eye);
}

/* Box-drawing rule instead of a styled <hr>. U+2500 is in the font subset. */
hr {
  border: 0;
  border-top: var(--bw) solid var(--rule);
  margin: var(--s5) 0;
}

/* The real box-drawing rule: a run of U+2500 clipped to the container width,
   which is what a terminal actually draws. Decorative, so it is generated
   content on an empty element and never announced. DESIGN-SYSTEM.md 4.4:
   the box-drawing block is in the font subset precisely for this. */
.rule {
  overflow: hidden;
  white-space: nowrap;
  color: var(--rule);
  user-select: none;
  line-height: 1;
  margin-block: var(--s4);
}
.rule::before {
  content: "────────────────────────────────────────────────────────────────────────────────────────────────";
}

/* --- links ---------------------------------------------------
   Underlined by default. On amber-on-black, amber links carry enough
   contrast (audited in DESIGN-SYSTEM.md section 3) but the underline
   stays: color is never the only signal. */
a {
  color: var(--eye);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
a:hover { color: var(--cream); text-decoration-thickness: 2px; }
a:visited { color: var(--violet); }

/* --- focus ---------------------------------------------------
   Never removed. A chunky square outline is MORE retro than a soft
   ring, so accessibility is free here. */
:focus-visible {
  outline: 3px solid var(--eye);
  outline-offset: 2px;
  border-radius: 0;
}

/* WCAG 2.2 SC 2.4.11 Focus Not Obscured (Minimum), AA. Added by the T14
   audit, which tabbed every stop on 25 routes and found the first footer
   link entirely hidden: Tab scrolls it to the bottom edge and the sticky
   status bar (32px plus a 2px rule) is painted on top of it. Chrome already
   compensates for the sticky header on the leading edge; it does not
   compensate for a bottom-anchored bar. `scroll-margin` is the mechanism the
   browser's own scroll-into-view honours, so no script is involved.

   Trailing 104px is the worst bottom stack: status bar 34, the mobile filter
   bar above it, and the 5px the 3px ring plus its 2px offset needs. Leading
   56px is the 45px sticky header plus the same ring allowance. */
:where(a, button, input, select, textarea, summary, [tabindex]) {
  scroll-margin-block-start: 56px;
  scroll-margin-block-end: 104px;
}

/* --- target size ---------------------------------------------
   WCAG 2.2 SC 2.5.8, AA. Added by the T14 audit, which measured every
   focusable box on 25 routes at 1280px and found the standalone link
   lists rendering 17px tall with 21px of pitch. SC 2.5.8's inline
   exception covers a link inside a sentence, whose height is set by the
   line-height of surrounding prose; it does not cover a link that IS the
   whole list item, which is what these are. Prose links keep the
   exception and are deliberately not matched here.

   24px is the SC floor, not the house number: --tap (44px) still governs
   buttons, table rows, facet chips and every control that takes a
   deliberate hit (DESIGN-SYSTEM.md 5). These are dense reference lists
   where 44px would triple the height of the footer.

   inline-flex rather than padding so the box grows symmetrically around
   the existing baseline and nothing shifts horizontally. */
.sitefoot__col li > a,
.shopnav__group li > a,
.carry li > a,
.carry li > .quiet > a,
.week li > a,
.nightlist li > a,
.roles__name {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  min-width: 24px;
}

/* --- forms ---------------------------------------------------
   Every control that has no fill of its own gets --rule-strong as its
   boundary. That is the SC 1.4.11 3:1 line; --rule composites to 1.83:1
   and can never be the only thing telling you where a control ends
   (DESIGN-SYSTEM.md 3.3). Checkboxes and radios opt out of the fill and
   the padding here and re-declare their own 16px box in components.css. */
input, select, textarea, button {
  font: inherit;
  color: inherit;
  border-radius: var(--radius);
  min-height: var(--tap);
}
input:not([type="checkbox"]):not([type="radio"]),
select,
textarea {
  padding: 0 var(--s2);
  background: var(--night);
  border: var(--bw) solid var(--rule-strong);
  /* 16px floor on mobile: below it iOS Safari zooms the viewport on focus. */
  font-size: max(var(--fs), 16px);
}
textarea { padding: var(--s2); line-height: var(--lh); }
@media (min-width: 1024px) and (pointer: fine) {
  input:not([type="checkbox"]):not([type="radio"]), select, textarea { font-size: 14px; }
}
fieldset {
  border: var(--bw) solid var(--rule);
  padding: var(--pad) var(--pad-lg) var(--pad-lg);
}
legend {
  font-size: max(12px, 0.75em);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--eye);
  padding: 0 var(--s2);
}

/* --- tables --------------------------------------------------
   Real <table> for tabular data: correct semantics, screen-reader
   navigation, and exactly the density we want. The mobile transform
   lives in components.css (card T2). */
table { border-collapse: collapse; width: 100%; }
th, td {
  padding: calc(var(--pad) - 1px) var(--pad);
  border: 1px solid var(--rule-quiet);
  text-align: left;
  vertical-align: top;
}
th {
  font-weight: 600;
  color: var(--eye);
  font-size: max(12px, 0.8em);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom-color: var(--rule);
}
tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.02); }

/* --- media ---------------------------------------------------- */
img, svg, video { max-width: 100%; height: auto; display: block; }

/* --- utility -------------------------------------------------- */
.wrap { width: 100%; max-width: 1180px; margin: 0 auto; padding: 0 var(--pad-lg); }
.prose > * + * { margin-top: var(--s4); }
.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.skip {
  position: absolute; left: -9999px; top: 0; z-index: var(--z-skip);
  background: var(--eye); color: var(--night); padding: var(--s3) var(--s4);
  font-weight: 600;
}
.skip:focus { left: 0; }

/* --- cross-document view transitions -------------------------
   PERFORMANCE-SPEC.md 4.4, allowed narrowly. 120ms against the --t-view
   150ms ceiling in tokens.css. The reason for the cap, stated so nobody
   raises it later: a transition delays the NEW page's first paint by the
   length of the animation, so on a navigation that is genuinely instant
   because the document was prerendered, it is pure added latency. If P12
   or P13 regresses, delete this block. It is decoration. */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 120ms;
  animation-timing-function: linear;
}

/* Query-facet updates are in-page DOM work by /js/facets.js, not navigations.
   Path-facet links ARE navigations and keep the transition. */
html[data-facet-update] { view-transition-name: none; }

/* --- motion policy -------------------------------------------
   One blanket rule. Every animation in this codebase must survive it.
   No <marquee>, no <blink>, no autoplay audio, no custom cursors. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
  @view-transition { navigation: none; }
}
