/* ══════════════════════════════════════════════════════════════════════
   KILN — colour layer. Step 1 of the redesign: COLOUR ONLY.

   Founder, 2026-07-28: "This is just a color change first. Then we will
   redesign everything." and "no cream or claude shade at all. shades of grey."

   So this file changes NOTHING but colour. No type, no spacing, no radius,
   no shadows, no layout, no markup, no sections, no copy. It redefines the
   colour variables the pages already use and stops there. Every page keeps
   its exact structure — only the values behind the existing variable names
   change.

   ── THE IDEA ────────────────────────────────────────────────────────
   ASH IS THE SUBSTRATE. FIRE IS THE SIGNAL. FIRE IS SCARCE.

   Ash is at least 92% of every surface. Fire appears only where something
   is genuinely happening. If fire is everywhere it is decoration and this
   has failed; if fire is rare it is information and it works.

   Fire is a TEMPERATURE SCALE, not a palette. Combustion runs deep
   brown-red → orange → pale gold-white — the hottest part of a flame is
   nearly white, not orange. Risk 0–100 maps onto that ramp natively, so a
   heat index is READ as a temperature rather than decoded from a legend.
   Never use a fire stop for a meaning that is not heat.

   ── WHY EVERY ASH STEP IS R=G=B ─────────────────────────────────────
   Strictly neutral. Not "cool grey", not "warm grey" — neutral. The old
   palette was warm throughout (#ECEAE6, #F7F4EF, #18140F, #FBFAF7): red
   channel above blue on every single step. That warm cast IS the Claude
   read, and it survives any accent change, which is why swapping only the
   accent would not have worked.

   Holding the substrate at zero chroma also means FIRE IS THE ONLY COLOUR
   IN THE SYSTEM. Nothing competes with it, so it needs no help to be
   noticed — which is what lets the fire budget stay as small as it does.
   ══════════════════════════════════════════════════════════════════════ */

/* Three families, one request. CSP on these pages already allows
   fonts.googleapis.com (style-src) and fonts.gstatic.com (font-src), so
   nothing needs widening. display=swap so text paints immediately in the
   fallback rather than blocking. */
/* ⚠ MEASURED 2026-07-28: the page renders JetBrains Mono at w600 and w700
   while this request only ever asked for 400 and 500. Those weights were
   being SYNTHESISED — the browser smearing a 400 face to fake bold, which
   on a monospace reads muddy at 9–13px, exactly the sizes carrying every
   label and number. The weights are now requested rather than faked. */
@import url('https://fonts.googleapis.com/css2?family=Archivo:wght@400;600;700&family=JetBrains+Mono:wght@400;600;700&display=swap');

:root {
  /* ── ASH — substrate. COOL GRAPHITE. (founder, 2026-07-29) ───────
     Was strictly R=G=B. The neutrality rule existed to escape a WARM
     cast — red above blue on every step was the Claude read, and it
     survived any accent change. Cool is the opposite direction, not a
     relapse: it reads as instrument rather than paper.

     ★ AND IT MAKES FIRE HOTTER. Orange against neutral grey is just
     orange; against cool graphite it is complementary, so the same fire
     stop reads more urgent without being used any more often. The fire
     budget stays small and buys more.

     ── HOW EACH STEP WAS DERIVED ──────────────────────────────────
     HOLD GREEN, shift red down and blue up by the same delta. Green
     carries 0.7152 of relative luminance, so holding it holds the
     brightness of every step — and therefore every contrast ratio the
     audit measures. Drift is 0.2126(-d) + 0.0722(+d) = -0.14d, under
     0.5% at every step. Contrast survives BY CONSTRUCTION, which is the
     same reason the original neutralisation preserved luminance.

     The delta tapers toward the light end: a strong shift on near-white
     reads as tinted paper, which is a different cliché from the one we
     just left. */
  --ash-000: #080B0E;   /* chrome — deepest, never flat #000        */
  --ash-050: #101418;   /* canvas                                    */
  --ash-100: #171C21;   /* panel                                     */
  --ash-200: #20262C;
  --ash-300: #2D343B;
  --ash-400: #424A52;
  --ash-500: #656E77;
  --ash-600: #939BA3;
  --ash-700: #BEC4CA;
  --ash-750: #D4D9DE;
  --ash-800: #DFE3E7;
  --ash-850: #ECEFF2;
  --ash-900: #F5F7F9;
  --ash-950: #FBFCFD;

  /* ── FIRE — signal only. Combustion temperature, cool → hot. ───── */
  --fire-100: #5C2410;   /* barely alight                            */
  --fire-200: #8F3617;   /* ember     — quiet decay                  */
  --fire-300: #B54A1E;
  --fire-400: #E2622A;   /* flame     — act this week                */
  --fire-500: #F98B3D;
  --fire-600: #FFC773;   /* flashover — high value, leaving          */

  /* ── STEAM — cool counterpoint, recovery only. The one non-fire
     chroma, because "saved" must not read as a temperature.
     steam-200 exists for light surfaces, where 400 cannot hold 4.5:1. */
  --steam-200: #3F5A5E;
  --steam-400: #9FB8BD;
  --steam-600: #C9DADD;

  /* ── SEMANTIC STATES — the only names a component should reference.
     Reaching past these to a raw ramp stop is styling, not encoding. */
  --state-cold:      var(--ash-400);    /* healthy, no signal        */
  --state-ember:     var(--fire-200);   /* quiet decay               */
  --state-flame:     var(--fire-400);   /* act this week             */
  --state-flashover: var(--fire-600);   /* high value, leaving       */
  --state-steam:     var(--steam-200);  /* saved, recovered          */
  --state-smoke:     var(--ash-500);    /* trailing, historical      */
}

