/* ============================================================
   tokens.css — THE BRAND CONTRACT  (Bifrost 2.0)
   ------------------------------------------------------------
   The complete set of design tokens every medium engine
   (deck-core.css, doc-core.css) consumes, plus a neutral
   greyscale default so the system renders on its own.

   A brand pack (brands/<brand>/…) re-declares the --c-* colour
   tokens and the --font-* roles to re-skin the whole system.
   Brands touch ONLY the "BRAND-OVERRIDABLE" groups below.
   Everything else — type scale, spacing, rules — is shared
   structure.

   ── Naming note (2.0) ────────────────────────────────────────
   The colour names now mirror the Figma variable roles in
   "Bifrost 2.0 | Brand Resources" one-to-one, so a value can be
   traced from Figma to CSS without a lookup table:

     Figma                  CSS
     Background/Base    →   --c-bg-base
     Background/Core    →   --c-bg-core
     Background/Highlight → --c-bg-high
     Ink/100%           →   --c-ink
     Ink/Tint 1..4      →   --c-ink-1 .. --c-ink-4
     Accent/100%        →   --c-accent
     Accent/80..20%     →   --c-accent-80 .. --c-accent-20

   Legacy 1.0 names (--c-surface, --c-fg, --c-paper,
   --c-shade-*) are kept as aliases at the bottom of the colour
   group so existing artifacts and brand packs keep rendering.
   New work should use the 2.0 names.

   Token groups:
     1. Colour contract   (--c-*)          ← brands override
     2. Type family       (--font-*)       ← brands override
     3. Type scale        (--fs-*, --lh-*, --tr-*)
     4. Spacing scale     (--s-*)
     5. Rules / radii / motion             ← brands may override radii
   Spec: reference/BRAND-PACK.md
   ============================================================ */

