/* ---------------------------------------------------------------------------
   VENDORED FILE. DO NOT EDIT.

   Source:  aline-no/aline-design-system @ v5.0.0
   Synced:  2026-11-01 by scripts/sync-to-decks.mjs
   Fonts:   ./fonts/, copied in the same pass. Both travel together.

   Edit the design system and re-run the sync. Anything changed here is lost on
   the next one, and a value that exists only in this file is a value the rest
   of Aline does not have.
   --------------------------------------------------------------------------- */

/* =========================================================================
   Aline Design System v5.0.0 — single-file build
   DO NOT EDIT. Generated by scripts/build-tokens.mjs.
   Source: git+ssh://git@github.com/aline-no/aline-design-system.git

   fonts.css + tokens.css + surfaces.css + theme.css, flattened. No @import,
   no Tailwind, no cascade layers. Font files are in ./fonts/ next to this
   file and must be copied with it.
   ========================================================================= */

/* =========================================================================
   Aline Design System — Fonts
   Self-hosted woff2 subsets. The seed loaded these from fonts.googleapis.com
   at render time, which puts a network call between a projector and a working
   slide. Decks are presented on conference wifi and borrowed machines, so the
   fonts ship as bytes in the repo. See the vendoring contract in README.md.

   Licences: Inter and Inter Tight (SIL OFL 1.1, fonts/LICENSE-Inter.txt),
   JetBrains Mono (SIL OFL 1.1).

   Paths are relative to this file. Import it before tokens.css, or use
   dist/aline-tokens.css which inlines this block.
   ========================================================================= */

/* ---- Inter (body) ---- */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/inter-latin-400-normal.woff2") format("woff2");
  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+2074, 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-weight: 500;
  font-display: swap;
  src: url("fonts/inter-latin-500-normal.woff2") format("woff2");
  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+2074, 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-weight: 600;
  font-display: swap;
  src: url("fonts/inter-latin-600-normal.woff2") format("woff2");
  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+2074, 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-weight: 700;
  font-display: swap;
  src: url("fonts/inter-latin-700-normal.woff2") format("woff2");
  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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Inter latin-ext. Norwegian sits in the latin range, so this is the
   fallback for quoted names and borrowed words, not for Line's own copy. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/inter-latin-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, 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: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/inter-latin-ext-500-normal.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, 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: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/inter-latin-ext-600-normal.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, 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: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/inter-latin-ext-700-normal.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---- Inter Tight (display / headings) ----
   Weights 500 to 900. 400 is not shipped: nothing renders Inter Tight at 400,
   so it would be dead bytes. 800 and 900 were added for the display weights,
   because a browser asked for a weight it does not have synthesises one by
   smearing the outlines, and on a tight display face that reads as a printing
   fault rather than as emphasis. 45 KB for the pair, latin only, matching the
   other three. */
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/inter-tight-latin-500-normal.woff2") format("woff2");
  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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/inter-tight-latin-600-normal.woff2") format("woff2");
  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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/inter-tight-latin-700-normal.woff2") format("woff2");
  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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("fonts/inter-tight-latin-800-normal.woff2") format("woff2");
  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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("fonts/inter-tight-latin-900-normal.woff2") format("woff2");
  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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- JetBrains Mono (eyebrows, code, labels) ---- */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/jetbrains-mono-latin-400-normal.woff2") format("woff2");
  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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/jetbrains-mono-latin-500-normal.woff2") format("woff2");
  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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* =========================================================================
   Aline Design System — Tokens
   Source of truth for every value in the system. A hex appears here and
   nowhere else.
   Aesthetic: warm off-white grounds, cool ink, single lime-green accent,
   square corners.

   This file declares variables only. No @import, no url(), no rules, so it
   resolves identically over file://, through a bundler, and inlined into a
   generated HTML file.
     Fonts        fonts.css (npm) or dist/aline-tokens.css (vendored)
     Type styles  theme.css
     Surfaces     surfaces.css

   :root carries the LIGHT surface. .surface-light restates it verbatim and
   .surface-dark restates the same token names with dark values, so a
   component is written once and is correct on either. See surfaces.css.
   ========================================================================= */