/* ══════════════════════════════════════════════════════════════════════
   THE REMAP
   ──────────────────────────────────────────────────────────────────────
   Everything below re-points a variable the pages ALREADY use. No new
   class, no new element, no page edit beyond one <link>. Reversible by
   deleting the link.

   Two naming schemes exist in the codebase and both are covered:
     · marketing pages — --bg / --surface / --text-N / --fire / --go
     · dashboard       — --k / --k2 / --b / --c / --g / --a / --card
   A variable missed here keeps its warm value and shows up immediately as
   the one cream patch on a grey page, which is the intended failure mode:
   loud, not silent.
   ══════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Grounds ──────────────────────────────────────────────────── */
  --bg:        var(--ash-850);   /* was #ECEAE6 warm parchment       */
  --bg-2:      var(--ash-800);   /* was #E2DFD9                      */
  --bg-3:      var(--ash-750);   /* was #D5D1CA                      */
  --bg2:       var(--ash-900);   /* dashboard alias, was #EFEAE1     */
  --surface:   var(--ash-900);   /* was #F5F3EF                      */
  --card:      var(--ash-950);   /* was #FBFAF7 / #FDFCFA            */

  /* ── Dark grounds (dark bands inside light pages) ─────────────── */
  --dark:      var(--ash-050);   /* was #221E19 warm near-black      */
  --dark-mid:  var(--ash-100);   /* was #1A1510                      */
  --dark-deep: var(--ash-000);   /* was #100D09                      */

  /* ── Text ramp ────────────────────────────────────────────────── */
  --text:      var(--ash-050);   /* was #1C1A17                      */
  --text-1:    var(--ash-050);
  --text-2:    var(--ash-400);   /* was #3E3C37                      */
  --text-3:    var(--ash-500);   /* was #706D65                      */
  /* ⚠ Raised from ash-600 (2.42:1 — a PRE-EXISTING failure the old warm
     #8A867E also had, now visible because it is being measured). #616161
     clears 4.9:1 while staying clearly subordinate to text-3. */
  --text-4:    #616161;
  --text-5:    #616161;
  --text-lbl:  var(--ash-400);   /* was #605C55                      */

  /* ── Fire. The only chroma on the page. ───────────────────────── */
  /* ⚠ fire-300, not 400, on LIGHT grounds. Measured: #E2622A as TEXT on
     #EFEFEF is 2.72:1 — it looks like an accent and reads like a smudge.
     fire-300 clears 5.6:1 as text AND 7.6:1 as a button fill, so the one
     token serves both uses on this ground. Dark grounds step back up to
     fire-500 via [data-ground="dark"], which is also the physically
     right direction — a flame reads hotter against black than paper. */
  --fire:        var(--fire-300);
  --fire-dark:   var(--fire-300);   /* the cooler stop, not "darker" */
  --fire-on-dk:  var(--fire-500);   /* on ash-000 the ramp shifts up */

  /* ── Recovery. Green leaves the system entirely — it is the one
     hue that reads as "success" in every SaaS template, and steam
     carries the same meaning without the association. On light
     grounds it must be steam-200 or it fails contrast. ─────────── */
  --go:   var(--steam-200);      /* was #1E7A46                      */
  --gold: var(--fire-200);       /* was #B8860B — caution IS low heat */

  /* ── Dashboard short scheme ───────────────────────────────────── */
  --k:    var(--ash-050);        /* was #18140F                      */
  --k2:   var(--ash-400);        /* was #3D342A                      */
  --k3:   var(--ash-500);        /* was #5F574C                      */
  --k4:   var(--ash-600);        /* was #7E7466                      */
  --b:    var(--ash-750);        /* border, was #E2DFD9              */
  --c:    var(--fire-400);       /* was #D4620A                      */
  --cd:   var(--fire-300);       /* was #B8460A                      */
  --g:    var(--steam-200);      /* was #1E7A46                      */
  --a:    var(--fire-200);       /* was #B8860B                      */
}

