/* =============================================================================
   cal — CANONICAL BRAND TOKENS
   -----------------------------------------------------------------------------
   Single source of truth. Hardcoded from:
     brand/CAL-BRAND-SYSTEM.md  (v3, 2026-07-13)
     brand/cal-brand-system.html (visual brand book :root)
     native/ios/CalApp/Sources/CalApp/Support/CalTheme.swift (shipping native)

   Version: 2.0 (brand v4), 2026-09-17. Previous: 1.1, locked 2026-08-06.
   v4 changes the TYPE SYSTEM only. Every colour, size, space, radius, shadow
   and motion value below is unchanged from 1.1. Decision record:
     brand/v4/DECISION-2026-09-17-direction.md
   Composed reference page: brand/v4/cal-brand-v4.html
   Supersedes: packages/ui/src/tokens.css (which mirrored the LEGACY live site:
               Fraunces / Inter / IBM Plex Mono, --dim #6b6b6b).

   GROUND RULES (from the brand system, do not violate):
     - One green accent. Green means "this answer is sourced." Never a second green.
     - Green is a MARKER, never a letter. No green text, no green brackets.
       ONE EXCEPTION, granted 2026-08-06 and scoped deliberately narrow:
       the hero Turn's second line (.turn__b) may be set in --green-deep
       italic, at display size, once per page, on marketing surfaces only.
       Forbidden inside the workbench, inside any document artifact, in
       email, and anywhere below display size. See --green-deep below.
     - No gradients, no gloss, no 3D, no shadows. Hairlines and negative space only.
     - Warm paper, never pure white. Warm near-black, never pure black.
     - Radius 0. cal is rectangular.
     - Amber is a fill/marker with ink on top. NEVER amber text on paper (1.94:1).
     - No em dashes in user-facing copy.
     - No gradients, ever, including as an "AI" cue. (v4)
     - No monospace voice. Citations, kickers, dates and section refs are set
       in the sans. A real monospace is kept only for code. (v4)
   ============================================================================= */

/* ---- FONTS -----------------------------------------------------------------
   SELF-HOSTED in packages/ui/fonts/ (see its README for licences). The URLs are
   relative to this file, so they resolve under the /packages/ui/ nginx alias on
   every VPS surface and under ../../packages/ui/ in a local checkout. No page
   needs a Google Fonts <link> for the brand faces any more.
     Zodiak            ITF Free Font License. Served exactly as downloaded:
                       the licence forbids subsetting and format conversion.
     Schibsted Grotesk SIL OFL 1.1.
   --------------------------------------------------------------------------- */
@font-face { font-family: 'Zodiak'; src: url('../fonts/Zodiak-Variable.woff2') format('woff2');
             font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: 'Zodiak'; src: url('../fonts/Zodiak-VariableItalic.woff2') format('woff2');
             font-weight: 100 900; font-style: italic; font-display: swap; }
@font-face { font-family: 'Schibsted Grotesk'; src: url('../fonts/SchibstedGrotesk-Variable.woff2') format('woff2');
             font-weight: 400 900; font-style: normal; font-display: swap; }
@font-face { font-family: 'Schibsted Grotesk'; src: url('../fonts/SchibstedGrotesk-VariableItalic.woff2') format('woff2');
             font-weight: 400 900; font-style: italic; font-display: swap; }