:root {
  /* ---- Brand core ----
     The three values the brand is recognised by. --aline-fg and --aline-green
     are fixed points and never move. --aline-bg tracks the light ground. */
  --aline-bg:         #FAF8F5; /* warm off-white — never pure white */
  --aline-fg:         #1C1C1C; /* near-black, the historical brand ink */
  --aline-green:      #D3FA9D; /* the single brand colour */

  /* ---- Neutral scale (unchanged in v2) ---- */
  --neutral-0:   #FFFFFF;
  --neutral-50:  #FAFAFA;
  --neutral-100: #F5F5F5;
  --neutral-200: #E0E0E0; /* hsl 0 0% 88% — v1 border reference */
  --neutral-300: #C7C7C7;
  --neutral-400: #999999;
  --neutral-500: #737373;
  --neutral-600: #525252;
  --neutral-700: #2E2E2E;
  --neutral-800: #1C1C1C; /* = --aline-fg */
  --neutral-900: #0A0A0B;

  /* ---- Grounds (light surface) ----
     Six steps from the page down to the edge of a component. Ratio is against
     the ground the token sits on: the page for most of them. Grounds sit at
     hue 40 and stay warm; saturation, not hue, is what makes a warm neutral
     read brown, so the saturation stays low. */
  --background: #FAF8F5; /* 1.00 — the page */
  --surface:    #F5F3EF; /* 1.05 — a card lifted off it */
  --sunken:     #EEECE7; /* 1.11 — a well cut into it */
  --block:      #E8E7E6; /* 1.17 — a filled inline element */
  --hair:       #E2E1DF; /* 1.23 — rule inside a component */
  --border:     #D3D2CF; /* 1.43 — edge around one */

  /* ---- Paper ----
     The one ground the system does not paint. On paper the sheet is the
     ground, so a printed document paints nothing and lets it through, and
     --background over it prints the page as a box floating on white. Declared
     on :root only and deliberately absent from surfaces.css: paper does not
     flip, a dark section prints on the same white sheet as a light one. It is
     also the only pure white the system uses, which is why it reads from the
     neutral scale rather than from the grounds above it. */
  --paper:      var(--neutral-0);

  /* ---- Text, four levels ----
     v1 ran headings at 16:1 and muted at 4.5:1 with nothing between, so
     anything secondary fell off a cliff and read as switched off. --body is
     the default for a paragraph. Every text level sits at hue 220 and stays
     cool against the warm grounds. */
  --foreground:       #1E1D1A; /* 15.90 — headings */
  --body:             #40454F; /*  9.08 — running text, the default for a paragraph */
  --muted-foreground: #636874; /*  5.26 — genuinely secondary, one notch down */
  --tert:             #8A8F99; /*  3.06 — labels and metadata, 12px and up */

  /* ---- Accent ----
     --accent is the brand green on both surfaces and is for non-text shapes
     only: dots, rules, chart series, a filled button. On the cream ground it
     measures 1.10:1, which as small type is not low contrast, it is invisible,
     and darkening it enough to pass always lands in moss. So accent-role TYPE
     reads --ink, charcoal on light and green on dark, and a component written
     against --ink is correct on both with no branching. The green is never
     darkened. See the accent rule in DESIGN.md. */
  --accent: #D3FA9D; /* 1.10 on this surface — non-text fills only */
  --ink:    #1E1D1A; /* 15.90 — accent-role type */
  --wash:   #F6FCEE; /* 1.01 — faint green tint ground */

  /* ---- Panel ----
     The dark block inside a light layout, and the only place the green
     appears as type on a light page. Callout, active phase card and CTA block
     are the usual three. Ratios are against --panel. */
  --panel:            #131416; /* 17.39 against the page, the same black as the dark surface */
  --panel-foreground: #D8DADE; /* 13.17 on the panel */
  --panel-ink:        #D3FA9D; /* 15.74 on the panel */

  /* ---- Contrast pairs ---- */
  --primary-foreground: #FAF8F5; /* 15.90 — on --foreground */
  --accent-foreground:  #1C1C1C; /* 14.55 — on --accent */

  /* ---- Status ----
     Functional colour, not brand colour. D6 says no new colours, and that rule
     is about the palette a page is DESIGNED in: one accent and neutrals. A
     status colour is not designed with, it is read. Four states, and each one
     carries three roles because a fill and the type on it are never the same
     value:

       --x       the mark. A dot, a bar, a left edge, a chip fill. It never
                 carries a word, so it is not held to a text ratio and takes
                 every point of chroma its hue holds. The first set was pinned
                 to 3.2:1 on cream at a flat chroma of 0.17 and every one of
                 them came out muted, because pinning a fill to a text ratio is
                 what turns an amber into a brown. Amber proves it: --warning
                 sits a full lightness step above the rest, at 0.74, because
                 any amber dark enough to read as text reads as mud.
       --x-ink   the word. Clears 4.5:1 on the page ground and on its own wash,
                 which is the pair that actually ships: a coloured word inside
                 a tinted badge.
       --x-wash  the badge ground. Pitched by presence, not by ratio: the four
                 land at 1.10 to 1.14:1 on cream, and each hue takes the chroma
                 it can hold at that lightness. Two earlier sets bracket this
                 one. The first sat at 1.03 to 1.05:1, a tint you cannot see.
                 The second went to 1.17 to 1.23:1 and read as a filled chip
                 rather than a tinted one, loud enough that four badges in a
                 row became the loudest thing on the page. 2026-09-18: this set
                 is the midpoint of the two, blended in OKLCH so each hue keeps
                 its own chroma rather than being washed toward grey. The ink
                 pairs are untouched, because a lighter ground only raises their
                 ratio: they now clear 5.25:1 at worst on light and 6.56:1 on
                 dark. If a badge ever needs to shout, that is a --x mark or a
                 border, not a heavier wash.

     The three-role shape is not new, it is --accent / --ink / --wash applied
     to a second family. Warning sits at OKLCH hue 76, well clear of the brand
     lime at 127, so an amber badge never reads as a green one gone wrong. */
  --success:       #00AF59; /* 2.72 — mark */
  --success-ink:   #006F36; /* 5.95 — text */
  --success-wash:  #CBF9D7; /* 1.10 — badge ground */
  --warning:       #E29B00; /* 2.22 — mark */
  --warning-ink:   #815700; /* 6.01 — text */
  --warning-wash:  #FFE7C6; /* 1.13 — badge ground */
  --danger:        #E93954; /* 3.83 — mark */
  --danger-ink:    #C10037; /* 5.96 — text */
  --danger-wash:   #FFE4E2; /* 1.14 — badge ground */
  --info:          #008FF4; /* 3.18 — mark */
  --info-ink:      #0062AA; /* 5.95 — text */
  --info-wash:     #DCEEFF; /* 1.12 — badge ground */
  --pending:       #B8F05C; /* 1.27 — placeholder chip and edge, diagram highlight, never type. D18 */

  /* ---- Chart series ----
     For the dashboards in the Al___ suite. Series 1 is var(--ink), so it is
     charcoal on a light surface and the brand green on a dark one, the same
     rule accent-role type already follows. That keeps the green out of a 2px
     line on cream, where it measures 1.10:1 and disappears, without ever
     darkening it. Series 2 to 5 rotate hue at a fixed lightness so no series
     reads as more important than another.

     The lightness is 0.66, not the 0.58 the first set used. At 0.58 the whole
     series sat above 4:1 on cream, which is a text ratio, and a chart read as
     four dark blocks. There is no ochre in the set: hue 65 at that lightness
     is brown, and a brown series beside a lime brand reads as dirt. Series 5
     is teal instead, which is the one hue far enough from both the blue and
     the lime to stay countable. */
  --chart-1: var(--ink);
  --chart-2: #0095FE; /* 2.94 */
  --chart-3: #F8495F; /* 3.24 */
  --chart-4: #A969FF; /* 3.22 */
  --chart-5: #00A8A4; /* 2.78 */

  /* ---- Interaction states ----
     These values were already decided, they were just written in prose in
     DESIGN.md instead of here, so every consumer re-read a doc to find them.
     --surface-hover is one ground step toward contrast, --border-hover is one
     line step, and the two fills are their base at 90% over the page, which is
     what `bg-primary/90` meant. */
  --surface-hover: var(--sunken);
  --border-hover:  #C4C3C0; /* 1.66 — one step past --border */
  --primary-hover: #343330; /* 11.92 — --primary at 90% over the page */
  --accent-hover:  #D7FAA6;

  /* ---- Compatibility aliases ----
     Kept so a v1 consumer and every shadcn component keep resolving. Each one
     is an alias onto a ground or text token above, which means each one has to
     be RESTATED in both surface blocks: a var() inside a custom property
     resolves on the element it is declared on, not where it is used, so
     --card: var(--surface) left only on :root would carry the light literal
     into .surface-dark. See surfaces.css. */
  --primary:         var(--foreground); /* the filled button is ink, not green */
  --card:            var(--surface);
  --card-foreground: var(--foreground);
  --muted:           var(--sunken);
  --input:           var(--border);

  /* ---- Fixed, surface-independent ---- */
  --ring: var(--aline-green); /* focus is always brand green, on both surfaces */

  /* --destructive was hsl(0 84% 60%) here and surface-independent, which made
     it the one semantic colour that did not flip. It is now an alias and is
     restated in both surface blocks like every other alias.

     It points at --danger-ink, not --danger. --danger is a mark and carries no
     word, so it is free to stay bright; the destructive button is a solid that
     carries its label, which is the job --x-ink is defined by. Aliased onto
     --danger the label ran at 3.21:1 on the old value and would run at 3.83:1
     on the new one. On --danger-ink it clears 5.96:1 light and 7.99:1 dark. */
  --destructive:            var(--danger-ink);
  --destructive-foreground: var(--background);

  /* ---- Foreground-on-dark opacity ladder ----
     Tracks --foreground on the dark surface (#F7F6F2). */
  --fg-90: rgb(247 246 242 / 0.90);
  --fg-70: rgb(247 246 242 / 0.70);
  --fg-60: rgb(247 246 242 / 0.60);
  --fg-50: rgb(247 246 242 / 0.50);
  --fg-40: rgb(247 246 242 / 0.40);
  --fg-30: rgb(247 246 242 / 0.30);
  --fg-20: rgb(247 246 242 / 0.20);
  --fg-10: rgb(247 246 242 / 0.10);

  /* ---- Background-on-light opacity ladder (unchanged in v2) ----
     Dark ink on cream. */
  --bg-ink-90: rgb(28 28 28 / 0.90);
  --bg-ink-70: rgb(28 28 28 / 0.70);
  --bg-ink-60: rgb(28 28 28 / 0.60);
  --bg-ink-50: rgb(28 28 28 / 0.50);
  --bg-ink-40: rgb(28 28 28 / 0.40);
  --bg-ink-30: rgb(28 28 28 / 0.30);
  --bg-ink-20: rgb(28 28 28 / 0.20);
  --bg-ink-10: rgb(28 28 28 / 0.10);

  /* ---- Type ---- */
  --font-sans:    "Inter", system-ui, -apple-system, Segoe UI, sans-serif;
  --font-display: "Inter Tight", "Inter", system-ui, -apple-system, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ---- Weight ----
     Absent in v2.0.0, which is why font-weight was typed by hand 43 times
     across the consumers that do not go through Tailwind. Six rungs, matching
     Tailwind's names so the preset maps one to one, then four ROLE tokens on
     top. Reach for the role, not the rung: the rungs are the scale, the roles
     are the decision.

     2026-09-18: those 43 are now wired. Adding the tokens was not the fix,
     because a hand-typed weight still wins. The kits were the worst of it,
     every heading carried fontWeight:500 as a React INLINE style, which beats
     the theme.css element rule outright, so the display face rendered at
     medium no matter what the token said and the titles read thin. If a
     weight looks wrong, look for a literal overriding the token before
     touching the token.

     Inter Tight reads heavier than its size, so --weight-display at 800 on a
     72px line is a genuinely heavy headline. That is the intent. See the note
     in DESIGN.md before moving it to 900. */
  --weight-normal:     400;
  --weight-medium:     500;
  --weight-semibold:   600;
  --weight-bold:       700;
  --weight-extrabold:  800;
  --weight-black:      900;

  --weight-body:    var(--weight-normal);   /* running text */
  --weight-ui:      var(--weight-medium);   /* labels, buttons */
  --weight-heading: var(--weight-bold);     /* card titles, subheads */
  --weight-display: var(--weight-extrabold);/* the one big line on a page */

  /* Scale (Inter Tight display tightens letter-spacing via tracking)
     Web surfaces only. A deck authors against a fixed 1920x1080 canvas and
     keeps its own scale; see the boundary rule in DESIGN.md. */
  --text-3xs:  0.625rem;  /* 10, a sidebar group label only */
  --text-2xs:  0.6875rem; /* 11, no DS pattern uses it, kept for consumers that do */
  --text-xs:   0.75rem;   /* 12 */
  --text-sm:   0.875rem;  /* 14 */
  --text-base: 1rem;      /* 16 */
  --text-lg:   1.125rem;  /* 18 */
  --text-xl:   1.25rem;   /* 20 */
  --text-2xl:  1.5rem;    /* 24 */
  --text-3xl:  1.875rem;  /* 30 */
  --text-4xl:  2.25rem;   /* 36 */
  --text-5xl:  3rem;      /* 48 */
  --text-6xl:  3.75rem;   /* 60 */
  --text-7xl:  4.5rem;    /* 72 */

  --leading-tight:   1.05;
  --leading-snug:    1.2;
  --leading-normal:  1.5;
  --leading-relaxed: 1.65;

  /* The tightest step is off the heading ladder since 2026-10-11. It was
     written for the display weights on the theory that a heavier face needs
     less air around its counters, and the opposite is what the eye reports:
     at --weight-display the display line and h1 read cramped at -0.04em and
     correct at -0.02em, which is where h2 already sat. The ladder keys
     tracking to heading level and never reads weight, so the two axes were
     being collapsed into one and weight lost. It stays in the scale and
     stays exported as a utility, for a large figure or a lockup set at a
     light weight, where the original reasoning does hold. Nothing in
     theme.css points at it. */
  --tracking-tighter: -0.04em;
  --tracking-tight:  -0.02em;
  --tracking-snug:   -0.01em;
  --tracking-normal:  0;
  --tracking-wide:    0.02em;

  /* Uppercase needs more air than a lowercase label at the same size, because
     caps have no descenders or x-height variation to separate them and the
     counters run square. --tracking-wide at 0.02em is the lowercase label
     value and reads cramped set in caps. Chosen against the real guide labels
     at 0.02, 0.06, 0.09 and 0.12em; 0.06 is the one that opens the word
     without spelling it out. Use it for any uppercase type, which in practice
     means .caps. */
  --tracking-wider:   0.06em;

  /* The eyebrow only: 11px mono caps at body weight need twice the caps air
     to read as a label and not a word. Taken from the Vibelabs course pages,
     which set their section eyebrows at 0.12em. */
  --tracking-widest:  0.12em;

  /* ---- Type styles (composite) ----
     One property that carries weight, size, leading and family together, in
     CSS `font` shorthand order. A declaration becomes one line instead of
     four, and Alto gets a usable string out of tokens.json rather than four
     values it has to reassemble.

     Body, UI and eyebrow only. There were four display styles here too and
     they are cut, because the `font` shorthand CANNOT carry letter-spacing and
     at display sizes the tracking is doing as much work as the weight. A
     --type-h1 that still needed a --tracking-tighter line beside it collapsed
     four declarations into two and saved nothing worth a token. Headings are
     set by the h1 to h4 rules in theme.css, which carry their own tracking.
     Body text does not track, so down here the shorthand is the whole style
     and four declarations really do become one. */
  --type-body:    var(--weight-body) var(--text-base)/var(--leading-normal) var(--font-sans);
  --type-ui:      var(--weight-ui) var(--text-sm)/var(--leading-normal) var(--font-sans);
  --type-eyebrow: var(--weight-body) var(--text-xs)/var(--leading-normal) var(--font-mono);

  /* ---- Shape ----
     Square, everywhere. All seven radius tokens are 0, so a card, a panel, an
     input, an image, a section, a button, a badge, a chip and a tab all have
     hard corners. There is no surface-against-control line any more: the pill
     was compensating for the move to square surfaces, and on a page where
     everything else has hard corners it is the only curve on the screen.
     See D7 for the original rule and D23 for why it went.

     --radius-full keeps its name so the control declarations in patterns.css
     keep resolving, which is what makes this one value rather than an audit.
     A shape that genuinely has to be round points at --radius-ramp-full.

     The v1 rounded scale is kept below as --radius-ramp-*, unused, carrying
     the same values it had. Re-rounding everything is pointing seven tokens at
     seven tokens and nothing else in the system moves.

     Deliberately NOT a calc() multiplier. calc(0.75rem * 0) is the more
     elegant single toggle and it writes that string into tokens.json, which
     Alto consumes from Python and cannot evaluate. Literal values only. */
  --radius-xs:   0;
  --radius-sm:   0;
  --radius:      0; /* base: cards, panels, inputs */
  --radius-lg:   0;
  --radius-xl:   0;
  --radius-2xl:  0;
  --radius-full: 0; /* buttons, badges, tabs, chips: square since D23 */

  /* The rounded ramp, parked. Point the seven zeros above at these to re-round. */
  --radius-ramp-xs:   0.25rem;  /* 4  */
  --radius-ramp-sm:   0.5rem;   /* 8  */
  --radius-ramp:      0.75rem;  /* 12 */
  --radius-ramp-lg:   1rem;     /* 16 */
  --radius-ramp-xl:   1.5rem;   /* 24 */
  --radius-ramp-2xl:  2rem;     /* 32 */
  --radius-ramp-full: 9999px;

  /* ---- Spacing (Tailwind-aligned) ----
     Web surfaces only, same boundary as the type scale. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;     /* section padding target */

  /* ---- Rails and measure ----
     Not a new scale. Every one of these was already a number in the system,
     it was just written in prose or typed into one consumer:
       48rem  long-form reading width, DESIGN.md layout rules
       62rem  the offer and report page, templates/_document.css --doc-page
       70rem  site max content width, DESIGN.md layout rules
       80rem  the al-suite grid rail, ui-kits/al-suite/README.md
     --measure is the 66ch already used on the document lede. A rail caps a
     layout, a measure caps a line, and a wide rail with no measure inside it
     is how a two-column document ends up with 120-character lines. */
  --rail-prose: 48rem; /* 768  — long-form reading */
  --rail-doc:   62rem; /* 992  — offer, report */
  --rail-site:  70rem; /* 1120 — marketing pages */
  --rail-app:   80rem; /* 1280 — dashboard grid */

  --measure:        66ch; /* body copy */
  --measure-narrow: 52ch; /* a lede, a pull quote, a caption */

  --gutter:    1.5rem; /* 24 — the page edge, small screens up */
  --gutter-lg: 3rem;   /* 48 — the page edge from --rail-site up */

  /* ---- App shell ----
     Dimensions for the Al___ suite chrome. The sidebar collapses to an icon
     rail, it never disappears, so the collapsed width is a token rather than
     zero. 16rem is shadcn's sidebar default, kept so a scaffolded Sidebar needs
     no override.

     2026-09-18: --shell-topbar was 52px and the comment here claimed 56 and 52
     were "the values al-suite already uses". Only 56 was. The kit built its
     topbar and its sidebar header from two separate 56s and they drifted apart
     the moment one of them became padding-driven. Both now read the token, and
     the token is 56 so that it matches --shell-rail: at 56 a collapsed sidebar
     is an exact square against the seam and the whole chrome is one number. */
  --shell-sidebar:   16rem; /* 256 — expanded */
  --shell-rail:      56px;  /* collapsed to icons */
  --shell-topbar:    56px;  /* one number with the rail, so the seam squares up */

  /* ---- Icon ----
     Four sizes, tied to the type scale rather than picked: --icon sits with
     --text-base, --icon-sm with --text-sm, --icon-lg with --text-xl and
     --icon-xl with --text-2xl, which is why an icon set beside a 14px label
     does not look a size too big. They exist because al-suite was drawing icons
     at 13, 14, 15 and 16 in one screen, and four sizes inside one component set
     is four accidents, not a scale.

     Carbon draws four sizes and only four: 16, 20, 24 and 32. --icon, --icon-lg
     and --icon-xl land on three of them, so a glyph at those steps gets the
     drawing Carbon made for that size rather than a scaled one. --icon-sm at 14
     does not, and scales the 16 drawing. That is deliberate: it sits with
     --text-sm and reading beside the label matters more than the hinting. Any
     size that is not on this list gives up the per-step drawing, which is the
     argument for not adding one. */
  --icon:    16px;
  --icon-sm: 14px;
  --icon-lg: 20px;
  --icon-xl: 24px;

  /* ---- Shadows (minimal — Aline uses near-none) ---- */
  --shadow-xs: 0 1px 2px rgb(0 0 0 / 0.04);
  --shadow-sm: 0 1px 3px rgb(0 0 0 / 0.06), 0 1px 2px rgb(0 0 0 / 0.04);
  --shadow:    0 4px 16px rgb(0 0 0 / 0.06);
  --shadow-lg: 0 12px 40px rgb(0 0 0 / 0.10);

  /* An offset with no blur, in the accent. The only depth move in the system
     that does not go soft, which is why it suits square corners. It is the
     green used as a shape behind a shape, so it stays inside the accent rule.
     Use it on one element per view at most. */
  --shadow-hard:    8px 8px 0 var(--accent);
  --shadow-hard-sm: 4px 4px 0 var(--accent);

  /* ---- Ring / focus ---- */
  --ring-offset: 2px;

  /* ---- Motion ---- */
  --ease-out: cubic-bezier(0.25, 0.1, 0.25, 1);
  --dur-fast: 150ms;
  --dur:      300ms;
  --dur-slow: 600ms;
}