/* ══════════════════════════════════════════════════════════════════════
   TYPE — the second half of step 1.
   Founder: "font too from the pic I shared. everywhere in the website
   every section."

   Same mechanism as the colour: re-point the three variables the pages
   already use. No new class, no restructure, no copy change.

   Three registers, each with one job:
     display — headlines only. Archivo, a grotesque. Replaces Fraunces.
     ui      — all prose, body, buttons, labels. Inter Tight.
     data    — every number, ID, metric, timestamp, and every uppercase
               micro-label. JetBrains Mono.

   ⚠ The old --body was 'DM Mono' — body copy across the site was set in a
   MONOSPACE. Moving it to a proportional sans is the single largest visual
   change in this step and it changes line lengths, so layouts want a look
   before this goes to Hostinger.

   Warm optical serif is Claude-coded now regardless of how it is used,
   which is why Fraunces goes rather than being re-weighted. The tonal
   opposite of "serif for warmth" is "mono for precision", and that is what
   carries the numbers.
   ══════════════════════════════════════════════════════════════════════ */

:root {
  --font-display: 'Archivo', system-ui, -apple-system, sans-serif;
  /* ⚠ WAS Inter Tight. Measured: only 11 elements on index used it, and
     they rendered at 13px — the same size Archivo was already using for
     body copy. Two near-identical grotesques at one size is not a register
     distinction, it is mush, and indistinctness is what reads as generic.
     Collapsed to two families with genuinely disjoint jobs: Archivo reads,
     JetBrains Mono carries data and labels. Reversible in one line if the
     three-family brief is reinstated. */
  --font-ui:      'Archivo', system-ui, -apple-system, sans-serif;
  --font-data:    'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;

  /* ── THE LADDER, AS RESPONSIVE TOKENS ────────────────────────────
     Measured 2026-07-28: index.html rendered 16 distinct sizes. Every
     FIXED size on the page was already on the ladder — all eight strays
     came from 22 clamp() declarations.

     ★ Fluid type and a discrete ladder are incompatible BY CONSTRUCTION.
     A clamp() between two steps must pass through the 19–29px hole, and
     that hole is the entire point of the ladder — it is what stops the
     16–32px mush that reads as ordinary. clamp() does not violate the
     ladder by accident; it cannot honour it at all.

     So the step is discrete and the RESPONSIVENESS moves into the token.
     One place decides how the ladder compresses, instead of 22 independent
     clamp curves each inventing their own. Tuning vw coefficients so the
     sizes happen to land on-ladder at the two widths the audit measures
     would make the gate pass without making the design true. */
  --t-9:  9px;
  --t-11: 11px;
  --t-13: 13px;
  --t-15: 15px;
  --t-18: 18px;
  --t-30: 30px;
  --t-44: 44px;
  --t-64: 64px;

  /* The legacy names the pages actually reference. --serif keeps its name
     while no longer being a serif; renaming it would mean touching every
     page, which is exactly what this step avoids. */
  --serif: var(--font-display);
  --body:  var(--font-ui);
  --mono:  var(--font-data);
}

/* Numbers must not jitter when they update. A retention product is a
   numbers product, and a figure that shifts width on refresh looks
   amateur at the exact moment credibility matters. */
:root { font-variant-numeric: tabular-nums; }

