/* =========================================================================
   FRONTIER PRIME — the identity layer.   THE SURVEY DECK.

   Loaded LAST on every page (owner.json -> theme.css_overlay -> /css/owner.css),
   after site.css and after the page and atmosphere sheets, so it wins on equal
   specificity. Where site.css uses a more specific selector this file matches
   or raises it. There is no `!important` anywhere in here, deliberately: a rule
   that can only win by shouting is a rule somebody else will have to fight.

   ---------------------------------------------------------------------------
   THE METAPHOR, and what it is NOT

   The site is the INSTRUMENT DECK of a survey station: a milled plate laid over
   a plotting sheet. The ground is a chart — a real plotting grid the island is
   drawn on. Every panel is an instrument SEATED on that deck, registered by
   four corner brackets rather than wrapped in a border. Every heading stands on
   a DATUM RULE, the way a reading stands on a baseline. The chrome spends no
   colour at all: on this site every colour is a READING — health is red because
   health is red, prime is gold because prime is gold — and a house accent
   competing with them would make the instruments harder to read, not prettier.

   It is not a terminal, a console, a shell, a CRT or a boot sequence. It is not
   a specimen archive, a dossier system or a genome readout. Those are two other
   islands' identities and they stay theirs. Nothing here types itself out,
   scrambles a glyph, prints a prompt, wraps a label in brackets, blinks a block
   cursor or draws a scanline. The medium is different on purpose: those sites
   are a SCREEN THAT GLOWS; this one is a DRAWN CHART ON A LIT DECK.

   ---------------------------------------------------------------------------
   HOUSE RULES OBSERVED HERE

   - ZERO COLOUR LITERALS. Every value below is a role token from theme.css or a
     color-mix() of one. That is the shared-sheet rule and this file keeps it
     even though the gate does not scan it — because it is also what makes the
     light lane work for free: theme.palette_light swaps the tokens and every
     rule in this file follows without a second copy.
   - NO NEW MARKUP. The assembler owns the fragments. Everything here hangs off
     classes site.css already defines, so a page this file has never seen simply
     inherits the deck rather than breaking on it.
   - MOTION HAS ONE AUTHORED MOMENT and it fails OPEN: the resting state is the
     finished picture, so no-JS, print and prefers-reduced-motion all get the
     complete page rather than an empty one.
   ========================================================================= */

:root {
  /* ---- the deck's own material, mixed from the owner's tokens ----
     Named for what they DO, like every token in this system. */
  --fp-rule:        color-mix(in srgb, var(--edge) 52%, transparent);
  --fp-rule-soft:   color-mix(in srgb, var(--edge) 30%, transparent);
  --fp-tick:        color-mix(in srgb, var(--edge) 44%, transparent);
  --fp-bracket:     color-mix(in srgb, var(--edge-lit) 88%, transparent);
  --fp-bracket-hot: var(--accent);
  --fp-chamfer:     color-mix(in srgb, var(--edge-lit) 26%, transparent);

  /* The plotting sheet. A major hairline every 96px on both axes, and a fine
     registration dot at every 24px intersection — a plotting sheet, not a
     wireframe. Three layers, all static, all paint-only. */
  --fp-grid:
    repeating-linear-gradient(90deg, var(--fp-rule-soft) 0 1px, transparent 1px 96px),
    repeating-linear-gradient(180deg, var(--fp-rule-soft) 0 1px, transparent 1px 96px),
    radial-gradient(circle at 0 0, var(--fp-tick) 0 1px, transparent 1.3px);

  /* The four corner brackets, as one background list. 10px arms, 1px stroke.
     Drawn with gradients rather than pseudo-elements because site.css already
     spends `.card::before` on the lit top edge, and an identity layer that
     needed a free pseudo-element would break on the first component that had
     none. */
  --fp-brk-arm: 12px;
  --fp-brackets:
    linear-gradient(var(--fp-bracket), var(--fp-bracket)) left  0    top    0    / var(--fp-brk-arm) 1px no-repeat,
    linear-gradient(var(--fp-bracket), var(--fp-bracket)) left  0    top    0    / 1px var(--fp-brk-arm) no-repeat,
    linear-gradient(var(--fp-bracket), var(--fp-bracket)) right 0    top    0    / var(--fp-brk-arm) 1px no-repeat,
    linear-gradient(var(--fp-bracket), var(--fp-bracket)) right 0    top    0    / 1px var(--fp-brk-arm) no-repeat,
    linear-gradient(var(--fp-bracket), var(--fp-bracket)) left  0    bottom 0    / var(--fp-brk-arm) 1px no-repeat,
    linear-gradient(var(--fp-bracket), var(--fp-bracket)) left  0    bottom 0    / 1px var(--fp-brk-arm) no-repeat,
    linear-gradient(var(--fp-bracket), var(--fp-bracket)) right 0    bottom 0    / var(--fp-brk-arm) 1px no-repeat,
    linear-gradient(var(--fp-bracket), var(--fp-bracket)) right 0    bottom 0    / 1px var(--fp-brk-arm) no-repeat;

  /* Motion. One curve, one duration, used everywhere — an instrument settles,
     it does not bounce. These also retune webcore's own motion engine, which
     reads --mo-base / --mo-stagger / --mo-hero back out of the sheet at arm
     time, so the whole site slows or quickens from these three lines. */
  --fp-settle: cubic-bezier(.16, 1, .3, 1);
  --fp-quick: 160ms;
  --mo-base: 420ms;
  --mo-stagger: 52ms;
  --mo-hero: 620ms;
}