/* =========================================================================
   Aline Design System — Surfaces
   Requires tokens.css.

   Dark is a SURFACE, not a theme. There is no toggle and nothing here reads
   prefers-color-scheme. A surface is chosen per page or per section, with
   data-surface on <html> or on a <section>. Decks and product UI are usually
   dark, articles usually light.

   Both surfaces are first class and declare the IDENTICAL token set, so a
   component is written once and is correct on either. scripts/build-tokens.mjs
   --check enforces that: same token names in both blocks, and .surface-light
   resolving to exactly what :root says.

   Why every alias is restated in both blocks:
   a var() inside a custom property resolves on the element it is DECLARED on,
   not where it is used. --card: var(--surface) left only on :root would carry
   the LIGHT literal into .surface-dark, because --card computes once on :root
   and only the resulting value inherits. Restating it inside each block is
   what makes it pick up that block's --surface.
   ========================================================================= */

/* ---- Light ----
   Written out rather than left to :root so a dark section can contain a light
   one. Without it nesting only works one way: .surface-dark reassigns the
   semantic tokens and nothing inside can put them back.

   A slide picks its ground with data-theme, the one attribute a deck author
   writes, so the same selectors carry it. Green is light underneath: the
   slide package lays the accent over this block in slides/slides.css, and
   text on green follows the light text roles until it does. */