:root {
  /* ========================================================
     1. COLOUR CONTRACT  — BRAND-OVERRIDABLE
     --------------------------------------------------------
     Semantic, brand-neutral names. A brand may declare private
     raw vars (e.g. --bf-orange) but must map them onto THESE
     names. No brand ever references another brand's raw palette.
     Defaults below are a neutral warm greyscale.
     ======================================================== */

  /* --- Backgrounds: three plates, Base is the ground --------
     In 2.0 the plates get LIGHTER as they come forward:
     Base (the page/slide ground) → Core → Highlight (brightest).
     This inverts 1.0, where surface-2 was a darker "depth"
     tint. Cards now sit lighter than the ground, not darker. */
  --c-bg-base:   #DED9D6;   /* the ground: every slide + page   */
  --c-bg-core:   #EFEBE9;   /* cards, plates, table fills       */
  --c-bg-high:   #F4F1EF;   /* brightest plate; knockout type   */

  /* --- Ink: one colour, four tints -------------------------
     Tints are alpha, not mixed hex, so they hold over any
     plate or photograph. A brand overrides all five. */
  --c-ink:       #000000;                 /* Ink/100% — body, display, rules */
  --c-ink-1:     rgba(0, 0, 0, 0.60);     /* Ink/Tint 1 — dimmed prose       */
  --c-ink-2:     rgba(0, 0, 0, 0.40);     /* Ink/Tint 2 — secondary prose    */
  --c-ink-3:     rgba(0, 0, 0, 0.20);     /* Ink/Tint 3 — eyebrows, labels   */
  --c-ink-4:     rgba(0, 0, 0, 0.10);     /* Ink/Tint 4 — ghost arcs, plates */

  /* --- The inverse ground -----------------------------------
     Ink, but as a PLATE, resolved once here at the root.
     Why it has to exist: a rule that inverts a region reassigns
     --c-ink on the very element it paints, and custom-property
     substitution uses the value declared ON that element — so
     `background: var(--c-ink); --c-ink: var(--c-bg-base);` in one
     rule paints bone, not black. Verified in Chromium. Any rule
     that flips ink must paint its plate from this token, which
     nothing downstream reassigns. Used by deck-core's
     .slide--dark and by ui-core's inverted mode. */
  --c-ground-inverse: var(--c-ink);

  /* Ink FOR that inverse ground, and its two web stops (60/20 —
     the inverted ramp has no 40% and no 10%). The web source names
     this Inverted Primary and sets it to pure white on the three
     light-ground brands and to the deep green on the dark-ground
     one; it is the one place the family does use white. Defaults
     to the brightest plate so a brand that never declares it
     still inverts sensibly. */
  --c-ink-inverse:   var(--c-bg-core);
  --c-ink-inverse-1: color-mix(in srgb, var(--c-ink-inverse) 60%, transparent);
  --c-ink-inverse-3: color-mix(in srgb, var(--c-ink-inverse) 20%, transparent);

  /* --- The COPY ink -----------------------------------------
     A second ink, for running text, and on most brands it is the
     same colour as the first. It exists because one brand's ink is
     a saturated mid-tone: legible as a 128px title, not legible as
     14px prose. The web source solves that with a separate ramp
     (Colors/Black, Black 60, Black 20) which appears on that brand
     only, and body text and links are bound to it. Defaults to the
     ink ramp, so on a brand where the two agree nothing changes.
     Stops mirror the ink tints: -1 is 60%, -3 is 20%. */
  --c-ink-body:   var(--c-ink);
  --c-ink-body-1: var(--c-ink-1);
  --c-ink-body-3: var(--c-ink-3);

  /* --- The footer watermark ---------------------------------
     A 10% ink, and the only 10% on the web side — the web ramp is
     100/60/40/20 and has no 10% step, so the oversized footer
     logotype could not otherwise be expressed. NOT derivable from
     the ink ramp either: on the brand whose ink is a saturated
     mid-tone the source still specifies 10% BLACK here, not 10% of
     that ink. Defaults to the print 10% tint, which is byte-correct
     on three of the four Bifrost brands and visibly wrong on the
     fourth — which is why the brand packs emit it. */
  --c-footer-logo: var(--c-ink-4);

  /* --- Accent: signature colour + an opacity ramp -----------
     Defaults to ink so a monochrome brand stays monochrome.
     NOTE: the Bifrost deck templates use accent almost nowhere
     — it lives in the logomark and in document story accents.
     Reach for ink and its tints first; accent is a signal, not
     a decoration. See reference/AUTHORING.md. */
  --c-accent:    var(--c-ink);
  --c-accent-80: color-mix(in srgb, var(--c-accent) 80%, transparent);
  --c-accent-60: color-mix(in srgb, var(--c-accent) 60%, transparent);
  --c-accent-40: color-mix(in srgb, var(--c-accent) 40%, transparent);
  --c-accent-20: color-mix(in srgb, var(--c-accent) 20%, transparent);

  /* --- Legacy 1.0 aliases (do not use in new work) ---------- */
  --c-surface:   var(--c-bg-base);
  --c-surface-2: var(--c-bg-core);
  --c-paper:     var(--c-bg-high);
  --c-fg:        var(--c-ink);
  --c-muted:     var(--c-ink-2);
  --c-shade-12:  var(--c-ink-4);
  --c-shade-24:  var(--c-ink-3);
  --c-shade-64:  var(--c-ink-1);

  /* ========================================================
     2. TYPE FAMILY  — BRAND-OVERRIDABLE
     --------------------------------------------------------
  /* The DISPLAY WEIGHT, and it is brand-overridable for a licensing
     reason rather than a stylistic one. 400 is the default because
     most display faces own a Regular. One of the Bifrost display
     faces does not: it is licensed in Light 300 and Medium 500 only,
     and because the house sets `font-synthesis: none` (correctly —
     nobody wants a faked weight) asking for 400 renders the MEDIUM
     rather than falling back to the Light. Measured in Chromium at
     64px: "Handgloves" came out 345.02px against the 338.56px the
     Figma draws. Every display title on that brand was one weight too
     heavy, which is the kind of error that looks like nothing and
     reads as the wrong brand. */
  --fw-display: 400;

  /* ========================================================
     TYPEFACES
     --------------------------------------------------------
     Three roles. --font-display and --font-sans may be the
     same family or two; --font-logo is the wordmark face and
     is only ever used inside a lockup or a display watermark.

     A brand FAMILY may override --font-display per sub-brand:
     Bifrost Forge sets titles to GT Standard while its siblings
     use Concrette M. That is why --font-display is declared in
     the sub-brand layer, not the house layer.
     ======================================================== */
  --font-display: -apple-system, BlinkMacSystemFont, "Segoe UI",
                  system-ui, "Helvetica Neue", Arial, sans-serif;
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI",
               system-ui, "Helvetica Neue", Arial, sans-serif;
  --font-logo: var(--font-display);
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Tracking, as a brand-set value. Concrette M runs at -6%;
     GT Standard runs at 0%. A sub-brand that switches its
     display face must switch its display tracking with it. */
  --tr-display: -0.06em;
  --tr-body:     0;

  /* ========================================================
     3. TYPE SCALE
     --------------------------------------------------------
     Deck canvas is 1920x1080 in 2.0 (was 1600x900 in 1.0), so
     these px values map 1:1 onto the Figma source. Document
     scale is separate and lives in the --fsd-* group.
     ======================================================== */

  /* Deck display sizes, straight off the Figma slide set */
  --fs-d-hero:   380px;  /* title-contents monster title      */
  --fs-d-statement: 275px; /* divider headline                */
  --fs-d-xl:     200px;  /* title-paragraph density A         */
  --fs-d-lg:     166px;  /* standard slide title              */
  --fs-d-md:     100px;  /* title in a column / dense slide   */

  /* Deck body + data sizes */
  --fs-value:     64px;  /* chart value label                 */
  --fs-figure:    50px;  /* mosaic figure                     */
  --fs-lead:      30px;  /* contents list                     */
  --fs-body:      23px;  /* THE deck body size — one size     */
  --fs-label:     24px;  /* chart + diagram labels            */
  --fs-micro:     17px;  /* diagram column labels             */

  /* Document (A4) scale — 1190x1684 canvas */
  --fsd-title:   108px;  /* document cover title              */
  --fsd-h2:       40px;  /* section heading                   */
  --fsd-h3:       36px;  /* numbered section heading          */
  --fsd-letter:   28px;  /* letterhead body                   */
  --fsd-body:     20px;  /* THE document body size            */

  /* Line heights */
  --lh-display: 0.95;  /* every Concrette / display setting   */
  --lh-tight:   1.00;
  --lh-snug:    1.20;  /* deck body, labels                   */
  --lh-body:    1.50;  /* document body                       */
  --lh-letter:  1.60;  /* letterhead body                     */
  --lh-loose:   2.30;  /* standalone contents list            */

  /* ========================================================
     4. SPACING SCALE
     --------------------------------------------------------
     The 2.0 templates are built on a 40px module: 40 is the
     margin, the gutter, and the gap between blocks. --s-gap
     and --s-margin are the two that carry the layouts.
     ======================================================== */
  --s-1:  4px;
  --s-2:  8px;
  --s-3: 14px;
  --s-4: 20px;
  --s-5: 30px;
  --s-6: 40px;    /* THE module: margin, gutter, block gap    */
  --s-7: 60px;
  --s-8: 80px;    /* document block gap, wide gutter          */
  --s-9: 120px;
  --s-10: 160px;

  --s-margin: var(--s-6);   /* slide + page outer margin       */
  --s-gap:    var(--s-6);   /* default gap between blocks      */

  /* ========================================================
     5. RULES / RADII / MOTION
     --------------------------------------------------------
     Two stroke weights, deliberately. Structural line work —
     table rules, arch arcs, section rules — is 2px. Chart and
     diagram line-art is 1px, so data never out-shouts
     structure. Do not invent a third weight.
     ======================================================== */
  --rule-w:       2px;    /* structural: table, arch, section  */
  --rule-w-fine:  1px;    /* chart + diagram line-art          */

  /* Radii — BRAND-OVERRIDABLE.
     The deck and document templates are square: --radius-card
     is 0 for every Bifrost brand in print and on screen-as-
     paper. Corner rounding IS a brand differentiator, but only
     on the WEBSITE, which is why --radius-web exists separately
     and no deck primitive consumes it. Studios and Forge round
     more; Group and Partners stay near-straight. Never round a
     deck plate to "match the website" — the notes are explicit
     that no curve reads better at slide scale. */
  --radius-0:     0;
  --radius-card:  0;       /* plates, tables, photo frames     */
  --radius-soft:  4px;     /* portrait placeholders only       */
  --radius-web:   0;       /* website surfaces; brands raise it */
  --radius-pill:  999px;   /* dots, bubbles, tag pills          */

  /* The website has TWO named radii, not a ramp: one for
     component backgrounds (cards, fields, plates) and one for
     buttons. On some brands they differ — 20px vs 30px — so a
     single --radius-web cannot express the difference. Both
     default to the square contract; brand packs set them. The
     ui medium consumes these; deck and document never do. */
  --radius-component: var(--radius-web);
  --radius-button:    var(--radius-web);

  --ease:      cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur-fast:  120ms;
  --dur-base:  240ms;
  --dur-slow:  480ms;
}