/* =========================================================================
   1. THE GROUND IS A CHART

   ★ IT IS ITS OWN LAYER, NOT AN EXTRA STOP ON MAIN'S RAMP, AND THAT IS A BUG
     REPORT. The first cut added the grid to `main { background-image }`. It
     rendered nothing at all, on every page, and nothing failed: `backdrop.css`
     restates that ramp as `.night[data-atmos] ~ main`, which is two classes to
     a bare type selector, so a plain `main` rule from a later sheet loses the
     tie no matter how late it loads. Measured, not guessed —
     getComputedStyle(main).backgroundImage came back as the ramp alone.
     Raising the selector is the fleet's rule (never `!important`), but the
     honest fix is not to compete for that property at all: restating somebody
     else's ramp would mean copying `--atmos-page-heavy` and its light twin
     into this file, where they would rot the first time the atmosphere layer
     retuned them.

     So the chart gets a layer of its own. `main` becomes a stacking context
     (`isolation`), and the sheet is a FIXED pseudo-element at z-index -1 —
     which inside that context paints above main's own background and below
     every scrap of its content. Fixed, so the deck stays still while the page
     travels over it, and so a ten-thousand-pixel page costs exactly one
     viewport of grid.
   ========================================================================= */
main {
  position: relative;
  isolation: isolate;
}
main::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: var(--fp-grid);
  background-size: auto, auto, 24px 24px;
  background-repeat: repeat, repeat, repeat;
}

/* =========================================================================
   2. TYPE — engineered, not decorated
   One family does the talking (Inter, as both display and UI) and the mono is
   quarantined to MEASUREMENT: counts, timers, prices, coordinates, balances.
   Mono as a costume for "technical" is the one thing this island will not do,
   because it is also the loudest tell of a site that already exists.
   ========================================================================= */
.hero h1,
.page-h1,
.sec-head h2,
.page-h2,
.cta-card h2 {
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: -.034em;
  text-wrap: balance;
}
.hero h1 { line-height: .96; }
.card h3, .cta-card h3 { font-weight: 700; letter-spacing: -.018em; }

/* The lede reads at a real measure. 62ch is the shared cap; this face at this
   size wants a touch more air between the lines to sit under a heavy heading. */
.hero .lede { line-height: 1.66; max-width: 56ch; }
.sec-head p { line-height: 1.62; }

/* ---- the datum label ----
   site.css draws `.eyebrow` and `.hero .kicker` as wide-tracked caps with an
   accent bar. Here they become what they actually are on an instrument: the
   label engraved beside the reading. Quieter tracking, a shorter tick, and the
   tick is a HAIRLINE WITH A CAP rather than a coloured bar — the survey mark
   for a measured origin. */