.surface-light,
[data-surface="light"],
[data-slide][data-theme="light"],
[data-slide][data-theme="green"] {
  /* grounds */
  --background: #FAF8F5;
  --surface:    #F5F3EF;
  --sunken:     #EEECE7;
  --block:      #E8E7E6;
  --hair:       #E2E1DF;
  --border:     #D3D2CF;

  /* text */
  --foreground:       #1E1D1A;
  --body:             #40454F;
  --muted-foreground: #636874;
  --tert:             #8A8F99;

  /* accent — green is non-text fills only on this surface, type reads --ink */
  --accent: #D3FA9D;
  --ink:    #1E1D1A;
  --wash:   #F6FCEE;

  /* panel: the dark block inside a light layout, and the only place the green
     appears as type on a light page */
  --panel:            #131416;
  --panel-foreground: #D8DADE;
  --panel-ink:        #D3FA9D;

  /* contrast pairs */
  --primary-foreground: #FAF8F5;
  --accent-foreground:  #1C1C1C;

  /* status: mark, text, ground. Same three roles as --accent / --ink / --wash */
  --success:       #00AF59;
  --success-ink:   #006F36;
  --success-wash:  #CBF9D7;
  --warning:       #E29B00;
  --warning-ink:   #815700;
  --warning-wash:  #FFE7C6;
  --danger:        #E93954;
  --danger-ink:    #C10037;
  --danger-wash:   #FFE4E2;
  --info:          #008FF4;
  --info-ink:      #0062AA;
  --info-wash:     #DCEEFF;
  /* pending: a fuller step of the brand green at the same hue, for a
     placeholder's mark and a diagram's highlight. A fill and an edge, never
     type. See D18. */
  --pending:       #B8F05C;
  --destructive:            var(--danger-ink);
  --destructive-foreground: var(--background);

  /* chart series: 1 follows --ink, charcoal on light and green on dark */
  --chart-1: var(--ink);
  --chart-2: #0095FE;
  --chart-3: #F8495F;
  --chart-4: #A969FF;
  --chart-5: #00A8A4;

  /* interaction states */
  --surface-hover: var(--sunken);
  --border-hover:  #C4C3C0;
  --primary-hover: #343330;
  --accent-hover:  #D7FAA6;

  /* aliases, restated */
  --primary:         var(--foreground);
  --card:            var(--surface);
  --card-foreground: var(--foreground);
  --muted:           var(--sunken);
  --input:           var(--border);

  color: var(--body);
  background: var(--background);
}

