@import url("https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700&display=swap");

@layer tokens {
  /* ===================================================
     Base Root Tokens – The Gnostic Key
     Version: 2.3  Luxe Base Refresh (2026)
     Notes:
     - Neutral foundation with warm parchment/gold soul
     - Full parity with every pillar theme + dark base
     - Grids left completely untouched as requested
     =================================================== */

  :root {
    /* Typography */
    --font-serif: "Libre Baskerville", serif;      /* editorial body role */
    --font-display: "Cormorant Garamond", serif;   /* display / heading role */
    --page-title: "Cinzel Decorative", serif;      /* page-title role */

    /* Confirmed monospace role: components/accessibility-read-aloud.css
       .read-aloud-guide-shortcut (Batch 5A). */
    --font-mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;

    --font-size-base: 1rem;
    --font-size-vs: 0.8rem;
    --font-size-sm: 1rem;
    --font-size-md: 1.2rem;
    --font-size-lg: 1.5rem;
    --font-size-xl: 1.75rem;
    --font-size-logo: 2rem;
    --font-size-nav: 1.1rem;
    --font-size-toggle: 1.2rem;

    /* UI/label font used by eyebrow, kicker and breadcrumb-style selectors.
       Reviewed for Batch 3A: its ~16 live consumers span site-header
       hierarchy labels, dashboard UI, badges, and page-specific pillar
       eyebrows (gnostic-eye, teachings, zoe-speaks, obsidian-key, gallery,
       forge, shop, community), each sitting under a different ancestor
       font-family context. They cannot be mapped to one unambiguous
       currently rendered font without a full per-consumer audit, so this
       remains `inherit` and stays a transitional token pending that audit. */
    --font-ui: inherit;

    /* Type tokens (single source of truth) */
    --type-body-font: var(--font-serif);
    --type-body-size: 1.25rem;
    --type-body-line: 1.85;
    --type-body-weight: 400;

    --type-copy-size: 1em;
    --type-copy-line: 1.6;

    --type-list-size: 1em;
    --type-list-line: var(--type-copy-line);
    --list-indent: 1.25em;
    --list-gap: 0.55em;

    /* ===================================================
       Semantic typography contract (Batch 3A)
       Canonical size, line-height, weight and tracking roles for the
       whole site. Values are the current effective rendered values of
       each role's clearest live consumer(s), confirmed by inspection —
       no new visual scale was invented. Only typography-scale.css's own
       rules consume these in this batch (body, headings, page titles,
       paragraphs, lists, card titles, badges, links, small text, strong/
       emphasis); every other listed role is defined here as the
       confirmed canonical value for a future consumer-migration batch
       and is not wired into any component, layout or page file yet.
       =================================================== */

    /* Weight roles: the four weights already in live use site-wide. */
    --type-weight-regular: 400;
    --type-weight-medium: 500;
    --type-weight-semibold: 600;
    --type-weight-bold: 700;

    /* Tracking (letter-spacing) roles. */
    --type-tracking-heading: 0.04em;     /* h1–h6 default, h2/h3, .card-title (typography-scale.css) */
    --type-tracking-page-title: 0.025em; /* h1/.page-title/.index-heading (typography-scale.css) */
    --type-tracking-badge: 0.05em;       /* .badge/.card-badge/.banner (typography-scale.css) */
    --type-tracking-eyebrow: 0.12em;     /* Batch 5A comment correction: this was marked "not yet
                                             consumed" when written, but Batch 3C already wired it
                                             into the canonical eyebrow role below (10 occurrences) —
                                             consistent across community/forge/gallery/shop landing
                                             eyebrows and pillar-landing-masthead__eyebrow */

    /* Size roles beyond body/editorial copy (already defined above). */
    --type-page-title-size: clamp(1.8rem, 8vw, 2.6rem);   /* Batch 3N: confirmed this exactly matches :where(.page-title)'s @768px tier in layout/page-structure.css, not its desktop/base rule as originally assumed — now given its first real consumer at that breakpoint. See --type-page-title-size-desktop below for the corrected base-tier token. */
    --type-hero-title-size: clamp(1.55rem, 3.8vw, 2.9rem); /* components/hero-typography.css .hero-title */
    --type-section-heading-size: clamp(1.8rem, 3vw, 2.7rem); /* components/section-heading.css */
    --type-card-title-size: var(--font-size-md, 1.2rem); /* components/card-core.css .gnostic-card .card-title */
    --type-card-title-size-large: clamp(1.4rem, 2.6vw, 2rem); /* Batch 4K: large standard/no-media card-title tier, shared by 6 live contextual consumers (dashboard bookmark cards, dashboard highest-engagement override, community no-media cards, standard-card-variants no-media cards, homepage standard pathway cards, founder tier-name heading as a title-equivalent no-media consumer) — distinct from the smaller canonical --type-card-title-size */
    --type-editorial-card-title-size-large: clamp(1.4rem, 2.6vw, 2rem); /* Batch 4M: large featured/live/series editorial media-card title tier, currently shared by one canonical selector across three live Obsidian Key route families — distinct from the large standard/no-media card-title token above */
    --type-eyebrow-size: 0.74rem;    /* consistent across landing-page eyebrow selectors */
    --type-badge-size: 0.85em;       /* .badge/.card-badge/.banner (typography-scale.css) */
    --type-button-size: var(--font-size-base, 1rem); /* components/button-styles.css .btn */
    --type-small-size: var(--font-size-vs, 0.8rem);  /* .small (typography-scale.css) */
    --type-citation-size: clamp(0.8rem, 1.2vw, var(--font-size-sm)); /* components/blockquotes.css cite */
    --type-caption-size: clamp(0.85rem, 1.2vw, var(--font-size-sm)); /* components/image-blocks.css .caption-gnostic */

    /* Batch 3B additions: the badge family's actual dominant live values
       diverge from the generic --type-badge-size/--type-badge role above
       (0.85em/600/0.05em), which turned out to be shadowed everywhere it
       was checked (see the Batch 3B report). These four roles are the
       values that genuinely repeat across real, currently-winning badge
       rules in components/badges.css, components/editorial-card-system.css
       and layout/dashboard-styles.css, confirmed by inspection before
       being added — not an invented scale. */
    --type-badge-size-tier: 0.68rem;      /* dominant .tier-badge/.card-badge/.banner size (4 occurrences) */
    --type-badge-tracking-tier: 0.09em;   /* paired tracking for the above (2 occurrences) */
    --type-badge-size-corner: 0.72rem;    /* .badge-bl/.badge-br corner tier-badge reset variant (2 occurrences) */
    --type-badge-tracking-corner: 0.12em; /* paired tracking for the above (2 occurrences) */
    --type-badge-line: 1;                 /* shared "no baseline wobble" line-height across the whole badge family */

    /* Batch 3C additions: the eyebrow family. --type-eyebrow-size (0.74rem)
       and --type-tracking-eyebrow (0.12em) from Batch 3A are confirmed as
       the genuine canonical eyebrow role — now backed by ten identical live
       occurrences (community/forge/gallery/shop landing eyebrows, the
       gnostic-eye/obsidian-key/teachings/zoe-speaks section eyebrows, the
       home pathway-heading/featured-publications eyebrow, and the home
       hero-masthead eyebrow at desktop width). The five roles below are
       distinct, equally well-evidenced recurring variants found during
       this batch's audit — not an invented scale; each has at least two
       confirmed identical live occurrences (see the Batch 3C report). */
    --type-eyebrow-line: 1.35;                        /* canonical eyebrow line-height (10 occurrences) */
    --type-eyebrow-size-masthead: clamp(0.66rem, 0.9vw, 0.74rem); /* unified reading and landing masthead eyebrow */
    --type-eyebrow-size-compact: 0.72rem;             /* card/dashboard-strip/shop-cart eyebrow variant (6 occurrences) */
    --type-eyebrow-line-compact: 1.3;                 /* paired line-height for the above (5 occurrences) */
    --type-eyebrow-size-emphasis: 0.78rem;             /* shop-detail/shop-download-success/dark-room-kicker (3 occurrences) */
    --type-eyebrow-tracking-subtle: 0.08em;            /* dashboard kicker family, tgk-preview-gate__eyebrow, shop-cart-item__eyebrow (3 occurrences) */
    --type-eyebrow-tracking-minimal: 0.07em;           /* dashboard-account-sanction-kicker + dashboard-keys-week-kicker (2 occurrences) */

    /* Batch 3D additions: metadata and captions. Batch 3A named "metadata"
       and "caption" as size roles but only ever defined the caption ones
       (--type-caption-size/--type-caption-line, both below, unconsumed
       until this batch); no metadata token existed yet. The canonical
       metadata role is now established from its clearest, most
       authoritative live implementation (.page-meta.header-inline, the
       site's page byline). The variant tokens each have at least two
       confirmed identical live occurrences of the same semantic role,
       kept as separate tokens from same-valued eyebrow/badge tokens even
       where the number coincides, since the roles are genuinely distinct. */
    --type-metadata-size: clamp(0.76rem, 1.2vw, 0.9rem); /* canonical: layout/site-header.css .page-meta.header-inline byline */
    --type-metadata-line: 1.45;                          /* canonical: .page-meta.header-inline, dashboard bookmark timestamp/episode/part (2 occurrences) */
    --type-metadata-size-card: 0.72rem;                  /* card/product metadata: .shop-card__meta, .editorial-card__footer (2 occurrences) */
    --type-metadata-tracking-card: 0.12em;               /* paired tracking for the above (2 occurrences) */
    --type-metadata-size-discussion: 0.7rem;             /* community discussion metadata: .discussion-message-meta, .discussion-message-reply-count (2 occurrences) */

    /* Batch 3E additions: card-description copy. The canonical role
       (--type-copy-size/--type-copy-line, editorial copy from Batch 3A)
       already matches card-core.css's .gnostic-card .card-desc exactly —
       that rule was already fully token-based before this batch and is
       the live baseline whenever no more-specific card variant applies.
       These four roles are distinct, well-evidenced variants layered on
       top of that baseline by specific card contexts (portal-grid
       editorial cards, line-clamped compact cards). */
    --type-card-desc-line-editorial: 1.65;  /* editorial/portal-grid card description line-height (6 occurrences) */
    --type-card-desc-size-excerpt: 0.8em;   /* compact excerpt size for :has(.card-media) editorial cards (3 occurrences) */
    --type-card-desc-size-compact: 0.9rem;  /* compact/line-clamped card description size (3 occurrences) */
    --type-card-desc-line-clamped: 1.45;    /* line-clamped "featured" card description line-height (2 occurrences) */

    /* Subsection headings (h2/h3), UI copy and label roles are not yet
       backed by one unambiguous global size: h2/h3 currently carry no
       explicit font-size in typography-scale.css (browser default),
       --font-ui consumers vary by context (see --font-ui above), and the
       one located .form-label instance (0.78rem/0.04em tracking) is not
       yet confirmed as a repo-wide recurring pattern. Left undefined
       rather than invented; see the Batch 3A report for the full audit. */

    /* Line-height roles. */
    --type-lead-line: 1.9;             /* Batch 4B: reactivated — components/community.css .lead's line-height exactly matched this since Batch 3A but was never wired in; given its first real consumer here */
    --type-hero-title-line: 1.06;      /* components/hero-typography.css .hero-title */
    --type-heading-line: 1.08;         /* components/section-heading.css :where(.section-heading) */
    --type-ui-control-line: 1.1;       /* components/button-styles.css control line-height */
    --type-caption-line: 1.65;         /* components/image-blocks.css .caption-gnostic */
    --type-citation-line: 1.45;        /* components/blockquotes.css cite */
    /* Batch 3F correction: Batch 3A assumed blockquote text was ordinary
       paragraph copy and so did not give it its own token. Batch 3F's
       audit of the actual canonical :where(blockquote) rule in
       components/blockquotes.css found it does not match --type-copy-size/
       --type-copy-line (1em/1.6) at all — it has always had its own
       distinct size and line-height. --type-quote-size/--type-quote-line
       below are the correction, derived from that same rule's real values;
       --type-copy-size/--type-copy-line themselves were not changed.
       Card-title and generic heading line-height are still not set
       anywhere and remain intentionally undefined. */
    --type-quote-size: clamp(1.05rem, 1.7vw, 1.3rem); /* components/blockquotes.css :where(blockquote) */
    --type-quote-line: 1.85;                          /* components/blockquotes.css :where(blockquote) */

    /* Batch 3G additions: editorial lists. --type-list-size/--type-list-line
       (defined in the Type tokens block above) correctly represent
       typography-scale.css's bare :where(ul, ol) rule and remain accurate
       for that rule — they were not changed. But the site's actual dominant
       editorial list rule is layout/blocks.css's :where(.section-block) ul,
       ol (@layer components, so it outranks that base rule wherever content
       sits inside .section-block, the standard prose wrapper). Its values
       never matched --type-list-size/--type-list-line, so — following the
       same non-destructive correction pattern as Batch 3F's quote tokens —
       new tokens were added rather than redefining the existing ones. The
       "compact" tokens are a second, separately-evidenced role: two live
       selectors (lists.css .list-emoji > li and :where(ol:not([class])) > li)
       set font-size directly on <li>, which always wins over an inherited
       container value, at every breakpoint, with identical values at each
       tier — five confirmed occurrence pairs in total (see the Batch 3G
       report). */
    --type-list-item-size-editorial: clamp(1rem, 1.4vw, var(--font-size-base)); /* layout/blocks.css :where(.section-block) ul, ol */
    --type-list-line-editorial: 1.8;                  /* paired line-height for the above */
    --type-list-item-size-compact: clamp(1rem, 1.2vw, var(--type-body-size)); /* components/lists.css .list-emoji > li, :where(ol:not([class])) > li (2) */
    --type-list-item-size-compact-tablet: clamp(1rem, 1.8vw, 1.05rem);   /* same pair, @1024px (2) */
    --type-list-item-size-compact-mobile: clamp(0.98rem, 4vw, 1.05rem); /* same pair, @768px (2) */
    --type-list-item-size-compact-narrow: 0.96rem;    /* same pair, @420px (2) */
    --type-list-item-size-compact-min: 0.93rem;       /* same pair, @340px (2) */

    /* Batch 3H additions: buttons. --type-button-size and
       --type-ui-control-line (both defined above, Batch 3A) were already
       derived directly from components/button-styles.css's canonical .btn
       and matched it exactly, but had zero consumers until this batch —
       first wired here. Batch 3A's canonical role never covered weight or
       tracking, so --type-button-tracking completes it now, confirmed by
       two independent live selectors sharing the exact value (.btn itself
       and community.css's .intent-toggle); button weight reuses the
       existing generic --type-weight-semibold rather than a new token,
       since no distinct button-specific weight value was found anywhere.
       --type-button-size-compact is a separate, evidence-backed variant:
       two independently live selectors (vault-rights-admin.css and
       community.css) share the exact same reduced size. Two further
       candidate dashboard-button variants were investigated and found to
       be dead CSS — see the Batch 3H report — and were not used as
       evidence for any token. */
    --type-button-tracking: 0.05em;       /* canonical: components/button-styles.css .btn, confirmed by community.css .intent-toggle (2) */
    --type-button-size-compact: 0.75rem;  /* components/vault-rights-admin.css .vault-rights-table .btn, community.css .reply-context .btn-link (2) */

    /* Batch 3I additions: navigation. The site has no separate always-on
       desktop nav bar — #mobileNav (the drawer, opened by the hamburger
       toggle at every viewport width) is the entire primary navigation
       system; --font-size-nav (existing token) turned out to govern only
       .drawer-label, the drawer's section-heading role, not the nav links
       themselves (see the Batch 3I report). --type-nav-link-size/-tracking
       are the actual canonical link role, confirmed by three independent
       live selectors sharing identical values (#mobileNav a, .logout-btn
       .nav-signout, #mobileNav li.disabled span); .page-tabs .tab-link
       (in-page/episode/community navigation) shares the same size and
       tracking but a different weight, so it reuses these two rather than
       needing its own. Named --type-nav-link-size (not --type-nav-size) to
       avoid colliding with the pre-existing, unused Batch 3A --type-nav-size
       alias, which this batch found did not match any live selector and was
       removed as zero-consumer in Batch 5B. Breadcrumb tokens are kept deliberately separate from every other
       role even where numbers coincide (per instruction), split into two
       genuinely distinct live breadcrumb implementations. */
    --type-nav-link-size: var(--font-size-base, 1rem); /* canonical: #mobileNav a, .logout-btn.nav-signout, #mobileNav li.disabled span (3) */
    --type-nav-tracking: 0.05em;                   /* same three, plus .page-tabs .tab-link (4) */
    --type-breadcrumb-size: 0.68rem;               /* canonical: unified masthead breadcrumb */
    --type-breadcrumb-tracking: 0.1em;             /* paired with the above */
    --type-breadcrumb-size-masthead: clamp(0.66rem, 0.9vw, 0.74rem); /* pillar-landing-masthead breadcrumb variant (2 occurrences) */
    --type-breadcrumb-tracking-masthead: 0.06em;   /* paired with the above (2 occurrences) */

    /* --font-size-xs: reviewed again in Batch 3K, still left undefined —
       its remaining consumers still disagree, so defining it to either
       value would change someone's rendered output. Final status of the
       original four:
       - founder.css .founder-card-payment: resolved in Batch 3D, migrated
         to --type-small-size (its `0.8rem` fallback, unchanged).
       - visibility-gates.css .gate-footnote/.locked-note: resolved in
         Batch 3J, migrated to --type-footnote-size below (their `0.8rem`
         fallback, unchanged).
       - page-intro-dropdown.css .dossier-toggle summary (mobile tier):
         resolved in Batch 3K, migrated to the new --type-control-size-compact
         below (its `0.75rem` fallback, unchanged). Confirmed live and
         genuinely a compact expand/collapse control, not a footnote,
         caption or eyebrow.
       - visibility-gates.css .tgk-preview-gate__eyebrow: investigated
         again in Batch 3K. It is a genuine, live eyebrow (its
         letter-spacing already consumes --type-eyebrow-tracking-subtle,
         Batch 3C) — but its `0.8rem` font-size does not match any
         established eyebrow role (canonical 0.74rem, masthead
         clamp(0.66rem,0.9vw,0.74rem), compact 0.72rem, emphasis 0.78rem),
         and no second live eyebrow at exactly 0.8rem was found to justify
         a new variant token. Left deliberately unresolved rather than
         forced onto a mismatched or unevidenced token — its `0.8rem`
         fallback remains exactly as before.
       Three of the four are now resolved; the eyebrow consumer remains
       genuinely unresolved, by design, pending further live evidence. */
    --type-footnote-size: 0.8rem; /* canonical: utilities/visibility-gates.css .gate-footnote, .locked-note */
    --type-control-size-compact: 0.75rem; /* canonical: components/page-intro-dropdown.css .dossier-toggle summary (mobile), a single shared selector confirmed live across 4 dossier routes */

    /* Batch 3L additions: form labels and requirement indicators. Batch 3A
       left the general label role unresolved because live values differed
       — that remains correct for general UI labels, but form-specific
       labels turned out to share a genuine, well-evidenced role of their
       own. --type-form-label-size/-tracking and --type-form-label-size-compact/
       --type-form-requirement-size are scoped strictly to form fields and
       do not generalise to other interface labels (eyebrows, badges, nav,
       dashboard panel labels all keep their own separate tokens, confirmed
       during this batch's audit). No form-validation-message token was
       added: the only live implementation with explicit typography
       (error-messages.css #login-status/.auth-error) exists on a single
       route, short of the "two occurrences, or one shared selector across
       multiple forms" evidence bar this batch requires — its literal
       values were migrated to existing generic tokens instead (see the
       Batch 3L report). */
    --type-form-label-size: var(--font-size-sm, 1rem); /* canonical: .form-group label, .founder-modal-label, .shop-filter label, .floating-field label (4) */
    --type-form-label-tracking: 0.04em; /* .shop-filter label, .composer-sublabel, .discussion-form .form-requirement (3) */
    --type-form-label-size-compact: 0.78rem; /* canonical: community.css .composer-sublabel, a single shared selector rendered across many community reply forms */
    --type-form-requirement-size: 0.66rem; /* canonical: community.css .discussion-form .form-requirement, confirmed live across 3 uses in reply-prompt.njk */

    /* Batch 3M additions: subsection and component headings. The general
       subsection-heading role stayed unresolved through Batch 3A because
       live h3–h6 values genuinely disagree across the site (confirmed
       again here — dashboard, gallery and guide-page headings each use
       distinct one-off values, see the Batch 3M report). Two coherent
       roles did emerge from live evidence: a canonical modal/dialog
       heading (one implementation, but rendered globally via base.njk on
       every page) and a canonical shop/product-panel heading (one
       implementation, rendered across every product route via
       product.njk). Both meet this batch's "one shared canonical selector
       across multiple live routes" evidence bar. No single generic
       "subsection heading" token was created — that would force unrelated
       one-off headings onto a shared role they don't actually share. */
    --type-modal-heading-size: 1.25rem; /* canonical: community.css #report-modal .tgk-modal-panel h3, rendered globally via base.njk */
    --type-panel-heading-size: clamp(1.2rem, 2vw, 1.45rem); /* canonical: components/shop.css .shop-detail__information h3, rendered across every shop product route */
    --type-panel-heading-line: 1.15; /* paired line-height for the above */

    /* Batch 3N additions: page titles and .index-heading. Confirmed
       --type-page-title-size (above) actually matches :where(.page-title)'s
       @768px tier, not its desktop/base rule — corrected non-destructively
       by adding --type-page-title-size-desktop below, following the same
       pattern already used for the Batch 3F quote and Batch 3G list
       corrections. --type-page-title-line covers both the desktop and
       @768px tiers, which share an identical value (1.1). .index-heading
       (layout/site-header.css) was found to be the sole live-winning
       rule — the shared h1/.page-title/.index-heading grouping in
       typography-scale.css is completely shadowed for .index-heading's
       font-family, font-weight and letter-spacing (site-header.css
       overrides all three, and @layer layout always outranks @layer base
       regardless of specificity). Confirmed live at all ~40 uses
       (font-style: italic and font-weight: 400 — an editorial intro
       sentence treatment, not the bold display-font title the shared rule
       alone would suggest), rendered across every one of those routes —
       meeting the "one canonical shared selector across multiple live
       routes" evidence bar. */
    --type-page-title-size-desktop: clamp(2rem, 4.5vw, var(--font-size-xl)); /* canonical: layout/page-structure.css :where(.page-title), desktop/base tier */
    --type-page-title-line: 1.1; /* :where(.page-title), desktop and @768px tiers (2 occurrences, identical value) */
    --type-index-heading-size: clamp(0.95rem, 1.6vw, 1.35rem); /* canonical: layout/site-header.css .index-heading, the sole live-winning rule across ~40 routes */
    --type-index-heading-line: 1.7; /* paired line-height for the above */

    /* Batch 3O additions: hero and masthead titles. --type-hero-title-size/
       -line (Batch 3A) were correctly derived from components/hero-typography.css's
       .hero-title (the compact reading-page masthead, no hero image) and
       had zero consumers until now — both confirmed accurate and given
       their first real use. Everything below is new: the compact masthead
       hierarchy (site/pillar/series/season/episode/part titles, all in
       layout/site-header.css and hero-typography.css), the homepage's
       own large hero (a structurally different context, .is-home.with-hero-media),
       and the shop product-page hero restored in Batch 2B.4 (body.shop-product,
       compact but distinctly sized from the reading-page compact masthead).
       Each family is kept separate even where numbers coincide with an
       unrelated role (eyebrow, badge, button tracking values recur here
       purely by coincidence and were not reused). Font-size was prioritised
       across the whole hierarchy since it is the most visible property;
       line-height and tracking were only tokenised where they are shared
       across two or more selectors — one-off line-height/tracking values
       for individual masthead levels were left as literals, documented in
       the Batch 3O report. */
    --type-hero-title-tracking: 0.025em; /* compact .hero-title, .episode-title (2) */
    --type-hero-title-size-compact-mobile: clamp(1.35rem, 7vw, 2rem); /* @768px, shared by both (2) */
    --type-hero-title-line-compact-mobile: 1.08; /* @768px, shared by both (2) */
    --type-hero-title-size-compact-narrow: clamp(1.2rem, 7.2vw, 1.7rem); /* @420px, shared by both (2) */

    --type-hero-copy-size: clamp(0.98rem, 1.6vw, 1.18rem); /* compact .hero-subtitle, .page-tagline/.home-tagline (2) */
    --type-hero-copy-line: 1.55;
    --type-hero-copy-tracking: 0.01em;
    --type-hero-copy-size-mobile: clamp(0.95rem, 4vw, 1.08rem); /* @768px, shared (2) */
    --type-hero-copy-line-mobile: 1.5;
    --type-hero-copy-size-narrow: 0.92rem; /* @420px, shared (2) */
    --type-hero-copy-line-narrow: 1.48;

    --type-site-title-size: clamp(0.68rem, 1vw, 0.82rem); /* canonical: layout/site-header.css .site-title, single selector across every reading-page route */
    --type-pillar-title-size: clamp(0.78rem, 1.25vw, 0.95rem);
    --type-pillar-title-tracking: 0.18em;
    --type-series-title-size: clamp(1rem, 1.8vw, 1.35rem);
    --type-series-title-tracking: 0.12em;
    --type-season-title-size: clamp(0.88rem, 1.5vw, 1.08rem);
    --type-episode-title-size: clamp(1.55rem, 3.6vw, 2.8rem);
    --type-part-title-size: clamp(1rem, 1.9vw, 1.35rem);

    --type-homepage-hero-title-size: clamp(1.6rem, 3.5vw, 3.5rem); /* canonical: components/site-masthead.css .is-home.with-hero-media .hero-title */
    --type-homepage-hero-title-line: 0.96;
    --type-homepage-hero-subtitle-size: clamp(1rem, 1.8vw, 1.8rem);
    --type-homepage-hero-subtitle-line: 1.15;

    --type-product-hero-title-size: clamp(1.35rem, 2.6vw, 2.1rem); /* canonical: components/shop.css body.shop-product .hero-title, restored in Batch 2B.4, rendered across every shop product route */
    --type-product-hero-title-line: 1.1;
    --type-product-hero-subtitle-size: clamp(0.85rem, 1.3vw, 1rem);
    --type-product-hero-subtitle-line: 1.4;
    --type-product-masthead-title-size: 0.7rem; /* body.shop-product .pillar-title, .series-title (2) */
    --type-product-masthead-title-tracking: 0.1em;

    /* --ritual-font-size: reviewed. All five consumers (layout/blocks.css)
       already read `var(--ritual-font-size, var(--type-copy-size, 1em))`
       — an alias of editorial copy sizing, not a distinct ritual-component
       value. Defined explicitly as that alias below: value-preserving,
       since it resolves to exactly what already rendered via the fallback. */
    --ritual-font-size: var(--type-copy-size, 1em);

    /* Batch 4B additions: body, lead and general supporting-copy typography.
       --type-lead-size/--type-lead-line (Batch 3A) were flagged as
       zero-consumer in the Batch 4A dead-CSS audit. --type-lead-size was
       confirmed to remain unused — components/community.css .lead sources
       its font-size from --type-copy-size instead, a distinct, correct
       decision from an earlier batch — and was removed as zero-consumer in
       Batch 5B. --type-lead-line (1.9), however,
       exactly matches .lead's previously hard-coded line-height and has
       been given its first real consumer below — this is live evidence
       independently proving the role, not a token being wired up merely
       to give it a consumer.
       --type-supporting-copy-size/-line are new: six identical
       "-about__copy" selectors across the community, forge, gnostic-eye,
       obsidian-key, teachings and zoe-speaks landing pages share the exact
       same font-size and line-height for their about/explanatory
       paragraphs (components/pages/*.css). The line-height role is also
       confirmed by a seventh, independently authored selector at the
       identical value (pages/home.css .home-pathway-heading intro
       paragraph) — its font-size differs and was left as a literal.
       --type-lead-compact-size/-line are new: layout/page-structure.css's
       .section-subtitle and .dossier-date-tagline share an identical
       compact override at the @768px breakpoint, distinct from both
       tokens above and from every hero-copy-mobile value already defined
       (1.05rem/1.6 here vs 1.08rem/1.5 for hero copy — not merged despite
       the numeric closeness). Their desktop-tier font-size values differ
       per selector and were left as literals. */
    --type-supporting-copy-size: clamp(1rem, 1.35vw, 1.12rem); /* .community-about__copy, .forge-about__copy, .gnostic-eye-about__copy, .obsidian-key-about__copy, .teachings-about__copy, .zoe-speaks-about__copy (6) */
    --type-supporting-copy-line: 1.7; /* same 6, plus pages/home.css .home-pathway-heading p (7) */
    --type-lead-compact-size: clamp(0.95rem, 4vw, 1.05rem); /* .section-subtitle, .dossier-date-tagline @768px (2) */
    --type-lead-compact-line: 1.6; /* same 2 */

    /* Legacy aliases */
    --font-base-size: var(--type-body-size);
    --font-base-line: var(--type-body-line);

    /* Neutral defaults (themes override) */
    --bg-primary: #f9f5eb;
    --bg-secondary: #f0e9d8;
    --bg-surface: var(--bg-primary);
    --surface-elevated: #fffaf0;
    --card-surface: color-mix(in srgb, var(--bg-surface) 94%, var(--highlight) 6%);
    --bg-alt: #f6f1e4;

    --bg-color: transparent;
    --bg-wash: transparent;

    --text-primary: #1f1c16;
    --text-secondary: #524c42;
    --text-muted: #6d6658;
    --text-accent: #8f6f24;

    --strong-text: #8f6f24;
    --text-strong: var(--strong-text);
    --text-normal: var(--text-secondary);

    --gold-accent: #c9aa71;
    --purple-accent: #8b6fc1;
    --vault-accent: #5a4b91;

    --highlight: #d6ad55;

    --shadow-glow: rgba(143, 111, 36, 0.22);
    --accent-glow: rgba(214, 173, 85, 0.34);
    --accent-soft: rgba(143, 111, 36, 0.20);
    --accent-soft-glow: rgba(143, 111, 36, 0.28);

    --soft-gold: #f5e9c8;
    --golden-blaze: #ead6a0;
    --gold-tone: #9f7b2a;

    --accent: var(--text-accent);
    --accent-page: #a37d29;

    --border-accent: rgba(143, 111, 36, 0.36);
    --border-soft: rgba(143, 111, 36, 0.26);
    --divider-border: rgba(143, 111, 36, 0.48);
    --divider-border-soft: rgba(143, 111, 36, 0.34);
    --gold-border: rgba(143, 111, 36, 0.42);

    /* Gradients used across modules */
    --overlay-bg-gradient: none;
    --bg-gradient: var(--overlay-bg-gradient);
    --card-gradient: color-mix(in srgb, var(--bg-secondary) 94%, var(--highlight) 6%);

    /* Sections */
    --section-bg-top: #f0e9d8;
    --section-bg-bottom: #e8dfc8;
    --section-border: rgba(143, 111, 36, 0.42);
    --section-title-color: var(--text-accent);
    --section-subtitle-color: var(--text-secondary);

    --blockquote-text: var(--text-primary);
    --cite-color: var(--text-accent);

    /* Badge tokens referenced by verify banner and other UI */
    --badge-bg: rgba(255, 244, 210, 0.82);
    --badge-text: #735c1e;
    --badge-shadow: 0 2px 8px rgba(217, 177, 79, 0.20);

    /* Page + radius */
    --border-radius-base: 0.75rem;
    --border-radius-lg: 1.25rem;
    --radius-sm: 0.35rem;
    --radius-md: 8px;
    --radius-xl: 1.75rem;

    --page-box-shadow: 0 0 20px rgba(217, 177, 79, 0.20);
    --page-shadow-soft: 0 12px 28px rgba(0, 0, 0, 0.09);

    /* Buttons */
    --btn-font: var(--font-display);
    --btn-radius: var(--border-radius-base);
    --btn-padding: 0.65rem 1.25rem;
    --btn-padding-lg: 0.8rem 1.6rem;
    --btn-shadow: var(--shadow-glow);
    --btn-max-width: 320px;

    /* Forms */
    --input-bg: #f0e9d8;
    --input-bg-focus: #f9f5eb;
    --input-border: rgba(31, 28, 22, 0.24);
    --input-focus: var(--text-accent);
    --input-focus-border: var(--input-focus);
    --input-placeholder: #b49e7a;
    --input-text: var(--text-primary);
    --input-disabled-bg: rgba(232, 223, 200, 0.72);
    --input-disabled-text: rgba(31, 28, 22, 0.62);
    --input-padding: 0.85rem 1.1rem;
    --link-color: var(--text-accent);
    --link-hover: var(--accent-page);
    --link-active: #6f551b;
    --link-visited: #735c1e;

    --form-error-color: #d63c3c;
    --form-success-color: #32a862;

    /* Spacing */
    --space-2xs: 0.125rem;
    --space-xs: 0.25rem;
    --space-vs: 0.35rem;
    --space-sm: 0.5rem;
    --space-md: 1rem;
    --space-lg: 2rem;
    --space-xl: 3rem;

    /* Site-wide content width on desktop (≥1025px). Change once here to reflow everything. */
    --site-content-width: 75%;

    /* Grid helpers (used by your portal and pillar grids) – UNCHANGED */
    --grid-max-width: 1100px;
    --max-width-container: 1400px;
    --grid-card-min: 280px;
    --grid-gap: var(--space-md);
    --grid-max-cols: 4;
    --grid-max-width-calc: calc(
      var(--grid-max-cols) * var(--grid-card-min) +
      (var(--grid-max-cols) - 1) * var(--grid-gap)
    );

    /* Glyphs */
    --glyph-size-small: 1.6rem;
    --glyph-size-base: 2.2rem;
    --glyph-size-large: 3rem;
    --glyph-margin-bottom: 1rem;
    --glyph-color: var(--text-accent);

    /* Quiz */
    --quiz-wrong-bg: rgba(255, 90, 60, 0.12);
    --quiz-wrong-text: #cc4444;
    --quiz-outline-selected: var(--highlight);
    --quiz-reveal-text: var(--text-secondary);

    /* Footer */
    --footer-opacity: 0.93;

    /* Motion */
    --transition-default: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

    /* Background painter defaults */
    --overlay-img: none;
    --bg-opacity: 0.33;

    /* Z-index */
    --z-header: 3000;
    --z-floating: 9000;
    --z-drawer: 12000;
    --z-overlay: 11990;
    --z-hamburger: 12010;

    /* Verify banner tokens */
    --verify-banner-gap: 0.6rem;
    --verify-banner-padding: 0.75rem 1rem;
    --verify-banner-margin: 0 0 1rem 0;
    --verify-banner-radius: 0.75rem;
    --verify-banner-border: 1px solid var(--section-border);
    --verify-banner-bg: var(--badge-bg);
    --verify-banner-text: var(--badge-text);
    --verify-banner-shadow: var(--badge-shadow);
    --verify-banner-font-size: 0.9rem;
    --verify-banner-align: centre;

    --verify-btn-bg: var(--text-accent);
    --verify-btn-text: var(--bg-primary);
    --verify-btn-border: 1px solid var(--accent-page);
    --verify-btn-radius: 0.5rem;
    --verify-btn-padding: 0.35rem 0.75rem;
    --verify-btn-weight: 500;
    --verify-btn-transition: all 0.2s ease-in-out;

    /* Hero overlay readability tokens */
    --hero-overlay-text: var(--text-accent);
    --hero-overlay-subtext: color-mix(in srgb, var(--text-accent) 96%, transparent);
    --hero-overlay-rule: color-mix(in srgb, var(--text-accent) 78%, transparent);
    --hero-overlay-shadow-title:
      0 1px 0 rgba(255, 255, 255, 0.05),
      0 2px 8px rgba(0, 0, 0, 0.45);
    --hero-overlay-shadow-copy: 0 2px 10px rgba(0, 0, 0, 0.55);
    --hero-overlay-cta-text: var(--hero-overlay-text);
    --hero-overlay-cta-border: color-mix(in srgb, var(--hero-overlay-text) 82%, transparent);
    --hero-overlay-cta-border-strong: color-mix(in srgb, var(--hero-overlay-text) 100%, transparent);
    --hero-overlay-cta-inner-border: color-mix(in srgb, var(--hero-overlay-text) 48%, transparent);
    --hero-overlay-cta-inner-shadow: inset 0 0 8px color-mix(in srgb, var(--hero-overlay-text) 12%, transparent);
  }

}
