/* ==========================================================================
   AcmaCorp Design System v1.0
   --------------------------------------------------------------------------
   Single source of truth for colour, type, spacing, radius, elevation and
   layout. style.css was normalised to reference these tokens, so changing a
   value here changes it site-wide.

   Load order: after style.css. Custom properties resolve after the full
   cascade, and every var() in style.css carries a literal fallback, so the
   site still renders correctly if this file fails to load.

   Docs: /docs/design-system.md
   ========================================================================== */

/* ==========================================================================
   METRIC-MATCHED FALLBACK FACES
   --------------------------------------------------------------------------
   Both webfonts come from Google Fonts with display=swap, which means the
   page paints in a fallback face first and re-renders when the webfont
   arrives. Whether that re-render moves the layout depends entirely on how
   closely the fallback's metrics match, and by default they do not match at
   all. Measured on this site with the canvas text metrics API:

     face                 avg advance   ascent   descent
     Plus Jakarta Sans      2039.5        104       22
     Arial                  1945.5         91       21     (+4.8% narrower)
     system-ui (Segoe UI)   1963.9        108       25     (+8.0% narrower)
     Geist 700              2156.7        101       30
     Arial 700              2111.4         91       21     (+2.2% narrower)

   So every line box changed height and every paragraph rewrapped slightly at
   the moment the font swapped.

   These overrides are necessary but not sufficient: they fix the line box and
   the average advance, and they cannot fix the `ch` unit, whose reference
   glyph is a different proportion of the em in each face. See --ds-ch below
   for that half of the problem, which turned out to be the larger one.

   These two faces are Arial re-metricked to the numbers above, so the
   fallback occupies the same space as the webfont it stands in for. The swap
   still changes the letterforms -- it can no longer change the layout.
   Arial rather than system-ui because it is the closest of the two on both
   axes and is present on every platform that matters; Liberation Sans is the
   metric-identical Linux substitute.

   size-adjust normalises the advance width; ascent/descent-override rebuild
   the line box; line-gap-override: 0% because neither webfont carries a gap.
   Re-derive these if either family is ever swapped -- they are measurements
   of two specific faces, not general-purpose values.
   ========================================================================== */

/* Plus Jakarta Sans stand-in, regular and medium. */
@font-face {
  font-family: "AcmaSans Fallback";
  font-style: normal;
  font-weight: 400 500;
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 104.8%;
  ascent-override: 99.2%;
  descent-override: 21%;
  line-gap-override: 0%;
}

/* Plus Jakarta Sans stand-in, semibold and bold. Arial's bold is
   proportionally wider than its regular, so this needs its own adjustment --
   a single rule tuned on the regular would leave every heading and button
   mis-measured in the other direction. */
@font-face {
  font-family: "AcmaSans Fallback";
  font-style: normal;
  font-weight: 600 700;
  src: local("Arial Bold"), local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 100%;
  ascent-override: 104%;
  descent-override: 22%;
  line-gap-override: 0%;
}

/* Geist stand-in. Display use only, and only at 700 -- see the font request
   in header.php, which no longer ships Geist 500 or 600. */
@font-face {
  font-family: "AcmaDisplay Fallback";
  font-style: normal;
  font-weight: 700;
  src: local("Arial Bold"), local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 102.2%;
  ascent-override: 98.9%;
  descent-override: 29.4%;
  line-gap-override: 0%;
}