[style*="--mono"], .mono, code, kbd, pre, samp,
[class*="num"], [class*="metric"], [class*="stat"] {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ══════════════════════════════════════════════════════════════════════
   DISPLAY REGISTER — the actual anti-Claude move.
   ──────────────────────────────────────────────────────────────────────
   Swapping the typeface was not enough and the founder said so: "still
   claudey". The measurement explains it — the headline rendered
   rgb(198,198,198) at weight 400. Mid-grey, thin, on a soft ground.
   SOFT CONTRAST AND LIGHT WEIGHT *ARE* THE EDITORIAL REGISTER; the serif
   was only the most obvious carrier of it. Keep the softness and the page
   still reads calm and literary in any typeface.

   That grey was not arbitrary either: it is the luminance-faithful ghost
   of the old cream #D4C5A9. Preserving lightness was right for body text
   and exactly wrong here — for display type the lightness WAS the problem.

   High contrast + weight 600 + tight tracking is what reads engineered.
   ══════════════════════════════════════════════════════════════════════ */

/* --display IS --text. A parallel token looked tidier and immediately
   regressed 92 elements: it defaulted near-black, which is right on light
   and wrong in every dark area that is not explicitly tagged. --text is
   already ground-aware and already proven at zero failures, so display type
   inherits that instead of maintaining a second opinion about the ground.
   The register change lives in WEIGHT and TRACKING, not in a second colour. */
:root { --display: var(--text); }  /* retained for future use; headings use a literal, see kiln_recolour notes */

h1, h2, h3,
.k-display, [class*="dh-title"], [class*="hero-h"] {
  font-family: var(--font-display) !important;
  font-weight: 600 !important;
  letter-spacing: -0.03em;
  line-height: 1.05;
}
h4, h5, h6 { font-family: var(--font-display); font-weight: 500; letter-spacing: -0.02em; }


/* ── INK — the strong-action fill. ────────────────────────────────────
   16 buttons in the dashboard were written 'background:var(--t1); color:#fff'
   — dark ink, white label. That is correct on a light page and inverts into
   an invisible white-on-white button the moment --t1 becomes light. The fill
   and its label have to move TOGETHER, so they are one pair of tokens rather
   than a colour and a hardcoded #fff that know nothing about each other. */
:root { --ink: var(--ash-050); --ink-on: var(--ash-950); }

/* ══════════════════════════════════════════════════════════════════════
   CHAR — the dark theme. The product, not the story.
   Applied via data-theme="char" on <html>. Marketing pages stay light.

   "Dark but not everything dark": depth comes from an ELEVATION LADDER,
   not from flat black. With shadows gone (see MATERIAL below) a lighter
   step of ash is the only way a surface can read as raised — so the ladder
   is doing structural work, not decoration.

     chrome / sidebar   ash-000   deepest, the frame
     canvas             ash-050   the page
     panel / card       ash-100   raised, where the work happens
     hairline           ash-300

   Never pure #000. A true black has no room beneath it, so the deepest
   surface would have nowhere to go and every panel above it would have to
   climb — which is how a dark UI ends up looking grey and washed.
   ══════════════════════════════════════════════════════════════════════ */

[data-theme="char"] {
  /* Grounds */
  --bg:        var(--ash-050);
  --bg-2:      var(--ash-100);
  --bg-3:      var(--ash-200);
  --bg2:       var(--ash-100);
  --surface:   var(--ash-100);
  --card:      var(--ash-100);
  --sb:        var(--ash-000);   /* sidebar / chrome — deepest */

  --dark:      var(--ash-000);
  --dark-mid:  var(--ash-050);
  --dark-deep: var(--ash-000);

  /* Text. The founder's standing note is that faint text was too light —
     so the ramp is deliberately tighter at the bottom than a mechanical
     inversion would give, and t4 stays legible rather than decorative. */
  --text:     var(--ash-850);
  --text-1:   var(--ash-850);
  --text-2:   var(--ash-700);
  --text-3:   var(--ash-600);
  --text-4:   #8A8A8A;
  --text-5:   #8A8A8A;
  --text-lbl: var(--ash-600);

  --t1: var(--ash-850);
  --t2: var(--ash-700);
  --t3: var(--ash-600);
  --t4: #8A8A8A;

  /* Rules. Light ink at low alpha — a dark hairline on a dark ground is
     nothing at all. */
  --b:  rgba(255,255,255,.10);
  --b2: rgba(255,255,255,.16);

  /* Fire shifts one stop UP on dark. The ramp was built to be read against
     near-black, and #E2622A on ash-050 clears 4.5:1, but text-weight fire
     wants the hotter stop to stay comfortable at small sizes. */
  --fire:       var(--fire-400);
  --fire-dark:  var(--fire-300);
  --fire-on-dk: var(--fire-500);
  --c:  var(--fire-400);
  --cd: var(--fire-300);

  /* Recovery reads cool and light on dark — steam-400 rather than the
     darkened steam-200 the light theme needs. */
  --go:   var(--steam-400);
  --g:    var(--steam-400);
  --gold: var(--fire-500);
  --a:    var(--fire-500);

  --k:  var(--ash-850);
  --k2: var(--ash-700);
  --k3: var(--ash-600);
  --k4: #8A8A8A;
}
[data-theme="char"] { --ink: var(--ash-800); --ink-on: var(--ash-000); }

/* ══════════════════════════════════════════════════════════════════════
   GROUND-AWARE ACCENTS
   ──────────────────────────────────────────────────────────────────────
   A light page still contains dark bands — the hero on index.html is
   near-black inside an otherwise light document. The accents that are
   legible on a light ground are the wrong ones there, and a contrast
   audit measured exactly that: ember #8F3617 on #262626 at 1.95:1,
   steam-200 on the same ground at 2.04:1. Both unreadable, both invisible
   to a reviewer skimming for "does it look right".

   ONE TOKEN CANNOT SERVE BOTH GROUNDS. A colour dark enough to read on
   light is too dark to read on black, and there is no value that satisfies
   both — so instead of compromising the colour, the GROUND declares
   itself and the accents re-point through inheritance. Every descendant
   of a dark band gets the dark-ground variants automatically, with no
   per-element work and nothing to keep in sync by hand.

   Fire steps UP the combustion ramp on dark and DOWN on light, which is
   the physically correct direction anyway: a flame reads hotter against
   black than it does against paper.
   ══════════════════════════════════════════════════════════════════════ */

[data-ground="dark"] {
  --fire:     var(--fire-500);   /* one stop hotter, to clear the ground */
  --fire-dark:var(--fire-400);
  --c:        var(--fire-500);
  --cd:       var(--fire-400);
  --gold:     var(--fire-500);
  --a:        var(--fire-500);

  /* Steam inverts outright: the light-ground variant is a deep teal that
     vanishes on black, the dark-ground one is pale. */
  --go: var(--steam-400);
  --g:  var(--steam-400);

  /* Text ramp on a dark band inside a light page. */
  --text:   var(--ash-850);
  --text-1: var(--ash-850);
  --text-2: var(--ash-700);
  --text-3: var(--ash-600);
  --text-4: #8A8A8A;
  --text-5: #8A8A8A;
  --k:  var(--ash-850);
  --k2: var(--ash-700);
  --k3: var(--ash-600);
  --k4: #8A8A8A;
  --ink: var(--ash-800);
  --ink-on: var(--ash-000);
}

/* ══════════════════════════════════════════════════════════════════════
   MATERIAL — where most SaaS sites give themselves away.
   ══════════════════════════════════════════════════════════════════════ */

/* ── 1. NO SHADOWS. Anywhere. ─────────────────────────────────────────
   Soft drop shadows on rounded cards are the single most recognisable
   generic-SaaS signature. Elevation is a lighter ash step on dark and a
   hairline on light. Focus rings are exempt — they are an active state,
   not decoration, and removing them would break keyboard use. */
*:not(:focus):not(:focus-visible) { box-shadow: none !important; }

/* ── 2. RADIUS 2px. ───────────────────────────────────────────────────
   Large soft corners say friendly consumer app. This is an instrument.
   Of everything in this file, this single change alters the feel most.
   Circles are exempt: status dots and avatars stay round. */
*:not([style*="border-radius:50%"]):not([style*="border-radius: 50%"]) {
  border-radius: var(--radius) !important;
}
[style*="border-radius:50%"], [style*="border-radius: 50%"] { border-radius: 50% !important; }

/* ── 3. GRAIN. ────────────────────────────────────────────────────────
   Fine particulate at 3% on light, 5% on dark. It is the cheapest single
   move that stops a flat fill reading as a template — and it is literally
   what ash is. feTurbulence, so it costs no image request. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.03;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
[data-theme="char"] body::before { opacity: 0.05; }

/* ── 4. HEAT BLEED. Dark only. ────────────────────────────────────────
   Two very large, very soft washes anchored off-canvas, so the black has
   temperature and depth instead of reading as flat space. It must never
   be legible AS a gradient — if you can see where it begins it is too
   strong. Never on light: warm haze on a light ground is exactly the
   parchment feeling this whole system removes. */
[data-theme="char"] body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
  background:
    radial-gradient(55vw 55vw at 6% -12%,   rgba(92, 36, 16, 0.16) 0%, transparent 70%),
    radial-gradient(65vw 65vw at 104% 110%, rgba(92, 36, 16, 0.12) 0%, transparent 70%);
}

