/* ==========================================================================
   Nelix design tokens — single token layer.

   Implements docs/REDESIGN_CONTRACT.md exactly: surface ramp, azure accent,
   atmospheric glows, type scale, spacing, radii, elevation and motion.

   Sections 02–09 are the contract verbatim. Section 10 holds the handful of
   tokens the contract does not specify (spacing ladder, stacking order, small
   radii, header height). There is no legacy alias layer and no second palette.
   ========================================================================== */

/* ------------------------------------------------------------- 01 typeface
   Inter variable, self-hosted. The `opsz` build carries the optical-size axis
   so display sizes tighten automatically. Latin + Latin-Extended only; the
   remaining subsets are not used anywhere on the site. */

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("../fonts/inter-latin-opsz-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("../fonts/inter-latin-ext-opsz-normal.woff2") format("woff2-variations");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Inter";
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url("../fonts/inter-latin-opsz-italic.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* ================================================ 00 measured reference
     Every colour, size and step below was measured off the rendered
     arm.com pages on 2 Aug 2026 with _tmp/arm-audit/measure.mjs (Chromium,
     widths 1440/1280/1024/768/375). Raw output: _tmp/arm-audit/arm-
     measurements.json. Nothing here is guessed from a screenshot.

     Naming note: the --nx-azure-* and --nx-navy-* families kept their
     historical names. The site has ~16 stylesheets and a legacy adapter in
     base.html referencing them; renaming would be a large mechanical change
     with no rendered difference, and doing it halfway is exactly the
     two-palette state this pass exists to avoid. The names are now
     historical labels, the values are Arm's. "azure" means the violet
     accent ramp; "navy" means the ink surface ramp. */

  /* --------------------------------------------------- 02 surface ramp
     Arm runs two surfaces and almost nothing between them: the ink
     #080225 and pure white, with #211B3B as the single elevated step
     (measured on the masthead indicator and the active tab) and #393551
     on inset figures. The old six-step navy gradient is gone; Arm's page
     is banded, not atmospheric. */
  --nx-void: #080225;
  --nx-abyss: #080225;
  --nx-navy-deep: #0d0730;
  --nx-navy: #151038;
  --nx-navy-lift: #211b3b;
  --nx-navy-edge: #393551;

  /* ------------------------------------------------------- 03 accent
     Arm's accent is violet, and it splits by surface. #7233F7 is the fill
     (buttons, markers) and measures 3.38:1 on ink, which clears the 3:1
     graphical-object floor but not 4.5:1, so it is never used as body
     text. #C7ADFC is the on-ink text violet at 10.34:1. #0057FF is the
     light-surface primary at 5.52:1 on white. */
  --nx-azure: #c7adfc;      /* accent text on ink        10.34:1 on #080225 */
  --nx-azure-soft: #d1bafc; /* accent text, lifted       11.61:1 on #080225 */
  --nx-azure-deep: #7233f7; /* accent fill                5.94:1 with white */
  /* Semantic alias for primary pill CTAs. Measured live off arm.com
     carousel "Read the blog" / Learn more (rgb(114,51,247)), Aug 2026. */
  --nx-cta-purple: var(--nx-azure-deep);
  --nx-azure-ink: #211b3b;  /* accent-tinted surface */

  /* Light-surface accent. Violet on white is a fill only; blue is Arm's
     text/link colour on white bands. */
  --nx-blue: #0057ff;       /* primary fill on light       5.52:1 with white */
  --nx-blue-deep: #0047d6;  /* link text on light          7.31:1 on white */

  /* Amber. Arm uses it for the active state and nothing else. It measures
     1.85:1 on white, so it is an ink-surface colour only and never marks
     state on a light band; the light bands use --nx-status-*-on-light. */
  --nx-amber: #ffae2d;      /* active state on ink        10.85:1 on #080225 */

  /* Violet hover. Measured live off the primary CTA: #7233F7 -> #6023DE. */
  --nx-violet-hover: #6023de; /* 7.52:1 with white */
  /* Alias used by page CSS (--_accent fallbacks). Same fill as CTA purple. */
  --nx-violet: var(--nx-azure-deep);

  /* Cyan. Card eyebrow on ink bands only (13.35:1). Unused hero-cyan token
     removed — contract forbids the prior cyan fill on the public site. */
  --nx-cyan: #02eaea;       /* card eyebrow on ink       13.35:1 on #080225 */

  /* White, named so bands can say what surface they are rather than
     spelling the literal. */
  --nx-white: #ffffff;

  /* Card hover wipe. Measured on c-carousel-card::before, which slides a
     #FAFAFA panel up behind the text on hover. Ink text stays 19.24:1. */
  --nx-wipe: #fafafa;

  /* Inset figure surface on ink bands, measured on the animated card
     figure. White body copy holds 11.65:1 against it. */
  --nx-surface-card: #393551;

  /* Atmospheric glow — retinted to the violet fill. */
  --nx-glow-a06: rgba(114, 51, 247, 0.06);
  --nx-glow-a10: rgba(114, 51, 247, 0.1);
  --nx-glow-a18: rgba(114, 51, 247, 0.18);
  --nx-glow-a28: rgba(114, 51, 247, 0.28);

  /* -------------------------------------------------------- 04 type ink
     Measured: pure white carries most of Arm's on-ink text (105 nodes at
     1440), #E6E6E9 the secondary run, #A3A8AE the muted one. */
  --nx-text: #ffffff;       /* 20.08:1 on #080225 */
  --nx-text-body: #e6e6e9;  /* 16.12:1 on #080225 */
  --nx-text-muted: #a3a8ae; /*  8.39:1 on #080225 */
  --nx-text-faint: #797e86; /*  4.92:1 on #080225, still AA body */

  /* On white bands. Arm sets headings in the ink itself. */
  --nx-text-on-light: #080225;       /* 20.08:1 on white */
  --nx-text-on-light-muted: #5a5668; /*  7.08:1 on white */

  /* ------------------------------------------------------- 05 structure */
  --nx-line: rgba(255, 255, 255, 0.07);
  --nx-line-strong: rgba(255, 255, 255, 0.13);
  --nx-line-accent: rgba(114, 51, 247, 0.34);

  /* Card hairline on white. Measured #E5ECEB, which is 1.20:1 against
     white. That is Arm's own value and it is below the 3:1 graphics floor,
     kept deliberately: the border is decorative, the cards are also
     separated by a 24px gap, and every piece of information inside a card
     carries full contrast on its own. Nothing is conveyed by the border. */
  --nx-line-on-light: #e5eceb;

  /* Status, three states, on the Arm palette.

     Nelix is pre-silicon and these three labels are how the site says so, so
     they are load-bearing rather than decorative. Arm has no equivalent
     component; the colours are drawn from Arm's own accents.

     Colour never carries a state on its own. Each state also has a stroke
     style and a marker silhouette, defined in section 11 below and in the
     .na-chip rules in nx-arm.css, so the distinction survives greyscale and
     every form of colour blindness.

     The rebuilt homepage puts the status cards on a WHITE band, which the
     ink colours cannot serve: amber measures 1.85:1 on white and violet-light
     1.94:1. Every state therefore has an -on-light twin, and the component
     picks by surface rather than by guessing. */
  --nx-status-active: #ffae2d; /* in progress            10.85:1 on #080225 */
  --nx-status-hold: #a3a8ae;   /* defined / not started   8.39:1 on #080225 */
  --nx-status-done: #c7adfc;   /* complete               10.34:1 on #080225 */
  /* Same three states on white bands. Measured against #FFFFFF. */
  --nx-status-active-on-light: #0047d6; /* 7.31:1 */
  --nx-status-hold-on-light: #5a5668;   /* 7.08:1 */
  --nx-status-done-on-light: #7233f7;   /* 5.94:1 */

  /* Caution / failure — desaturated clay-rust, outside the azure ramp.
     The brief bans gold, green, cyan and purple but is silent on red; a
     saturated alarm red would break the calm mood, so these stay clay.
     Never overload --nx-status-hold for warn/fail/loss: hold means only
     "defined / not started". Attenuation (signal loss) is not a status —
     use --nx-text-faint / --nx-line-strong, not these tokens. */
  --nx-status-warn: #e08a78; /* caution — solid stroke, hollow diamond */
  --nx-status-fail: #c97868; /* failure — solid stroke, cross marker */

  /* Dash rhythm for the `hold` state, kept beside the colour it belongs to so
     consumers never invent their own. On SVG geometry these resolve as user
     units, matching the existing .nxd-route--dashed register. */
  --nx-status-dash-on: 4px;
  --nx-status-dash-off: 3px;

  /* ------------------------------------------------------- 06 elevation
     Arm has no elevation hierarchy. The whole homepage carries three
     shadow declarations across roughly 900 rendered elements, and none of
     them separates one card tier from another. Both tokens below collapse
     onto the one measured value so nothing on the site can build a stack
     of tiers that Arm does not have. */
  --nx-shadow-panel: 0 4px 6px rgba(0, 0, 0, 0.15);
  --nx-shadow-lift: 0 4px 15px rgba(0, 0, 0, 0.35);
  --nx-shadow-glow: 0 0 0 1px var(--nx-line-accent);

  /* ------------------------------------------------------ 07 typography

     Arm sets everything in Aeonik, a licensed Monotype grotesk that Nelix
     has no rights to. Substituted with Inter, already self-hosted here and
     the closest freely-licensed match: both are neo-grotesks with a tall
     x-height, near-vertical terminals and a low-contrast geometric bowl.
     Inter's variable build covers 100-900, so the four weights Arm uses
     (100, 300, 400, 500) are all real cuts rather than synthesised.

     Weight discipline, measured: Arm's content type never exceeds 500. The
     one 700 on the page is the mobile nav trigger at 375. Nothing below
     goes above 500.

     Sizes are the measured 375 and 1440 endpoints with a linear ramp
     between them. Tracking is POSITIVE on body copy (0.5px at 18px) and
     slightly negative on the display sizes, which is the reverse of the
     scale this file used to carry. */
  --nx-font: "Inter var", "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* measured 38px @375 -> 65px @1440, weight 100 */
  --nx-fs-hero: clamp(38px, 28.49px + 2.535vw, 65px);
  /* measured 40px @375 -> 80px @1440, weight 400 */
  --nx-fs-display: clamp(40px, 25.92px + 3.756vw, 80px);
  --nx-fs-h1: var(--nx-fs-display);
  /* measured 24px @375 -> 32px @1440, weight 400 */
  --nx-fs-h2: clamp(24px, 21.18px + 0.751vw, 32px);
  /* measured 27px @375 -> 30px @1440, weight 300 */
  --nx-fs-h3: clamp(27px, 25.94px + 0.282vw, 30px);
  /* measured 20px @375 -> 24px @1440, weight 500 */
  --nx-fs-h4: clamp(20px, 18.59px + 0.376vw, 24px);
  /* measured 20px @375 -> 24px @1440, weight 400 */
  --nx-fs-lead: clamp(20px, 18.59px + 0.376vw, 24px);
  /* measured 16px @375 -> 18px @1440 */
  --nx-fs-body: clamp(16px, 15.3px + 0.188vw, 18px);
  --nx-fs-cta: 20px;     /* measured, does not scale */
  --nx-fs-btn: 16px;     /* measured, does not scale */
  --nx-fs-caption: 14px; /* measured */
  --nx-fs-eyebrow: 12px; /* measured: band eyebrows */
  /* measured: the masthead eyebrow runs a size up from the band eyebrows,
     16/24 rather than 12/18. Two roles, both taken off arm.com. */
  --nx-fs-eyebrow-lead: 16px;

  --nx-lh-hero: 1.077; /* measured: 65/70 on the masthead title */
  --nx-lh-display: 1.12;
  --nx-lh-heading: 1.2;
  --nx-lh-h3: 1.13;
  --nx-lh-h4: 1.083; /* measured: 24/26 on Arm's card titles */
  --nx-lh-lead: 1.33;
  --nx-lh-body: 1.45;

  --nx-tracking-display: -0.006em; /* measured -0.5px at 80px */
  --nx-tracking-heading: 0;
  --nx-tracking-lead: 0.021em;     /* measured 0.5px at 24px */
  --nx-tracking-body: 0.028em;     /* measured 0.5px at 18px */
  --nx-tracking-cta: 0.018em;      /* measured 0.36px at 20px */
  --nx-tracking-eyebrow: 0.02em;   /* measured 0.24px at 12px */

  /* Weight roles. Named so no component writes a number.

     Arm declares 100 on its masthead title and renders it in Aeonik, whose
     thin cut is visibly heavier than Inter's. Setting Inter to a literal 100
     at 65px produced a hairline the reference does not have. 200 is the
     weight at which the substituted face matches Arm's rendered stroke,
     which is the thing being copied.

     Re-checked by rendering 100, 150 and 200 against a crop of Arm's own
     title at the same size: 100 is visibly thinner than the reference, 150
     is still light, 200 sits on it. */
  --nx-fw-hero: 200;
  --nx-fw-light: 300;
  --nx-fw-regular: 400;
  --nx-fw-medium: 500;

  /* -------------------------------------------- 08 spacing & composition

     Arm runs two independent scales and this is the single most copied
     thing on the page.

     Section rhythm is 15px-based: the measured band paddings are 45, 90,
     120 and 125, and the page gutter is 15. 125 is 120 plus a 5px optical
     nudge on one band, kept because it is what Arm renders. 30 and 60 sit
     on the same grid and cover separation *inside* a band, where 45 is the
     smallest measured value and 90 is already a band's worth of air.

     The 38px on the stat and icon cards belongs to neither scale. It is a
     component padding, measured on c-image-above-content-card at every
     width, and it is carried as its own token rather than rounded to 45.

     Component gaps measured in use: 2, 4, 10, 12, 16, 20, 24, 30. The
     earlier audit note that "only 8/12/16/24 exist" did not survive
     re-measurement; 8 never appears and 10/20/30 all do. */
  --nx-sp-15: 15px;
  --nx-sp-20: 20px;
  --nx-sp-24: 24px;
  --nx-sp-30: 30px;
  --nx-sp-35: 35px; /* measured: footer top padding */
  --nx-sp-38: 38px;
  --nx-sp-45: 45px;
  --nx-sp-60: 60px;
  --nx-sp-90: 90px;
  --nx-sp-120: 120px;
  --nx-sp-125: 125px;

  --nx-gap-2: 2px;
  --nx-gap-4: 4px;
  --nx-gap-8: 8px;
  --nx-gap-10: 10px;
  --nx-gap-12: 12px;
  --nx-gap-16: 16px;
  --nx-gap-20: 20px;
  --nx-gap-24: 24px;
  --nx-gap-30: 30px;

  /* Band padding. Arm does not scale these with the viewport; the same 45
     and 120 render at 375 as at 1440. Only the 120/125 band is eased down
     on small screens, below, because at 375 it costs a full screen height. */
  --nx-space-section: var(--nx-sp-45);
  --nx-space-section-lg: var(--nx-sp-120);
  --nx-space-block: var(--nx-sp-45);
  /* 15px at the Arm cap; mid-desktop gets more so 1280 is not cramped
     relative to the 55px side margin that appears once the 1360 container
     floats inside a 1440 viewport. */
  --nx-gutter: clamp(15px, 2.4vw, 40px);

  /* Measured: outer container 1360px, inner content column 1330px, i.e. a
     second 15px inset. At every width below the cap the container is
     viewport minus 30 (1250 @1280, 994 @1024, 738 @768), which is the
     15px gutter confirming itself. */
  --nx-container: 1360px;
  --nx-container-inner: 1330px;
  --nx-container-tight: 800px;

  /* Measured: cards are square. Every c-carousel-card and
     c-image-above-content-card renders border-radius 0px. Buttons are the
     only pill on the page. */
  --nx-radius: 0;
  --nx-radius-lg: 0;
  --nx-radius-btn: 40px;

  /* ---------------------------------------------------------- 09 motion */
  --nx-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --nx-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --nx-dur-fast: 180ms;
  --nx-dur-mid: 400ms; /* plate/mosaic image zoom; between fast and --nx-dur */
  --nx-dur: 420ms;
  --nx-dur-slow: 900ms;

  /* ====================================== 10 extensions beyond the contract

     These are NOT compatibility shims and NOT a second palette. They are
     real, load-bearing tokens for dimensions the contract simply does not
     specify — a 4px spacing ladder, a stacking order, small radii, the
     header height, the ambient loop duration, and the die-grid hairline.
     Every one of them has live consumers; the contract has no equivalent.

     The Section 10 legacy alias block that used to live here (--nx-accent,
     --nx-ink-*, --nx-cyan, --nx-font-display, --nx-text-Nxl, …) has been
     retired: its consumers now reference the contract tokens directly. */

  /* Die-grid hairline. Far fainter than --nx-line, which would read as a
     visible rule when tiled at 64px. */
  --nx-grid-line: rgba(255, 255, 255, 0.028);

  /* 4px spacing ladder. Kept complete: it is an ordinal scale, and removing
     intermediate steps makes the surviving names misleading. */
  --nx-space-0: 0;
  --nx-space-1: 0.25rem;
  --nx-space-2: 0.5rem;
  --nx-space-3: 0.75rem;
  --nx-space-4: 1rem;
  --nx-space-5: 1.25rem;
  --nx-space-6: 1.5rem;
  --nx-space-7: 1.75rem;
  --nx-space-8: 2rem;
  --nx-space-9: 2.25rem;
  --nx-space-10: 2.5rem;
  --nx-space-12: 3rem;
  --nx-space-16: 4rem;
  --nx-space-20: 5rem;
  --nx-space-24: 6rem;
  --nx-space-32: 8rem;

  /* Section rhythm variants, all on the measured 15px section scale. */
  --nx-section-y: var(--nx-space-section);
  --nx-section-y-sm: var(--nx-sp-20);
  --nx-section-y-lg: var(--nx-sp-90);

  /* Full-bleed measure. Arm caps at 1360 and has nothing wider, so this is
     the same value rather than a second, looser container. */
  --nx-container-wide: var(--nx-container);

  /* Small radii. Measured: the only non-zero radii Arm renders outside the
     40px button pill are a 4px chip and third-party cookie chrome. */
  --nx-radius-xs: 4px;
  --nx-radius-sm: 4px;
  --nx-radius-pill: var(--nx-radius-btn);

  /* Ambient loop duration for traces and slow drifts (contract §5 calls for
     18–26s but names no token). */
  --nx-dur-ambient: 22s;

  /* Stacking order. Kept complete for the same reason as the spacing ladder. */
  --nx-z-base: 1;
  --nx-z-sticky: 900;
  --nx-z-header: 1000;
  --nx-z-mega: 1010;
  --nx-z-overlay: 1040;
  --nx-z-modal: 1050;

  /* Fixed header height — layout depends on it (main is offset by it).
     Arm's top bar measures 80px; we match that so the chrome reads as the
     same class of product, not a denser SaaS toolbar. */
  --nx-header-h: 80px;
}

/* Arm holds its band padding constant across breakpoints, with one
   exception worth copying rather than mimicking blindly: the 120/125 ink
   band is 1369px tall at 1440 and its padding alone eats most of a 375
   viewport. Arm's own mobile rendering compresses it. Below 768 the large
   band steps down to 45, which is the next value on the same 15px scale. */
@media (max-width: 47.9375rem) {
  :root {
    --nx-space-section-lg: var(--nx-sp-45);
    --nx-section-y-lg: var(--nx-sp-45);
  }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --nx-dur-fast: 1ms;
    --nx-dur-mid: 1ms;
    --nx-dur: 1ms;
    --nx-dur-slow: 1ms;
    --nx-dur-ambient: 1ms;
  }
}