:root {
  /* ---------------------------------------------------------------- COLOUR */

  /* Primary — AcmaCorp orange, darkened to clear WCAG AA and held on the
     brand mark's own hue.

     The mark is #FF7F1F, HSL(26, 100%, 56%). Verified rather than assumed:
     acmacorp_light.svg and acmacorp_dark.svg both declare `fill:#ff7f1f`, and
     the raster lockups sample #ff801e / #fc821e, which is webp drift and not a
     different colour. It cannot be an action -- white text on it is 2.53:1 and
     fails AA in both directions -- so a darker orange is required.

     The first one, #B8501A, was HSL(21, 75%, 41%): 5 degrees off the mark's
     hue and a quarter less saturated. On the page that read as two unrelated
     oranges: a vivid mark above a browner button.

     #B65002 is HSL(26, 98%, 36%) -- the mark's exact hue, all but two points
     of its saturation, and very slightly darker. It is better than the colour
     it replaces on every measure that matters, not merely different:

        white text on it   5.08:1   (was 5.00)
        as text on white   5.08:1   (was 5.00)
        as text on #F1F4F9 4.60:1   (was 4.53)

     That last row is the binding one and it is easy to miss. The secondary
     buttons, the eyebrows and the article category links set this colour as
     TEXT, and half of them sit on the surface ground rather than on white --
     which costs about half a point. A first attempt at HSL(26, 95%, 37%)
     measured 4.94 on white and looked safe, but 4.48 on surface, putting six
     real elements under AA.

     Do not raise the lightness to chase the mark further: 37% is close to the
     ceiling for white text at AA. Where the mark's own colour must appear on
     an action, use --ds-primary-vivid with an INK label on an ink ground
     (7.36:1) -- never with a white one. */
  --ds-primary:            #B65002;
  --ds-primary-hover:      #974302;
  --ds-primary-active:     #7E3701;
  --ds-primary-soft:       #FDF0E7;
  /* Original vivid orange. Decorative use only — never behind or as text. */
  --ds-primary-vivid:      #FF7F1F;

  /* Secondary — consolidated from four near-identical blues
     (#0450BD, #0140A8, #0452BF, #1C447F). 7.2:1 on white. */
  --ds-secondary:          #0450BD;
  --ds-secondary-hover:    #033C90;
  --ds-secondary-soft:     #EAF1FB;

  /* Neutrals — warm-biased so they sit with the orange rather than against it */
  --ds-ink:                #001427;   /* brand navy, headings on light      */
  --ds-text:               #28282B;   /* body copy, 14.9:1                  */
  --ds-text-muted:         #5F5A54;   /* secondary copy, 6.4:1 (was #999)   */
  /* Third text tier, below muted. It was referenced twice in sections.css --
     the post-card byline and the logo-wall disclaimer -- and never declared
     here, so both rendered on the literal #8A837A fallback: 3.74:1 on white,
     a WCAG AA failure on the only two text runs using it. Declared at 4.68:1,
     which clears AA for small text and stays a step lighter than muted. */
  --ds-faint:              #7A736A;   /* tertiary copy, 4.68:1              */
  --ds-text-inverse:       #FFFFFF;
  --ds-white:              #FFFFFF;
  --ds-surface:            #F1F4F9;   /* section fills                      */
  --ds-surface-2:          #FAFBFD;
  --ds-border:             #DDE3EC;
  --ds-border-strong:      #C3CCDA;

  /* Supporting accents — gradients and data viz only, not body text */
  --ds-accent-magenta:     #C2148B;
  --ds-accent-violet:      #792091;
  --ds-accent-indigo:      #233099;

  /* Semantic */
  --ds-success:            #1E7A4B;
  --ds-warning:            #8A5A00;
  --ds-danger:             #B3261E;

  /* ------------------------------------------------------------ TYPOGRAPHY */

  /* Primary: body, UI, and headings. Self-hosted, weights 100–900.
     Secondary slot is deliberately the same family — introducing a second
     webfont costs an extra request and a FOUT for no structural gain. To
     adopt a display face later, change --ds-font-display only. */
  /* The fallback faces below the webfonts are metric-matched, not generic.
     Measured on this site: Plus Jakarta Sans sets 8.0% wider than system-ui
     and 4.8% wider than Arial at the same size, with a natural line box of
     126 against system-ui's 133. So every block of text reflowed when the
     webfont swapped in -- lines rewrapped and line boxes changed height,
     which the layout-shift observer recorded on the header nav and the proof
     band. "AcmaSans Fallback" and "AcmaDisplay Fallback" are
     Arial re-metricked to those measurements (see the @font-face block after
     this one), so the swap is now a change of shape at identical dimensions.
     Keep the generic families at the end for the case where even Arial is
     missing. */
  --ds-font-primary: "Plus Jakarta Sans", "AcmaSans Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;
  --ds-font-display: "Geist", "AcmaDisplay Fallback", "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --ds-font-mono:    ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Type scale — 14 steps. Replaces 37 arbitrary declared sizes. */
  --ds-text-2xs:  0.75rem;   /* 12 — legal, captions            */
  --ds-text-xs:   0.875rem;  /* 14 — labels, meta               */
  --ds-text-sm:   1rem;      /* 16 — small body, UI             */
  --ds-text-base: 1.125rem;  /* 18 — body default               */
  --ds-text-lg:   1.25rem;   /* 20 — lead paragraph, H6         */
  --ds-text-xl:   1.5rem;    /* 24 — H5                         */
  --ds-text-2xl:  1.75rem;   /* 28 — H4                         */
  --ds-text-3xl:  2rem;      /* 32 — H3                         */
  --ds-text-4xl:  2.5rem;    /* 40 — H2                         */
  --ds-text-5xl:  3rem;      /* 48 — H1                         */
  --ds-text-6xl:  4rem;      /* 64 — hero                       */
  --ds-text-7xl:  5rem;      /* 80 — display                    */
  --ds-text-8xl:  6rem;      /* 96 — statistic numerals         */
  --ds-text-9xl:  8rem;      /* 128 — statistic numerals        */

  /* Fluid display scale.

     The discrete --ds-text-* steps above are the vocabulary; these six ramps
     are how headings actually use it. Before this, 23 different clamp()
     expressions were declared across sections.css, responsive.css and
     mobile-density.css -- one per component, each invented at the moment that
     component was written. The result was 20 distinct rendered heading sizes
     across the site, five of which (17, 22, 37, 52, 70px) sat on no scale at
     all.

     Every ramp below is solved so that its two endpoints are steps on the
     discrete scale: the minimum is what it renders at 375px, the maximum what
     it renders at 1440px and above. Between those it interpolates, which is
     the point of fluid type -- but it can no longer land somewhere arbitrary
     at the two widths the design is actually reviewed at.

       1  40 -> 64   hero h1
       2  32 -> 48   page h1, statistic numerals
       3  28 -> 40   section h2
       4  24 -> 32   h3
       5  20 -> 24   h4, drawer headings, wide card titles
       6  18 -> 20   compact card titles, FAQ questions
     --ds-lede-size   16 -> 20   supporting copy under a heading           */
  --ds-display-1: clamp(2.5rem,   1.972rem + 2.2535vw, 4rem);
  --ds-display-2: clamp(2rem,     1.648rem + 1.5023vw, 3rem);
  --ds-display-3: clamp(1.75rem,  1.486rem + 1.1268vw, 2.5rem);
  --ds-display-4: clamp(1.5rem,   1.324rem + 0.7512vw, 2rem);
  --ds-display-5: clamp(1.25rem,  1.162rem + 0.3756vw, 1.5rem);
  --ds-display-6: clamp(1.125rem, 1.081rem + 0.1878vw, 1.25rem);
  --ds-lede-size: clamp(1rem,     0.912rem + 0.3756vw, 1.25rem);

  /* Statistic numerals, 48 -> 96.

     --ds-text-8xl (96) and --ds-text-9xl (128) were both declared "statistic
     numerals" in the scale above and referenced by nothing in the component
     layer -- the proof band rendered at --ds-display-2, so the figures came
     out smaller than the section heading of the band below them. There was no
     ramp that reached the step the scale had reserved. This is it, solved on
     the same two fixed points as the six above: --ds-text-5xl at 375px,
     --ds-text-8xl at 1440px. */
  --ds-display-stat: clamp(3rem, 1.9437rem + 4.507vw, 6rem);

  /* Leading.

     These are unitless on purpose. The legacy layer expressed leading as an
     absolute length -- `line-height: 1.875rem` and 35 other rem values, 329
     declarations in style.css -- which detaches the line box from the type it
     is setting. The measured consequence: --ds-text-sm rendered at seven
     different ratios across the site (1.25 to 2.56), --ds-text-xl at six
     (1.08 to 1.71, and 1.08 is tighter than the face's own cap height), and
     --ds-text-5xl at 0.83, where descenders collide with the line below. A
     unitless ratio scales with whatever font-size the element resolves to,
     which is the only form that survives a fluid clamp() ramp.

     Four ratios carry all running text; --ds-leading-none is for single-line
     controls, and --ds-leading-ui for compact interface text that should not
     take the full reading leading. */
  --ds-leading-none:    1;
  --ds-leading-tight:   1.15;
  --ds-leading-snug:    1.3;
  --ds-leading-ui:      1.45;
  --ds-leading-normal:  1.6;
  --ds-leading-relaxed: 1.75;

  /* Paragraph rhythm. Spacing between paragraphs is one rhythm, set once, and
     it is the only paragraph boundary marker -- no first-line indent on top of
     it. Sized against the body line box so the space reads as one blank line
     rather than an arbitrary gap. */
  --ds-paragraph-gap: 1.1em;

  /* The scale describes what is actually loaded. Geist ships 500/600/700 and
     Plus Jakarta Sans ships 400/500/600/700 from the Google Fonts request in
     header.php, so those four are the whole vocabulary.

     --ds-weight-semibold was referenced by nine rules in sections.css and
     never declared here; it rendered at 600 on the var() fallback alone.
     --ds-weight-light (300) is gone: nothing referenced it, and no 300 face is
     loaded for either family, so anything that had used it would have
     synthesised a faux-light. Add the weight to the font request first if the
     design ever needs one. */
  --ds-weight-regular:  400;
  --ds-weight-medium:   500;
  --ds-weight-semibold: 600;
  --ds-weight-bold:     700;

  /* Tracking is in em, never px or rem. The legacy layer had 19 absolute
     values (0.025rem, 0.03125rem, 0.05625rem ...) which stay 0.4px whether
     they are tracking a 12px label or a 64px hero, so the same declaration
     read as loose on small text and invisible on large. em ties the tracking
     to the type it is spacing. */
  --ds-tracking-tighter: -0.03em;  /* display sizes, 48px and up            */
  --ds-tracking-tight:  -0.02em;
  --ds-tracking-snug:   -0.01em;   /* h3/h4, where -0.02 closes the counters */
  --ds-tracking-normal: 0;
  --ds-tracking-wide:   0.03em;
  --ds-tracking-caps:   0.08em;

  /* ------------------------------------------------------- UI TYPE ROLES */
  /* Three interface roles that were never declared, so every component that
     needed one invented it. Measured across 20 pages: buttons rendered in 10
     distinct combinations (3 sizes x 4 weights x 5 leadings x 6 tracking
     values) and navigation in 10 more (12px to 20px, weight 400 to 700,
     leading 1.00 to 1.83). A button is a target and a nav link is a
     destination; each is one role, not ten. */

  /* Button: one step larger and one step tighter than a label. Uppercase. */
  --ds-button-size:      var(--ds-text-sm);
  --ds-button-weight:    var(--ds-weight-medium);
  --ds-button-leading:   var(--ds-leading-none);
  --ds-button-tracking:  var(--ds-tracking-wide);

  /* Navigation, three levels that share one role and differ only by step:

       L1  top bar, uppercase        16px semibold, 0.03em
       L2  mega-menu column heading  18px bold, sentence case
       L3  mega-menu links           14px medium, sentence case

     The values are what the top bar already ships; what it did not have was
     any of its four stale breakpoint overrides agreeing with them. */
  --ds-nav-size:         var(--ds-text-sm);
  --ds-nav-size-head:    var(--ds-text-base);
  --ds-nav-size-sub:     var(--ds-text-xs);
  --ds-nav-size-mobile:  var(--ds-text-base);
  --ds-nav-weight:       var(--ds-weight-semibold);
  --ds-nav-leading:      var(--ds-leading-snug);
  --ds-nav-tracking:     var(--ds-tracking-wide);

  /* Footer and utility column headings. These are labels that happen to be
     marked up as headings -- "JOIN OUR TEAM", "STAY CONNECTED", "More Links"
     rendered at 20/20/16px in three different weights and three leadings on
     every page of the site. One role, so the footer reads as one band. */
  --ds-subhead-size:     var(--ds-text-xs);
  --ds-subhead-weight:   var(--ds-weight-semibold);
  --ds-subhead-leading:  var(--ds-leading-snug);
  --ds-subhead-tracking: var(--ds-tracking-caps);

  /* --------------------------------------------------------------- SPACING */
  /* 8px grid. --ds-space-1 is the only half-step, for optical adjustments. */
  --ds-space-1:  4px;
  --ds-space-2:  8px;
  --ds-space-3:  12px;
  --ds-space-4:  16px;
  --ds-space-5:  24px;
  --ds-space-6:  32px;
  --ds-space-7:  40px;
  --ds-space-8:  48px;
  --ds-space-9:  64px;
  --ds-space-10: 80px;
  --ds-space-11: 96px;
  --ds-space-12: 128px;

  /* Vertical rhythm between full-width sections.

     This is now the site's only source for section padding. It was two
     sources: this step-based token, which nothing outside .ds-section
     consumed, and --acma-section-y in sections.css, which the homepage used.
     Measured across 21 pages at three widths, the result was 36 distinct
     top/bottom padding pairs -- 96/104 on inner pages, 104/104 on the
     homepage, 32/128 on listings, 96/192 on the partner wall, and so on. One
     fluid ramp replaces them, with no breakpoint table behind it.

     --ds-section-y-tight is for bands rather than sections: the proof band,
     the legal pages' single content block, anything that reads as a strip.
     The ramp is solved for two fixed points rather than eyeballed: 40px at
     375, which is what mobile-density.css had already established as the
     right mobile gap, and 104px at 1440, which is what the homepage was
     using. Everything between is interpolated, and it caps at 112px so very
     wide screens do not drift. */
  --ds-section-y:       clamp(2.5rem, 1.1rem + 6vw, 7rem);
  --ds-section-y-tight: clamp(1.75rem, 0.8rem + 4vw, 4.5rem);
  /* Kept as aliases: .ds-section and a handful of utility rules reference
     them, and a step-based value here would reintroduce the second scale. */
  --ds-section-y-md: var(--ds-section-y);
  --ds-section-y-sm: var(--ds-section-y-tight);

  /* ---------------------------------------------------------------- RADIUS */
  /* Replaces 15 values. 50%/100% circles are left as-is where used. */
  --ds-radius-sm:     4px;
  --ds-radius-md:     8px;
  --ds-radius-lg:     16px;
  --ds-radius-pill:   999px;
  --ds-radius-circle: 50%;

  /* ------------------------------------------------------------- ELEVATION */
  --ds-shadow-sm: 0 1px 2px rgba(0, 20, 39, .06), 0 1px 3px rgba(0, 20, 39, .08);
  --ds-shadow-md: 0 2px 4px rgba(0, 20, 39, .06), 0 8px 20px -6px rgba(0, 20, 39, .12);
  --ds-shadow-lg: 0 4px 8px rgba(0, 20, 39, .07), 0 20px 44px -12px rgba(0, 20, 39, .18);
  --ds-shadow-focus: 0 0 0 3px rgba(4, 80, 189, .35);

  /* ----------------------------------------------------------------- LAYOUT */
  --ds-container-max: 1616px;   /* matches the existing .wrapper contract */
  --ds-container-pad: var(--ds-space-10);
  /* Comfortable reading width: about 70 characters of prose.
     NOT 70ch. The `ch` unit is the width of the zero glyph, and Plus Jakarta
     Sans has a wide one -- measured on an article at 18px, the zero is 13.18px
     against an 8.53px average prose glyph, a ratio of 1.54. So the old 68ch
     resolved to 896px, which is 105 characters, and capped nothing: the
     article column is 817px (96 characters) and never reached it.
     45ch resolves to ~593px, which is ~70 characters in this face. Kept in
     `ch` rather than rem so it still scales with the element's font size;
     recalibrate this number if the body face ever changes. */
  /* Reading measure.

     Expressed through --ds-ch, not in `ch`. The `ch` unit is the advance of
     the font's own "0", and that is not a constant across faces: measured
     here, Plus Jakarta Sans's zero is 0.732em and the Arial-based fallback's
     is 0.583em -- 25.6% narrower. Since `size-adjust` scales the whole em
     uniformly it cannot correct a difference in one glyph's proportion, so a
     `ch` column was a different width before and after the font swap. The
     homepage hero deck measured 629px in the fallback and 791px in Plus
     Jakarta Sans; the paragraph rewrapped from four lines to three, the hero
     lost 32px, and everything below it jumped. That was the single largest
     layout shift on the site.

     --ds-ch is Plus Jakarta Sans's own ratio frozen as an em value, so
     `calc(54 * var(--ds-ch))` still reads as "54 characters", still scales
     with the element's font-size, and is now the same width in both faces.
     Set a measure this way; never in raw `ch`. */
  --ds-ch: 0.732em;
  --ds-measure: calc(45 * var(--ds-ch));

  /* Two values were used through var() but never declared, so they resolved on
     their literal fallbacks and could not be changed from here -- which is the
     whole point of a token. Declared at the values that were shipping.
     (--ds-text-subtle was a third: an undeclared fourth text tier at 3.66:1.
     It is gone; the system's three tiers are text, muted and faint.) */
  --ds-carousel-bleed: 15px;   /* every template's .wrapper is padded 15px at mobile */
  --ds-crit-bg:        #F7E4E7;
  --ds-grid-gutter: var(--ds-space-5);

  /* ------------------------------------------------------------------ MOTION */
  --ds-ease: cubic-bezier(.4, 0, .2, 1);
  --ds-duration: 180ms;
  --ds-transition: var(--ds-duration) var(--ds-ease);
}