.eyebrow {
  font-weight: 650;
  letter-spacing: .12em;
  font-size: 11px;
  color: var(--ink-3);
  gap: 9px;
}
.eyebrow::before,
.hero .kicker::before {
  width: 18px;
  height: 5px;
  border-radius: 0;
  background:
    linear-gradient(var(--fp-tick), var(--fp-tick)) left bottom / 18px 1px no-repeat,
    linear-gradient(var(--fp-tick), var(--fp-tick)) left bottom / 1px 5px no-repeat,
    linear-gradient(var(--accent), var(--accent)) right bottom / 1px 5px no-repeat;
}
.hero .kicker {
  font-weight: 650;
  letter-spacing: .16em;
  font-size: 11px;
  color: var(--ink-2);
}

/* =========================================================================
   2b. THE SHARED CINEMATIC LAYER IS TURNED DOWN, DELIBERATELY

   `cinema.css` is the fleet's atmosphere sheet and its material is VOLCANIC:
   it clips a travelling `--lava` gradient to every heading, blooms it with an
   accent drop-shadow, and animates the flow for ever. On a molten island that
   is the right sheet. On a survey station it is the wrong element entirely —
   and on the first rendered pass it also read as a defect rather than an
   effect: an animated gradient behind transparent glyphs with a 10px accent
   bloom prints as a doubled, ghosted headline in a still frame, which is what
   a screenshot, a print sheet and a slow paint all are.

   So the headings take solid ink. Emphasis on this site comes from weight and
   size, which is also the cheaper of the two: no `background-clip`, no
   `filter`, no infinite animation on eleven elements per page.

   The @supports fence is copied from cinema.css on purpose — that is where it
   puts the rules, so this is where they have to be answered, at the same
   specificity and later in the cascade. The status figures come with them:
   the numbers a player reads for information are the last thing that should
   be painted through a moving gradient.
   ========================================================================= */
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .hero h1,
  .page-h1,
  .sec-head h2,
  .status .fig b {
    background-image: none;
    color: var(--fg);
    -webkit-text-fill-color: currentColor;
    filter: none;
    animation: none;
    text-shadow: var(--shadow-text);
  }
  .status .fig b { text-shadow: none; }
}

/* The page head's accent wash and its short accent segment are cinema.css's
   marks. This island's page head is a DATUM: the same tick ladder every other
   heading stands on, with one accent origin mark at the left where the
   measurement starts. Same selector as cinema's, so it is a clean replacement
   rather than a fight. */
:is(.page-head, .sec-head:has(> .page-h1))::before {
  background: none;
}
:is(.page-head, .sec-head:has(> .page-h1)) {
  border-bottom-color: var(--fp-rule);
}
:is(.page-head, .sec-head:has(> .page-h1))::after {
  width: 100%;
  height: 5px;
  bottom: -5px;
  border-radius: 0;
  background:
    linear-gradient(var(--accent), var(--accent)) left bottom / 34px 2px no-repeat,
    repeating-linear-gradient(90deg, var(--fp-tick) 0 1px, transparent 1px 8px)
      left bottom / 100% 3px no-repeat,
    repeating-linear-gradient(90deg, var(--fp-rule) 0 1px, transparent 1px 48px)
      left bottom / 100% 5px no-repeat;
  transform-origin: left center;
  animation: fp-draw 620ms var(--fp-settle) both;
}

/* ---- the datum rule ----
   Every section heading stands on a measured baseline: a hairline with a tick
   ladder, minor every 8px and a longer major every 48px. This is the single
   repeated structural mark of the whole site.
   `position: relative` on the block, the rule on ::after, so no markup moves. */
.sec-head {
  position: relative;
  padding-bottom: 16px;
}
.sec-head::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 5px;
  background:
    linear-gradient(var(--fp-rule), var(--fp-rule)) left bottom / 100% 1px no-repeat,
    repeating-linear-gradient(90deg, var(--fp-tick) 0 1px, transparent 1px 8px) left bottom / 100% 3px no-repeat,
    repeating-linear-gradient(90deg, var(--fp-rule) 0 1px, transparent 1px 48px) left bottom / 100% 5px no-repeat;
  transform-origin: left center;
  animation: fp-draw 620ms var(--fp-settle) both;
}
@keyframes fp-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* =========================================================================
   3. MEASUREMENTS ARE SET AS MEASUREMENTS
   Tabular figures so a changing number does not reflow its own row, and the
   mono face only where the glyphs are a reading.
   ========================================================================= */