/* ============================================ 11 status-state treatment
   The three status states share one hue now, so colour alone cannot carry
   them. Each state also gets a stroke style and a marker silhouette, which
   survive greyscale and every form of colour blindness:

     in progress            solid border, filled 5px marker
     defined / not started  dashed border, hollow marker
     complete               solid border, filled 7px marker

   Everything here is derived from --nx-status-*; no state colour is written
   out again. Two declarations also replace border colours that were pinned to
   the old brass and teal as raw rgba() and would otherwise have survived the
   token change.

   These are component rules, not tokens, and they live here only because the
   sheets that own the selectors (nx-system.css, nx-inner.css,
   nx-diagrams.css) are being edited by other streams in the same pass. The
   doubled class selectors are what let them win from a sheet that loads first.
   Fold each rule into its owning sheet once that pass is over and this section
   goes away. */

/* Status pills — nx-system.css .nx-pill */
.nx-pill.nx-pill--progress {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--nx-status-hold) 34%, transparent);
}

.nx-pill.nx-pill--progress::before {
  width: 6px;
  height: 6px;
  background: transparent;
  box-shadow: inset 0 0 0 1.5px currentColor;
}

.nx-pill.nx-pill--done {
  border-color: color-mix(in srgb, var(--nx-status-done) 30%, transparent);
}