/* ---- Dark ----
   Whole surface sits at hue 220, grounds and text together. --sunken goes
   DOWN from the ground here where on light it goes down in lightness too, so
   a well reads as a well on both. --panel on dark is the sunken ground,
   because a darker block on an already dark page is the same gesture. */
.surface-dark,
[data-surface="dark"],
[data-slide][data-theme="dark"] {
  /* grounds */
  --background: #131416;
  --surface:    #1A1B1E;
  --sunken:     #0C0C0E;
  --block:      #25282C;
  --hair:       rgb(255 255 255 / 0.10); /* one alpha hair, correct on ground, card and sunken alike */
  --border:     #32363E;

  /* text */
  --foreground:       #F7F6F2;
  --body:             #D8DADE;
  --muted-foreground: #ACB0B9;
  --tert:             #848A94;

  /* accent — on dark the green IS the accent type colour, so --ink is green */
  --accent: #D3FA9D;
  --ink:    #D3FA9D;
  --wash:   #21242A;

  /* panel */
  --panel:            #0C0C0E;
  --panel-foreground: #D8DADE;
  --panel-ink:        #D3FA9D;

  /* contrast pairs */
  --primary-foreground: #131416;
  --accent-foreground:  #131416;

  /* status: mark, text, ground. Same three roles as --accent / --ink / --wash */
  --success:       #00DB71;
  --success-ink:   #00C465;
  --success-wash:  #112B1B;
  --warning:       #FFB329;
  --warning-ink:   #E49D00;
  --warning-wash:  #322209;
  --danger:        #FF9498;
  --danger-ink:    #FF878D;
  --danger-wash:   #391C1B;
  --info:          #7BBDFF;
  --info-ink:      #5EAFFF;
  --info-wash:     #12273A;
  --pending:       #D3FA9D; /* the brand green itself, it already reads on dark. D18 */
  --destructive:            var(--danger-ink);
  --destructive-foreground: var(--background);

  /* chart series: 1 follows --ink, charcoal on light and green on dark */
  --chart-1: var(--ink);
  --chart-2: #88C3FF;
  --chart-3: #FF9FA2;
  --chart-4: #C9ACFF;
  --chart-5: #00D9D4;

  /* interaction states */
  --surface-hover: var(--block);
  --border-hover:  #3F444C;
  --primary-hover: #E0DFDC;
  --accent-hover:  #C0E390;

  /* aliases, restated */
  --primary:         var(--foreground);
  --card:            var(--surface);
  --card-foreground: var(--foreground);
  --muted:           var(--sunken);
  --input:           var(--border);

  color: var(--body);
  background: var(--background);
}

