/* Silurian marketing site: one source for the tokens.

   Every colour the site renders and the font declaration are defined here and
   nowhere else. Layout stays embedded in each page. Linked by index.html,
   forecast-risk.html and privacy.html.

   This file buys prevention, not repair. Nothing looks different because of it.
   What it removes is the condition that let forecast-risk.html run a second
   palette in Production for weeks without anyone seeing it: three pages using
   three names for the same role, with nothing connecting them. */

/* The font URL is root-relative on purpose. A URL inside a linked stylesheet
   resolves against the stylesheet, not the page, so a page-relative URL would
   break the moment this file moved to a subdirectory. It would break quietly:
   font-display: swap paints a fallback rather than raising an error, so the
   site would look deliberate while being wrong. Do not make it relative. */
@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/Archivo-Variable.ttf") format("truetype");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

:root {
  /* Ground and surfaces. The site has surfaces on both sides of its own ground,
     which inverts the usual expectation: --color-surface sits darker than the
     page and --color-paper sits lighter. The darker panel is deliberate and is
     recorded in CLAUDE.md section 9. */
  --color-bg: #f3f2f2;
  --color-surface: #eae9e9;

  /* --color-paper carries two roles on one value: a surface lifted off the page
     ground, such as the masthead band and the chart box, and type or marks
     reversed out of a filled accent or ink field. One token rather than two,
     because the system is print derived and both are the same idea, bare paper.
     The design system named this role itself, in index.html: "type reversed to
     the paper token". The trade: if the surface white ever moves off pure white,
     the token splits then, and the split is cheap when it is actually needed.
     Note that privacy.html defines --paper meaning #f3f2f2, a different name for
     a different value. That one disappears in S1.3. */
  --color-paper: #fff;

  /* Ink and drawn structure. Rules are solid, not faded: this system does not
     fade its rules, so the divider carries the full ink value. */
  --color-text: #3f3d3b;
  --color-divider: #3f3d3b;

  /* The one accent. Spent as a mark or a field, never as a status palette. */
  --color-accent: #ec6917;

  /* Approved brand tokens. --color-charcoal-deep was applied for the first time
     on 6 September 2026, as the Run sample analysis label on forecast-risk.html:
     it is the only ink that reaches 4.5 against the accent at that control's
     size, measuring 5.52 where paper is 3.18 and the page ink 3.40. Its value
     also appears in the logo, but as a raw hex in the SVG rather than through
     this token. --color-neutral-brand remains approved and unapplied, and is
     not a dead value: do not remove it as unused. */
  --color-charcoal-deep: #1a1918;
  --color-neutral-brand: #cabfad;

  /* Secondary text: panel subheads, metric labels and chart axis labels.
     Note that Assay uses #68615e for the same role, one digit apart. Nobody
     decided that difference; it is recorded as band 2.9.2, not fixed here. */
  --color-text-muted: #66615f;

  /* Body copy reversed on the dark risk card. Distinct from --color-paper on
     purpose: paper is pure white reversed on the orange field, this is
     softened white on charcoal. Two grounds, two values. */
  --color-text-on-dark: #e3dfdd;

  /* Chart furniture, forecast-risk.html only. --color-chart-series names one
     line today, the projected inventory, so the name overpromises. It is
     still the right name: series extends when a second line appears, where
     an inventory name would have to be renamed, and extending is cheaper
     than renaming. */
  --color-chart-grid: #d1cdca;
  --color-chart-series: #77716e;

  /* Status colours. THESE THREE ARE DEFINED TWICE, deliberately and with the
     duplicate recorded rather than created quietly. Assay declares the same
     three values in forecast-app/static/index.html as --good, --warn and
     --bad. The two products deploy through separate Vercel projects from
     separate directories and cannot share this file today without a build
     step. Change both sides or neither. The pairs are held equal by
     test_status_colours_match_assay, which fails if either side moves. */
  --color-status-good: #356b46;
  --color-status-warn: #9a5a12;
  --color-status-bad: #a52a1f;

  /* Rule weights are deliberately not tokens. The site draws structure with 2px
     seams and 1px hairlines and nothing else, and CLAUDE.md section 9 names the
     2px drawn rule as a brand rule, so the case for a token exists. Two values
     used consistently do not need naming. Revisit if a third weight appears. */

  /* Type. There was no type scale on this site until 6 September 2026, on the
     ground that 24 distinct raw sizes on one page is a list rather than a
     scale, and that creating one is design work rather than extraction. The
     design session has now made that decision and the six steps below are the
     result. They are extracted, not invented: every step is a size already in
     use, nothing moved by more than 2px, and the sizes were already clustering
     on a ratio of about 1.28 from the 15px body.

     display 40 replaces 42. title 31 replaces 30 and 32. subhead 25 replaces
     22, 25 and 26. lead 19 replaces 17, 19 and 20. body 15 replaces 14, 15,
     15.5 and 16. label 12 replaces 11, 12 and 13.

     The pages adopt these one at a time, as they did with the colours. The
     about section of index.html is first and the rest of the site still
     carries raw sizes, so do not read a page's silence as adoption. Two
     mappings are still open and are deliberately not applied anywhere yet:
     11 to 12 on the uppercase micro-labels, which read larger than nominal
     because they are caps, and 16 to 15 on privacy.html, the one page with
     sustained reading.

     Seven steps, not six. --text-poster was added on 6 September 2026 after the
     same clamp() blind spot was found in the closing line, which renders 56px
     and is display type in the page's one accent field rather than a section
     head. Folding it into the 31px title step would take the page's single
     loud moment quiet.

     No exceptions inside the scale, decided rather than defaulted: the
     uppercase micro-labels go to 12 and not 11, because one pixel on tracked
     caps is invisible and an exception written in on day one is how the last
     list of sizes started. privacy.html body goes to 15 with everything else,
     and its sustained reading is answered by leading and measure, 1.65 and
     34em, rather than by that pixel.

     Two steps carry a taper, --text-display and --text-poster, and both are
     written once here rather than per element. The rest are flat. The
     raw-value control pins colours and not type, so nothing stops a stray
     size yet: a control follows once the rollout is complete, which the
     design session set as the condition rather than doing it now.

     THE RULE FOR A FLUID SIZE, and it exists because ignoring it cost this
     project four wrong numbers in two documents: a clamp() is classified by
     what it renders at desktop, never by the number typed at the small end.
     The minimum is a mobile floor, not a role. Read a clamp() in a browser
     before assigning it a step. Under this rule the two secondary page
     headlines, which rendered 76px and 68px, take the 40px display step with
     every other page headline, and forecast-risk.html's stat value takes
     display because it already rendered 40px.

     POSTER IS ONE PER PAGE, ON THE SINGLE LOUDEST ELEMENT, and it is not
     welded to any component. Settled by the design session on 7 September
     2026 after three rounds of asking, and both of the readings it rejects
     are worth knowing. Once per site makes the step unusable the moment a
     fourth page exists, and a token only one element may ever use is not a
     scale step, it is that element's private size, which is how the last
     list of sizes started. Once per closing panel welds a size to a
     component: on the homepage the loudest thing genuinely is the closing
     line, so poster lands there, and on forecastability.html the loudest
     thing is the 92.5% numeral, so poster lands there and that page's
     closing field takes --text-title instead. Same rule, different element,
     one poster either way.

     The test for a future page is a copy test, not a type test: if two
     elements are competing for poster, the page has two climaxes and the
     copy is the problem. A page headline still never takes poster, and a
     page may have none, as privacy.html does.

     The count is held by test_a_page_spends_poster_at_most_once.

     A TYPE STEP IS A LAYOUT CHANGE. Moving forecast-risk.html's table from
     11px to the 12px step pushed it 10px past a 320px viewport and the page
     scrolled sideways. Nothing in the diff showed it. Roll a type change out
     with a render check at several widths, never a source read-through. */
  --text-display: clamp(30px, 3.6vw, 40px);
  --text-poster: clamp(34px, 4.2vw, 56px);
  --text-title: 31px;
  --text-subhead: 25px;
  --text-lead: 19px;
  --text-body: 15px;
  --text-label: 12px;

  /* The wordmark is not in the scale and is not an exception to it. It is
     the mark rather than type, so it carries its own token outside the
     seven steps: no step matches a 15 to 18 taper, and an eighth step for
     one element buys nothing. This keeps the scale free of exceptions and
     leaves the type control nothing to permit, because a token is not a
     hand-written size. */
  --wordmark-size: clamp(15px, 1.8vw, 18px);

  /* Spacing. Moved here from index.html on 17 September 2026, where the four
     of them were declared and nowhere else. Any other page naming
     var(--space-4) got nothing: an undefined custom property makes the
     declaration invalid at computed-value time, so it fails silently, with
     no error in the console and nothing in the diff to see. It had not bitten
     yet, and a note is not a control, so test_no_page_uses_an_undeclared_var
     now catches the whole class rather than this one instance.

     The values are unchanged and carry their original .0 so a reader can see
     nothing was retuned in the move. There is still no spacing scale on this
     site: four steps that stop at 16px are a handful of values with a shared
     prefix, and pages continue to use literal px for layout. */
  --space-1: 4.0px;
  --space-2: 8.0px;
  --space-3: 12.0px;
  --space-4: 16.0px;

  --font-heading: "Archivo", system-ui, sans-serif;
  --font-heading-weight: 800;
  --font-body: "Archivo", system-ui, sans-serif;
}