.fig b,
.lb-v,
.status-figs .fig b,
.item-price,
.nav-pts,
.slot-growth {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  letter-spacing: -.01em;
}
.fig b { font-weight: 600; }
.fig span,
.lb-k,
.status-src,
.item-buy {
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  font-size: 10.5px;
  color: var(--ink-3);
}

/* =========================================================================
   4. PANELS ARE INSTRUMENTS SEATED ON THE DECK
   Corner brackets instead of a wrapped border; a chamfer instead of a glow.
   `.card::after` is free — site.css spends only `::before` — so the brackets
   ride their own layer and the card keeps its grain and its lit top edge.
   ========================================================================= */
.card,
.cta-card,
.status,
.notice,
.item,
.slot,
.feat {
  position: relative;
}
.card::after,
.status::after,
.item::after,
.slot::after,
.feat::after {
  content: "";
  position: absolute;
  inset: 5px;
  pointer-events: none;
  background: var(--fp-brackets);
  opacity: .85;
  transition: opacity var(--fp-quick) var(--fp-settle);
}
/* The feature tiles run twelve to a page, so they take the mark at a shorter
   arm and a lower weight. A dozen instruments at panel strength is a pattern,
   not a system — the mark has to scale DOWN with the component or the page
   turns into a field of brackets. */
.feat::after {
  --fp-brk-arm: 7px;
  inset: 4px;
  opacity: .6;
}
.card:hover::after,
.item:hover::after,
.slot:hover::after,
.feat:hover::after { opacity: 1; }

/* The seat. A card is milled INTO the deck rather than floating over it: the
   hairline is tighter, the shadow keeps its offset and blur (a zero-offset
   halo is decoration, not depth), and the top chamfer is a real 1px highlight
   rather than a soft bloom. */
.card,
.item,
.slot,
.status,
.notice,
.feat {
  border-color: color-mix(in srgb, var(--border) 88%, var(--bg));
  box-shadow:
    0 1px 0 var(--fp-chamfer) inset,
    0 14px 30px -24px var(--edge-sink);
}

/* The live status panel is the deck's primary instrument: it earns the one
   piece of chrome that is allowed to take the accent. */
.status::after { background: var(--fp-brackets); }
.status { border-color: color-mix(in srgb, var(--accent) 24%, var(--border)); }
.status::after { --fp-bracket: var(--fp-bracket-hot); opacity: .9; }

/* =========================================================================
   5. CONTROLS
   Squared to the owner's own 2px geometry (theme.geometry, not a literal), a
   machined chamfer on the top edge, and a press that travels 1px like a real
   key rather than scaling.
   ========================================================================= */
.btn {
  font-weight: 650;
  letter-spacing: .01em;
  box-shadow: 0 1px 0 var(--fp-chamfer) inset, 0 8px 18px -16px var(--edge-sink);
  transition: transform var(--fp-quick) var(--fp-settle),
              border-color var(--fp-quick) var(--fp-settle),
              background var(--fp-quick) var(--fp-settle);
}
.btn:hover { border-color: var(--edge-lit); }
.btn-primary { font-weight: 700; letter-spacing: .012em; }
.btn-ghost { box-shadow: none; }
.btn-ghost:hover { background: var(--surface-hover); }

/* ---- focus is never optional, and never invisible ----
   Two rings, so the marker survives on a surface of any lightness: the accent
   ring plus a 1px counter-ring in the page's own ground. Raised above
   site.css's own :focus rules by listing the same elements at equal
   specificity later in the cascade. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent-hi);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
.btn:focus-visible,
.nav-links a:focus-visible,
.nav-cta:focus-visible,
.nav-chip:focus-visible {
  outline: 2px solid var(--accent-hi);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--bg) 82%, transparent);
}

/* =========================================================================
   6. THE DECK RAIL (top nav)
   A measured edge, not a floating bar: the bottom of the nav carries the same
   tick ladder the section rules do, so the chrome and the content are drawn in
   one hand. The current page is marked by a bracket under the label rather
   than a coloured pill.
   ========================================================================= */