:root {

  /* ==== TYPEFACES ==== v4: two brand families, three roles. Do not add a third. */
  --serif:    'Zodiak', 'Source Serif 4', Georgia, 'Times New Roman', serif;
  --wordmark: var(--serif);   /* the logotype: Zodiak 700, tracking -0.015em */
  --sans:     'Schibsted Grotesk', system-ui, -apple-system, 'Helvetica Neue', sans-serif;
  --cite:     var(--sans);    /* the citation layer (v4) */
  --code:     ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --mono:     var(--cite);    /* LEGACY NAME, repointed in v4. ~700 rules across the
                                 product use var(--mono) for kickers, eyebrows, dates and
                                 citations: that layer is now the sans, per Chris
                                 2026-09-17. Real code keeps a monospace through the
                                 code/pre/kbd/samp rule at the bottom of this file. */

  /* wordmark  = the cal / AskCal logotype ONLY. Never a heading, never UI.
     serif     = display, the answer verdict, quoted guideline text, section
                 references (italic), and proof numerals (lining figures).
     sans      = everything structural: Ask, tags, headings, body, labels,
                 forms, financial numbers (tabular-nums inside columns only),
                 AND the citation layer: effective dates, doc IDs, hashes, kickers.
     code      = code, commands and JSON. Nothing else. */

  /* per-face tuning */
  --wm-weight: 700;          --wm-tracking: -0.015em;
  --display-weight: 400;

  /* ==== CORE PALETTE ==== contrast measured vs --paper / --paper-inset */
  --paper:        #F3F1EC;   /* page + app background. warm off-white.        */
  --paper-inset:  #ECE9E1;   /* cards, wells, inputs. one step down.          */
  --paper-raised: #FBFAF6;   /* raised surface. a hair above paper.           */
  --ink:          #1A1A1A;   /* primary text + the brackets. 15.42 / 14.35 AAA */
  --ink-muted:    #6A655C;   /* secondary text.              5.13 /  4.77 AA  */
  --ink-faint:    #8C877D;   /* placeholders, captions.      3.17 /  2.95 — NON-TEXT / LARGE ONLY */
  --hairline:     #E3DFD6;   /* dividers, borders.           1.18 /  1.10 — DECORATIVE ONLY, never text */
  --hairline-strong: #B9B3A6;/* UI borders needing 3:1.      2.44 /  2.27 — see note below */

  /* ==== THE GREEN ==== the single brand accent. Means: sourced. */
  --green:        #2D6A4F;   /* the answer, brand accent, approved. 5.66 / 5.27 AA text */
  --green-strong: #1D8A5C;   /* large marks + headline numerals ONLY. 3.84 / 3.57 */
  --green-dark:   #3F9069;   /* the answer in DARK MODE. 4.48 on ink — large text / UI only */
  --green-deep:   #1B4332;   /* THE HERO TURN ONLY. 9.81 / 9.13 — the single sanctioned
                                instance of green as a letter. Never use elsewhere. */
  --green-hover:  #245640;   /* v4: interactive states are steps of the one green */
  --green-active: #1B4332;

  /* ==== STATUS ==== quiet, never the brand. Always paired with an icon or label. */
  --status-approved: #2D6A4F; /* reuse the answer green so green means approval everywhere */
  --status-alert:    #E6A23C; /* amber. FILL/MARKER ONLY with ink on top (7.95). Never text on paper. */
  --status-action:   #1E5FA6; /* the only blue, demoted to status. 5.74 / 5.34 AA text */
  --status-declined: #B42318; /* muted brick. 5.82 / 5.42 AA text */
  --focus:           #1E5FA6; /* focus ring reuses the action blue */

  /* washes — tinted surfaces. A surface may ONLY be tinted to carry a status. */
  --green-wash:    #E7EFE9;
  --alert-wash:    #FAF0DE;
  --action-wash:   #E7EEF8;
  --declined-wash: #F8EAE8;

  /* ==== TYPE SCALE ==== base 16px. 11 sizes. Floor 12px. */
  --fs-wordmark: 40px;  /* 40 to 64. logotype only. */
  --fs-display:  clamp(2rem, 5.2vw, 3.25rem);   /* 32 → 52. Zodiak. The answer headline. */
  --fs-h1:       28px;  /* Schibsted 600 */
  --fs-h2:       22px;  /* Schibsted 600 */
  --fs-h3:       18px;  /* Schibsted 600 */
  --fs-lead:     19px;  /* Schibsted 400 */
  --fs-body:     15px;  /* Schibsted 400 — brand default UI body */
  --fs-body-lg:  16px;  /* Schibsted 400 — long-form reading */
  --fs-label:    13px;  /* Schibsted 500 — buttons, tags, nav */
  --fs-citation: 12px;  /* Schibsted (the cite layer) — §refs, IDs, effective dates */
  --fs-micro:    12px;  /* Schibsted — hashes, timestamps. HARD FLOOR. */

  --lh-wordmark: 1.05;  --lh-display: 1.1;   --lh-h1: 1.2;
  --lh-h2: 1.25;        --lh-body: 1.55;     --lh-label: 1.4;  --lh-citation: 1.5;
  --ls-display: -0.018em; --ls-tight: -0.01em; --ls-normal: 0; --ls-caps: 0.08em;

  /* v4 additions. Tracking curve after apple.com (2026-09-17): negative at label
     size, slightly positive through the lead, negative again at display. */
  --fs-turn:     clamp(36px, 5.85vw, 84px);   /* the hero Turn. Marketing only. */
  --fs-numeral:  clamp(48px, 7vw, 96px);      /* proof numerals, serif, one row per surface */
  --ls-label:   -0.012em;    /* 13 to 14px sans */
  --ls-lead:     0.01em;     /* 19 to 28px sans */
  --ls-turn:    -0.02em;     /* the Turn only */
  --ls-kicker:   0.12em;     /* caps kickers and index numbers */

  /* ==== SPACING ==== 4px base */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px;
  --s6:32px; --s7:48px; --s8:64px; --s9:96px; --s10:128px;

  /* ==== RADIUS ==== SHARP. cal is rectangular. */
  --r-0: 0; --r-sm: 0; --r-md: 0; --r-lg: 0;
  --r-full: 9999px;   /* status dots and avatars ONLY */

  /* ==== SHADOWS ==== none. Use hairlines. */
  --shadow-sm: none; --shadow-md: none;

  /* ==== MOTION ==== transform + opacity only. Never animate layout. Micro moves 100-300ms;
     signature moments (hero set, scroll arrivals, chart draw-in) run longer, play once,
     never loop. See brand/CAL-BRAND-SYSTEM.md section 8. */
  --dur-fast: 100ms; --dur-base: 180ms; --dur-slow: 300ms;
  --ease: cubic-bezier(.22,.61,.36,1);

  /* ==== LAYOUT ==== */
  --max: 1140px; --max-prose: 68ch; --max-narrow: 46ch;
  /* breakpoints, mobile-first: 480 / 720 / 960 / 1200. Nothing else. */

  /* ==== MARK GEOMETRY ==== all values key off mark height M */
  --mark-stroke-ratio: 0.16;  /* bracket stroke   */
  --mark-square-ratio: 0.14;  /* green square     */
  --mark-gap-ratio:    0.40;  /* mark → wordmark  */
  --mark-tag-ratio:    0.60;  /* product tag : cal */
  --mark-min: 20px;           /* below this, mark alone */
}