/* Container padding steps down on the theme's real breakpoints. */
@media (max-width: 1599px) { :root { --ds-container-pad: var(--ds-space-11); } }
@media (max-width: 1439px) { :root { --ds-container-pad: var(--ds-space-10); } }
@media (max-width: 1199px) { :root { --ds-container-pad: var(--ds-space-6); } }
@media (max-width: 767px)  { :root { --ds-container-pad: var(--ds-space-5); } }
@media (max-width: 479px)  { :root { --ds-container-pad: var(--ds-space-4); } }


/* ==========================================================================
   BASE TYPOGRAPHY
   :where() keeps specificity at 0, so these act as a floor that any existing
   component style still overrides. Nothing currently-styled changes; only
   headings that were never given a size pick these up.
   ========================================================================== */

:where(body) {
  font-family: var(--ds-font-primary);
  font-size: var(--ds-text-base);
  line-height: var(--ds-leading-normal);
  color: var(--ds-text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

:where(h1, h2, h3, h4, h5, h6) {
  font-family: var(--ds-font-display);
  font-weight: var(--ds-weight-bold);
  line-height: var(--ds-leading-tight);
  letter-spacing: var(--ds-tracking-tight);
  text-wrap: balance;
  /* Colour is deliberately NOT set here. Headings inherit from their section,
     so headings inside dark bands stay legible. Use .ds-heading-ink to opt in
     to the navy on light surfaces. */
}
:where(.ds-heading-ink) { color: var(--ds-ink); }

/* Heading sizes are the fluid ramps, not the discrete steps.

   The discrete steps are the vocabulary the ramps are solved against; they
   are not themselves a responsive scale. Setting h2 to --ds-text-4xl pins it
   at 40px from 320px to 4K, which is how the legacy layer set every heading
   on the site -- so a page built from sections.css had headings that
   responded to the viewport and a page built from style.css did not, and the
   two sat next to each other in the same footer. Every level now runs on the
   ramp solved for it, so one h2 behaves like every other h2 at every width.

   Tracking loosens as size drops because -0.02em closes the counters on a
   20px heading while barely registering on a 64px one. */
:where(h1) { font-size: var(--ds-display-2); letter-spacing: var(--ds-tracking-tight); }
:where(h2) { font-size: var(--ds-display-3); letter-spacing: var(--ds-tracking-tight); }
:where(h3) { font-size: var(--ds-display-4); line-height: var(--ds-leading-snug); letter-spacing: var(--ds-tracking-snug); }
:where(h4) { font-size: var(--ds-display-5); line-height: var(--ds-leading-snug); letter-spacing: var(--ds-tracking-snug); }
:where(h5) { font-size: var(--ds-display-6); line-height: var(--ds-leading-snug); letter-spacing: var(--ds-tracking-normal); }
:where(h6) { font-size: var(--ds-text-sm);   line-height: var(--ds-leading-snug); letter-spacing: var(--ds-tracking-normal); }

/* The hero h1 is the one heading that reaches --ds-display-1. It is opt-in
   rather than the h1 default, because most pages carry a page title rather
   than a hero and 64px is too much voice for those. */
:where(.ds-heading-hero) { font-size: var(--ds-display-1); letter-spacing: var(--ds-tracking-tighter); }

/* text-wrap: pretty prevents the single-word last line. It is ignored where
   unsupported, so it costs nothing. */
:where(p) { line-height: var(--ds-leading-normal); text-wrap: pretty; }

/* Paragraph rhythm: one blank-line gap between paragraphs, no gap after the
   last one, and no first-line indent -- indent and spacing together
   double-mark the same boundary. */
:where(p):not(:last-child) { margin-bottom: var(--ds-paragraph-gap); }
:where(small) { font-size: var(--ds-text-xs); color: var(--ds-text-muted); }
:where(strong, b) { font-weight: var(--ds-weight-bold); }

/* Statistics align on the digit, never drift by glyph width. */
:where(.ds-figure) { font-variant-numeric: tabular-nums; }

/* Utility classes for new markup */
.ds-lead      { font-size: var(--ds-text-lg); line-height: var(--ds-leading-relaxed); color: var(--ds-text-muted); }
.ds-caption   { font-size: var(--ds-text-2xs); color: var(--ds-text-muted); }
.ds-eyebrow   { font-size: var(--ds-text-xs); font-weight: var(--ds-weight-medium);
                letter-spacing: var(--ds-tracking-caps); text-transform: uppercase;
                color: var(--ds-primary); }
.ds-measure   { max-width: var(--ds-measure); }

/* The three UI roles as classes, for markup that can use them directly. The
   legacy components that could not (their selectors outrank anything
   declared here) were rewritten in place against the same tokens, so the
   role is shared even where the class is not. */
.ds-nav-link  { font-family: var(--ds-font-primary); font-size: var(--ds-nav-size);
                font-weight: var(--ds-nav-weight); line-height: var(--ds-nav-leading);
                letter-spacing: var(--ds-nav-tracking); }
.ds-nav-link--sub { font-size: var(--ds-nav-size-sub); }
.ds-subhead   { font-family: var(--ds-font-primary); font-size: var(--ds-subhead-size);
                font-weight: var(--ds-subhead-weight); line-height: var(--ds-subhead-leading);
                letter-spacing: var(--ds-subhead-tracking); text-transform: uppercase; }


/* ==========================================================================
   BUTTON SYSTEM
   .ds-btn is the canonical component for new markup. The state normalisation
   further down applies to the theme's existing CTA classes so that focus,
   hover and disabled behave identically everywhere without changing layout.
   ========================================================================== */

.ds-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-2);
  font-family: var(--ds-font-primary);
  font-size: var(--ds-button-size);
  font-weight: var(--ds-button-weight);
  line-height: var(--ds-button-leading);
  letter-spacing: var(--ds-button-tracking);
  text-transform: uppercase;
  text-decoration: none;
  padding: var(--ds-space-4) var(--ds-space-6);
  min-height: 48px;                       /* AA target size */
  border: 1px solid transparent;
  border-radius: var(--ds-radius-pill);
  cursor: pointer;
  transition: background-color var(--ds-transition), border-color var(--ds-transition),
              color var(--ds-transition), box-shadow var(--ds-transition);
}