/* =========================================================================
   Aline Design System — Theme
   Semantic text styles and utilities. Pulls in the values it styles with.
   Import this file and you get the whole system; import tokens.css alone if
   you only want the variables (Tailwind consumers usually do).
   ========================================================================= */

/* =========================================================================
   Semantic text styles

   Four text levels, not two. v1 ran --foreground at 16:1 and
   --muted-foreground at 4.5:1 with nothing between, so anything secondary
   fell off that cliff and read as switched off. That is why running text on
   the site kept getting set to --foreground and the muted token went unused.

     --foreground        headings
     --body              running text, the DEFAULT for a paragraph
     --muted-foreground  genuinely secondary, one notch down
     --tert              labels and metadata, 12px and up. Eyebrows are the
                         exception, 10 to 11px caps where the tracking and
                         uppercase carry the legibility

   Headings set their colour explicitly. The page default is --body, so a
   heading that inherited would quietly drop a level.

   Headings use Inter Tight with tighter tracking than body (house rule).
   NEVER end a heading with a period.
   ========================================================================= */

html { font-family: var(--font-sans); color: var(--body); background: var(--background); }
body { font: 400 var(--text-base)/var(--leading-normal) var(--font-sans); color: var(--body); background: var(--background); -webkit-font-smoothing: antialiased; font-feature-settings: "rlig" 1, "calt" 1; }