/* ==== DARK MODE ==== */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --paper:        #1A1A1A;
    --paper-inset:  #141312;
    --paper-raised: #242422;
    --ink:          #F3F1EC;
    --ink-muted:    #C4C0B6;
    --ink-faint:    #8C877D;
    --hairline:     #3A3833;
    --hairline-strong: #5A574F;
    --green:        #3F9069;   /* lifted for contrast on ink */
    --green-strong: #4FA67C;
    --green-hover:  #4FA67C;
    --green-wash:   #17251D;
    --status-approved: #3F9069;
    --status-action:   #7FA9E8;
    --status-declined: #E08585;
    --focus:           #7FA9E8;
    --action-wash:  #161D29;
    --alert-wash:   #2A2113;
    --declined-wash:#2A1717;
  }
}
[data-theme="dark"] {
  color-scheme: dark;
  --paper:#1A1A1A; --paper-inset:#141312; --paper-raised:#242422;
  --ink:#F3F1EC; --ink-muted:#C4C0B6; --ink-faint:#8C877D;
  --hairline:#3A3833; --hairline-strong:#5A574F;
  --green:#3F9069; --green-strong:#4FA67C; --green-hover:#4FA67C; --green-wash:#17251D;
  --status-approved:#3F9069; --status-action:#7FA9E8; --status-declined:#E08585;
  --focus:#7FA9E8; --action-wash:#161D29; --alert-wash:#2A2113; --declined-wash:#2A1717;
}