.ds-btn--primary   { background: var(--ds-primary); color: var(--ds-text-inverse); }
.ds-btn--primary:hover  { background: var(--ds-primary-hover); color: var(--ds-text-inverse); }
.ds-btn--primary:active { background: var(--ds-primary-active); }

.ds-btn--secondary { background: transparent; color: var(--ds-primary); border-color: var(--ds-primary); }
.ds-btn--secondary:hover { background: var(--ds-primary-soft); color: var(--ds-primary-hover); border-color: var(--ds-primary-hover); }

.ds-btn--ghost     { background: transparent; color: var(--ds-secondary); padding-inline: var(--ds-space-3); }
.ds-btn--ghost:hover { background: var(--ds-secondary-soft); }

.ds-btn--inverse   { background: var(--ds-white); color: var(--ds-ink); }
.ds-btn--inverse:hover { background: var(--ds-surface); }

.ds-btn--sm { font-size: var(--ds-text-xs); padding: var(--ds-space-3) var(--ds-space-5); min-height: 40px; }
.ds-btn--lg { font-size: var(--ds-text-base); padding: var(--ds-space-5) var(--ds-space-8); min-height: 56px; }

.ds-btn:disabled,
.ds-btn[aria-disabled="true"],
.ds-btn.is-disabled {
  background: var(--ds-border);
  color: var(--ds-text-muted);
  border-color: transparent;
  cursor: not-allowed;
  opacity: .7;
  pointer-events: none;
}