/* ── 5. HAIRLINES ─────────────────────────────────────────────────────
   The structural grammar. Any 1px border collapses to a hairline so
   structure is drawn, not fenced. */
hr { border: 0; border-top: var(--hair) solid var(--rule, rgba(128,128,128,.25)); }

/* Sanctioned fire exception — focus is an active state. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 1px solid var(--fire-400) !important;
  outline-offset: 2px;
}

/* ── MOTION ───────────────────────────────────────────────────────────
   Ember pulse: 3.5s, slow enough to read as breathing coals rather than a
   blink. Only on at-risk states — a healthy account is perfectly still,
   and stillness is what makes movement mean something. */
@keyframes k-ember { from { opacity: .55; } to { opacity: 1; } }
.k-pulse { animation: k-ember 3.5s ease-in-out infinite alternate; }

@keyframes k-ignite { 0% { filter: brightness(1); } 12% { filter: brightness(1.55); } 100% { filter: brightness(1); } }
.k-ignite { animation: k-ignite var(--dur-slow) var(--ease) 1; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* Progressive enhancement; ignored where unsupported. */
::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) {
  animation-duration: .25s;
  animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
}

/* ══════════════════════════════════════════════════════════════════════
   STRUCTURE LAYER — the pass that changes the FEEL.
   Founder: "not much of a change it feels" · "lets change the structure too".

   Colour and type were paint on an unchanged skeleton. This is the skeleton.
   Still presentation-only: no markup moves, no DOM reorder, no id or handler
   touched. Every rule acts on elements that already exist, so the JS cannot
   notice it happened.

   Anthropic's layout grammar is centred, airy, generous, calm. The opposite —
   and the thing that reads as an instrument — is LEFT-ALIGNED, GRIDDED,
   DENSE, drawn with hairlines like a technical drawing.

   ⚠ `!important` on the spacing rules is not laziness. This site carries
   2,849 INLINE style attributes and its section padding is written on the
   elements themselves; a plain stylesheet cannot reach any of it. The first
   attempt at this layer had no !important, changed nothing visible, and I
   reported it as done — see the note in the commit.
   ══════════════════════════════════════════════════════════════════════ */