/* ==== NIGHT ==== the signed-in app (Command Center and its tools). 2026-10-03.
   Decision record: brand/v5-night/DECISION-2026-10-03-night.md.

   SCOPE: only a page that sets <html data-theme="night">. Today that is
   apps/copilot. askcal.io, every other subdomain, every document, email and
   share card stay on the paper brand above, unchanged.

   Night breaks four paper rules on purpose, and only inside that scope:
     1. Radius. The app is rounded: --r-sm / --r-md / --r-lg / --r-xl carry
        real values here. Pills use --r-full.
     2. A third typeface. Bricolage Grotesque (SIL OFL 1.1, self-hosted) sets
        display headings through --display. Zodiak keeps the wordmark and the
        italic section references; Schibsted Grotesk keeps everything else.
     3. The green. On a dark ground the one green is #57E08A, the dark value of
        the same accent. It has four jobs and no others: the primary action,
        the cited square, the live dot, and the verdict word (--signal, the one
        place it is a letter; the arrow inside the primary action uses it too). Text on a green fill is --on-signal.
     4. Dark first. There is no paper theme inside the app.
   Still true in Night: no gradients, no shadows, no gloss; filled square means
   sourced and hollow square means lender overlay or not verified; amber is a
   fill with dark text on it, never text; 12px type floor.

   Contrast, measured on --paper #0C1210 / --paper-inset #151D19 / --paper-raised
   #1D2822: --ink 16.7 / 15.2 / 13.5, --ink-muted 10.3 / 9.3 / 8.3, --ink-faint
   7.2 / 6.5 / 5.8 (so, unlike paper, faint is real text here), --green 11.2 /
   10.2 / 9.0, --status-declined 9.2 / 8.4 / 7.4, --status-action 9.0 / 8.2 /
   7.2. --on-signal on --green is 11.2 and on amber 8.7.
   --hairline-strong #5C6A61 is 3.3 / 3.0 / 2.7: it is the 3:1 edge for inputs
   (WCAG 1.4.11) on the ground and on a surface, not on surface 2.
   --hairline is decorative only. */
@font-face { font-family: 'Bricolage Grotesque'; src: url('../fonts/BricolageGrotesque-Variable-latin.woff2') format('woff2');
             font-weight: 200 800; font-style: normal; font-display: swap;
             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; }

[data-theme="night"] {
  color-scheme: dark;
  --paper:        #0C1210;   /* the ground */
  --paper-inset:  #151D19;   /* surface: cards, the ask box, wells */
  --paper-raised: #1D2822;   /* surface 2: chips, inputs on a card, menus */
  --night-hover:  #26342C;   /* hover and pressed, one step up again */
  --ink:          #EEF2EE;
  --ink-muted:    #B6C2BA;
  --ink-faint:    #94A399;
  --hairline:     #26332B;
  --hairline-strong: #5C6A61;

  --green:        #57E08A;
  --green-strong: #57E08A;
  --green-dark:   #57E08A;
  --green-deep:   #7BEAA4;   /* in Night this is the hover step, lighter not darker */
  --green-hover:  #7BEAA4;
  --green-active: #45C877;
  --signal:       #57E08A;   /* green as a glyph, the two places Night allows it: the
                                verdict word, and the arrow inside the primary action */
  --on-signal:    #0C1210;   /* text and icons on a green or amber fill */
  --green-print:  #2D6A4F;   /* the paper green, for anything that leaves the app */

  --status-approved: #57E08A;
  --status-alert:    #E6A23C;
  --status-action:   #8AB4F8;
  --status-declined: #FF9A8A;
  --focus:           #8AB4F8;
  --green-wash:    #14261B;
  --alert-wash:    #2B2413;
  --action-wash:   #152030;
  --declined-wash: #2C1917;

  --display: 'Bricolage Grotesque', 'Schibsted Grotesk', system-ui, sans-serif;
  --ls-display: -0.03em;

  --r-sm: 12px; --r-md: 20px; --r-lg: 28px; --r-xl: 36px;
}