/* 2.5rem is the one size on this page that is not a step on the scale. It is
   the fluid FLOOR of the display line, half a step above --text-4xl and half
   below --text-5xl, and both of those are wrong: 4xl makes the display line
   the same size as h1 on a phone, 5xl makes it 20% bigger than it is today. */
.h-display, h1.display {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: clamp(2.5rem, 6vw, var(--text-7xl));
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--foreground);
}
h1, .h1 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: clamp(var(--text-4xl), 4.5vw, var(--text-6xl));
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--foreground);
}
h2, .h2 {
  font-family: var(--font-display);
  font-weight: var(--weight-heading);
  font-size: clamp(var(--text-3xl), 3vw, var(--text-4xl));
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--foreground);
}
h3, .h3 {
  font-family: var(--font-display);
  font-weight: var(--weight-heading);
  font-size: var(--text-2xl);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-snug);
  color: var(--foreground);
}
h4, .h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-heading);
  font-size: var(--text-xl);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-snug);
  color: var(--foreground);
}

/* The 18px heading. A card title, a subhead, a sidebar label: heading weight
   and family at body size, which is the one step the ladder was missing and
   the one place a consumer was forced to restate the system inline. Three
   card titles on aline.no and the WorkCard kit all carried the same six
   declarations because this rule did not exist. Semantic level and visual
   level are separate, so a card title stays <h3 class="h5"> where the
   document outline needs an h3. */