.nx-pill.nx-pill--done::before {
  width: 7px;
  height: 7px;
}

/* Inner-page status tags — nx-inner.css .nx-ip-tag (a rotated square) */
.nx-ip-tag.nx-ip-tag--hold::before {
  background: transparent;
  box-shadow: inset 0 0 0 1px currentColor;
}

.nx-ip-tag.nx-ip-tag--done::before {
  width: 7px;
  height: 7px;
}

/* Diagram legend keys and large hold geometry — nx-diagrams.css.
   Nodes and cells are 4–6 units across, where a 4/3 dash reads as noise
   rather than as a dash, so they keep their solid stroke and rely on the
   legend and label instead. */
.nxd__key.nxd__key--hold::before {
  background: repeating-linear-gradient(
    90deg,
    var(--nx-status-hold) 0 var(--nx-status-dash-on),
    transparent var(--nx-status-dash-on)
      calc(var(--nx-status-dash-on) + var(--nx-status-dash-off))
  );
}

.nxd__key.nxd__key--done::before {
  height: 3px;
}

/* Dashed, and no longer at 0.6 opacity. The brass carried enough weight at 0.6
   to sit around 3.3:1 against the diagram fill; the azure step does not, and a
   dashed stroke has less ink on the page than a solid one to begin with. At
   0.85 these measure ~4:1. */
.nxd .nxd-block--hold,
.nxd .nxd-bracket--hold {
  stroke-dasharray: var(--nx-status-dash-on) var(--nx-status-dash-off);
  stroke-opacity: 0.85;
}

/* .nxd-tech inherits fill-opacity: 0.9, which pulled the hold label to 4.38:1
   against the diagram fill. Full opacity puts it back on 5.10:1, matching what
   .nxd-tech--mute already does for the same reason. */
.nxd .nxd-tech--hold {
  fill-opacity: 1;
}