/* ==== MODERN ==== ValueGuard, light. 2026-10-07.
   Decision: Chris, 2026-10-07 ("not the vibe, fresh sleek and modern"), light, applied to
   the ValueGuard page and its shareable PDF report.

   SCOPE: only a page or document that sets data-theme="modern". Today that is
   apps/valueguard and the ValueGuard report PDF. Every other surface keeps its theme.

   Modern is the paper brand without the paper: cool white and grey surfaces, one
   sans typeface (Schibsted Grotesk) set tight at display size, rounded cards, and
   hairlines instead of shadows. Zodiak survives only in the wordmark.
   Kept from the brand: one green that means sourced (a marker, a fill with white on
   it, and the verdict mark, never a gradient), filled square = sourced, hollow square
   = not verified, amber is a fill with ink on it, 12px type floor, no gradients, no
   shadows, no gloss, no em dashes.

   Contrast: --ink 18.5 on --paper-raised, --ink-muted 6.2 / 5.8 on raised / paper,
   --green 5.4 on raised and 5.0 on paper, white on --green 5.4. --ink-faint (3.7) is
   non-text only. --hairline-strong is the 3:1 edge for inputs on white. */
:root[data-theme="modern"] {   /* :root[...] so it outranks the prefers-color-scheme dark block above */
  color-scheme: light;
  --paper:        #F5F7F9;   /* the ground, cool */
  --paper-inset:  #EDF0F3;   /* wells, table stripes, inputs at rest */
  --paper-raised: #FFFFFF;   /* cards and sheets */
  --ink:          #0E141B;
  --ink-muted:    #556270;
  --ink-faint:    #7A8794;   /* non-text only */
  --hairline:     #E3E8ED;
  --hairline-strong: #8A96A3;

  --green:        #0B7A4B;
  --green-strong: #0B7A4B;
  --green-dark:   #0B7A4B;
  --green-deep:   #0B7A4B;
  --green-hover:  #09663E;
  --green-active: #075233;
  --on-signal:    #FFFFFF;   /* text on a green fill */

  --status-approved: #0B7A4B;
  --status-alert:    #E6A23C;   /* fill only, ink on top */
  --status-action:   #1D5FD0;
  --status-declined: #B42318;
  --focus:           #1D5FD0;
  --green-wash:    #E6F5EE;
  --alert-wash:    #FDF3E0;
  --action-wash:   #E8EFFB;
  --declined-wash: #FBEBE9;

  --serif:   var(--sans);      /* no serif inside Modern */
  --wordmark: 'Zodiak', Georgia, serif;
  --display: var(--sans);
  --display-weight: 600;
  --ls-display: -0.035em;
  --ls-tight: -0.02em;

  --r-sm: 8px; --r-md: 12px; --r-lg: 16px; --r-xl: 24px;
}

/* ==== GLOBAL BASELINE ==== */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  *,*::before,*::after { animation-duration:1ms!important; transition-duration:1ms!important; }
}
.tabular { font-variant-numeric: tabular-nums lining-nums; }

/* =============================================================================
   NOTES / OPEN ITEMS
   -----------------------------------------------------------------------------
   0. TYPE SYSTEM v4 — DECIDED 2026-09-17. Zodiak (display, wordmark, quoted
      guideline text, section refs, proof numerals) and Schibsted Grotesk
      (everything else, including citations). Newsreader, Geist and Geist Mono
      are retired. --mono now points at the sans; code keeps a real monospace.
      The native bundle in native/ios/CalApp/Sources/CalApp/Resources/Fonts is
      NOT yet re-cut; that is a separate PR.

   1. WORDMARK SERIF — RESOLVED 2026-08-06. Instrument Serif is retired;
      --wordmark aliases --serif (Newsreader). Rationale from §3: Instrument is
      single-weight and high-contrast, so it thinned and read condensed at 36px
      nav and favicon sizes. Three families now. The native app font bundle in
      Sources/CalApp/Resources needs re-cutting to match — see BUILD phase 04.

   2. --ink-faint #8C877D is 3.17:1 on paper. It FAILS AA for normal text.
      Allowed for: placeholders, disabled states, and 24px+ display text.
      For real secondary content use --ink-muted #6A655C (5.13:1).

   3. --green-dark #3F9069 on --ink is 4.48:1, marginally under the 4.5 AA
      threshold for normal text. Use it at 18.66px+ semibold or 24px+, or for
      UI/marker fills. For small dark-mode body text use --ink-muted.

   4. --hairline #E3DFD6 is 1.18:1. It is a DIVIDER, never text and never a
      control border that must meet WCAG 1.4.11 (3:1). Use --hairline-strong
      for input borders; on paper it is 2.44:1, so pair it with an interior
      fill change or bump to --ink-muted where 3:1 is required.

   5. CAL-BRAND-SYSTEM.md flags a typo to fix at source: the board prints the
      green as #2D6AAF (blue). Correct value is #2D6A4F.

   6. LEGACY values now retired. Do not reintroduce:
        Fraunces / Inter / IBM Plex Mono   (old web stack)
        Instrument Serif                   (wordmark, retired 2026-08-06)
        Newsreader / Geist / Geist Mono    (v3 stack, retired 2026-09-17)
        Server Mono                        (no section sign in v1.200)
        --dim #6b6b6b   -> --ink-muted #6A655C   (6b6b6b fails AA at 4.32:1)
        --rule #d8d4c8  -> --hairline  #E3DFD6
        --paper-deep #ebe7dd -> --paper-inset #ECE9E1
        --blue #1f4f9c  -> --status-action #1E5FA6
        --amber #a06820 -> --status-alert #E6A23C (fill only)
   ============================================================================= */