/* ── 1. DENSITY. ──────────────────────────────────────────────────────
   Generous vertical rhythm reads calm and considered. An instrument is
   dense: more information per screen, fewer scrolls between two numbers
   you are trying to compare. Sections were 96px top and bottom. */
section, .section-wrap, [class*="-band"], [class*="-section"] {
  padding-top: 56px !important;
  padding-bottom: 56px !important;
}
@media (max-width: 768px) {
  section, .section-wrap, [class*="-band"], [class*="-section"] {
    padding-top: 40px !important;
    padding-bottom: 40px !important;
  }
}
:root { --pad-y: 56px; }

/* ── 2. STOP CENTRING. ────────────────────────────────────────────────
   A centred column is the loudest editorial signal on a page — it says
   essay, not instrument. Controls keep their own centring, because there
   it is mechanical rather than editorial. */
section, .section-wrap, .dh-inner, .ab-inner,
section > h1, section > h2, section > h3, section > p {
  text-align: left !important;
}
button, .btn, [class*="btn"], [class*="cta"], th, [class*="badge"],
[class*="pill"], [class*="tag"], [class*="chip"] { text-align: revert !important; }

/* ── 3. HAIRLINES AS THE GRAMMAR. ─────────────────────────────────────
   A rule at every section boundary is what makes a page read as drawn to
   a grid rather than stacked. */
section + section, .section-wrap + .section-wrap {
  border-top: var(--hair) solid var(--rule, rgba(128,128,128,.16));
}

/* ── 4. PROSE MEASURE. ────────────────────────────────────────────────
   Full-width text is an essay's grammar. A measure keeps prose scannable
   and stops the page filling edge to edge. */