h5, .h5 {
  font-family: var(--font-display);
  font-weight: var(--weight-heading);
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-snug);
  color: var(--foreground);
}

/* Uppercase owns its own tracking, because the transform is what creates the
   need for it. Written as two classes a consumer would have to restate tracking
   as a utility on a heading, which is exactly what the type rule forbids, so
   .caps carries both. */
.caps {
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
}

/* The eyebrow is accent-role type, so it reads --ink: charcoal on light,
   brand green on dark. Written once, correct on both. Small, thin mono caps
   at --tracking-widest. Declared after .caps so .eyebrow.caps keeps the
   eyebrow's wider tracking. */
.eyebrow {
  font: var(--type-eyebrow);
  text-transform: uppercase;
  letter-spacing: var(--tracking-widest);
  color: var(--ink);
}

p, .p {
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--body);
  text-wrap: pretty;
}
.p-sm { font-size: var(--text-sm); line-height: var(--leading-normal); }
.p-xs { font-size: var(--text-xs); line-height: var(--leading-normal); }

/* The two levels below --body. Use --tert at 12px and up only. */
.p-muted { color: var(--muted-foreground); }
.p-tert  { color: var(--tert); }

.lede {
  font-size: var(--text-xl);
  line-height: var(--leading-relaxed);
  color: var(--foreground);
}

code, kbd, .mono {
  font-family: var(--font-mono);
  font-size: 0.95em;
}

a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 2px; }

/* =========================================================================
   Utilities
   ========================================================================= */

/* Two weights of line, deliberately. --hair is the rule INSIDE a component,
   --border is the edge AROUND one. Using one for both is what makes a card
   grid look like a spreadsheet. */
.u-divider   { border-top: 1px solid var(--hair); }
.u-rule      { border-top: 1px solid var(--border); }
.u-border    { border: 1px solid var(--border); }
.u-container { max-width: var(--rail-site); margin-inline: auto; padding-inline: clamp(var(--gutter), 4vw, var(--gutter-lg)); }

/* The dark block inside a light layout: callout, active phase card, CTA block.
   This is the only place the brand green appears as TYPE on a light page,
   which is what --panel-ink is for. Reassigns the text tokens so anything
   inside is correct without branching.

   It does not reassign --border or --hair. A panel that needs rules or an
   edge inside it wants the complete dark token set, so use .surface-dark
   instead: .panel is the block, .surface-dark is a surface. */
.panel {
  --background: var(--panel);
  --foreground: var(--panel-foreground);
  --body:       var(--panel-foreground);
  --ink:        var(--panel-ink);
  background: var(--panel);
  color: var(--panel-foreground);
}

/* Focus ring — always brand green, on both surfaces */
:focus-visible { outline: 2px solid var(--ring); outline-offset: var(--ring-offset); }