/* =============================================================================
   THE HERO TURN — the one sanctioned instance of green as a letter.
   Marketing surfaces only. Once per page. Never in the workbench or a document.
   ============================================================================= */
.turn        { font-family: var(--serif); font-size: var(--fs-display);
               line-height: 1.05; letter-spacing: var(--ls-display);
               font-optical-sizing: auto; margin: 0; }
.turn__a     { color: var(--ink); display: block; }
.turn__b     { color: var(--green-deep); font-style: italic; display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .turn__b { color: var(--green-dark); }
}
[data-theme="dark"] .turn__b { color: var(--green-dark); }


/* =============================================================================
   v4 BASELINE AND COMPONENTS
   Class names are prefixed cal- on purpose: .cite, .stamp and .idx already
   exist on product pages with other meanings.
   ============================================================================= */

/* Code stays monospace even where a page styles it with var(--mono): the custom
   property is re-declared on the element, so var(--mono) resolves to --code
   inside code, pre, kbd and samp. */
code, pre, kbd, samp { --mono: var(--code); }

.lining { font-variant-numeric: lining-nums proportional-nums; }

/* The wordmark */
.cal-wordmark { font-family: var(--wordmark); font-weight: var(--wm-weight);
                letter-spacing: var(--wm-tracking); line-height: 1; color: var(--ink); }

/* Kicker and index: a green square, then letterspaced caps in the sans */
.cal-idx { font-family: var(--cite); font-weight: 500; font-size: var(--fs-micro);
           letter-spacing: var(--ls-kicker); text-transform: uppercase; color: var(--ink-muted);
           display: flex; gap: 12px; align-items: center; }
.cal-idx::before { content: ""; width: 8px; height: 8px; background: var(--green); flex: none; }

/* The citation, as a marginal note. Never green text. */
.cal-cite      { font-family: var(--cite); font-size: 13px; line-height: 1.5; color: var(--ink);
                 font-variant-numeric: lining-nums; }
.cal-cite__src { font-weight: 600; }
.cal-cite__sec { font-family: var(--serif); font-style: italic; font-size: 17px; line-height: 1.4; }
.cal-cite__quote { font-family: var(--serif); font-size: 17px; line-height: 1.4; }
.cal-cite__meta { display: grid; grid-template-columns: auto 1fr; gap: 0 16px; font-size: var(--fs-micro); }
.cal-cite__meta dt { color: var(--ink-muted); }
.cal-cite__meta dd { margin: 0; font-variant-numeric: tabular-nums; }

/* The square: filled means sourced, hollow means overlay or not yet verified */
.cal-sq { display: inline-block; width: 8px; height: 8px; background: var(--green);
          transition: transform 120ms var(--ease); }
.cal-sq--hollow { background: transparent; outline: 1px solid var(--ink); outline-offset: -1px; }
.cal-sq:hover, .cal-sq:focus-visible { transform: scale(1.28); }