.nav {
  border-bottom: 1px solid var(--fp-rule);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--bg-deep) 60%, transparent);
}
.nav::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  pointer-events: none;
  background: repeating-linear-gradient(90deg, var(--fp-tick) 0 1px, transparent 1px 8px)
              left bottom / 100% 3px no-repeat;
  opacity: .55;
}
.nav-links a {
  font-weight: 600;
  letter-spacing: .008em;
  border-radius: var(--r-xs);
}
.nav-links a[aria-current="page"] { background: transparent; color: var(--fg); }
.nav-links a[aria-current="page"]::before {
  height: 2px;
  border-radius: 0;
  background: var(--accent);
}
.brand-txt b { font-weight: 800; letter-spacing: -.018em; }
.brand-txt span {
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* =========================================================================
   7. THE LIVE BAR is a readout strip
   ========================================================================= */
.lb-sep { background: var(--fp-rule); }
.lb-k { letter-spacing: .08em; }

/* =========================================================================
   8. FOOTER — the chart's marginalia block
   ========================================================================= */
.foot { border-top: 1px solid var(--fp-rule); }
.foot-brand b { font-weight: 800; letter-spacing: -.014em; }
.foot-links a { font-weight: 550; }
.foot-legal { letter-spacing: .01em; }

/* =========================================================================
   9. PILLS AND TABS — engraved plates, not capsules
   The pill radius already comes from theme.geometry (r_pill: 2px), so these
   only fix weight and tracking.
   ========================================================================= */
.pill, .shop-pill, .item-tag {
  font-weight: 650;
  letter-spacing: .09em;
  text-transform: uppercase;
}
.tabs button { font-weight: 650; letter-spacing: .04em; }
.tabs button[aria-selected="true"]::after { height: 2px; border-radius: 0; }

/* =========================================================================
   10. RESPONSIVE — the deck never scrolls sideways
   Nothing above adds width (every mark is a background or an inset absolute),
   and these are the guards that keep it that way when a page adds content this
   file has never seen. A wide table or a wide row scrolls INSIDE its own box.
   ========================================================================= */
html, body { overflow-x: hidden; }
main img, main svg, main video, main canvas, main iframe { max-width: 100%; }
main table { display: block; width: 100%; overflow-x: auto; }

@media (max-width: 640px) {
  /* The plotting grid is a texture, not a subject. At phone width a 96px cell
     is a third of the screen and reads as a table; halve it and lift the dots
     off so the ground stays quiet under a single-column page. */
  :root {
    --fp-grid:
      repeating-linear-gradient(90deg, var(--fp-rule-soft) 0 1px, transparent 1px 64px),
      repeating-linear-gradient(180deg, var(--fp-rule-soft) 0 1px, transparent 1px 64px),
      radial-gradient(circle at 0 0, transparent 0 1.3px, transparent 1.3px);
    --fp-brk-arm: 7px;
  }
  .hero h1 { letter-spacing: -.026em; }
  .sec-head::after { height: 3px; }
}

/* =========================================================================
   11. REDUCED MOTION — the finished picture, immediately
   The one authored moment is the datum rule drawing itself. Its RESTING state
   is the drawn rule, so removing the animation removes an entrance and never
   a line: this is the fail-open direction, and it is the same direction print
   and a dead script both land in.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .sec-head::after,
  :is(.page-head, .sec-head:has(> .page-h1))::after { animation: none; }
  /* cinema.css freezes its lava under reduced motion rather than removing it,
     and re-asserts the accent bloom while doing so. This island removed the
     lava outright, so the bloom has to be answered here too or it comes back
     for exactly the readers who asked for less. */
  .hero h1, .page-h1, .sec-head h2, .status .fig b { filter: none; }
  .card::after,
  .status::after,
  .item::after,
  .slot::after,
  .feat::after { transition: none; }
  .btn { transition: none; }
}

@media print {
  main::before { display: none; }
  .card::after, .status::after, .item::after, .slot::after,
  .feat::after { opacity: 1; }
  .sec-head::after,
  :is(.page-head, .sec-head:has(> .page-h1))::after { animation: none; }
}