p, li { max-width: 74ch; }
[class*="hero"] p, .dh-sub, [class*="sub"] { max-width: 64ch; }

/* ── 5. MICRO-LABELS ARE THE SIGNATURE. ───────────────────────────────
   The 11px mono uppercase label above everything is what carries the
   identity from page to page. Made consistent rather than approximately
   consistent. */
[class*="label"], [class*="eyebrow"], [class*="kicker"], [class*="-lbl"], .k-label {
  font-family: var(--font-data) !important;
  font-size: 11px !important;
  letter-spacing: .14em !important;
  text-transform: uppercase;
}

/* ── 6. EVERY NUMBER TABULAR. ─────────────────────────────────────────
   A retention product is a numbers product; a figure that changes width
   on update looks amateur exactly when credibility matters. */
* { font-variant-numeric: tabular-nums; }

/* ── 7. LINKS ARE NOT DECORATION. ─────────────────────────────────────
   Fire is reserved for signal, so a body link is underlined rather than
   coloured — which also keeps the fire budget where it belongs. */
p a, li a { color: inherit; text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: var(--rule-strong, rgba(128,128,128,.45)); }
p a:hover, li a:hover { text-decoration-color: currentColor; }

/* ══════════════════════════════════════════════════════════════════════
   THE LADDER COMPRESSES — one place, not 22 clamp curves.

   Only the three DISPLAY steps move. The reading steps (9/11/13/15) are
   already at their floor: shrinking body text on a small screen is how a
   page becomes unreadable on the device most people hold. And the steps
   land on OTHER LADDER STEPS, never between them — a compressed ladder is
   still a ladder, or the discipline was pointless.
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {
  :root {
    --t-64: 44px;
    --t-44: 30px;
    --t-30: 18px;
  }
}
@media (max-width: 480px) {
  :root {
    --t-64: 30px;
    --t-44: 30px;
    --t-30: 18px;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   UNSTYLED LINKS — measured, not assumed.

   The audit found #0000EE rendering on imprint-connect, proof and
   responsible-ai: the BROWSER DEFAULT blue. Those anchors carry no class
   and no inline style, so nothing in the design system ever reached them —
   bright blue links on a strictly greyscale site, shipped.

   They do NOT get fire. Fire is the signal and it is scarce: "never use a
   fire stop for a meaning that is not heat", and a link is not heat. Spend
   it on a navigation affordance and it stops meaning risk anywhere else.

   So the link stays in the substrate and earns its affordance from the
   underline instead of from hue — which is also the one link treatment
   that survives being read by someone who cannot distinguish the colour.

   ⚠ :where(), NOT :not() directly. The first attempt used
   a:not([class]):not([style]) — specificity 0,2,1, which BEAT the footer's
   own .ft a rule and repainted 36 deliberately-styled links to inherit,
   failing contrast on a dark footer. :where() contributes ZERO
   specificity, so this is a true fallback: it reaches only anchors no
   other rule ever claimed, and loses every tie by construction.
   ══════════════════════════════════════════════════════════════════════ */
a:where(:not([class]):not([style])) {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--ash-600);
  text-underline-offset: 2px;
}
a:where(:not([class]):not([style])):hover {
  text-decoration-color: currentColor;
}

/* ══════════════════════════════════════════════════════════════════════
   BASE LAYER — the two places the type system leaked, both measured.

   1. FORM CONTROLS DO NOT INHERIT font-family. A <button> with no explicit
      font renders in the OPERATING SYSTEM's UI font — Arial on Windows.
      That is why the census reported "Arial" with no Arial anywhere in the
      source. `font: inherit` is the standard reset and it is load-bearing
      here: every unstyled button on every page was silently outside the
      type system.

   2. code / pre / kbd / samp inherit the UA's GENERIC `monospace`, which
      resolves to whatever the browser picks — not JetBrains Mono. Same
      class of leak: a family we never chose, rendering our content.

   :where() so both carry ZERO specificity. These are defaults for elements
   nobody styled, and they must lose to every real rule — the lesson from
   the link fallback, which at 0,2,1 beat the footer's own rule and
   repainted 36 links.
   ══════════════════════════════════════════════════════════════════════ */
:where(button, input, select, textarea, optgroup) {
  font: inherit;
  letter-spacing: inherit;
}
:where(code, pre, kbd, samp) {
  font-family: var(--font-data);
}