/* The citation as a live object. The marker is the square plus the section
   reference; hovering or focusing it (keyboard gets the same treatment as
   the mouse, on purpose) scales the square and underlines the reference.
   The effective date is composed outside the marker everywhere it is used,
   so it is never part of this and never moves. */
.cal-cite-marker { display: inline-flex; align-items: center; gap: 6px;
                   color: var(--ink); text-decoration: none; }
.cal-cite-marker:hover, .cal-cite-marker:focus-visible { color: var(--ink); text-decoration: none; }
.cal-cite-marker .cal-sq { flex: none; }
.cal-cite-marker:hover .cal-sq,
.cal-cite-marker:focus-visible .cal-sq { transform: scale(1.28); }
.cal-cite-marker .cal-cite__sec { text-decoration: none; text-underline-offset: 2px; }
.cal-cite-marker:hover .cal-cite__sec,
.cal-cite-marker:focus-visible .cal-cite__sec { text-decoration: underline; }

/* The stamp: ink border, caps, green square. Never a green border. */
.cal-stamp { display: inline-flex; align-items: center; gap: 8px; border: 1px solid var(--ink);
             color: var(--ink); font-family: var(--cite); font-weight: 500; font-size: var(--fs-micro);
             letter-spacing: 0.14em; text-transform: uppercase; padding: 6px 10px; }
.cal-stamp::before { content: ""; width: 8px; height: 8px; background: var(--green); }

/* Rules: hierarchy comes from weight */
.cal-rule-hair   { border: 0; border-top: 1px solid var(--hairline); }
.cal-rule-ink    { border: 0; border-top: 1px solid var(--ink); }
.cal-rule-heavy  { border: 0; border-top: 2px solid var(--ink); }
.cal-rule-double { border: 0; border-top: 3px double var(--ink); }

/* A rule drawing in once, on first view: scaleX from the left edge.
   Add .cal-rule-draw to a standalone rule element (an <hr>, a real box -
   not a border property, which can't be transformed independently of
   whatever it belongs to). Fires on load, like the ink-set, never on
   scroll: nothing sits at scaleX(0) waiting on an observer, it is just
   already finished by the time anyone scrolls this far. Transform only,
   per the brief - no opacity here. */
@keyframes cal-rule-draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
.cal-rule-draw { transform-origin: left; animation: cal-rule-draw 300ms var(--ease) both; }
@media (prefers-reduced-motion: reduce) {
  .cal-rule-draw { animation: none; }
}

/* Paper grain: OFF unless a marketing page opts in with <html data-grain="on"> */
html[data-grain="on"] body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0; opacity: 0.035;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.6 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* The ink sets: the one load motion, for the hero Turn on marketing pages.
   Add .cal-ink-set to .turn. Zodiak's weight axis thickens from a hairline. */
@keyframes cal-ink-set {
  from { font-variation-settings: "wght" 150; opacity: 0; }
  to   { font-variation-settings: "wght" 400; opacity: 1; }
}
.turn.cal-ink-set .turn__a,
.turn.cal-ink-set .turn__b { animation: cal-ink-set 640ms cubic-bezier(.16,1,.3,1) both; }
.turn.cal-ink-set .turn__b { animation-delay: 90ms; }
@media (prefers-reduced-motion: reduce) {
  .turn.cal-ink-set .turn__a, .turn.cal-ink-set .turn__b { animation: none; }
}

/* Same signature, generic: any heading may set into the paper on load
   without the hero Turn's markup, its green line, or its marketing-only
   scope. base.css gives h1-h4 weight 500 (not the Turn's 400), so this
   targets 500: the animation's "both" fill holds its last keyframe after
   it ends, and a mismatched target would leave the heading underweight
   forever instead of settling into what it already renders today. */
@keyframes cal-ink-set-heading {
  from { font-variation-settings: "wght" 150; opacity: 0; }
  to   { font-variation-settings: "wght" 500; opacity: 1; }
}
:is(h1, h2, h3, h4).cal-ink-set:not(.turn) {
  animation: cal-ink-set-heading 640ms cubic-bezier(.16,1,.3,1) both;
}
@media (prefers-reduced-motion: reduce) {
  :is(h1, h2, h3, h4).cal-ink-set:not(.turn) { animation: none; }
}