/* --- state normalisation for the theme's existing CTA classes -------------
   Appearance (colour, radius, size) was already unified by tokenising
   style.css. This only adds the states that were missing or inconsistent. */
form .submit-btn,
.form-btn,
.join-team-btn,
.banner-cta a,
.ds-btn {
  transition: background-color var(--ds-transition), border-color var(--ds-transition),
              color var(--ds-transition), box-shadow var(--ds-transition),
              transform var(--ds-transition);
}

form .submit-btn:disabled,
.form-btn:disabled,
button:disabled,
input[type="submit"]:disabled {
  cursor: not-allowed;
  opacity: .55;
  filter: grayscale(.35);
}


/* ==========================================================================
   CARDS AND SURFACES
   ========================================================================== */

.ds-card {
  background: var(--ds-white);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  padding: var(--ds-space-5);
  box-shadow: var(--ds-shadow-sm);
  transition: box-shadow var(--ds-transition), transform var(--ds-transition);
}
.ds-card--interactive:hover { box-shadow: var(--ds-shadow-md); transform: translateY(-2px); }
.ds-card--flat   { box-shadow: none; }
.ds-card--filled { background: var(--ds-surface); border-color: transparent; }

.ds-surface        { background: var(--ds-surface); }
.ds-surface-invert { background: var(--ds-ink); color: var(--ds-text-inverse); }
.ds-surface-invert :where(h1, h2, h3, h4, h5, h6) { color: var(--ds-text-inverse); }