/* ============================================================
   BASE ELEMENTS — consume the contract, brand-neutral
   ============================================================ */
html { color-scheme: light; }

body {
  margin: 0;
  background: var(--c-bg-base);
  color: var(--c-ink);
  font-family: var(--font-sans);
  font-weight: 300;
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ------------------------------------------------------------
   Display type.
   Every display setting in 2.0 is the same recipe: the brand's
   display face, its display tracking, 0.95 line-height. Only
   the size changes. Cap-trim (below) is what makes a CSS
   heading sit where the Figma frame says it should.
   ------------------------------------------------------------ */
.h-display, .h1, .h2, .h3,
h1, h2, h3 {
  font-family: var(--font-display);
  /* NOT a literal 400. A brand's display face may not own that weight:
     one of the Bifrost display faces is licensed in Light 300 and
     Medium 500 only, and `font-synthesis: none` means asking for 400
     silently renders the MEDIUM. Measured in Chromium at 64px:
     "Handgloves" came out 345.02px wide against the 338.56px the file
     draws, so every display title on that brand was one weight too
     heavy and 1.9% too wide. The brand pack declares what it owns. */
  font-weight: var(--fw-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
  color: var(--c-ink);
  margin: 0;
  text-wrap: balance;
  /* Figma trims display text to the cap box. Without this the
     first line sits ~0.15em low and every measured y drifts. */
  text-box: trim-both cap alphabetic;
}

.h-display { font-size: var(--fs-d-lg); }
h1, .h1    { font-size: var(--fs-d-lg); }
h2, .h2    { font-size: var(--fs-d-md); }
h3, .h3    { font-size: var(--fsd-h2); }

p, .p {
  font-family: var(--font-sans);
  font-weight: 300;
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-body);
  color: var(--c-ink);
  text-wrap: pretty;
  margin: 0;
}

/* Label — the workhorse UI setting: diagram labels, chart
   categories, eyebrows. Medium weight, never dimmed by default. */
.label {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-body);
  color: var(--c-ink);
}

/* Eyebrow — the small tint-3 line above a label. The 2.0
   templates use this constantly: a date over a name, a role
   under a name, a category under a figure. */
.eyebrow {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  color: var(--c-ink-3);
}

/* Meta / caption — running furniture, footers, page numbers */
.meta {
  font-family: var(--font-sans);
  font-weight: 300;
  font-size: var(--fsd-body);
  line-height: var(--lh-tight);
  color: var(--c-ink-3);
  letter-spacing: var(--tr-body);
}

.caption, small {
  font-family: var(--font-sans);
  font-weight: 300;
  font-size: var(--fs-micro);
  line-height: var(--lh-snug);
  color: var(--c-ink-3);
  letter-spacing: var(--tr-body);
}

code, .code {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: 0.92em;
  color: var(--c-ink);
  background: var(--c-bg-core);
  padding: 0.1em 0.35em;
  border-radius: var(--radius-0);
}

strong, b { font-weight: 500; }
em { font-style: italic; }

hr, .rule { border: 0; border-top: var(--rule-w) solid var(--c-ink); margin: 0; }
.rule-fine { border-top-width: var(--rule-w-fine); }
.rule-soft { border-top-color: var(--c-ink-3); }