/* ==========================================================================
   LAYOUT
   ========================================================================== */

.ds-container {
  width: 100%;
  max-width: var(--ds-container-max);
  margin-inline: auto;
  padding-inline: var(--ds-container-pad);
}
.ds-section   { padding-block: var(--ds-section-y); }
.ds-stack > * + * { margin-top: var(--ds-space-5); }

.ds-grid { display: grid; gap: var(--ds-grid-gutter); }
.ds-grid--2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.ds-grid--3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.ds-grid--4 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }


/* ==========================================================================
   ACCESSIBILITY
   The theme previously relied on the UA default focus ring, which several
   resets removed. This restores a consistent, visible focus state.
   ========================================================================== */

:focus-visible {
  outline: 2px solid var(--ds-secondary);
  outline-offset: 2px;
  border-radius: var(--ds-radius-sm);
}
.ds-btn:focus-visible,
form .submit-btn:focus-visible,
.form-btn:focus-visible {
  outline: 2px solid var(--ds-secondary);
  outline-offset: 3px;
  box-shadow: var(--ds-shadow-focus);
}

.ds-visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.ds-skip-link {
  position: absolute; left: var(--ds-space-4); top: -100px; z-index: 100000;
  background: var(--ds-ink); color: var(--ds-text-inverse);
  padding: var(--ds-space-3) var(--ds-space-5);
  border-radius: 0 0 var(--ds-radius-md) var(--ds-radius-md);
  font-size: var(--ds-text-sm); text-decoration: none;
  transition: top var(--ds-transition);
}
.ds-skip-link:focus { top: 0; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
