{"version":3,"sourceRoot":null,"mappings":";AAoBA,0GACA,4GACA,2GACA,yGACA,2GAMA,wGAIA,0GACA,yGACA,uGACA,wGAKA,+fAuBA,4GACA,4GACA,2GACA,yGACA,2GACA,uGACA,0GACA,yGACA,uGACA,wGASA,6FACA,+FACA,8FACA,4FACA,8FACA,2FACA,6FACA,4FACA,0FACA,2FAKA,4iBAqBA,wEAwCA,+EACA,6EACA,iFACA,kFACA,6EACA,gFACA,uFACA,qFACA,kFACA,mFACA,8EACA,8EASA,oDAiBA,2EACA,0EACA,yEACA,wEACA,wEACA,wEACA,yEACA,0EACA,0EACA,0EACA,gFACA,gFACA,4EACA,4EAEA,0EACA,0EACA,yEACA,wEACA,uEACA,uEACA,uEACA,wEACA,yEACA,yEACA,yEACA,mEACA,2EACA,sEACA,6EACA,2EACA,+EACA,8EACA,8EACA,8EACA,+EACA,gFAEA,oDACA,kDACA,iDACA,iDACA,iDACA,kDACA,mDACA,qDACA,yDACA,uDACA,sDACA,sDACA,sDACA,uDACA,uDACA,sDACA,sDACA,sDACA,uDACA,oDAEA,u5DA8JA,6EACE,ixLAiKF,wCACE,s9FA0FF,wEACE,u4CAmDF,wCACA,ytZAmQA,uinBAmjBA,wCACE,olGAwDF,sqTA6lBA,uCAIA,sPAUA,4CACE,sCAGF,6CAKA,2BAIA,qBAIA,uBAIA,+BAIA,gCAIA,4FAQA,qBAIA,uBAWA,yEAIA,wVAUA,uRAUA,2LACA,2LACA,2LACA,2LACA,2LACA,2LAEA,uEAMA,kDAIA,sCAIA,wCAIA,kJAOA,yDAKA,2DAKA,8EAMA,cACA,kBAIA,2WAUA,6EACA,8CACA,4CACA,6CAEA,gCAIA,+MASA,sSAYA,kFAQA,4EAQA,wDAIA,oFAKA,mFAOA,0GAKA,0GAMA,4BAIA,iDAIA,mDAIA,gDAIA,wHAOA,sBAGA,iEAGA,yBAIA,sBACA,6EAEA,6IAKA,6CAIA,yCAIA,uBAIA,6CAIA,4JAcA,itBAgCA,8aAcA,0LAUA,2FASA,4NAAA,oNA8BA,kKAMA,6JAOA,4EAKA,6CAKA,iCACE,+BAOF,0DAIA,mZAOA,0FASA,4sBAsBA,6TAQA,oaAQA,yTAUA,uJAUA,gCAGA,8ZAaA,mHAKA,iFAMA,wKAKA,2JAKA,wOAQA,2JAOA,6KAMA,yIAMA,mFAMA,2IAOA,+JAwDA,m4CA8CA,0IAQA,sQAOA,kRAOA,4QAOA,gQAOA,oPAOA,sQAOA,sQAOA,sQAOA,oPAOA,gQA2BA,wFAMA,wCAGE,4FAKA,8HAOF,2FAKA,kKAgBA,8DAGA,+EACA,mFACA,iFACA,6EAEA,2OASA,wCAGE,2GAOA,wPAaA,gHAMA,wdAeA,yKAyBF,+SAMA,mTAMA,iTAMA,yTAQA,kHAOA,oDAIA,0CAGA,gMAaA,8CACE,yFAMF,gCAIA,0BACE,oCAkBF,6XAiCA,wCACE,wCACE,ikCA4BJ,+DAMA,uKAMA,6KAMA,iQAYA,8LASA,sGAOA,mCAKA,oGAOA,4EAIA,0HAIA,8CACE,6FAGA,qHA2CF,gDACA,2DACA,yDACA,yDACA,yDACA,2DACA,6DAEA,sDACA,qIAoBA,gEAOA,gDACA,8CACA,8CACA,8CACA,gDAGA,oGAGA,gGAIA,uKAMA,iOASA,oEACA,sEACA,8CACA,8CAEA,6JASA,0GAGA,6IAOA,kJAOA,2DACA,yDACA,uDACA,uDAIA,kCAKA,sCA4BA,wCACA,+lUA2BA,qEAKA,qCACA,mCACA,mCACA,mCACA,qCACA,uCAEA,qCACA,oCACA,uCAEA,0BACA,mCACA,iCACA,iCACA,iCACA,mCACA,qCAIA,0GAOA,4IAQA,4EAaA,iDAOA,gJAOA,uCACA,qCACA,qCACA,qCACA,uCACA,yCAEA,sCACA,2CACA,0CACA,mDAIA,kEAMA,wEAKA,+HAYA,8EAKA,6CACA,2CAIA,oEAMA,wFAKA,4EACA,6CAIA,iIAMA,iGAIA,iDACA,+CACA,+CACA,+CACA,iDACA,mDAEA,qCAMA,iEAKA,uDAIA,6CACA,6EAKA,sDACA,oDACA,oDACA,oDACA,sDACA,wDAEA,0LAQA,8CACA,4CACA,4CACA,4CACA,8CACA,gDAEA,sVAYA,yHAOA,8CAIA,gCAEA,kDACA,sDACA,uDAIA,oHAQA,gFAOA,sDACA,oDACA,sDACA,0DACA,gDACA,gDACA,sDAQA,gEAKA,gVAYA,wOAmBA,0TAaA,2CACA,2GACA,2GAEA,sEAQA,kFAOA,mCAIA,yJAOA,0FAMA,kFAMA,uCACE,8CAGA,kDACA,kDAIF,4EAOA,oHAWA,0BACE,oDACA,qDAGF,0BACE,oDACA,oDACA,oDACA,qDAIF,4GAMA,0BACE,gDACA,gDACA,gDACA,iDAGF,2KAKA,+BAEA,4BACA,4BACA,4BACA,4BAGA,obA+BA,uCACA,mDACA,iDAEA,sOAQA,6BACE,qCAGF,gDACE,+CAIF,+BACA,+BACA,+BAKA,kEACA,4DAKA,kCACA,gCACA,+BACA,2CAOA,6BACE,sDAIF,uDACA,yDAUA,uEAKA,2DACA,+EACA,4DACA,wEACA,qJACA,mGACA,iDACA,wCACA,mFACA,gCACA,gCACA,sDACA,oDACA,4DACA,6IACA,mJACA,uDACA,qGAIA,+EAGA,iFACA,+CACA,iHAMA,0CACA,2DACA,8CACA,wFACA,+IACA,kDACA,6DAEA,qDAIA,uEAMA,mHAUA,sCAEA,sCACA,yDAKA,kDAIA,6CAKA,gDAIA,sXAkBA,uHAMA,0CAIA,6RAkCA,oPAiBA,qPAiBA,8QAiBA,6VAmBA,4VAmBA,6DAKA,+CAEA,0IACA,kJACA,8IACA,sIACA,0IACA,0IACA,0IACA,0IACA,8HACA,sIAEA,wEACE,k6CA0CF,8CAIA,wHASA,4FAKA,8CACA,8CACA,0DAQA,8WAUA,yDAIA,+FAMA,yHASA,8BACE,gGAKF,4GAKA,0EAMA,mDACA,iDACA,iDACA,iDACA,mDAEA,yEAIA,8JAMA,gFAIA,wHASA,2EAKA,iEACA,qEAMA,2HA6CA,gCACA,+BAWA,0QAYA,+LACA,+LACA,+LACA,+LACA,+LACA,+LASA,8NACA,wNACA,kNACA,kNACA,kNACA,wNACA,8NACA,8NACA,8NAiEA,yOAMA,2DACA,8DACA,wEACA,4DACA,8EACA,+GAIA,8FAOA,qDAeA,yHACA,+HACA,4HACA,sHASA,2IAaA,kGAKA,oFACA,oFACA,oFAcA,yJAKA,gEACA,gEACA,gEACA,gEACA,gEACA,gEACA,gEACA,gEACA,gEAEA,qDACA,gCACA,sCACA,sCACA,sCAgDA,2GAUA,2EAMA,qCAIA,6WA0BA,yDAKA,+RA0BA,8DAIA,8DAYA,iIAMA,+HAMA,oHAKA,2GAOA,gEAKA,+HAKA,6BAMA,gCAaA,mCACE,0DAMF,0EACA,uEAEA,sUA2BA,wCACA,s4BAmBA,slBAMA,kbAkBM,sxCAaA,y3FA0DA,w/FAuDN,wEACE,+8CAiCF,wwBAcA,uCACE,sCAUF,8CAEE,4BAIA,+RASA,sCACE,mJAQF,kDACA,oDACA,0DACA,8DACA,8DACA,gEACA,oDACA,wDAKA,0PAUA,sCACE,8SAYF,6CACA,oDACA,wDACA,wDACA,0DACA,kDASA,sCACE,qXAaA,0CACA,iDACA,qDACA,qDACA,uDACA,mDAaF,mHAOA,wDACE,wDASF,4DACE,+BACA,0CACA,2CACA,2CACA,2CACA,2CACA,2CACA,2CACA,6CAKJ,iDACA,kDACA,kFACA,qFACA,kFACA,oFACA,oEACA,sEAEA,oFACA,qFACA,oFACA,oFAEA,qCACA,oFAEA,6CACA,0DACA,8DAGA,wFACE,gSAMA,8CACE,4DAMJ,+CACE,0DAaF,wCAIA,6KAOA,uGAOA,8BACE,kKAQF,uCACE,0IAQA,8JAUF,yMAWA,+BACE,uDAMA,sDAKF,6CACE,+DAOF,qCACE,4CAuCF,wBACE,wOAgCF,8FAMA,sFAQA,4QAeA,iYAYA,qDAMA,wKAWA,iFAMA,kTAUA,8eAYA,4KAMA,8BACE,sCAIA,iDAIA,2CAKA,4DAMA,mGAOA,qJAQA,qGAcF,yBAIA,aAOE,wFAMA,8CAIA,kDAOA,yKAMA,+CAIA,8DAKA,iCAIA,sBAIA,oCAQA,kBACA,kBACA,kBACA,kBACA,kBACA,kBAEA,qBAKA,8GAKA,qGAKA,qCAIA,sBACA,uCACA,oCAGA,sHAMA","sources":["slashed.full.flat.css"],"sourcesContent":["/*! SLASHED v0.7.31 — slashed.full.flat.css (flat) | MIT License | github.com/codeslash-dev/SLASHED */\n\n/* ─── core/layers.css ─── */\n/* SLASHED — core/layers.css\n   Global cascade order for every SLASHED layer.\n   Import before all framework modules. */\n\n/* ─── core/tokens.css ─── */\n/* SLASHED — core/tokens.css\n   @layer slashed.tokens\n   Core design tokens: color sources, semantic colors, type, spacing, radii, shadows, motion, z-index.\n   Prefix: --sf-*; brand theming starts with six -source-light tokens. */\n\n\n/* ============================================================\n   @property — BRAND COLORS (-source-light source tokens, animatable)\n   Override these 6 tokens to rebrand — dark mode auto-derives.\n   Optionally set --sf-color-X-source-dark for full control.\n   ============================================================ */\n\n@property --sf-color-primary-source-light   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.47 0.27 264); }\n@property --sf-color-secondary-source-light { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.22 0.04 264); }\n@property --sf-color-tertiary-source-light  { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.42 0.22 295); }\n@property --sf-color-action-source-light    { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.50 0.22 235); }\n@property --sf-color-neutral-source-light   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.52 0.025 260); }\n/* initial-value is 0.96 (not 0.99) so the +0.02/+0.04 surface offsets produce\n   visually distinct levels in light mode. At 0.99 all lighter surfaces clamp\n   to pure white and become indistinguishable. 0.96 gives: bg=0.98, inset=0.94,\n   raised=1.0→white — all distinct. Consumers using near-1.0 values should rely\n   on shadows rather than lightness for elevation. */\n@property --sf-color-base-source-light  { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.96 0.006 250); }\n\n/* @property — STATUS COLORS (-source-light source tokens) */\n\n@property --sf-color-success-source-light { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.50 0.16 145); }\n@property --sf-color-warning-source-light { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.75 0.17 80);  }\n@property --sf-color-info-source-light    { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.48 0.18 235); }\n@property --sf-color-danger-source-light  { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.48 0.22 12);  }\n\n/* Plain :root mirrors — character-for-character identical to each @property\n   initial-value above. Engines lacking @property support read the token value\n   from here. Do NOT edit these independently from the initial-value strings. */\n:root {\n  --sf-color-primary-source-light:   oklch(0.47 0.27 264);\n  --sf-color-secondary-source-light: oklch(0.22 0.04 264);\n  --sf-color-tertiary-source-light:  oklch(0.42 0.22 295);\n  --sf-color-action-source-light:    oklch(0.50 0.22 235);\n  --sf-color-neutral-source-light:   oklch(0.52 0.025 260);\n  --sf-color-base-source-light:      oklch(0.96 0.006 250);\n  --sf-color-success-source-light:   oklch(0.50 0.16 145);\n  --sf-color-warning-source-light:   oklch(0.75 0.17 80);\n  --sf-color-info-source-light:      oklch(0.48 0.18 235);\n  --sf-color-danger-source-light:    oklch(0.48 0.22 12);\n}\n\n/* @property — DARK SOURCE TOKENS (-dark, animatable) */\n/* Registers the auto-computed dark counterparts as typed <color> so their\n   resolved absolute value is inherited by child elements (e.g. a section\n   with [data-theme=\"dark\"]). Without @property these tokens inherit as raw\n   text, and the nested var()-in-oklch-from chain fails type-checking on\n   registered child properties.\n   initial-value = dark-mode value derived from the formula in themes.css\n   (clamp(0.65, 0.95 - l*0.5, 0.88) for brand/status; inverted for base).\n   Consumers who set --sf-color-X-dark explicitly do not need to register it\n   — their override is a plain OKLCH literal and passes type-checking directly. */\n@property --sf-color-primary-source-dark   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.715 0.243 264);  }\n@property --sf-color-secondary-source-dark { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.84 0.036 264);   }\n@property --sf-color-tertiary-source-dark  { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.74 0.198 295);   }\n@property --sf-color-action-source-dark    { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.70 0.198 235);   }\n@property --sf-color-neutral-source-dark   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.69 0.0225 260);  }\n@property --sf-color-base-source-dark      { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.22 0.003 250);   }\n@property --sf-color-success-source-dark   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.70 0.144 145);   }\n@property --sf-color-warning-source-dark   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.65 0.153 80);    }\n@property --sf-color-info-source-dark      { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.71 0.162 235);   }\n@property --sf-color-danger-source-dark    { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.71 0.198 12);    }\n\n/* @property — COMPUTED COLOR TOKENS (brand + status)\n   Registers the computed tokens as typed <color> so CSS transitions can\n   interpolate between light and dark values when [data-theme] changes.\n   initial-value = light-mode value (safe fallback if nothing sets the token).\n   Child-element theming works because [data-theme=\"dark\"] in themes.css\n   assigns var(--sf-color-X-dark) — now a registered typed <color> whose\n   absolute value is inherited, so no multi-level var() resolution is needed. */\n@property --sf-color-primary   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.47 0.27 264); }\n@property --sf-color-secondary { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.22 0.04 264); }\n@property --sf-color-tertiary  { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.42 0.22 295); }\n@property --sf-color-action    { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.50 0.22 235); }\n@property --sf-color-neutral   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.52 0.025 260); }\n@property --sf-color-base      { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.96 0.006 250); }\n@property --sf-color-success   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.50 0.16 145); }\n@property --sf-color-warning   { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.75 0.17 80);  }\n@property --sf-color-info      { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.48 0.18 235); }\n@property --sf-color-danger    { syntax: \"<color>\"; inherits: true; initial-value: oklch(0.48 0.22 12);  }\n\n/* Plain :root mirrors for computed tokens — resolve to the -source-light source token\n   so user overrides to --sf-color-X-source-light are respected in all browsers.\n   Overridden by the @supports block in themes.css whenever dark mode is active. */\n:root {\n  --sf-color-primary:   var(--sf-color-primary-source-light);\n  --sf-color-secondary: var(--sf-color-secondary-source-light);\n  --sf-color-tertiary:  var(--sf-color-tertiary-source-light);\n  --sf-color-action:    var(--sf-color-action-source-light);\n  --sf-color-neutral:   var(--sf-color-neutral-source-light);\n  --sf-color-base:      var(--sf-color-base-source-light);\n  --sf-color-success:   var(--sf-color-success-source-light);\n  --sf-color-warning:   var(--sf-color-warning-source-light);\n  --sf-color-info:      var(--sf-color-info-source-light);\n  --sf-color-danger:    var(--sf-color-danger-source-light);\n}\n\n/* Mode flag — INTERNAL, not a public hook (SL-003: same \"--sf-is-*\" naming\n   pattern as the public flags below, opposite contract — read here, don't\n   set). Drives formula direction for non-color dark overrides. Set only by\n   themes.css via [data-theme=\"dark\"] and the prefers-color-scheme media\n   query; every other read site (core/tokens.css, the configurator's power\n   knobs) only reads it inside calc() expressions. Setting it directly\n   desyncs it from color-scheme/[data-theme] and produces an inconsistent\n   theme. */\n@property --sf-is-dark { syntax: \"<integer>\"; inherits: true; initial-value: 0; }\n\n/* No --sf-is-active/-current/-pressed/-open here: they registered an\n   INTERACTION STATE FLAGS mechanism (inheritable custom properties set by\n   .sf-is-active/.sf-is-open/etc for a consumer's own calc() to branch on)\n   with zero consumers anywhere in this codebase, its demo, or the\n   configurator beyond its own preview toggle — speculative surface,\n   removed. Style off [aria-current]/[aria-expanded]/[aria-pressed]\n   instead; see docs/states.md § \"Prefer native state\". */\n\n/* ============================================================\n   FLUID SCALE ENGINE — generative inputs\n   ------------------------------------------------------------\n   The fluid type / space / display scales are computed at runtime\n   from these scalars. Override any of them on :root and every\n   clamp() recalibrates — no build step, no token regeneration.\n\n     --sf-fluid-min-vw / --sf-fluid-max-vw   viewport range (rem, unitless)\n                                             over which values interpolate.\n     --sf-text-ratio-min / -max              modular ratio of the TYPE scale\n                                             at min / max viewport (dual-ratio:\n                                             subtler on mobile, larger on desktop).\n     --sf-text-base-min / -max               --sf-text-m endpoints (rem, unitless).\n     --sf-text-display-base-min / -max       --sf-text-display-s endpoints.\n     --sf-space-ratio-min / -max             modular ratio of the SPACE scale.\n     --sf-space-base-min / -max              --sf-space-m endpoints (rem, unitless).\n     --sf-fluid-width                        the length every fluid clamp()\n                                             interpolates against. Defaults to\n                                             100vw (viewport-relative). Override\n                                             to 100cqi on a container scope to make\n                                             the type + space + display scales\n                                             container-relative — see .sf-fluid-cq\n                                             in core/layout.css (issue #497).\n\n   Registered as <number> so they can be used as pow() exponents/operands\n   and multiplied by 1rem in calc(). Requires CSS pow() (Chrome 125+,\n   Safari 15.4+, Firefox 118+); the effective SLASHED floor is higher\n   (Chrome 125 / Safari 18.0 / Firefox 129), set by the colour system —\n   see browser floor. Plain :root mirrors\n   below keep values readable; do NOT edit them independently. */\n@property --sf-fluid-min-vw          { syntax: \"<number>\"; inherits: true; initial-value: 22.5; }\n@property --sf-fluid-max-vw          { syntax: \"<number>\"; inherits: true; initial-value: 90; }\n@property --sf-text-ratio-min        { syntax: \"<number>\"; inherits: true; initial-value: 1.25; }\n@property --sf-text-ratio-max        { syntax: \"<number>\"; inherits: true; initial-value: 1.333; }\n@property --sf-text-base-min         { syntax: \"<number>\"; inherits: true; initial-value: 1; }\n@property --sf-text-base-max         { syntax: \"<number>\"; inherits: true; initial-value: 1.25; }\n@property --sf-text-display-base-min { syntax: \"<number>\"; inherits: true; initial-value: 2.4; }\n@property --sf-text-display-base-max { syntax: \"<number>\"; inherits: true; initial-value: 3; }\n@property --sf-space-ratio-min       { syntax: \"<number>\"; inherits: true; initial-value: 1.25; }\n@property --sf-space-ratio-max       { syntax: \"<number>\"; inherits: true; initial-value: 1.333; }\n@property --sf-space-base-min        { syntax: \"<number>\"; inherits: true; initial-value: 1; }\n@property --sf-space-base-max        { syntax: \"<number>\"; inherits: true; initial-value: 2; }\n\n/* Fluid interpolation driver — the length term every fluid clamp() below\n   measures against. Universal syntax (\"*\") not \"<length>\": a registered\n   <length> requires a computationally-independent initial-value, and 100vw\n   (viewport-dependent) is not one. The real default lives on :root; an\n   opt-in scope (e.g. .sf-fluid-cq) overrides it to 100cqi so the whole\n   generative scale becomes container-relative without duplicating a single\n   formula. */\n@property --sf-fluid-width           { syntax: \"*\"; inherits: true; }\n\n/* ── Output token @property registrations ──────────────────────────────────\n   Radius + space: <length> syntax enables CSS transitions on layout values —\n   border-radius/padding/gap etc. now interpolate instead of snapping.\n   Shadow: syntax:\"*\" (no <shadow> type in spec); inherits:true so :root values\n   cascade normally; registers the properties formally for DevTools inspection.\n\n   initial-value ≠ :root default (by spec): a registered <length> requires a\n   computationally-independent initial-value, so these carry `initial-value: 0`\n   while their real defaults are the calc()-derived values set on :root below\n   (see --sf-fluid-width above for the same constraint stated at length). One\n   consequence worth flagging: once a property is registered, the initial\n   value IS a value — so a fallback like `var(--sf-radius-m, 12px)` will NEVER\n   fire; an unset --sf-radius-m resolves to the registered `0`, not to \"no\n   value\". Author fallbacks against the token's :root default, not this 0. */\n\n@property --sf-radius-none  { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-2xs   { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-xs    { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-s     { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-m     { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-l     { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-xl    { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-2xl   { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-3xl   { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-4xl   { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-radius-full  { syntax: \"<length>\"; inherits: true; initial-value: 9999px; }\n@property --sf-radius-pill  { syntax: \"<length>\"; inherits: true; initial-value: 9999px; }\n@property --sf-radius-outer { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-media-radius { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n\n@property --sf-space-none       { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-px         { syntax: \"<length>\"; inherits: true; initial-value: 1px; }\n@property --sf-space-2xs        { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-xs         { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-s          { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-m          { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-l          { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-xl         { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-2xl        { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-3xl        { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-space-4xl        { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-gap              { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-content-gap      { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-gutter           { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-component-pad    { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-field-block      { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-section-pad--xs  { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-section-pad--s   { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-section-pad--m   { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-section-pad--l   { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-section-pad--xl  { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n@property --sf-section-pad--2xl { syntax: \"<length>\"; inherits: true; initial-value: 0; }\n\n@property --sf-shadow-none      { syntax: \"*\"; inherits: true; }\n@property --sf-shadow-xs        { syntax: \"*\"; inherits: true; }\n@property --sf-shadow-s         { syntax: \"*\"; inherits: true; }\n@property --sf-shadow-m         { syntax: \"*\"; inherits: true; }\n@property --sf-shadow-l         { syntax: \"*\"; inherits: true; }\n@property --sf-shadow-xl        { syntax: \"*\"; inherits: true; }\n@property --sf-shadow-2xl       { syntax: \"*\"; inherits: true; }\n@property --sf-shadow-inner     { syntax: \"*\"; inherits: true; }\n@property --sf-text-shadow-none { syntax: \"*\"; inherits: true; }\n@property --sf-text-shadow-xs   { syntax: \"*\"; inherits: true; }\n@property --sf-text-shadow-s    { syntax: \"*\"; inherits: true; }\n@property --sf-text-shadow-m    { syntax: \"*\"; inherits: true; }\n@property --sf-text-shadow-l    { syntax: \"*\"; inherits: true; }\n@property --sf-text-shadow-xl   { syntax: \"*\"; inherits: true; }\n@property --sf-drop-shadow-xs   { syntax: \"*\"; inherits: true; }\n@property --sf-drop-shadow-s    { syntax: \"*\"; inherits: true; }\n@property --sf-drop-shadow-m    { syntax: \"*\"; inherits: true; }\n@property --sf-drop-shadow-l    { syntax: \"*\"; inherits: true; }\n@property --sf-drop-shadow-xl   { syntax: \"*\"; inherits: true; }\n@property --sf-shadow-glow      { syntax: \"*\"; inherits: true; }\n\n:root {\n  --sf-fluid-min-vw:          22.5;\n  --sf-fluid-max-vw:          90;\n  --sf-fluid-width:           100vw;  /* interpolation driver; 100cqi on a container scope → container-relative fluid (#497) */\n  --sf-text-ratio-min:        1.25;\n  --sf-text-ratio-max:        1.333;\n  --sf-text-base-min:         1;\n  --sf-text-base-max:         1.25;\n  --sf-text-display-base-min: 2.4;\n  --sf-text-display-base-max: 3;\n  --sf-space-ratio-min:       1.25;\n  --sf-space-ratio-max:       1.333;\n  --sf-space-base-min:        1;\n  --sf-space-base-max:        2;\n}\n\n/* ============================================================\n   DERIVED SEMANTIC TOKENS\n   ============================================================ */\n\n:root {\n\n  /* ----------------------------------------------------------\n     Color scheme\n     ---------------------------------------------------------- */\n  --sf-color-scheme: light dark;\n\n  /* ----------------------------------------------------------\n     LumLocker — OKLCH L value used by the\n     :root[data-lumlocker] override in core/themes.css.\n     Locks the 4 brand colors (primary, secondary, tertiary, action)\n     to one shared lightness while keeping their individual hue and\n     chroma. Neutral and base are excluded — neutral is a desaturated\n     grey (locking it to a brand L would make it chromatic) and base\n     must remain near-white in light mode for the page background.\n\n     --sf-lumlocker is the LIGHT-mode target. Dark mode uses\n     --sf-lumlocker-dark, which defaults to the mirror of the light L\n     around 0.59 — the midpoint between the light (~0.96) and dark\n     (~0.22) page backgrounds — i.e. calc(1.18 - L). Mirroring around\n     the background midpoint (not 0.5) is what keeps the lock's\n     contrast against the surface equal in both themes; a naive 1 - L\n     would leave the dark lock too dark to read. Clamped to a visible\n     band. A single knob that works in both themes. Override either:\n       :root { --sf-lumlocker: 0.55 }          (light)\n       :root { --sf-lumlocker-dark: 0.82 }     (dark, breaks the mirror)\n     ---------------------------------------------------------- */\n  --sf-lumlocker: 0.65;\n  --sf-lumlocker-dark: clamp(0.5, calc(1.18 - var(--sf-lumlocker)), 0.92);\n\n  /* ----------------------------------------------------------\n     Resolved color tokens — auto-switch via light-dark().\n     Components reference these. Override the -source-light / -source-dark\n     source tokens above to customise; or override these directly\n     with your own light-dark() expression.\n     ---------------------------------------------------------- */\n  /* Surface alias (plain var — no IACVT, stays ungated) */\n  --sf-color-surface: var(--sf-color-base);\n\n  /* ----------------------------------------------------------\n     Text — plain var aliases (ungated)\n     ---------------------------------------------------------- */\n\n  /* ----------------------------------------------------------\n     Text-on-color — plain var aliases (ungated)\n     ---------------------------------------------------------- */\n  --sf-color-text--on-base:    var(--sf-color-text);\n\n  /* Static fallbacks for engines that support oklch(from …) but not sign()\n     (Chrome 125–137, Firefox 128–130). The sign() gate below overrides these\n     with the exact auto-contrast formula when the engine supports it.\n     Derived from the default palette at threshold 0.6: surfaces with L < 0.6\n     get near-white text (0.95); warning (L 0.75) and code (on light inset)\n     get near-black (0.1). Custom palettes must override --sf-color-text--on-*\n     manually if their surface colours differ from the defaults. */\n  --sf-color-text--on-primary:   oklch(0.95 0 0);\n  --sf-color-text--on-secondary: oklch(0.95 0 0);\n  --sf-color-text--on-tertiary:  oklch(0.95 0 0);\n  --sf-color-text--on-action:    oklch(0.95 0 0);\n  --sf-color-text--on-neutral:   oklch(0.95 0 0);\n  --sf-color-text--on-success:   oklch(0.95 0 0);\n  --sf-color-text--on-warning:   oklch(0.1  0 0);\n  --sf-color-text--on-info:      oklch(0.95 0 0);\n  --sf-color-text--on-danger:    oklch(0.95 0 0);\n  --sf-color-text--on-inverse:   oklch(0.95 0 0);\n  --sf-color-code-text:          oklch(0.1  0 0);\n\n  /* ----------------------------------------------------------\n     Borders — plain var aliases (ungated)\n     ---------------------------------------------------------- */\n  --sf-color-border--focus: var(--sf-color-action);\n\n  /* ----------------------------------------------------------\n     Links — plain var aliases and geometry (ungated)\n     ---------------------------------------------------------- */\n  --sf-color-link--disabled:  var(--sf-color-text--disabled);\n  /* Underline geometry — consumed by a:link in core/base.css and by\n     the .sf-link--* macros. `auto` defers to the font's own metrics;\n     set an explicit length (e.g. 0.08em) for a uniform rule. */\n  --sf-link-underline-offset:    0.15em;\n  --sf-link-underline-thickness: auto;\n\n  /* ----------------------------------------------------------\n     Interactive states — plain var aliases (ungated)\n     ---------------------------------------------------------- */\n  --sf-color-bg--disabled: var(--sf-color-inset);\n  --sf-color-code-bg:      var(--sf-color-inset);\n\n  /* ----------------------------------------------------------\n     Selection & backdrop — static values (ungated)\n     ---------------------------------------------------------- */\n  --sf-color-selection-text: inherit;\n  --sf-color-mark-text:      inherit;\n  /* Dim: classic semi-transparent black for modal backdrops, distinct from --sf-color-overlay */\n  --sf-color-dim:            oklch(0 0 0 / 0.5);\n  --sf-color-white:          oklch(100% 0 0);\n  --sf-color-black:          oklch(0% 0 0);\n\n  /* ----------------------------------------------------------\n     Scrollbar\n     ---------------------------------------------------------- */\n  --sf-scrollbar-thumb: var(--sf-color-neutral);\n  --sf-scrollbar-track: transparent;\n\n  /* ----------------------------------------------------------\n     Shadow strength — base opacity for light mode; auto-boosted by\n     +0.17 in dark mode via --sf-is-dark. Override with a calc() to\n     preserve the adaptation: calc(0.1 + var(--sf-is-dark) * 0.17).\n     ---------------------------------------------------------- */\n  --sf-shadow-strength:   calc(0.08 + var(--sf-is-dark) * 0.17);\n  /* Shadow lightness: 0.15 is the default density. Independent token allows\n     tuning shadow depth globally across light/dark and surfaces. */\n  --sf-shadow-lightness:  0.15;\n  /* ----------------------------------------------------------\n     Shadow glow color — tint used by --sf-shadow-glow. Override to\n     retint glows; opacity/dark-mode adaptation is controlled by\n     --sf-shadow-strength.\n     ---------------------------------------------------------- */\n  --sf-shadow-glow-color: var(--sf-color-primary);\n\n  /* ----------------------------------------------------------\n     Opacity — disabled state effects\n     ---------------------------------------------------------- */\n  --sf-opacity-disabled:  0.45;\n\n  /* ----------------------------------------------------------\n     Focus / form colors\n     ---------------------------------------------------------- */\n  --sf-focus-ring-color:  var(--sf-color-action);\n  --sf-focus-ring-shadow: 0 0 0 var(--sf-focus-ring-offset) var(--sf-color-bg, var(--sf-color-base-source-light, #fff)),\n                          0 0 0 calc(var(--sf-focus-ring-offset) + var(--sf-focus-ring-width)) var(--sf-focus-ring-color);\n  --sf-caret-color:       var(--sf-color-action);\n\n}\n/* ── @supports gate: light-dark() + oklch(from …) ──\n   Safari 15.4 supports light-dark() but only adds oklch(from) in 16.4.\n   Gating on both prevents Safari 15.x/16.x from parsing the derived\n   color tokens and silently failing all base colors. */\n@supports (color: light-dark(white, black)) and (color: oklch(from red l c h)) {\n  :root {\n\n    /* ----------------------------------------------------------\n       Resolved color tokens — auto-switch via light-dark().\n       Dark auto-derivation formula (brand + status):\n       clamp(0.65, 0.95 - l*0.5, 0.88) lightens dark-mode value relative to the light source.\n       Surface inverts: clamp(0.16, 1.18 - l, 0.24) — near-white flips to near-dark.\n       Override any --sf-color-X-dark to take full per-mode control.\n       SL-001: this same clamp() formula is re-declared flat in themes.css\n       (SECTION-LEVEL THEMING) so [data-theme] overrides on non-:root elements\n       still resolve correctly — light-dark() only bakes at :root. Keep both\n       copies in sync if the formula ever changes. */\n    --sf-color-primary:   light-dark(var(--sf-color-primary-source-light),   var(--sf-color-primary-source-dark,   oklch(from var(--sf-color-primary-source-light)   clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n    --sf-color-secondary: light-dark(var(--sf-color-secondary-source-light), var(--sf-color-secondary-source-dark, oklch(from var(--sf-color-secondary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n    --sf-color-tertiary:  light-dark(var(--sf-color-tertiary-source-light),  var(--sf-color-tertiary-source-dark,  oklch(from var(--sf-color-tertiary-source-light)  clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n    --sf-color-action:    light-dark(var(--sf-color-action-source-light),    var(--sf-color-action-source-dark,    oklch(from var(--sf-color-action-source-light)    clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n    --sf-color-neutral:   light-dark(var(--sf-color-neutral-source-light),   var(--sf-color-neutral-source-dark,   oklch(from var(--sf-color-neutral-source-light)   clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n    --sf-color-base:      light-dark(var(--sf-color-base-source-light),      var(--sf-color-base-source-dark,      oklch(from var(--sf-color-base-source-light)      clamp(0.16, calc(1.18 - l),        0.24) calc(c * 0.5) h)));\n\n    --sf-color-success: light-dark(var(--sf-color-success-source-light), var(--sf-color-success-source-dark, oklch(from var(--sf-color-success-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n    --sf-color-warning: light-dark(var(--sf-color-warning-source-light), var(--sf-color-warning-source-dark, oklch(from var(--sf-color-warning-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n\n    --sf-color-info:    light-dark(var(--sf-color-info-source-light),    var(--sf-color-info-source-dark,    oklch(from var(--sf-color-info-source-light)    clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n    --sf-color-danger:  light-dark(var(--sf-color-danger-source-light),  var(--sf-color-danger-source-dark,  oklch(from var(--sf-color-danger-source-light)  clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));\n\n    /* ----------------------------------------------------------\n       Text — light and dark require opposite formula directions,\n       so each side of light-dark() references its source token.\n       ---------------------------------------------------------- */\n    --sf-color-text: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h),\n      oklch(from var(--sf-color-neutral)       clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1)    c h)\n    );\n    --sf-color-text--muted: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.35, calc(l - var(--sf-contrast-bias)), 0.62) c h),\n      oklch(from var(--sf-color-neutral)       clamp(0.48, calc(l + var(--sf-contrast-bias)), 0.74) c h)\n    );\n    --sf-color-text--subtle: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.15, calc(l - 0.25 - var(--sf-contrast-bias)), 0.45) c h),\n      oklch(from var(--sf-color-neutral)       clamp(0.55, calc(l + 0.1 + var(--sf-contrast-bias)), 0.90) c h)\n    );\n    --sf-color-text--placeholder: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.45, calc(l + 0.15), 0.75) c h),\n      oklch(from var(--sf-color-neutral)       clamp(0.35, calc(l - 0.1),  0.65) c h)\n    );\n    --sf-color-text--disabled: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.55, calc(l + 0.25), 0.82) c h),\n      oklch(from var(--sf-color-neutral)       clamp(0.25, calc(l - 0.2),  0.55) c h)\n    );\n    --sf-color-text--inverse: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.85, calc(l + 0.4), 0.98) c h),\n      oklch(from var(--sf-color-neutral)       clamp(0.05, calc(l - 0.4), 0.35) c h)\n    );\n    --sf-color-heading: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h),\n      oklch(from var(--sf-color-neutral)       clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1)    c h)\n    );\n\n    /* ----------------------------------------------------------\n       Borders — direction-dependent, reference source tokens.\n       Light: borders are lighter than neutral (l + offset).\n       Dark:  borders are darker  than neutral (l - offset).\n       ---------------------------------------------------------- */\n    --sf-color-border: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.70, calc(l + 0.35), 0.95) 0.005 h),\n      oklch(from var(--sf-color-neutral)       clamp(0.25, calc(l - 0.3),  0.55) 0.005 h)\n    );\n    --sf-color-border--subtle: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.75, calc(l + 0.4),  0.97) 0.005 h),\n      oklch(from var(--sf-color-neutral)       clamp(0.20, calc(l - 0.38), 0.45) 0.005 h)\n    );\n    --sf-color-border--strong: light-dark(\n      oklch(from var(--sf-color-neutral-source-light) clamp(0.55, calc(l + 0.1),  0.85) 0.02  h),\n      oklch(from var(--sf-color-neutral)       clamp(0.38, calc(l - 0.1),  0.65) 0.02  h)\n    );\n\n    /* ----------------------------------------------------------\n       Links — derived from --sf-color-action (auto-adapts)\n       ---------------------------------------------------------- */\n    /* Links keep the action hue but CLAMP lightness toward a contrast-safe\n       band — a ceiling in light mode, a floor in dark mode — so link text\n       clears WCAG AA (4.5:1) on the page background for the default palette\n       AND the large majority of brand overrides (a fixed offset alone only\n       fixed the default). Lightness dominates OKLCH contrast but doesn't\n       fully determine it: very high-chroma hues (saturated yellow/green) can\n       still fall short even at a safe lightness — those remain the consumer's\n       responsibility (see docs/theming.md → \"Link contrast\").\n\n       NOTE: the consumer-facing :link rule in core/base.css uses\n       `a:link` (not bare `a`) so its specificity matches WebKit's UA\n       stylesheet `a:link { color: -webkit-link }`. Without that\n       pseudo-class the framework's `--sf-color-link` value is\n       silently ignored on unvisited anchors in WebKit and\n       `-webkit-link` (≈ #00728f in dark mode) paints instead —\n       regardless of how this token is computed. PR #73 and several\n       follow-up attempts mistakenly chased the formula. */\n    --sf-color-link:            light-dark(\n      oklch(from var(--sf-color-action) clamp(0, min(l - 0.07, 0.48), 1) c h),\n      oklch(from var(--sf-color-action) clamp(0.68, l, 1) c h)\n    );\n    --sf-color-link--hover:     light-dark(\n      oklch(from var(--sf-color-action) clamp(0, min(l - 0.15, 0.40), 1) c h),\n      oklch(from var(--sf-color-action) clamp(0, max(l + 0.10, 0.68), 1) c h)\n    );\n    --sf-color-link--active:    light-dark(\n      oklch(from var(--sf-color-action) clamp(0, min(l - 0.21, 0.34), 1) c h),\n      oklch(from var(--sf-color-action) clamp(0, max(l + 0.15, 0.74), 1) c h)\n    );\n    /* Visited link — 60° hue shift from action gives clearly distinct\n       chroma without colliding with default tertiary (h ≈ 310). Same\n       lightness clamp as the base link. If your brand puts action and\n       tertiary close in hue, override directly:\n         :root { --sf-color-link--visited: #6b46c1; } */\n    --sf-color-link--visited:   light-dark(\n      oklch(from var(--sf-color-action) clamp(0, min(l - 0.07, 0.48), 1) c calc(h + 60)),\n      oklch(from var(--sf-color-action) clamp(0.68, l, 1) c calc(h + 60))\n    );\n\n    /* ----------------------------------------------------------\n       Selection\n       ---------------------------------------------------------- */\n    --sf-color-selection-bg:   light-dark(\n      oklch(from var(--sf-color-action-source-light) l c h / 0.28),\n      oklch(from var(--sf-color-action-source-dark) clamp(0.62, calc(0.93 - l * 0.4), 0.78) c h / 0.55)\n    );\n\n    /* Alt selection — the opposite scheme's treatment, for a surface\n       that deliberately inverts colours relative to the page (e.g. a\n       dark card on a light page) where the default pairing above\n       would land with poor contrast. Consumed by .sf-selection--alt\n       (optional/utilities.css). */\n    --sf-color-selection-bg--alt: light-dark(\n      oklch(from var(--sf-color-action-source-dark) clamp(0.62, calc(0.93 - l * 0.4), 0.78) c h / 0.55),\n      oklch(from var(--sf-color-action-source-light) l c h / 0.28)\n    );\n    --sf-color-selection-text--alt: inherit;\n\n    /* ----------------------------------------------------------\n       Status triplets — strong (direction-dependent, uses light-dark)\n       danger = destructive actions, form validation errors, negative states\n       ---------------------------------------------------------- */\n    --sf-color-success-strong: light-dark(\n      oklch(from var(--sf-color-success-source-light) calc(l - 0.15) c h),\n      oklch(from var(--sf-color-success)       clamp(0.70, calc(l + 0.15), 1) c h)\n    );\n    --sf-color-warning-strong: light-dark(\n      oklch(from var(--sf-color-warning-source-light) calc(l - 0.25) c h),\n      oklch(from var(--sf-color-warning)       clamp(0.70, calc(l + 0.05), 1) c h)\n    );\n    --sf-color-info-strong: light-dark(\n      oklch(from var(--sf-color-info-source-light) calc(l - 0.1) c h),\n      oklch(from var(--sf-color-info)       clamp(0.70, calc(l + 0.15), 1) c h)\n    );\n    --sf-color-danger-strong: light-dark(\n      oklch(from var(--sf-color-danger-source-light) calc(l - 0.1) c h),\n      oklch(from var(--sf-color-danger)       clamp(0.70, calc(l + 0.15), 1) c h)\n    );\n\n  }\n}\n/* ── @supports gate: oklch(from …) relative color ── */\n@supports (color: oklch(from red l c h)) {\n  :root {\n\n    /* ----------------------------------------------------------\n       Surfaces — derived from --sf-color-base (auto-adapts)\n       ---------------------------------------------------------- */\n    --sf-color-bg:      oklch(from var(--sf-color-base) calc(l + 0.02) c h);\n    --sf-color-inset:   oklch(from var(--sf-color-base) calc(l - 0.02) c h);\n    --sf-color-raised:  oklch(from var(--sf-color-base) calc(l + 0.04) c h);\n    /* Overlay: high-opacity wash of the base color for light/dark mode safe layers */\n    --sf-color-overlay: oklch(from var(--sf-color-base) l c h / 0.9);\n    --sf-color-inverse: oklch(from var(--sf-color-base) calc(1 - l) c h);\n\n    /* ----------------------------------------------------------\n       Border alpha tokens\n       ---------------------------------------------------------- */\n    --sf-color-border--disabled: oklch(from var(--sf-color-border--subtle) l 0 h / 0.5);\n    --sf-color-border--translucent: oklch(from var(--sf-color-neutral) l c h / 0.15);\n\n    /* ----------------------------------------------------------\n       Link alpha token\n       ---------------------------------------------------------- */\n    --sf-color-link--underline: oklch(from var(--sf-color-action) l c h / 0.3);\n\n    /* ----------------------------------------------------------\n       Interactive states — derived from --sf-color-neutral (auto-adapts)\n       ---------------------------------------------------------- */\n    --sf-color-bg--hover:    oklch(from var(--sf-color-neutral) l c h / 0.08);\n    --sf-color-bg--active:   oklch(from var(--sf-color-neutral) l c h / 0.12);\n    --sf-color-bg--selected: oklch(from var(--sf-color-action) l c h / 0.1);\n    --sf-color-bg--focus:    oklch(from var(--sf-color-action) l c h / 0.06);\n\n    /* ----------------------------------------------------------\n       Selection & mark\n       ---------------------------------------------------------- */\n    --sf-color-mark-bg: oklch(from var(--sf-color-warning) l c h / 0.25);\n\n    /* ----------------------------------------------------------\n       Status triplets — subtle/muted/tint (alpha variants)\n       bg/border use same formula both modes. -tint is the 5%\n       near-transparent rung, mirroring the brand families'\n       --sf-color-{family}-tint aliases (full 10-family coverage).\n       ---------------------------------------------------------- */\n    --sf-color-success-subtle: oklch(from var(--sf-color-success) l c h / 0.12);\n    --sf-color-success-muted:  oklch(from var(--sf-color-success) l c h / 0.3);\n    --sf-color-success-tint:   oklch(from var(--sf-color-success) l c h / 0.05);\n\n    --sf-color-warning-subtle: oklch(from var(--sf-color-warning) l c h / 0.12);\n    --sf-color-warning-muted:  oklch(from var(--sf-color-warning) l c h / 0.3);\n    --sf-color-warning-tint:   oklch(from var(--sf-color-warning) l c h / 0.05);\n\n    --sf-color-info-subtle:    oklch(from var(--sf-color-info) l c h / 0.12);\n    --sf-color-info-muted:     oklch(from var(--sf-color-info) l c h / 0.3);\n    --sf-color-info-tint:      oklch(from var(--sf-color-info) l c h / 0.05);\n\n    --sf-color-danger-subtle:  oklch(from var(--sf-color-danger) l c h / 0.12);\n    --sf-color-danger-muted:   oklch(from var(--sf-color-danger) l c h / 0.3);\n    --sf-color-danger-tint:    oklch(from var(--sf-color-danger) l c h / 0.05);\n\n    /* ----------------------------------------------------------\n       Gradients — derived from brand colors (auto-adapt)\n       All 4 core brand families (primary/secondary/tertiary/action)\n       share the same darkening formula; --sf-gradient-brand is a\n       separate decorative hue-shift option, independent of the\n       colour axis.\n       ---------------------------------------------------------- */\n    --sf-gradient-primary:   linear-gradient(in oklch 135deg, var(--sf-color-primary), oklch(from var(--sf-color-primary) calc(l - 0.08) c h));\n    --sf-gradient-secondary: linear-gradient(in oklch 135deg, var(--sf-color-secondary), oklch(from var(--sf-color-secondary) calc(l - 0.08) c h));\n    --sf-gradient-tertiary:  linear-gradient(in oklch 135deg, var(--sf-color-tertiary), oklch(from var(--sf-color-tertiary) calc(l - 0.08) c h));\n    --sf-gradient-action:    linear-gradient(in oklch 135deg, var(--sf-color-action), oklch(from var(--sf-color-action) calc(l - 0.08) c h));\n    --sf-gradient-brand:     linear-gradient(in oklch 135deg, var(--sf-color-primary), oklch(from var(--sf-color-primary) l c calc(h + 30)));\n    --sf-gradient-surface:   linear-gradient(in oklab 180deg, var(--sf-color-surface), var(--sf-color-bg));\n\n    --sf-gradient-fade--r: linear-gradient(in oklch to right,  transparent, var(--sf-color-bg));\n    --sf-gradient-fade--l: linear-gradient(in oklch to left,   transparent, var(--sf-color-bg));\n    --sf-gradient-fade--t: linear-gradient(in oklch to top,    transparent, var(--sf-color-bg));\n    --sf-gradient-fade--b: linear-gradient(in oklch to bottom, transparent, var(--sf-color-bg));\n\n    /* ----------------------------------------------------------\n       Shadow glow\n       ---------------------------------------------------------- */\n    --sf-shadow-glow: 0 0 15px 2px oklch(from var(--sf-shadow-glow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2), 0.7));\n\n  }\n}\n\n/* ── @supports gate: oklch(from …) + sign() ──────────────────\n   Chrome added oklch(from) in v119 but sign() only in v138\n   (Mar 2026). Without this gate, Chrome 119–137 evaluates the\n   outer block to true but IACVT-crashes on sign() inside oklch(),\n   making all text-on-color and auto-contrast code text invisible. */\n@supports (color: oklch(from red l c h)) and (width: calc(1px * sign(1))) {\n  :root {\n\n    /* ----------------------------------------------------------\n       Code text — auto-contrasts with --sf-color-code-bg.\n       ---------------------------------------------------------- */\n    /* Inline-code text colour. Auto-contrasts with --sf-color-code-bg using\n       the same luminance formula as --sf-color-text--on-*. This prevents\n       invisible text when code appears inside inverted-colour containers\n       (e.g. sf-imposter with a dark background where inherited colour is\n       near-white). Override with a tint value if desired. */\n    --sf-color-code-text: oklch(from var(--sf-color-code-bg) clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n\n    /* ----------------------------------------------------------\n       Text-on-color — sign(var(--sf-contrast-threshold) - l) * 999 is mode-agnostic:\n       auto-selects light or dark text based on background luminance.\n       Uses resolved tokens — works for any user-supplied color.\n\n       CONTRAST NOTE: Guarantees ≥ 3:1 (WCAG AA Large Text / UI).\n       Colors in the mid-luminance range (L ≈ 0.52–0.67) may not\n       reach 4.5:1 (AA Normal Text) regardless of threshold chosen —\n       this is a mathematical limitation of any binary black/white\n       decision. The SLASHED configurator will warn users when their\n       brand colors fall in this range. For body text on colored\n       backgrounds, override --sf-color-text--on-* manually.\n       ---------------------------------------------------------- */\n    --sf-color-text--on-primary:   oklch(from var(--sf-color-primary)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-secondary: oklch(from var(--sf-color-secondary) clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-tertiary:  oklch(from var(--sf-color-tertiary)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-action:    oklch(from var(--sf-color-action)     clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-neutral:   oklch(from var(--sf-color-neutral)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-success:   oklch(from var(--sf-color-success)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-warning:   oklch(from var(--sf-color-warning)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-info:      oklch(from var(--sf-color-info)       clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-danger:    oklch(from var(--sf-color-danger)     clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-inverse:   oklch(from var(--sf-color-inverse)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n\n  }\n}\n\n/* ============================================================\n   COLOR PALETTE — numeric ramps, alpha variants + aliases\n\n   Numeric palette steps (-50…-950), alpha variants (-a5…-a80),\n   and semantic convenience aliases live in core as the single source\n   of truth for the 6 brand colour families. Shade steps mix toward\n   --sf-color-surface (tints) or --sf-color-text (shades); the base\n   family inverts tint direction so the ramp reads light→dark regardless\n   of the base surface value.\n   ============================================================ */\n\n/* ── @supports gate: palette ramps + alpha aliases ── */\n@supports (color: oklch(from red l c h)) {\n:root {\n\n  /* ----------------------------------------------------------\n     Palette ramp lightness anchors — PUBLIC-ADVANCED\n     Each numeric step is generated in OKLCH by pulling the family\n     colour's own lightness a fixed fraction toward an ABSOLUTE target:\n     tints (50-400) toward --sf-palette-tint-l, shades (600-950) toward\n     --sf-palette-shade-l. 500 = the family colour itself. Because the\n     targets are absolute (not the theme's surface/text tokens) and the\n     pull is clamped (max()/min()) so a tint can never end darker than\n     the base nor a shade lighter, the ramp is MONOTONIC light→dark for\n     ANY source colour and any anchor configuration — it cannot fold.\n     Per-step pull fractions and chroma taper are baked into each family\n     below; these two knobs set how light the lightest / how dark the\n     darkest step may reach. The `base` family keeps its own absolute\n     ladder (near-white→near-black) and does not read these.\n     ---------------------------------------------------------- */\n  --sf-palette-tint-l:  0.97;\n  --sf-palette-shade-l: 0.1;\n\n  /* ----------------------------------------------------------\n     primary\n     ---------------------------------------------------------- */\n  --sf-color-primary-50: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);\n  --sf-color-primary-100: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);\n  --sf-color-primary-200: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);\n  --sf-color-primary-300: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);\n  --sf-color-primary-400: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);\n  --sf-color-primary-500: var(--sf-color-primary);\n  --sf-color-primary-600: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);\n  --sf-color-primary-700: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);\n  --sf-color-primary-800: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);\n  --sf-color-primary-900: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);\n  --sf-color-primary-950: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);\n\n  --sf-color-primary-a5:  oklch(from var(--sf-color-primary) l c h / 0.05);\n  --sf-color-primary-a10: oklch(from var(--sf-color-primary) l c h / 0.10);\n  --sf-color-primary-a30: oklch(from var(--sf-color-primary) l c h / 0.30);\n  --sf-color-primary-a50: oklch(from var(--sf-color-primary) l c h / 0.50);\n  --sf-color-primary-a80: oklch(from var(--sf-color-primary) l c h / 0.80);\n\n  --sf-color-primary-superlight: var(--sf-color-primary-50);\n  --sf-color-primary-xlight:     var(--sf-color-primary-200);\n  --sf-color-primary-lighter:    var(--sf-color-primary-400);\n  --sf-color-primary-darker:     var(--sf-color-primary-600);\n  --sf-color-primary-xdark:      var(--sf-color-primary-800);\n  --sf-color-primary-superdark:  var(--sf-color-primary-950);\n  --sf-color-primary--hover:     var(--sf-color-primary-darker);\n  --sf-color-primary--active:    var(--sf-color-primary-xdark);\n  --sf-color-primary-subtle:     var(--sf-color-primary-a10);\n  --sf-color-primary-muted:      var(--sf-color-primary-a30);\n  --sf-color-primary-tint:      var(--sf-color-primary-a5);\n\n\n\n  /* ----------------------------------------------------------\n     secondary\n     ---------------------------------------------------------- */\n  --sf-color-secondary-50: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);\n  --sf-color-secondary-100: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);\n  --sf-color-secondary-200: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);\n  --sf-color-secondary-300: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);\n  --sf-color-secondary-400: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);\n  --sf-color-secondary-500: var(--sf-color-secondary);\n  --sf-color-secondary-600: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);\n  --sf-color-secondary-700: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);\n  --sf-color-secondary-800: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);\n  --sf-color-secondary-900: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);\n  --sf-color-secondary-950: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);\n\n  --sf-color-secondary-a5:  oklch(from var(--sf-color-secondary) l c h / 0.05);\n  --sf-color-secondary-a10: oklch(from var(--sf-color-secondary) l c h / 0.10);\n  --sf-color-secondary-a30: oklch(from var(--sf-color-secondary) l c h / 0.30);\n  --sf-color-secondary-a50: oklch(from var(--sf-color-secondary) l c h / 0.50);\n  --sf-color-secondary-a80: oklch(from var(--sf-color-secondary) l c h / 0.80);\n\n  --sf-color-secondary-superlight: var(--sf-color-secondary-50);\n  --sf-color-secondary-xlight:     var(--sf-color-secondary-200);\n  --sf-color-secondary-lighter:    var(--sf-color-secondary-400);\n  --sf-color-secondary-darker:     var(--sf-color-secondary-600);\n  --sf-color-secondary-xdark:      var(--sf-color-secondary-800);\n  --sf-color-secondary-superdark:  var(--sf-color-secondary-950);\n  --sf-color-secondary--hover:     var(--sf-color-secondary-darker);\n  --sf-color-secondary--active:    var(--sf-color-secondary-xdark);\n  --sf-color-secondary-subtle:     var(--sf-color-secondary-a10);\n  --sf-color-secondary-muted:      var(--sf-color-secondary-a30);\n  --sf-color-secondary-tint:      var(--sf-color-secondary-a5);\n\n\n\n  /* ----------------------------------------------------------\n     tertiary\n     ---------------------------------------------------------- */\n  --sf-color-tertiary-50: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);\n  --sf-color-tertiary-100: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);\n  --sf-color-tertiary-200: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);\n  --sf-color-tertiary-300: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);\n  --sf-color-tertiary-400: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);\n  --sf-color-tertiary-500: var(--sf-color-tertiary);\n  --sf-color-tertiary-600: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);\n  --sf-color-tertiary-700: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);\n  --sf-color-tertiary-800: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);\n  --sf-color-tertiary-900: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);\n  --sf-color-tertiary-950: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);\n\n  --sf-color-tertiary-a5:  oklch(from var(--sf-color-tertiary) l c h / 0.05);\n  --sf-color-tertiary-a10: oklch(from var(--sf-color-tertiary) l c h / 0.10);\n  --sf-color-tertiary-a30: oklch(from var(--sf-color-tertiary) l c h / 0.30);\n  --sf-color-tertiary-a50: oklch(from var(--sf-color-tertiary) l c h / 0.50);\n  --sf-color-tertiary-a80: oklch(from var(--sf-color-tertiary) l c h / 0.80);\n\n  --sf-color-tertiary-superlight: var(--sf-color-tertiary-50);\n  --sf-color-tertiary-xlight:     var(--sf-color-tertiary-200);\n  --sf-color-tertiary-lighter:    var(--sf-color-tertiary-400);\n  --sf-color-tertiary-darker:     var(--sf-color-tertiary-600);\n  --sf-color-tertiary-xdark:      var(--sf-color-tertiary-800);\n  --sf-color-tertiary-superdark:  var(--sf-color-tertiary-950);\n  --sf-color-tertiary--hover:     var(--sf-color-tertiary-darker);\n  --sf-color-tertiary--active:    var(--sf-color-tertiary-xdark);\n  --sf-color-tertiary-subtle:     var(--sf-color-tertiary-a10);\n  --sf-color-tertiary-muted:      var(--sf-color-tertiary-a30);\n  --sf-color-tertiary-tint:      var(--sf-color-tertiary-a5);\n\n\n\n  /* ----------------------------------------------------------\n     action\n     ---------------------------------------------------------- */\n  --sf-color-action-50: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);\n  --sf-color-action-100: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);\n  --sf-color-action-200: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);\n  --sf-color-action-300: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);\n  --sf-color-action-400: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);\n  --sf-color-action-500: var(--sf-color-action);\n  --sf-color-action-600: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);\n  --sf-color-action-700: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);\n  --sf-color-action-800: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);\n  --sf-color-action-900: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);\n  --sf-color-action-950: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);\n\n  --sf-color-action-a5:  oklch(from var(--sf-color-action) l c h / 0.05);\n  --sf-color-action-a10: oklch(from var(--sf-color-action) l c h / 0.10);\n  --sf-color-action-a30: oklch(from var(--sf-color-action) l c h / 0.30);\n  --sf-color-action-a50: oklch(from var(--sf-color-action) l c h / 0.50);\n  --sf-color-action-a80: oklch(from var(--sf-color-action) l c h / 0.80);\n\n  --sf-color-action-superlight: var(--sf-color-action-50);\n  --sf-color-action-xlight:     var(--sf-color-action-200);\n  --sf-color-action-lighter:    var(--sf-color-action-400);\n  --sf-color-action-darker:     var(--sf-color-action-600);\n  --sf-color-action-xdark:      var(--sf-color-action-800);\n  --sf-color-action-superdark:  var(--sf-color-action-950);\n  --sf-color-action--hover:     var(--sf-color-action-darker);\n  --sf-color-action--active:    var(--sf-color-action-xdark);\n  --sf-color-action-subtle:     var(--sf-color-action-a10);\n  --sf-color-action-muted:      var(--sf-color-action-a30);\n  --sf-color-action-tint:      var(--sf-color-action-a5);\n\n\n\n  /* ----------------------------------------------------------\n     neutral\n     ---------------------------------------------------------- */\n  --sf-color-neutral-50: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);\n  --sf-color-neutral-100: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);\n  --sf-color-neutral-200: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);\n  --sf-color-neutral-300: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);\n  --sf-color-neutral-400: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);\n  --sf-color-neutral-500: var(--sf-color-neutral);\n  --sf-color-neutral-600: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);\n  --sf-color-neutral-700: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);\n  --sf-color-neutral-800: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);\n  --sf-color-neutral-900: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);\n  --sf-color-neutral-950: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);\n\n  --sf-color-neutral-a5:  oklch(from var(--sf-color-neutral) l c h / 0.05);\n  --sf-color-neutral-a10: oklch(from var(--sf-color-neutral) l c h / 0.10);\n  --sf-color-neutral-a30: oklch(from var(--sf-color-neutral) l c h / 0.30);\n  --sf-color-neutral-a50: oklch(from var(--sf-color-neutral) l c h / 0.50);\n  --sf-color-neutral-a80: oklch(from var(--sf-color-neutral) l c h / 0.80);\n\n  --sf-color-neutral-superlight: var(--sf-color-neutral-50);\n  --sf-color-neutral-xlight:     var(--sf-color-neutral-200);\n  --sf-color-neutral-lighter:    var(--sf-color-neutral-400);\n  --sf-color-neutral-darker:     var(--sf-color-neutral-600);\n  --sf-color-neutral-xdark:      var(--sf-color-neutral-800);\n  --sf-color-neutral-superdark:  var(--sf-color-neutral-950);\n  --sf-color-neutral--hover:     var(--sf-color-neutral-darker);\n  --sf-color-neutral--active:    var(--sf-color-neutral-xdark);\n  --sf-color-neutral-subtle:     var(--sf-color-neutral-a10);\n  --sf-color-neutral-muted:      var(--sf-color-neutral-a30);\n  --sf-color-neutral-tint:      var(--sf-color-neutral-a5);\n\n\n\n  /* ----------------------------------------------------------\n     base — fixed-lightness ramp (mode-independent, monotonic)\n     ────────────────────────────────────────────────────────\n     base is a surface-elevation family, not a mid-lightness brand\n     colour. The ramp uses oklch() relative syntax with fixed L steps\n     spanning 0.97 → 0.06, preserving the base source's hue and chroma.\n     50 is always near-white; 950 is always near-black regardless of\n     light/dark mode or the source colour's position.\n\n     OKLCH L values (fixed, mode-independent):\n       base-50  = 0.97   near-white\n       base-100 = 0.94   very light gray\n       base-200 = 0.88   light gray\n       base-300 = 0.78   medium-light gray\n       base-400 = 0.65   medium gray\n       base-500 = 0.50   mid gray\n       base-600 = 0.37   medium-dark gray\n       base-700 = 0.27   dark gray\n       base-800 = 0.17   very dark gray\n       base-900 = 0.11   near-black\n       base-950 = 0.06   near-black\n\n     For mode-adaptive surface differentiation use the surface tokens\n     (--sf-color-inset / --sf-color-raised / --sf-color-bg) which derive\n     from --sf-color-base via relative oklch and adapt to light/dark mode.\n     For overlays use alpha variants (-a10…-a80).\n     ---------------------------------------------------------- */\n  --sf-color-base-50:  oklch(from var(--sf-color-base) 0.97 c h);\n  --sf-color-base-100: oklch(from var(--sf-color-base) 0.94 c h);\n  --sf-color-base-200: oklch(from var(--sf-color-base) 0.88 c h);\n  --sf-color-base-300: oklch(from var(--sf-color-base) 0.78 c h);\n  --sf-color-base-400: oklch(from var(--sf-color-base) 0.65 c h);\n  --sf-color-base-500: oklch(from var(--sf-color-base) 0.50 c h);\n  --sf-color-base-600: oklch(from var(--sf-color-base) 0.37 c h);\n  --sf-color-base-700: oklch(from var(--sf-color-base) 0.27 c h);\n  --sf-color-base-800: oklch(from var(--sf-color-base) 0.17 c h);\n  --sf-color-base-900: oklch(from var(--sf-color-base) 0.11 c h);\n  --sf-color-base-950: oklch(from var(--sf-color-base) 0.06 c h);\n\n  --sf-color-base-a5:  oklch(from var(--sf-color-base) l c h / 0.05);\n  --sf-color-base-a10: oklch(from var(--sf-color-base) l c h / 0.10);\n  --sf-color-base-a30: oklch(from var(--sf-color-base) l c h / 0.30);\n  --sf-color-base-a50: oklch(from var(--sf-color-base) l c h / 0.50);\n  --sf-color-base-a80: oklch(from var(--sf-color-base) l c h / 0.80);\n\n  /* No relative aliases (lighter/darker/xlight/…) on base: it is an\n     absolute scale, so a step's name would lie depending on where the\n     source sits (e.g. \"lighter\" would be darker than a near-white base\n     in light mode). For relative, mode-adaptive surface elevation use\n     --sf-color-bg / --sf-color-inset / --sf-color-raised instead. */\n  --sf-color-base--hover:     oklch(from var(--sf-color-base) clamp(0.01, calc(l - 0.04 + var(--sf-is-dark) * 0.08), 0.99) c h);\n  --sf-color-base--active:    oklch(from var(--sf-color-base) clamp(0.01, calc(l - 0.08 + var(--sf-is-dark) * 0.16), 0.99) c h);\n  --sf-color-base-subtle:     var(--sf-color-base-a10);\n  --sf-color-base-muted:      var(--sf-color-base-a30);\n  --sf-color-base-tint:      var(--sf-color-base-a5);\n\n\n}\n}\n\n/* ============================================================\n   NON-COLOR DESIGN TOKENS\n   ============================================================ */\n\n:root {\n\n  /* ----------------------------------------------------------\n     Scale multipliers\n     ---------------------------------------------------------- */\n  --sf-space-scale:        1;\n  --sf-text-scale:         1;\n  --sf-text-display-scale: 1;\n  --sf-radius-scale:       1;\n  --sf-motion-scale:       1;\n  --sf-section-scale:      1;\n\n  /* ----------------------------------------------------------\n     Font families\n     ---------------------------------------------------------- */\n  --sf-font-body:    system-ui, -apple-system, sans-serif;\n  --sf-font-heading: var(--sf-font-body);\n  --sf-font-display: var(--sf-font-heading);\n  --sf-font-mono:    ui-monospace, monospace;\n\n  /* Optional system-font stacks (zero-cost, no @import) */\n  --sf-font-humanist:  \"Seravek\", \"Gill Sans Nova\", \"Ubuntu\", \"Calibri\", \"DejaVu Sans\", source-sans-pro, sans-serif;\n  --sf-font-geometric: \"Avenir\", \"Montserrat\", \"Corbel\", \"URW Gothic\", source-sans-pro, sans-serif;\n  --sf-font-slab:      \"Rockwell\", \"Rockwell Nova\", \"Roboto Slab\", \"DejaVu Serif\", \"Sitka Small\", serif;\n\n  /* Opt-in OpenType / variable-font controls (token-only, not applied by the framework) */\n  --sf-font-features:  normal;  /* e.g. \"cv11\", \"ss01\" */\n  --sf-font-variation: normal;  /* e.g. \"wght\" 450, \"opsz\" 32 */\n  --sf-optical-sizing: auto;\n\n  /* ----------------------------------------------------------\n     Font weights\n     ---------------------------------------------------------- */\n  /* Base weights — trimmed, recognizable names. For an off-scale weight\n     (e.g. 100/900 display work) write font-weight: 100 directly, or re-tune\n     a role token below globally — every weight here is overridable. */\n  --sf-font-weight-light:    300;\n  --sf-font-weight-normal:   400;\n  --sf-font-weight-medium:   500;\n  --sf-font-weight-semibold: 600;\n  --sf-font-weight-bold:     700;\n\n  /* Semantic role aliases — set intent, not a number. Override these to\n     reweight the whole site (e.g. --sf-font-weight-body: 300). */\n  --sf-font-weight-body:        var(--sf-font-weight-normal);    /* body copy            */\n  --sf-font-weight-heading:     var(--sf-font-weight-semibold);  /* h1–h6                */\n  --sf-font-weight-display:     var(--sf-font-weight-bold);      /* hero / display       */\n  --sf-font-weight-interactive: var(--sf-font-weight-semibold);  /* buttons, badges, nav.\n     Note: \"interactive\" here names a TYPOGRAPHY WEIGHT TIER; .sf-card--interactive\n     names a card BEHAVIOUR modifier. Deliberate coexistence (different property\n     spaces) — do not introduce a third meaning of \"interactive\". */\n  --sf-font-weight-strong:      var(--sf-font-weight-bold);      /* <strong> / emphasis  */\n\n  /* ----------------------------------------------------------\n     Font sizes — fluid\n     ---------------------------------------------------------- */\n  /* ----------------------------------------------------------\n     Font sizes — fluid (generative)\n     Computed from --sf-text-ratio-{min,max} + --sf-text-base-{min,max}\n     over the --sf-fluid-{min,max}-vw range. Step exponent N is relative\n     to --sf-text-m (N=0): 2xs=-3 … 4xl=5. Override the inputs above to\n     reshape the whole scale; override an individual --sf-text-* to pin one.\n     ---------------------------------------------------------- */\n  --sf-text-2xs: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -3) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -3) * 1rem)) * var(--sf-text-scale));\n  --sf-text-xs:  calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -2) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -2) * 1rem)) * var(--sf-text-scale));\n  --sf-text-s:   calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -1) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -1) * 1rem)) * var(--sf-text-scale));\n  --sf-text-m:   calc(clamp(calc(var(--sf-text-base-min) * 1rem), calc((var(--sf-text-base-max) - var(--sf-text-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * 1rem), calc(var(--sf-text-base-max) * 1rem)) * var(--sf-text-scale));\n  --sf-text-l:   calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 1) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 1) * 1rem)) * var(--sf-text-scale));\n  --sf-text-xl:  calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 2) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 2) * 1rem)) * var(--sf-text-scale));\n  --sf-text-2xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 3) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 3) * 1rem)) * var(--sf-text-scale));\n  --sf-text-3xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 4) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 4) * 1rem)) * var(--sf-text-scale));\n  --sf-text-4xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 5) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 5) * 1rem)) * var(--sf-text-scale));\n\n  /* Display — reuses the type ratios with its own larger base (s=0, m=1, l=2). */\n  --sf-text-display-s: calc(clamp(calc(var(--sf-text-display-base-min) * 1rem), calc((var(--sf-text-display-base-max) - var(--sf-text-display-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * 1rem), calc(var(--sf-text-display-base-max) * 1rem)) * var(--sf-text-display-scale));\n  --sf-text-display-m: calc(clamp(calc(var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc((var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 1) - var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc(var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 1) * 1rem)) * var(--sf-text-display-scale));\n  --sf-text-display-l: calc(clamp(calc(var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc((var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 2) - var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc(var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 2) * 1rem)) * var(--sf-text-display-scale));\n\n  /* ----------------------------------------------------------\n     Line heights & letter spacing\n     ---------------------------------------------------------- */\n  --sf-leading-tight:   1.1;\n  --sf-leading-snug:    1.3;\n  --sf-leading-normal:  1.5;\n  --sf-leading-relaxed: 1.625;\n\n  /* Leading taper — progressive tightener for the per-size line-height\n     tokens below. Each step up the type scale subtracts\n     `step-index × taper` from that step's default leading.\n     0 (default) keeps the curated stepped defaults; try 0.02 for a smooth\n     metric taper across the scale. */\n  --sf-leading-taper: 0;\n\n  /* Display line-heights — display sizes need tighter leading than the\n     --sf-leading-* scale provides. Not auto-applied (display sizes have no\n     dedicated element); wire alongside font-size:\n       h1.hero { font-size: var(--sf-text-display-l);\n                 line-height: var(--sf-display-l-line-height); } */\n  --sf-display-s-line-height: var(--sf-leading-tight);\n  --sf-display-m-line-height: 1.05;\n  --sf-display-l-line-height: 1;\n\n  --sf-tracking-tight:   -0.025em;\n  --sf-tracking-normal:   0;\n  --sf-tracking-wide:     0.025em;\n  --sf-tracking-wider:    0.05em;\n  --sf-tracking-widest:   0.1em;\n\n  /* Numeric figure style — tabular-nums gives every digit a fixed\n     advance width so numbers line up in vertical columns (price\n     lists, totals, invoices, dashboards). Consumed by number inputs\n     in optional/forms.css and available to BEM components, e.g.\n     `.price { font-variant-numeric: var(--sf-font-numeric); }`.\n     Universal browser support. */\n  --sf-font-numeric: tabular-nums;\n\n  /* ----------------------------------------------------------\n     Per-size typography sub-properties\n     Not auto-applied — opt-in composable overrides. Wire alongside\n     font-size in your own rules:\n       .element { line-height: var(--sf-text-xl-line-height); }\n     Small text: relaxed leading. Body: normal. Large: progressively\n     tighter. --sf-leading-taper (default 0) tightens the whole\n     scale at once.\n     ---------------------------------------------------------- */\n\n  --sf-text-2xs-line-height:            var(--sf-leading-relaxed);\n  --sf-text-2xs-font-weight:            var(--sf-font-weight-body);\n  --sf-text-2xs-letter-spacing:         var(--sf-tracking-normal);\n  --sf-text-2xs-max-width:              55ch;\n\n  --sf-text-xs-line-height:             calc(var(--sf-leading-relaxed) - 1 * var(--sf-leading-taper));\n  --sf-text-xs-font-weight:             var(--sf-font-weight-body);\n  --sf-text-xs-letter-spacing:          var(--sf-tracking-normal);\n  --sf-text-xs-max-width:               60ch;\n\n  --sf-text-s-line-height:              calc(var(--sf-leading-relaxed) - 2 * var(--sf-leading-taper));\n  --sf-text-s-font-weight:              var(--sf-font-weight-body);\n  --sf-text-s-letter-spacing:           var(--sf-tracking-normal);\n  --sf-text-s-max-width:                65ch;\n\n  --sf-text-m-line-height:              calc(var(--sf-leading-normal) - 3 * var(--sf-leading-taper));\n  --sf-text-m-font-weight:              var(--sf-font-weight-body);\n  --sf-text-m-letter-spacing:           var(--sf-tracking-normal);\n  --sf-text-m-max-width:                65ch;\n\n  --sf-text-l-line-height:              calc(var(--sf-leading-normal) - 4 * var(--sf-leading-taper));\n  --sf-text-l-font-weight:              var(--sf-font-weight-body);\n  --sf-text-l-letter-spacing:           var(--sf-tracking-normal);\n  --sf-text-l-max-width:                none;\n\n  --sf-text-xl-line-height:             calc(var(--sf-leading-snug) - 5 * var(--sf-leading-taper));\n  --sf-text-xl-font-weight:             var(--sf-font-weight-body);\n  --sf-text-xl-letter-spacing:          var(--sf-tracking-normal);\n  --sf-text-xl-max-width:               none;\n\n  --sf-text-2xl-line-height:            calc(var(--sf-leading-snug) - 6 * var(--sf-leading-taper));\n  --sf-text-2xl-font-weight:            var(--sf-font-weight-heading);\n  --sf-text-2xl-letter-spacing:         var(--sf-tracking-normal);\n  --sf-text-2xl-max-width:              none;\n\n  --sf-text-3xl-line-height:            calc(var(--sf-leading-tight) - 7 * var(--sf-leading-taper));\n  --sf-text-3xl-font-weight:            var(--sf-font-weight-heading);\n  --sf-text-3xl-letter-spacing:         var(--sf-tracking-tight);\n  --sf-text-3xl-max-width:              none;\n\n  --sf-text-4xl-line-height:            calc(var(--sf-leading-tight) - 8 * var(--sf-leading-taper));\n  --sf-text-4xl-font-weight:            var(--sf-font-weight-heading);\n  --sf-text-4xl-letter-spacing:         var(--sf-tracking-tight);\n  --sf-text-4xl-max-width:              none;\n\n  /* ----------------------------------------------------------\n     Icon sizes — em-based by design.\n     Icons are sized in em so they scale with the surrounding\n     text: an icon in a button at --sf-text-m renders at 1rem;\n     moved into a heading at --sf-text-2xl, the same icon scales\n     up automatically.\n     Global scaling flows transitively through --sf-text-scale\n     (parent text grows → em-icons grow) — there is no separate\n     --sf-icon-scale knob by design. clamp() is intentionally\n     absent here: making icons fluid INDEPENDENTLY of context\n     would break the relationship to surrounding text.\n     Capped at --2xl (4em ≈ 64px on default text); above that the\n     element ceases to be an icon and becomes an illustration.\n     ---------------------------------------------------------- */\n  --sf-icon-xs:  0.875em;\n  --sf-icon-s:   1em;\n  --sf-icon-m:   1.5em;\n  --sf-icon-l:   2em;\n  --sf-icon-xl:  3em;\n  --sf-icon-2xl: 4em;\n\n  /* ----------------------------------------------------------\n     Spacing — fixed\n     ---------------------------------------------------------- */\n  --sf-space-none:   0;\n  --sf-space-px:     1px;\n\n  /* Spacing — fluid (generative). Same engine as type; space uses base_max=2\n     (more dramatic growth than type's 1.25). Step exponent N relative to\n     --sf-space-m (N=0): 2xs=-3 … 4xl=5. */\n  --sf-space-2xs: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -3) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -3) * 1rem)) * var(--sf-space-scale));\n  --sf-space-xs:  calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -2) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -2) * 1rem)) * var(--sf-space-scale));\n  --sf-space-s:   calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -1) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -1) * 1rem)) * var(--sf-space-scale));\n  --sf-space-m:   calc(clamp(calc(var(--sf-space-base-min) * 1rem), calc((var(--sf-space-base-max) - var(--sf-space-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * 1rem), calc(var(--sf-space-base-max) * 1rem)) * var(--sf-space-scale));\n  --sf-space-l:   calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 1) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 1) * 1rem)) * var(--sf-space-scale));\n  --sf-space-xl:  calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 2) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 2) * 1rem)) * var(--sf-space-scale));\n  --sf-space-2xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 3) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 3) * 1rem)) * var(--sf-space-scale));\n  --sf-space-3xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 4) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 4) * 1rem)) * var(--sf-space-scale));\n  --sf-space-4xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 5) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 5) * 1rem)) * var(--sf-space-scale));\n\n  /* ----------------------------------------------------------\n     Density — the compact ↔ comfortable dial for interactive\n     control GEOMETRY. 1 = default; <1 packs controls tighter\n     (dashboards, data tables, power-user tools), >1 loosens them.\n     It is a discrete design/product choice (or a user preference),\n     NOT a viewport response — control height must never shrink on\n     small screens where touch targets need to be larger, so unlike\n     the fluid text and space scales the size ladder stays non-fluid\n     and is scaled only by this deliberate knob. Orthogonal to\n     --sf-space-scale (overall whitespace) and --sf-section-scale\n     (macro section rhythm); combine them for a fully compact UI.\n     Accessibility is unaffected: the coarse-pointer floor lives on\n     --sf-touch-target (core/accessibility.css), never on a rung, so\n     a small --sf-density can't shrink native controls below the\n     WCAG target. Like the other global multipliers it is a :root\n     dial — the size ladder is computed at :root and inherits, so a\n     nested override does not retroactively rescale it (same\n     computed-value rule as --sf-space-scale et al.). */\n  --sf-density: 1;\n\n  /* ----------------------------------------------------------\n     UI sizes — a purely geometric rung ladder (+0.5rem / 8px per\n     step: 24 · 32 · 40 · 48 · 56 px at density 1). These are free\n     design knobs, scaled by --sf-density; overriding a rung just\n     rescales that component height. Accessibility floors live on\n     their own tokens (--sf-touch-target), never on a rung.\n     ---------------------------------------------------------- */\n  --sf-size-xs: calc(1.5rem * var(--sf-density));\n  --sf-size-s:  calc(2rem   * var(--sf-density));\n  --sf-size-m:  calc(2.5rem * var(--sf-density));\n  --sf-size-l:  calc(3rem   * var(--sf-density));\n  --sf-size-xl: calc(3.5rem * var(--sf-density));\n\n  /* ----------------------------------------------------------\n     Containers\n     ---------------------------------------------------------- */\n  --sf-container-narrow:  38rem;\n  --sf-container-prose:   65ch;\n  --sf-container-default: 75rem;\n  --sf-container-wide:    90rem;\n  --sf-container-full:    100%;\n\n  /* ----------------------------------------------------------\n     Aspect ratios\n     ---------------------------------------------------------- */\n  --sf-ratio-square:   1;\n  --sf-ratio-video:    16 / 9;\n  --sf-ratio-cinema:   21 / 9;\n  --sf-ratio-4-3:      4 / 3;\n  --sf-ratio-3-2:      3 / 2;\n  --sf-ratio-portrait: 3 / 4;\n  --sf-ratio-golden:   1.618 / 1;\n\n  /* ----------------------------------------------------------\n     Border widths\n     --sf-border-width-hairline: device-pixel-dependent. On 1x DPR\n     displays (Windows non-Retina) the browser will round 0.5px up\n     to 1px, so it visually matches --sf-border-width-1. On 2x+\n     DPR (macOS/iOS Retina, most modern phones) it renders as a\n     true half-pixel hairline. Use it for subtle separators where\n     1px on low-DPR is acceptable.\n     ---------------------------------------------------------- */\n  /* --sf-border-scale — global multiplier for border widths. Set to 0 for\n     borderless, 2 for heavy borders. Hairline is intentionally excluded\n     (it's a device-pixel constant, not a design variable). */\n  --sf-border-scale:           1;\n  --sf-border-width-hairline: 0.5px;\n  --sf-border-width-1:        calc(1px * var(--sf-border-scale, 1));\n  --sf-border-width-2:        calc(2px * var(--sf-border-scale, 1));\n  --sf-border-width-3:        calc(3px * var(--sf-border-scale, 1));\n  --sf-border-width-4:        calc(4px * var(--sf-border-scale, 1));\n\n  /* ----------------------------------------------------------\n     Border style — global knob paired with --sf-border-width-* and\n     --sf-color-border*. Consumer BEM:\n       .my-card { border: var(--sf-border-width-1) var(--sf-border-style) var(--sf-color-border); }\n     Set once on :root to restyle every framework border, or override\n     per element. For one-off decorative styles use the CSS keyword\n     directly (e.g. `border-style: dashed`).\n     ---------------------------------------------------------- */\n  --sf-border-style: solid;     /* default */\n\n  /* ----------------------------------------------------------\n     Border shorthands — convenience tokens composing width, style,\n     and color into a single value for the common cases.\n     subtle / strong vary COLOR CONTRAST only — all three use\n     --sf-border-width-1 (1px). This matches the IBM Carbon and\n     GitHub Primer convention where subtle/strong name a color axis,\n     not a weight axis. For a thicker border compose manually:\n       border: var(--sf-border-width-2) var(--sf-border-style) var(--sf-color-border--strong)\n     Usage: border: var(--sf-border);\n            border-bottom: var(--sf-border-subtle);\n     ---------------------------------------------------------- */\n  --sf-border:        var(--sf-border-width-1) var(--sf-border-style) var(--sf-color-border);\n  --sf-border-subtle: var(--sf-border-width-1) var(--sf-border-style) var(--sf-color-border--subtle);\n  --sf-border-strong: var(--sf-border-width-1) var(--sf-border-style) var(--sf-color-border--strong);\n\n  /* ----------------------------------------------------------\n     Divider — global separator system. Drives `hr` (base) and\n     the `.sf-divider` layout primitive.\n     ---------------------------------------------------------- */\n  --sf-divider-width: var(--sf-border-width-1);\n  --sf-divider-style: solid;\n  --sf-divider-color: var(--sf-color-border);\n  --sf-divider-gap:   var(--sf-space-m);\n\n  /* ----------------------------------------------------------\n     Border radius — scale ramp, all multiplied by --sf-radius-scale.\n     ---------------------------------------------------------- */\n  --sf-radius-none: 0;\n  --sf-radius-2xs:  calc(1px  * var(--sf-radius-scale));\n  --sf-radius-xs:   calc(2px  * var(--sf-radius-scale));\n  --sf-radius-s:    calc(4px  * var(--sf-radius-scale));\n  --sf-radius-m:    calc(8px  * var(--sf-radius-scale));\n  --sf-radius-l:    calc(12px * var(--sf-radius-scale));\n  --sf-radius-xl:   calc(16px * var(--sf-radius-scale));\n  --sf-radius-2xl:  calc(24px * var(--sf-radius-scale));\n  --sf-radius-3xl:  calc(32px * var(--sf-radius-scale));\n  --sf-radius-4xl:  calc(48px * var(--sf-radius-scale));\n  /* ----------------------------------------------------------\n     Full/pill — topological constants, not scaled by --sf-radius-scale.\n     A pill/circle is a topological constant, not a relative size:\n     any --sf-radius-scale: 0 (\"sharp\" design system) should still\n     render pill buttons as pills. 9999px is a magic-number convention\n     large enough to clip to half the shorter edge for any realistic UI.\n     ---------------------------------------------------------- */\n  --sf-radius-full: 9999px;\n  /* Pill — semantic alias of --sf-radius-full. Reach for this name\n     on rectangles you want capsule-shaped (badges, tags, chips); use\n     --sf-radius-full when you mean \"as round as topologically possible\". */\n  --sf-radius-pill: var(--sf-radius-full);\n  /* Concentric helper — outer radius for a container that wraps\n     content padded by --sf-component-pad with inner radius m.\n     Keeps inner elements visually proportional inside a padded box.\n     Override per use:\n       .my-card { border-radius: var(--sf-radius-outer); }\n     Maths: outer = inner + padding ⇒ aligned curves at corners. */\n  --sf-radius-outer: calc(var(--sf-radius-m) + var(--sf-component-pad));\n\n  /* Opt-in global media radius — 0 by default (off). Set to a\n     --sf-radius-* value to round <img>/<figure> globally:\n       :root { --sf-media-radius: var(--sf-radius-m); }\n     Applied via :where() in core/base.css so it never fights\n     .sf-bg-layer or a component's own radius. */\n  --sf-media-radius: 0;\n\n  /* ----------------------------------------------------------\n     Shadows — BEM consumer API\n     Use in your own classes: .card { box-shadow: var(--sf-shadow-m); }\n     ---------------------------------------------------------- */\n\n\n  /* ----------------------------------------------------------\n     Blur & opacity\n     One frosted-surface default (nav/overlay glass) and one general\n     de-emphasis opacity. For other amounts write the value directly:\n     backdrop-filter: blur(24px); opacity: .3;\n     (--sf-opacity-disabled is defined with the interaction tokens.)\n     ---------------------------------------------------------- */\n  --sf-blur:          12px;\n  --sf-opacity-muted: 0.5;\n\n  /* ----------------------------------------------------------\n     Motion & easing\n     ---------------------------------------------------------- */\n  --sf-duration-none:    0ms;\n  --sf-duration-instant: calc(100ms * var(--sf-motion-scale));\n  --sf-duration-fast:    calc(150ms * var(--sf-motion-scale));\n  --sf-duration-normal:  calc(250ms * var(--sf-motion-scale));\n  --sf-duration-slow:    calc(400ms * var(--sf-motion-scale));\n  --sf-duration-slower:  calc(600ms * var(--sf-motion-scale));\n\n  /* Opt-in light/dark cross-fade duration — the knob for .sf-theme-transition\n     (core/themes.css). Registered <color> tokens make the fade possible;\n     this controls how long it takes. */\n  --sf-theme-transition-duration: calc(300ms * var(--sf-motion-scale));\n\n  --sf-ease-linear:  linear;\n  --sf-ease-out:     cubic-bezier(0.25, 0, 0.15, 1);\n  --sf-ease-in:      cubic-bezier(0.5, 0, 0.75, 0.25);\n  --sf-ease-in-out:  cubic-bezier(0.4, 0, 0.2, 1);\n  --sf-ease-spring:    linear(0, 0.5, 1.1, 0.95, 1.02, 1);\n  --sf-ease-elastic:   linear(0, 0.3, 1.2, 0.9, 1.05, 1);\n  --sf-ease-bounce:    linear(0, 0.35 18%, 1 32%, 0.86 42%, 1.02 56%, 0.98 72%, 1);\n  --sf-ease-overshoot: linear(0, 0.6 30%, 1.08 55%, 0.98 75%, 1);\n\n  /* ----------------------------------------------------------\n     Animation presets — pair keyframes (core/motion.css) with\n     duration + easing. Use directly: animation: var(--sf-animation-fade-in);\n     ---------------------------------------------------------- */\n  --sf-animation-fade-in:        sf-fade-in        var(--sf-duration-normal) var(--sf-ease-out)       both;\n  --sf-animation-fade-out:       sf-fade-out       var(--sf-duration-normal) var(--sf-ease-in)        both;\n  --sf-animation-slide-in-up:    sf-slide-in-up    var(--sf-duration-normal) var(--sf-ease-out)       both;\n  --sf-animation-slide-in-down:  sf-slide-in-down  var(--sf-duration-normal) var(--sf-ease-out)       both;\n  --sf-animation-slide-in-left:  sf-slide-in-left  var(--sf-duration-normal) var(--sf-ease-out)       both;\n  --sf-animation-slide-in-right: sf-slide-in-right var(--sf-duration-normal) var(--sf-ease-out)       both;\n  --sf-animation-scale-up:       sf-scale-up       var(--sf-duration-normal) var(--sf-ease-overshoot) both;\n  --sf-animation-scale-down:     sf-scale-down     var(--sf-duration-normal) var(--sf-ease-in)        both;\n  --sf-animation-slide-out-up:    sf-slide-out-up    var(--sf-duration-normal) var(--sf-ease-in) both;\n  --sf-animation-slide-out-down:  sf-slide-out-down  var(--sf-duration-normal) var(--sf-ease-in) both;\n  --sf-animation-slide-out-left:  sf-slide-out-left  var(--sf-duration-normal) var(--sf-ease-in) both;\n  --sf-animation-slide-out-right: sf-slide-out-right var(--sf-duration-normal) var(--sf-ease-in) both;\n  --sf-animation-color-pulse:    sf-color-pulse    var(--sf-duration-slow)   var(--sf-ease-in-out)    infinite;\n  --sf-animation-ping:           sf-ping           var(--sf-duration-slow)   var(--sf-ease-out)       infinite;\n  --sf-animation-blink:          sf-blink          calc(1s * var(--sf-motion-scale)) steps(1, end) infinite;\n  --sf-animation-float:          sf-float          calc(3s * var(--sf-motion-scale)) var(--sf-ease-in-out) infinite;\n  --sf-animation-spin:    sf-spin var(--sf-duration-slower) linear infinite;\n  --sf-animation-shimmer: sf-shimmer calc(1.5s * var(--sf-motion-scale)) var(--sf-ease-in-out) infinite;\n\n  /* Stagger step — the per-item delay increment consumed by the .sf-stagger\n     utility (core/motion.css). One knob retunes the whole choreography; the\n     class multiplies it by the child's index and by --sf-motion-scale, so the\n     rhythm follows the motion knob without baking the scale in here. */\n  --sf-stagger-step: 75ms;\n\n  /* Hover-transform magnitudes — the .sf-hover-* utilities (optional/\n     utilities.css) read these so the effect strength is one global knob per\n     axis rather than hard-coded per class. --grow/--shrink are scale factors;\n     --lift is the float/sink translate distance; --slide is the slide\n     distance. */\n  --sf-hover-grow-scale:   1.05;\n  --sf-hover-shrink-scale: 0.95;\n  --sf-hover-lift:         0.25em;\n  --sf-hover-slide:        0.5em;\n\n  /* ----------------------------------------------------------\n     Scroll-driven animation range — consumer API. Attach these\n     to your own scroll-timeline via animation-range. Not consumed\n     by the framework itself; intended for BEM component authors.\n     ---------------------------------------------------------- */\n  --sf-scroll-timeline-range-start: entry 0%;\n  --sf-scroll-timeline-range-end:   cover 30%;\n\n  /* Exit counterpart — element is well into view before starting to\n     leave, finishing exactly as it scrolls fully out. */\n  --sf-scroll-timeline-range-exit-start: cover 70%;\n  --sf-scroll-timeline-range-exit-end:   exit 100%;\n\n  /* ----------------------------------------------------------\n     Mask scrim — edge-fade stops for scroll reels / overflow.\n     Use in a mask-image gradient to fade content near an edge:\n       mask-image: linear-gradient(to right,\n         transparent 0, #000 var(--sf-mask-scrim-start),\n         #000 calc(100% - var(--sf-mask-scrim-end)), transparent 100%);\n     ---------------------------------------------------------- */\n  --sf-mask-scrim-start: var(--sf-space-l);\n  --sf-mask-scrim-end:   var(--sf-space-l);\n\n  /* ----------------------------------------------------------\n     Z-index\n     ---------------------------------------------------------- */\n  /* Semantic z-index ladder — UI roles, not magic integers. Follows the\n     Bootstrap/Chakra convention (1000-base, ordered by stacking role) so\n     the names are familiar and the gaps leave room to insert custom layers.\n     Low-level rungs (below/base/raised) handle local stacking; the named\n     roles handle page chrome and overlays.\n\n     Modal / popover / tooltip components render in the browser TOP LAYER\n     (native <dialog> / [popover]), ordered above the page independently of\n     z-index. The --sf-z-modal / --sf-z-overlay / --sf-z-tooltip rungs are\n     the fallback for non-top-layer implementations that must beat the page. */\n  --sf-z-below:  -1;\n  --sf-z-base:    0;\n  --sf-z-raised:  1;\n  --sf-z-sticky:   1000;  /* sticky headers / sidebars            */\n  --sf-z-fixed:    1010;  /* fixed app chrome (navbar, FAB)       */\n  --sf-z-dropdown: 1020;  /* menus — clear sticky + fixed         */\n  --sf-z-overlay:  1030;  /* scrims / non-top-layer backdrops     */\n  --sf-z-modal:    1040;  /* dialogs (non-top-layer fallback)     */\n  --sf-z-toast:    1050;  /* transient notifications              */\n  --sf-z-tooltip:  1060;  /* tooltips — above everything          */\n\n  /* ----------------------------------------------------------\n     Layout & a11y\n     ---------------------------------------------------------- */\n  /* Header height fluidly interpolates between the mobile and desktop\n     tokens across the framework viewport range (--sf-fluid-{min,max}-vw),\n     the same range used by the fluid type/space scales. Override either\n     endpoint to retune; set both equal for a fixed height. clamp() keeps the\n     result bounded to the endpoints even when they are overridden. */\n  --sf-header-height-mobile:  3.5rem;\n  --sf-header-height-desktop: 5rem;\n  --sf-header-height: clamp(\n    var(--sf-header-height-mobile),\n    calc((var(--sf-header-height-desktop) - var(--sf-header-height-mobile)) / ((var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * 1rem) * (100vw - var(--sf-fluid-min-vw) * 1rem) + var(--sf-header-height-mobile)),\n    var(--sf-header-height-desktop));\n  --sf-sticky-offset-mobile:  var(--sf-header-height-mobile);\n  --sf-sticky-offset-desktop: var(--sf-header-height-desktop);\n  --sf-sticky-offset: clamp(\n    var(--sf-sticky-offset-mobile),\n    calc((var(--sf-sticky-offset-desktop) - var(--sf-sticky-offset-mobile)) / ((var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * 1rem) * (100vw - var(--sf-fluid-min-vw) * 1rem) + var(--sf-sticky-offset-mobile)),\n    var(--sf-sticky-offset-desktop));\n  /* Focus ring dimensions and minimum touch-target size. Governs keyboard\n     navigation affordance and WCAG 2.5.5 pointer-target requirements.\n     --sf-touch-target owns the 44px WCAG floor as a literal — it is NOT an\n     alias of a --sf-size-* rung, so retuning the size scale can never drag\n     the accessibility minimum below spec. Override it deliberately if you\n     have your own target policy. */\n  --sf-focus-ring-width:  2px;\n  --sf-focus-ring-offset: 2px;\n  --sf-focus-ring-style:  solid;\n  --sf-touch-target:      2.75rem;  /* 44px — WCAG 2.5.5 minimum, independent of the size scale */\n  /* Global text-contrast knob. Nudges derived reading-text colours\n     toward the extremes (darker in light mode, lighter in dark mode).\n     Positive = more contrast; 0 = no change. Consumed by\n     --sf-color-text, --sf-color-text--subtle, --sf-color-heading. */\n  --sf-contrast-bias:     0;\n  /* Lightness crossover for text-on-color auto-contrast. Colours with\n     L above this value get dark text; below get light text.\n     Default 0.6 guarantees ≥ 3:1 for most colours.\n     The binary choice (near-black or near-white) cannot guarantee 4.5:1 when\n     the background sits in the L ≈ 0.52–0.67 band — both extremes land near\n     the crossover. Two escape hatches:\n       1. Shift the threshold per surface — lower (e.g. 0.55) if your brand\n          lands near 0.6 and you prefer white text on it:\n            @layer slashed.overrides {\n              .sf-surface--primary { --sf-contrast-threshold: 0.55; }\n            }\n       2. Override the resolved token directly when an exact colour is needed:\n            @layer slashed.overrides {\n              .sf-surface--primary { --sf-color-text--on-primary: oklch(0.15 0 0); }\n            }\n     CSS `contrast-color()` (currently only in the spec, no browser support)\n     will replace this formula once it ships. */\n  --sf-contrast-threshold: 0.6;\n\n  /* Device safe-area insets (notches, rounded corners, home indicators).\n     0px on devices without intrusions. Read these in your own padding/\n     margin; the framework consumes them in layout edge spacing. */\n  --sf-safe-top:    env(safe-area-inset-top,    0px);\n  --sf-safe-bottom: env(safe-area-inset-bottom, 0px);\n  --sf-safe-left:   env(safe-area-inset-left,   0px);\n  --sf-safe-right:  env(safe-area-inset-right,  0px);\n\n  /* ----------------------------------------------------------\n     Print\n     ---------------------------------------------------------- */\n  --sf-print-page-margin: 2cm;\n  --sf-print-page-size:   a4;\n  --sf-print-base-size:   11pt;\n\n  /* ----------------------------------------------------------\n     Object fit / position — global defaults for replaced elements.\n     Applied in core/base.css on img and video. Override per element\n     via inline style=\"--sf-object-position: top\" or in BEM CSS.\n     ---------------------------------------------------------- */\n  --sf-object-fit:      cover;\n  --sf-object-position: 50% 50%;\n\n}\n\n/* @supports — Shadow ramp (box-shadow, text-shadow, drop-shadow) */\n@supports (color: oklch(from red l c h)) {\n  :root {\n\n    /* Shadow tint — near-black derived from the neutral; the tint simply\n       inherits the neutral's own chroma/hue, so a colourless neutral yields\n       colourless shadows. Forced dark in both modes; --sf-shadow-strength\n       handles dark-mode intensity. Override to a brand colour for explicitly\n       tinted shadows — keep it dark or you get bright slabs:\n       oklch(from var(--sf-color-primary) 0.15 c h). */\n    --sf-shadow-color: oklch(from var(--sf-color-neutral) var(--sf-shadow-lightness) c h);\n\n    /* Elevation shadow ramp — box-shadow presets from xs to 2xl.\n       Opacity scales with --sf-shadow-strength so dark-mode boost is automatic. */\n    --sf-shadow-none:  none;\n    --sf-shadow-xs:    0 1px 2px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7));\n    --sf-shadow-s:     0 1px 2px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7)),\n                       0 2px 6px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, var(--sf-shadow-strength), 0.7));\n    --sf-shadow-m:     0 1px 3px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7)),\n                       0 4px 12px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2), 0.7));\n    --sf-shadow-l:     0 2px 4px 0   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7)),\n                       0 8px 24px 0  oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 3), 0.7)),\n                       0 16px 48px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2), 0.7));\n    --sf-shadow-xl:    0 2px 8px 0   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7)),\n                       0 12px 36px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 3.5), 0.7)),\n                       0 24px 72px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2.5), 0.7));\n    --sf-shadow-2xl:   0 4px 12px 0       oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.6), 0.7)),\n                       0 20px 60px 0       oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 4), 0.7)),\n                       0 40px 100px -8px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 5), 0.7));\n    --sf-shadow-inner: inset 0 2px 4px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2), 0.7));\n\n    /* ----------------------------------------------------------\n       Text shadows — share --sf-shadow-color / --sf-shadow-strength\n       ---------------------------------------------------------- */\n    --sf-text-shadow-none: none;\n    --sf-text-shadow-xs: 0 0.5px 1px oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 1),   0.7));\n    --sf-text-shadow-s:  0 1px 2px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 1.5), 0.7));\n    --sf-text-shadow-m:  0 2px 4px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2),   0.7));\n    --sf-text-shadow-l:  0 4px 8px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2.5), 0.7));\n    --sf-text-shadow-xl: 0 8px 16px  oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 3),   0.7));\n\n    /* Drop shadows — for filter: drop-shadow() (respects alpha edges) */\n    --sf-drop-shadow-xs: drop-shadow(0 0.5px 1px  oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 1),   0.7)));\n    --sf-drop-shadow-s:  drop-shadow(0 1px 2px    oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 1.5), 0.7)));\n    --sf-drop-shadow-m:  drop-shadow(0 4px 6px    oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2),   0.7)));\n    --sf-drop-shadow-l:  drop-shadow(0 8px 16px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2.5), 0.7)));\n    --sf-drop-shadow-xl: drop-shadow(0 16px 32px  oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 3),   0.7)));\n\n  }\n}\n\n/* ============================================================\n   TYPOGRAPHY ALIASES — part of the per-style typography bundle\n   for a named text role (body, code, heading, h1–h6, display).\n   The full bundle spans font-family, size, weight, line-height,\n   and letter-spacing across related tokens.\n   ============================================================ */\n\n:root {\n  --sf-body-font-size:     var(--sf-text-m);\n  --sf-body-line-height:   var(--sf-leading-normal);\n  --sf-body-font-weight:   var(--sf-font-weight-body);\n  --sf-body-font-family:   var(--sf-font-body);\n  --sf-body-color:         var(--sf-color-text);\n  --sf-body-text-wrap:     pretty;\n  --sf-body-strong-weight: var(--sf-font-weight-strong);\n  --sf-body-em-style:      italic;\n\n  --sf-code-font-size:     0.875em;\n\n  --sf-heading-font-family: var(--sf-font-heading);\n  --sf-heading-color:       var(--sf-color-heading);\n  --sf-heading-text-wrap:   balance;\n\n  --sf-h1-size:           var(--sf-text-4xl);\n  --sf-h1-line-height:    var(--sf-leading-tight);\n  --sf-h1-font-weight:    var(--sf-font-weight-heading);\n  --sf-h1-letter-spacing: var(--sf-tracking-tight);\n\n  --sf-h2-size:           var(--sf-text-3xl);\n  --sf-h2-line-height:    var(--sf-leading-tight);\n  --sf-h2-font-weight:    var(--sf-font-weight-heading);\n  --sf-h2-letter-spacing: var(--sf-tracking-tight);\n\n  --sf-h3-size:           var(--sf-text-2xl);\n  --sf-h3-line-height:    var(--sf-leading-snug);\n  --sf-h3-font-weight:    var(--sf-font-weight-heading);\n  --sf-h3-letter-spacing: var(--sf-tracking-normal);\n\n  --sf-h4-size:           var(--sf-text-xl);\n  --sf-h4-line-height:    var(--sf-leading-snug);\n  --sf-h4-font-weight:    var(--sf-font-weight-heading);\n  --sf-h4-letter-spacing: var(--sf-tracking-normal);\n\n  --sf-h5-size:           var(--sf-text-l);\n  --sf-h5-line-height:    var(--sf-leading-normal);\n  --sf-h5-font-weight:    var(--sf-font-weight-heading);\n  --sf-h5-letter-spacing: var(--sf-tracking-normal);\n\n  --sf-h6-size:           var(--sf-text-m);\n  --sf-h6-line-height:    var(--sf-leading-normal);\n  --sf-h6-font-weight:    var(--sf-font-weight-heading);\n  --sf-h6-letter-spacing: var(--sf-tracking-wide);\n\n  /* ----------------------------------------------------------\n     Heading line-length constraints — public control hooks.\n     Default `none` = no constraint. Set to a ch value to cap\n     heading width independently of the prose container:\n       :root { --sf-h1-max-width: 20ch; --sf-h2-max-width: 28ch; }\n     Consumed by h1–h6 in core/base.css.\n     ---------------------------------------------------------- */\n  --sf-h1-max-width: none;\n  --sf-h2-max-width: none;\n  --sf-h3-max-width: none;\n  --sf-h4-max-width: none;\n  --sf-h5-max-width: none;\n  --sf-h6-max-width: none;\n\n  /* ----------------------------------------------------------\n     Semantic gap tokens — the three rhythms every layout primitive\n     defaults to. Also the BEM consumer API: .nav { gap: var(--sf-gap); }\n     Override globally to retune all primitives of that rhythm at once.\n     ---------------------------------------------------------- */\n  --sf-gap:           var(--sf-space-m);  /* loose: between components   */\n  --sf-content-gap:   var(--sf-space-s);  /* tight: within content       */\n  --sf-gutter:        var(--sf-space-l);  /* wide: page/section gutters  */\n  --sf-component-pad: var(--sf-space-m);  /* standard component padding  */\n  --sf-field-block:   var(--sf-space-xs); /* form-field block padding — matches the shipped field default (see optional/forms.css) */\n  --sf-field-required-marker: \" *\";\n  /* Leading space is baked into the default so consumers can fully\n     disable the indicator with `--sf-link-external-marker: \"\"` —\n     without the space a bare \"\" still left a stray space after the\n     link text. Override with your own glyph (include leading space\n     if you want one): `:root { --sf-link-external-marker: \" →\" }`. */\n  --sf-link-external-marker: \" \\2197\";  /* \" ↗\" — consumed by .sf-link-external */\n  /* Accessible name for the marker glyph, via the CSS alt-text syntax\n     (`content: <value> / <string>`) — read by screen readers in place\n     of the glyph, appended after the link's own text. Localise or\n     disable (together with the marker) per-site. */\n  --sf-link-external-label: \"opens in a new window or external site\";\n\n  /* ----------------------------------------------------------\n     Section padding\n     ---------------------------------------------------------- */\n  /* All sizes multiply by --sf-section-scale — one dial re-rhythms\n     every section on the page (default 1 = no change). */\n  --sf-section-pad:     var(--sf-section-pad--m);\n  --sf-section-pad--xs: calc(var(--sf-space-xl)  * var(--sf-section-scale));\n  --sf-section-pad--s:  calc(var(--sf-space-2xl) * var(--sf-section-scale));\n  --sf-section-pad--m:  calc(var(--sf-space-3xl) * var(--sf-section-scale));\n  --sf-section-pad--l:  calc(var(--sf-space-4xl) * var(--sf-section-scale));\n  --sf-section-pad--xl: calc(var(--sf-space-4xl) * 1.5 * var(--sf-section-scale));\n  --sf-section-pad--2xl: calc(var(--sf-space-4xl) * 2 * var(--sf-section-scale));\n\n  /* ----------------------------------------------------------\n     Transition shorthands\n\n     All tokens name an explicit property set (no `transition: all`).\n     The tempo presets (fast / slow / enter / exit) cover the curated\n     \"common interactive + entrance\" set — color, background-color,\n     border-color, box-shadow, opacity, transform, filter.\n     ---------------------------------------------------------- */\n  --sf-transition-colors:\n    color var(--sf-duration-normal) var(--sf-ease-out),\n    background-color var(--sf-duration-normal) var(--sf-ease-out),\n    border-color var(--sf-duration-normal) var(--sf-ease-out),\n    text-decoration-color var(--sf-duration-normal) var(--sf-ease-out),\n    fill var(--sf-duration-normal) var(--sf-ease-out),\n    stroke var(--sf-duration-normal) var(--sf-ease-out);\n  /* Form fields: color/bg at normal pace, border/shadow/opacity at fast\n     so focus rings and validation states react immediately. */\n  --sf-transition-form-field:\n    color              var(--sf-duration-normal) var(--sf-ease-out),\n    background-color   var(--sf-duration-normal) var(--sf-ease-out),\n    text-decoration-color var(--sf-duration-normal) var(--sf-ease-out),\n    fill               var(--sf-duration-normal) var(--sf-ease-out),\n    stroke             var(--sf-duration-normal) var(--sf-ease-out),\n    border-color       var(--sf-duration-fast)   var(--sf-ease-out),\n    box-shadow         var(--sf-duration-fast)   var(--sf-ease-out),\n    opacity            var(--sf-duration-fast)   var(--sf-ease-out);\n  /* Single-property transition: transform only. */\n  --sf-transition-transform: transform var(--sf-duration-normal) var(--sf-ease-out);\n  /* Single-property transition: opacity only. */\n  --sf-transition-opacity:   opacity var(--sf-duration-normal) var(--sf-ease-out);\n  /* Single-property transition: box-shadow only. */\n  --sf-transition-shadow:    box-shadow var(--sf-duration-normal) var(--sf-ease-out);\n\n  /* All interactive properties at fast duration — for hover/active states that need to feel snappy. */\n  --sf-transition-fast:\n    color var(--sf-duration-fast) var(--sf-ease-out),\n    background-color var(--sf-duration-fast) var(--sf-ease-out),\n    border-color var(--sf-duration-fast) var(--sf-ease-out),\n    box-shadow var(--sf-duration-fast) var(--sf-ease-out),\n    opacity var(--sf-duration-fast) var(--sf-ease-out),\n    transform var(--sf-duration-fast) var(--sf-ease-out),\n    filter var(--sf-duration-fast) var(--sf-ease-out);\n  /* All interactive properties at slow duration — for deliberate, attention-drawing animations. */\n  --sf-transition-slow:\n    color var(--sf-duration-slow) var(--sf-ease-in-out),\n    background-color var(--sf-duration-slow) var(--sf-ease-in-out),\n    border-color var(--sf-duration-slow) var(--sf-ease-in-out),\n    box-shadow var(--sf-duration-slow) var(--sf-ease-in-out),\n    opacity var(--sf-duration-slow) var(--sf-ease-in-out),\n    transform var(--sf-duration-slow) var(--sf-ease-in-out),\n    filter var(--sf-duration-slow) var(--sf-ease-in-out);\n  /* Entrance transition: normal duration + ease-out for elements entering the view. */\n  --sf-transition-enter:\n    color var(--sf-duration-normal) var(--sf-ease-out),\n    background-color var(--sf-duration-normal) var(--sf-ease-out),\n    border-color var(--sf-duration-normal) var(--sf-ease-out),\n    box-shadow var(--sf-duration-normal) var(--sf-ease-out),\n    opacity var(--sf-duration-normal) var(--sf-ease-out),\n    transform var(--sf-duration-normal) var(--sf-ease-out),\n    filter var(--sf-duration-normal) var(--sf-ease-out);\n  /* Exit transition: fast duration + ease-in so exits feel crisp and don't linger. */\n  --sf-transition-exit:\n    color var(--sf-duration-fast) var(--sf-ease-in),\n    background-color var(--sf-duration-fast) var(--sf-ease-in),\n    border-color var(--sf-duration-fast) var(--sf-ease-in),\n    box-shadow var(--sf-duration-fast) var(--sf-ease-in),\n    opacity var(--sf-duration-fast) var(--sf-ease-in),\n    transform var(--sf-duration-fast) var(--sf-ease-in),\n    filter var(--sf-duration-fast) var(--sf-ease-in);\n\n  /* Top-layer transition building block (dialog, [popover]).\n     transition-behavior: allow-discrete keeps the discrete `display`\n     and `overlay` properties in the transition so entry animations can\n     fire and exit animations finish before the element leaves the top\n     layer. Compose it into a component transition alongside the visual\n     properties.\n     NOTE: Requires @starting-style to be defined on the element for\n     the entrance transition to trigger.\n     Progressive enhancement — unsupporting engines simply show/hide instantly.\n     Chrome/Edge/Safari and Firefox (2025+) support allow-discrete. */\n  --sf-transition-overlay:\n    overlay var(--sf-duration-normal) allow-discrete,\n    display var(--sf-duration-normal) allow-discrete;\n}\n\n/* ─── core/tokens.layout.css ─── */\n/* SLASHED — core/tokens.layout.css\n   @layer slashed.tokens\n   Layout primitive override tokens for gaps, padding, min sizes, tracks, and containers.\n   Prefix: --sf-*; loaded before core/layout.css. */\n\n:root {\n\n  /* ----------------------------------------------------------\n     Stack\n     ---------------------------------------------------------- */\n  --sf-stack-gap: var(--sf-content-gap);\n\n  /* ----------------------------------------------------------\n     Box\n     ---------------------------------------------------------- */\n  --sf-box-padding:      var(--sf-space-m);\n  --sf-box-border-width: 0;\n  --sf-box-border-color: var(--sf-color-border);\n\n  /* ----------------------------------------------------------\n     Center\n     ---------------------------------------------------------- */\n  --sf-center-max:    var(--sf-container-default);\n  --sf-center-gutter: var(--sf-gutter);\n\n  /* ----------------------------------------------------------\n     Cluster\n     ---------------------------------------------------------- */\n  --sf-cluster-gap:     var(--sf-gap);\n  --sf-cluster-align:   center;\n  --sf-cluster-justify: flex-start;\n\n  /* ----------------------------------------------------------\n     Sidebar\n     ---------------------------------------------------------- */\n  --sf-sidebar-gap:           var(--sf-gap);\n  --sf-sidebar-min-width:     50%;           /* content column minimum */\n  --sf-sidebar-width:         18rem;         /* sidebar panel default size */\n\n  /* ----------------------------------------------------------\n     Switcher\n     ---------------------------------------------------------- */\n  --sf-switcher-threshold: 30rem;\n  --sf-switcher-gap:       var(--sf-gap);\n\n  /* ----------------------------------------------------------\n     Grid (auto-fill, breakpoint-free)\n     ---------------------------------------------------------- */\n  --sf-grid-min:         16rem;\n  --sf-grid-gap:         var(--sf-gap);\n\n  --sf-grid-min-xs:      10rem;\n  --sf-grid-min-s:       13rem;\n  --sf-grid-min-m:       16rem;\n  --sf-grid-min-l:       20rem;\n  --sf-grid-min-xl:      24rem;\n  --sf-grid-min-2xl:     28rem;\n\n  /* ----------------------------------------------------------\n     Equal columns — CSS multi-column flowing layout (not grid).\n     Content flows between columns like a newspaper: fills one\n     column top-to-bottom, continues at the top of the next.\n     Use for FAQ lists, prose, anything that should distribute\n     evenly without being pinned to discrete grid cells — reach\n     for .sf-grid/.sf-grid--fit instead when items need their own\n     fixed cell.\n     ---------------------------------------------------------- */\n  --sf-equal-min-col:    16rem;\n  --sf-equal-gap:        var(--sf-gap);\n  --sf-equal-rule-width: 0;\n  --sf-equal-rule-style: solid;\n  --sf-equal-rule-color: var(--sf-color-border);\n\n  /* ----------------------------------------------------------\n     Cover\n     ---------------------------------------------------------- */\n  --sf-cover-min-height: 100dvh;\n  --sf-cover-padding:    var(--sf-section-pad);\n\n  /* ----------------------------------------------------------\n     Frame\n     ---------------------------------------------------------- */\n  --sf-frame-ratio: 16 / 9;    /* literal <ratio>, valid in aspect-ratio */\n\n  /* ----------------------------------------------------------\n     Background layer (.sf-bg-layer) — cover media behind sibling content.\n     inset is a single length applied to every edge; the layer size is\n     derived from it, so a non-zero inset still fills correctly.\n     ---------------------------------------------------------- */\n  /* 0px, not bare 0 — .sf-bg-layer's inline-size/block-size multiply this by 2\n     inside a calc() alongside a percentage; a unitless 0 makes that\n     calc() a <number>/<percentage> type mismatch (invalid at\n     computed-value time), silently collapsing .sf-bg-layer to its intrinsic\n     size. */\n  --sf-bg-layer-inset:    0px;\n  --sf-bg-layer-fit:      cover;\n  --sf-bg-layer-position: 50% 50%;\n  --sf-bg-layer-radius:   0;\n  --sf-bg-layer-z:        -2;        /* behind content; above the parent background */\n\n  /* ----------------------------------------------------------\n     Icon (boxed variant) — extras for .sf-icon--boxed.\n     The naked .sf-icon sizing tokens (--sf-icon-xs..xl) live in\n     core/tokens.css alongside the typography scale.\n     ---------------------------------------------------------- */\n  --sf-icon-box-pad:    0.5em;\n  --sf-icon-box-radius: var(--sf-radius-s);\n  --sf-icon-box-bg:     var(--sf-color-inset);\n  --sf-icon-box-border: var(--sf-border-width-1) solid var(--sf-color-border);\n\n  /* ----------------------------------------------------------\n     Reel\n     ---------------------------------------------------------- */\n  --sf-reel-item-width: max-content;\n  --sf-reel-gap:        var(--sf-gap);\n  --sf-reel-height:     auto;\n\n  /* ----------------------------------------------------------\n     Imposter (centered absolute/fixed overlay)\n     ---------------------------------------------------------- */\n  --sf-imposter-margin: var(--sf-space-m);\n\n  /* ----------------------------------------------------------\n     Bento grid\n     ---------------------------------------------------------- */\n  --sf-bento-cols-default: 4;\n  --sf-bento-row-default:  10rem;\n  --sf-bento-row-compact:  6rem;\n  --sf-bento-row-tall:     16rem;\n  --sf-bento-gap:          var(--sf-gap);\n\n  /* ----------------------------------------------------------\n     Content grid (breakout pattern)\n     ---------------------------------------------------------- */\n  --sf-breakout-width: var(--sf-container-wide);\n  --sf-content-width:  var(--sf-container-default);\n\n  /* ----------------------------------------------------------\n     Prose\n     ---------------------------------------------------------- */\n  --sf-prose-paragraph: var(--sf-content-gap);\n\n  /* ----------------------------------------------------------\n     Alternate (zigzag)\n     ---------------------------------------------------------- */\n  --sf-alternate-gap:       var(--sf-content-gap);\n  --sf-alternate-inner-gap: var(--sf-gap);\n\n}\n\n/* ─── core/tokens.macros.css ─── */\n/* SLASHED — core/tokens.macros.css\n   @layer slashed.tokens\n   Macro recipe override tokens for prose, surfaces, flow, media, hero, scrims, and clamps.\n   Prefix: --sf-*; loaded before core/macros.css. */\n\n:root {\n\n  /* ----------------------------------------------------------\n     Flow — distance between flow children (lobotomized owl).\n     Consumed by .sf-flow > * + *.\n     ---------------------------------------------------------- */\n  --sf-flow-space: var(--sf-content-gap);\n\n  /* ----------------------------------------------------------\n     Line clamp — default line count for .sf-line-clamp-N.\n     Override per element: style=\"--sf-line-clamp: 5\".\n     The fixed-N variants .sf-line-clamp-2 / -3 don't read this\n     token (they hardcode the value), so the default only\n     applies to .sf-line-clamp-N callers.\n     ---------------------------------------------------------- */\n  --sf-line-clamp: 3;\n\n  /* ----------------------------------------------------------\n     Aspect ratio — default for .sf-aspect (generic ratio container,\n     distinct from layout's .sf-frame which has its own --sf-frame-ratio).\n     ---------------------------------------------------------- */\n  --sf-aspect: 16 / 9;\n\n  /* ----------------------------------------------------------\n     Prose — per-instance override knobs for .sf-prose.\n     All values default to system spacing/color tokens so prose\n     stays in sync with the global scale unless overridden.\n\n     Override per-element:\n       style=\"--sf-prose-marker-color: var(--sf-color-secondary)\"\n     ---------------------------------------------------------- */\n  --sf-prose-heading-gap:      var(--sf-space-s);\n  --sf-prose-list-gap:         var(--sf-space-xs);\n  --sf-prose-block-margin:     var(--sf-space-m);\n  --sf-prose-media-margin:     var(--sf-space-m);\n  --sf-prose-media-radius:     var(--sf-radius-m);\n  --sf-prose-figure-margin:    var(--sf-space-l);\n  --sf-prose-marker-color:     var(--sf-color-primary);\n  --sf-prose-figcaption-size:  var(--sf-text-s);\n  --sf-prose-blockquote-padding: var(--sf-space-m);\n  --sf-prose-blockquote-border:  var(--sf-border-width-2) solid var(--sf-color-border--subtle);\n  --sf-prose-hr-margin:          var(--sf-space-l);\n  --sf-prose-nested-list-gap:    var(--sf-space-2xs);\n  --sf-prose-table-pad:          var(--sf-space-xs);\n\n  /* ----------------------------------------------------------\n     Surface color — input for the generic .sf-surface macro.\n     Set it on any element carrying the class and the macro derives\n     background, auto-contrast foreground, and the full contextual\n     token set from it:\n       <section class=\"sf-surface\"\n                style=\"--sf-surface-color: var(--sf-color-primary-100)\">\n     Inherits: a nested .sf-surface picks up the outer surface's\n     color unless it sets its own. Any resolvable CSS color works.\n     ---------------------------------------------------------- */\n  --sf-surface-color: var(--sf-color-base);\n\n  /* ----------------------------------------------------------\n     Scroll shadow / overflow fade — mask gradient size.\n     Used by .sf-scroll-shadow (top+bottom) and .sf-overflow-fade\n     (end-edge horizontal fade).\n     ---------------------------------------------------------- */\n  --sf-scroll-shadow-size: 2rem;\n\n  /* ----------------------------------------------------------\n     Content visibility — placeholder size for .sf-content-auto.\n     Feeds contain-intrinsic-size so offscreen sections reserve\n     space before their first render, keeping the scrollbar and\n     scroll position stable. Override per element:\n     style=\"--sf-content-intrinsic-size: 800px\".\n     ---------------------------------------------------------- */\n  --sf-content-intrinsic-size: 500px;\n\n  /* ----------------------------------------------------------\n     Scrim — darkening overlay for text-over-image legibility,\n     consumed by the .sf-scrim macro. The gradient is composed\n     from a direction + a color stop so consumers can retune\n     either independently:\n       style=\"--sf-scrim-color: oklch(0 0 0 / 0.75)\"\n       style=\"--sf-scrim-direction: to top right\"\n     --sf-scrim-gradient is the final composed value; override it\n     directly for a multi-stop or radial scrim.\n     ---------------------------------------------------------- */\n  --sf-scrim-color:     oklch(0 0 0 / 0.55);\n  --sf-scrim-direction: to top;\n  --sf-scrim-gradient:  linear-gradient(var(--sf-scrim-direction), var(--sf-scrim-color), transparent);\n  /* Text-on-image legibility WITHOUT darkening the picture — a soft\n     shadow halo behind glyphs, consumed by .sf-text-protect. */\n  --sf-scrim-text-shadow: 0 1px 3px oklch(0 0 0 / 0.6);\n\n  /* ----------------------------------------------------------\n     Named background surface preset — input set for the .sf-surface-bg\n     macro (issue #523). One reusable, named background bundling a base\n     colour fallback + image/gradient/pattern + sizing + an optional\n     overlay + an optional animation. Define a preset by setting these\n     on a scope, then apply .sf-surface-bg to compose them:\n       .hero-surface {\n         --sf-surface-bg-image:   url(\"/hero.avif\");\n         --sf-surface-bg-overlay: var(--sf-scrim-gradient);  // reuse the scrim\n         --sf-surface-bg-animation: sf-pan 40s linear infinite;\n       }\n       <section class=\"hero-surface sf-surface-bg\">…</section>\n     -overlay layers ABOVE -image (first background-image layer). Builds on\n     the existing scrim + gradient tokens rather than new infra; for a\n     blurred backdrop compose .sf-scrim / a filter on top. Inert by default\n     (image/overlay/animation = none) so the bare class is a no-op until a\n     preset feeds it. ---------------------------------------------------- */\n  --sf-surface-bg-color:      transparent;\n  --sf-surface-bg-image:      none;\n  --sf-surface-bg-overlay:    none;\n  --sf-surface-bg-size:       cover;\n  --sf-surface-bg-position:   center;\n  --sf-surface-bg-repeat:     no-repeat;\n  --sf-surface-bg-attachment: scroll;\n  --sf-surface-bg-animation:  none;\n\n  /* ----------------------------------------------------------\n     Overlap recipe — how far .sf-overlap pulls into the adjacent\n     element. .sf-overlap-host's padding compensation defaults to this\n     same value via a var() fallback in the rule itself (not aliased\n     here — see core/macros.css), so one override on the host tunes\n     both unless --sf-overlap-host-pad is set independently.\n     ---------------------------------------------------------- */\n  --sf-overlap-pull: var(--sf-space-xl);\n\n}\n\n/* ─── optional/tokens.components.css ─── */\n/* SLASHED — optional/tokens.components.css\n   @layer slashed.tokens\n   Component token surface for the optional component module: card, field,\n   and button knobs. Prefix: --sf-*. */\n\n:root {\n\n  /* ============================================================\n   * CARD TOKENS\n   * ============================================================\n   * Concentric radius math: outer = inner + padding. Keeps inner\n   * elements that use the global --sf-radius-m visually\n   * proportional inside a padded card. */\n  --sf-card-padding:        var(--sf-space-l);\n  --sf-card-gap:            var(--sf-space-m);\n  --sf-card-radius:         var(--sf-radius-m);\n  --sf-card-radius-outer:   calc(var(--sf-card-radius) + var(--sf-card-padding));\n  --sf-card-bg:             var(--sf-color-surface);\n  --sf-card-border-width:   var(--sf-border-width-1);\n  --sf-card-border-color:   var(--sf-color-border);\n  --sf-card-shadow:         var(--sf-shadow-s);\n  /* Shadow escalation for the --elevated and --interactive modifiers.\n   * Both default to the same --sf-shadow-l step (elevated's resting shadow\n   * and interactive's hover shadow read as the same \"lifted\" level) — two\n   * tokens so each modifier can still be tuned independently. */\n  --sf-card-shadow--elevated: var(--sf-shadow-l);\n  --sf-card-shadow--hover:    var(--sf-shadow-l);\n\n  /* Smart-card subcomponents (.sf-card__media / __avatar / __title). Media\n   * defaults to the 16/9 ratio token; inner media radius mirrors the card's\n   * inner radius. */\n  --sf-card-media-ratio:    var(--sf-ratio-video);\n  --sf-card-media-radius:   var(--sf-card-radius, var(--sf-radius-m));\n  --sf-card-avatar-size:    2.5rem;\n  --sf-card-heading-size:   var(--sf-text-xl);\n\n  /* ============================================================\n   * FIELD TOKENS\n   * Override to give form fields a distinct visual language from\n   * buttons without touching global radius/spacing tokens. Consumed\n   * by the classless field rules in optional/forms.css (padding-block,\n   * padding-inline, border-radius); each fallback there equals these\n   * defaults so an unset knob renders identically.\n   * ============================================================ */\n  --sf-field-radius:         var(--sf-radius-m);\n  --sf-field-padding-block:  var(--sf-space-xs);\n  --sf-field-padding-inline: var(--sf-space-s);\n\n  /* ============================================================\n   * BUTTON TOKENS\n   * Override to give buttons a distinct visual language from\n   * form fields without touching global radius/spacing tokens.\n   * ============================================================ */\n  --sf-btn-radius:         var(--sf-radius-m);\n  --sf-btn-gap:            var(--sf-space-2xs);\n  --sf-btn-font-weight:    var(--sf-font-weight-interactive);\n  --sf-btn-border-width:   var(--sf-border-width-1);\n\n  /* Uniform label-size multiplier — the everyday \"make button text a little\n   * larger / smaller\" knob. Scales the resolved font-size of EVERY button\n   * size (.sf-btn--xs…xl) by the same factor while KEEPING the size ladder\n   * intact (xs < s < m < l < xl). Contrast with --sf-btn-font-size below,\n   * which flattens every size to one value. Applied in the font-size calc()\n   * in optional/components.css. */\n  --sf-btn-font-scale:     1;\n\n  /*\n   * The four SIZE-VARYING knobs are declared `initial` on purpose — NOT with\n   * a concrete default. Each size modifier (.sf-btn--xs/--s/--l/--xl) needs\n   * its own per-size value, and a rule-local declaration on the element\n   * always beats an inherited :root one; a concrete :root default here would\n   * make these knobs work on the default (m) button yet silently die on every\n   * sized button. `initial` sets each to the guaranteed-invalid value, so the\n   * property reads FIRST in its var() chain fall through to the rule-local\n   * `*--size` tier default (set per size in optional/components.css):\n   *   font-size: var(--sf-btn-font-size, var(--sf-btn-font-size--size));\n   * Setting one of these knobs on :root replaces the `initial` and therefore\n   * wins on EVERY button of any size — honouring the framework's \"one token\n   * on :root changes everything\" contract — while the default size scale is\n   * untouched. They stay PUBLIC knobs (catalogued, share-encodable), just with\n   * no baked-in value: the effective m-size default lives on the tier token.\n   */\n  --sf-btn-font-size:      initial;\n  --sf-btn-padding-block:  initial;\n  --sf-btn-padding-inline: initial;\n  --sf-btn-min-height:     initial;\n\n  /*\n   * Per-size knobs — one PUBLIC knob per size rung for each sizing property\n   * (label font-size, block/inline padding, min-height): the button\n   * counterpart of the per-heading typography knobs. Each is `initial` so,\n   * unset, that rung falls through to its own scale default (--sf-text-{size},\n   * --sf-space-*, --sf-size-{size}); set one on :root to retune a SINGLE\n   * rung's property without disturbing the others — unlike the flatten-all\n   * --sf-btn-{prop} overrides above, or the proportional --sf-btn-font-scale.\n   * Consumed per .sf-btn--{size} in optional/components.css as the first arg\n   * of the matching --sf-btn-{prop}--size tier token.\n   */\n  --sf-btn-xs-font-size:      initial;\n  --sf-btn-s-font-size:       initial;\n  --sf-btn-m-font-size:       initial;\n  --sf-btn-l-font-size:       initial;\n  --sf-btn-xl-font-size:      initial;\n  --sf-btn-xs-padding-block:  initial;\n  --sf-btn-s-padding-block:   initial;\n  --sf-btn-m-padding-block:   initial;\n  --sf-btn-l-padding-block:   initial;\n  --sf-btn-xl-padding-block:  initial;\n  --sf-btn-xs-padding-inline: initial;\n  --sf-btn-s-padding-inline:  initial;\n  --sf-btn-m-padding-inline:  initial;\n  --sf-btn-l-padding-inline:  initial;\n  --sf-btn-xl-padding-inline: initial;\n  --sf-btn-xs-min-height:     initial;\n  --sf-btn-s-min-height:      initial;\n  --sf-btn-m-min-height:      initial;\n  --sf-btn-l-min-height:      initial;\n  --sf-btn-xl-min-height:     initial;\n  /*\n   * Size modifiers (.sf-btn--xs/--s/--l/--xl) and the colour family\n   * (--sf-btn-color / --sf-btn-color--hover / --sf-btn-on-color) are\n   * rule-local overrides set in optional/components.css, not global knobs.\n   *\n   * Full-width: .sf-btn--block is unconditional; .sf-btn--block-cq\n   * stretches to 100% only inside a query container narrower than 20rem\n   * (no @media breakpoints). The threshold is a literal in the\n   * @container condition — query conditions cannot read var(), so\n   * there is no token for it.\n   */\n\n}\n\n/* ─── core/reset.css ─── */\n/* SLASHED — core/reset.css\n   @layer slashed.reset\n   Browser normalization, sizing defaults, viewport behavior, media safety, and form inheritance.\n   No component styling. */\n\n\n*, *::before, *::after {\n  box-sizing: border-box;\n}\n\nhtml {\n  /* stylelint-disable-next-line property-no-vendor-prefix -- Safari <17: unprefixed text-size-adjust only landed in Safari 17 */\n  -webkit-text-size-adjust: 100%;\n  text-size-adjust:          100%;\n  scroll-padding-block-start: calc(var(--sf-header-height, 5rem) + var(--sf-space-m, 1rem));\n  scrollbar-gutter:    stable;\n  color-scheme:        var(--sf-color-scheme, light dark);\n  hanging-punctuation: first last;\n}\n\n@supports (interpolate-size: allow-keywords) {\n  html { interpolate-size: allow-keywords; }\n}\n\nbody {\n  min-height:      100dvh;\n  min-inline-size: 320px;\n}\n\nbutton {\n  text-transform: none;\n}\n\nsearch {\n  display: block;\n}\n\nsummary {\n  cursor: pointer;\n}\n\ntable {\n  border-collapse: collapse;\n}\n\n[hidden] {\n  display: none !important;\n}\n\ndialog, [popover] {\n  padding:      0;\n  border:       none;\n  background:   Canvas;\n  color:        inherit;\n  color-scheme: inherit;\n}\n\nfieldset {\n  min-width: 0;\n}\n\n[inert] {\n  cursor: default;\n}\n\n/* ─── core/base.css ─── */\n/* SLASHED — core/base.css\n   @layer slashed.base\n   Element defaults for typography, media, links, tables, and forms.\n   Token-first, classless foundation. */\n\n\nhtml {\n  scrollbar-color: var(--sf-scrollbar-thumb) var(--sf-scrollbar-track);\n}\n\nbody {\n  margin:           0;\n  font-family:      var(--sf-body-font-family, var(--sf-font-body));\n  font-size:        var(--sf-body-font-size,   var(--sf-text-m));\n  line-height:      var(--sf-body-line-height, var(--sf-leading-normal));\n  font-weight:      var(--sf-body-font-weight, var(--sf-font-weight-body));\n  color:            var(--sf-body-color,       var(--sf-color-text));\n  background-color: var(--sf-color-bg, #fff);\n}\n\nh1, h2, h3, h4, h5, h6 {\n  margin:            0;\n  font-family:       var(--sf-heading-font-family, var(--sf-font-heading));\n  line-height:       var(--sf-leading-tight);\n  color:             var(--sf-heading-color, var(--sf-color-heading));\n  text-wrap:         var(--sf-heading-text-wrap);\n  overflow-wrap:     break-word;\n  text-rendering:    optimizelegibility;\n}\n\nh1 { font-size: var(--sf-h1-size); line-height: var(--sf-h1-line-height); font-weight: var(--sf-h1-font-weight); letter-spacing: var(--sf-h1-letter-spacing); max-inline-size: var(--sf-h1-max-width); }\nh2 { font-size: var(--sf-h2-size); line-height: var(--sf-h2-line-height); font-weight: var(--sf-h2-font-weight); letter-spacing: var(--sf-h2-letter-spacing); max-inline-size: var(--sf-h2-max-width); }\nh3 { font-size: var(--sf-h3-size); line-height: var(--sf-h3-line-height); font-weight: var(--sf-h3-font-weight); letter-spacing: var(--sf-h3-letter-spacing); max-inline-size: var(--sf-h3-max-width); }\nh4 { font-size: var(--sf-h4-size); line-height: var(--sf-h4-line-height); font-weight: var(--sf-h4-font-weight); letter-spacing: var(--sf-h4-letter-spacing); max-inline-size: var(--sf-h4-max-width); }\nh5 { font-size: var(--sf-h5-size); line-height: var(--sf-h5-line-height); font-weight: var(--sf-h5-font-weight); letter-spacing: var(--sf-h5-letter-spacing); max-inline-size: var(--sf-h5-max-width); }\nh6 { font-size: var(--sf-h6-size); line-height: var(--sf-h6-line-height); font-weight: var(--sf-h6-font-weight); letter-spacing: var(--sf-h6-letter-spacing); max-inline-size: var(--sf-h6-max-width); }\n\np {\n  margin:        0;\n  text-wrap:     var(--sf-body-text-wrap);\n  overflow-wrap: break-word;\n}\n\nb, strong {\n  font-weight: var(--sf-body-strong-weight);\n}\n\nem {\n  font-style: var(--sf-body-em-style);\n}\n\nsmall {\n  font-size: var(--sf-text-s, 0.875em);\n}\n\nmark {\n  background-color: var(--sf-color-mark-bg, Mark);\n  color:            var(--sf-color-mark-text, MarkText);\n  border-radius:    var(--sf-radius-xs);\n  padding-inline:   0.2em;\n}\n\nabbr[title] {\n  text-decoration: underline dotted;\n  cursor:          help;\n}\n\nkbd, samp {\n  font-family: var(--sf-font-mono);\n  font-size:   inherit;\n}\n\nsub, sup {\n  font-size:      75%;\n  line-height:    0;\n  position:       relative;\n  vertical-align: baseline;\n}\nsup { top:    -0.5em; }\nsub { bottom: -0.25em; }\n\n/* :link (0,1,1) not bare a: beats WebKit UA rule a:link { color: -webkit-link }\n   that silently overrides --sf-color-link in dark mode. */\na:link {\n  color:                   var(--sf-color-link);\n  text-decoration-color:   var(--sf-color-link--underline);\n  text-underline-offset:   var(--sf-link-underline-offset);\n  text-decoration-thickness: var(--sf-link-underline-thickness);\n  text-underline-position: from-font;\n  transition:\n    color                 var(--sf-duration-fast) var(--sf-ease-out),\n    text-decoration-color var(--sf-duration-fast) var(--sf-ease-out);\n}\na:hover   { color: var(--sf-color-link--hover);   text-decoration-color: currentcolor; }\na:visited { color: var(--sf-color-link--visited); }\na:active  { color: var(--sf-color-link--active);  }\na:not([class]) { text-decoration-skip-ink: auto; }\n\na, code {\n  overflow-wrap: break-word;\n}\n\ncode {\n  font-family:      var(--sf-font-mono);\n  font-size:        var(--sf-code-font-size);\n  padding:          0.125em 0.3em;\n  border-radius:    var(--sf-radius-xs);\n  background-color: var(--sf-color-code-bg);\n  color:            var(--sf-color-code-text, inherit);\n}\n\npre {\n  font-family:   var(--sf-font-mono);\n  font-size:     var(--sf-text-s);\n  padding:       var(--sf-space-m);\n  border-radius: var(--sf-radius-m);\n  background:    var(--sf-color-code-block-bg, var(--sf-color-code-bg));\n  color:         var(--sf-color-code-block-text, inherit);\n  overflow-x:      auto;\n  overflow-inline: auto;\n  tab-size:        2;\n  hyphens:       none;\n}\npre code {\n  background:    none;\n  color:         inherit;\n  padding:       0;\n  font-size:     inherit;\n  border-radius: 0;\n}\n\nimg, picture, video, canvas {\n  display:         block;\n  max-inline-size: 100%;\n  block-size:      auto;\n}\n\n/* Zero-specificity so .sf-bg-layer, .sf-frame > img, and any component's own\n   radius (later layer or higher specificity) always win. */\n:where(img, figure) {\n  border-radius: var(--sf-media-radius);\n}\n\nimg, video {\n  object-fit:      var(--sf-object-fit);\n  object-position: var(--sf-object-position);\n}\n\niframe, embed, object {\n  display:         block;\n  max-inline-size: 100%;\n  block-size:      auto;\n  border:          none;\n}\n\nhr {\n  border:             none;\n  border-block-start: var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);\n}\n\n::selection {\n  background:  var(--sf-color-selection-bg);\n  color:       var(--sf-color-selection-text);\n  text-shadow: none;\n}\n\nth, caption {\n  text-align: start;\n}\n\ninput, textarea {\n  caret-color: var(--sf-caret-color);\n}\n\ninput, progress {\n  accent-color: var(--sf-color-action);\n}\n\n::backdrop {\n  background-color: var(--sf-color-dim);\n}\n\nbutton, input, select, textarea {\n  font:           inherit;\n  color:          inherit;\n  letter-spacing: inherit;\n  color-scheme:   inherit;\n  line-height:    inherit;\n}\nbutton {\n  cursor: pointer;\n}\na, button, input, select, textarea, summary {\n  touch-action: manipulation;\n}\ntextarea {\n  resize: vertical;\n}\n\noptgroup { font: inherit; }\n::placeholder { opacity: 1; color: var(--sf-color-text--placeholder, currentcolor); }\n\nblockquote {\n  border-inline-start: var(--sf-border-width-3) var(--sf-border-style) var(--sf-color-border);\n  padding-inline-start: var(--sf-space-m);\n}\n\ndt {\n  font-weight: var(--sf-font-weight-heading);\n}\n\ndd {\n  margin-inline-start: var(--sf-space-m);\n}\n\ntable {\n  text-align: start;\n}\n\nth {\n  font-weight: var(--sf-font-weight-heading);\n}\n\ntd, th {\n  padding: var(--sf-space-2xs) var(--sf-space-xs);\n  border-block-end: var(--sf-border-width-hairline) var(--sf-border-style) var(--sf-color-border--subtle);\n}\n\n/* ─── optional/forms.css ─── */\n/* SLASHED — optional/forms.css\n   @layer slashed.forms\n   Classless form controls: text inputs, selects, textareas, checks/radios, fieldsets, labels.\n   Values resolve through core and optional component tokens. */\n\n\n/* Shared base for text-like inputs, select, textarea */\n\ninput:where(\n  [type=\"text\"], [type=\"email\"], [type=\"password\"], [type=\"url\"],\n  [type=\"tel\"], [type=\"number\"], [type=\"search\"], [type=\"date\"],\n  [type=\"datetime-local\"], [type=\"month\"], [type=\"week\"],\n  [type=\"time\"], :not([type])\n),\nselect,\ntextarea {\n\n  appearance: none;\n\n  display: block;\n  inline-size: 100%;\n  /* Field metrics resolve through the component-tier field knobs first, then\n     the core rhythm knob, then the literal — so overriding any of them retunes\n     fields without touching global spacing/radius. Every fallback equals the\n     shipped default, so the default render is unchanged. --sf-field-padding-*\n     and --sf-field-radius live in optional/tokens.components.css (present in\n     the -components/full bundles); --sf-field-block is the core-tier fallback\n     so the knob still works in the forms-only bundles. */\n  padding-block: var(--sf-field-padding-block, var(--sf-field-block, var(--sf-space-xs)));\n  padding-inline: var(--sf-field-padding-inline, var(--sf-space-s));\n  font-size: var(--sf-text-m);\n  line-height: var(--sf-leading-normal);\n  color: var(--sf-color-text);\n  background-color: var(--sf-color-surface);\n  border: var(--sf-border-width-1) solid var(--sf-field-border-color, var(--sf-color-border));\n  border-radius: var(--sf-field-radius, var(--sf-radius-m));\n  transition: var(--sf-transition-form-field);\n}\n\n/* Focus */\ninput:where(\n  [type=\"text\"], [type=\"email\"], [type=\"password\"], [type=\"url\"],\n  [type=\"tel\"], [type=\"number\"], [type=\"search\"], [type=\"date\"],\n  [type=\"datetime-local\"], [type=\"month\"], [type=\"week\"],\n  [type=\"time\"], :not([type])\n):focus-visible,\nselect:focus-visible,\ntextarea:focus-visible {\n  border-color: var(--sf-color-border--focus);\n  outline: var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-color-border--focus);\n  outline-offset: var(--sf-focus-ring-offset);\n}\n\n/* Disabled */\ninput:disabled,\nselect:disabled,\ntextarea:disabled {\n  background-color: var(--sf-color-bg--disabled);\n  color: var(--sf-color-text--disabled);\n  opacity: var(--sf-opacity-disabled);\n  cursor: not-allowed;\n}\n\n/* Placeholder */\ninput::placeholder,\ntextarea::placeholder {\n  color: var(--sf-color-text--placeholder);\n  opacity: 1;\n}\n\n/* Autofill: strips Safari's own dark-mode autofill background; Chromium/Firefox honour\n   the CSS background without this, but WebKit doesn't. */\n/* stylelint-disable selector-pseudo-class-no-unknown */\ninput:-webkit-autofill {\n  box-shadow: inset 0 0 0 1000px var(--sf-color-surface);\n  -webkit-text-fill-color: var(--sf-color-text);\n  caret-color: var(--sf-color-text);\n  border-color: var(--sf-field-border-color, var(--sf-color-border));\n}\ninput:autofill {\n  box-shadow: inset 0 0 0 1000px var(--sf-color-surface);\n  -webkit-text-fill-color: var(--sf-color-text);\n  caret-color: var(--sf-color-text);\n  border-color: var(--sf-field-border-color, var(--sf-color-border));\n}\n/* stylelint-enable selector-pseudo-class-no-unknown */\n\n/* Opt-in native validation feedback. Unconditional :user-invalid/:user-valid\n   styling was removed in 0.8.0 (see docs/migration.md): it fires on simple\n   focus+blur, so a still-empty required field could be marked invalid mid\n   multi-field form-fill, before any submit was attempted — the pattern\n   Bootstrap's own .was-validated gate exists to avoid. .sf-live-validate is\n   that same gate: put it on a <form> or <fieldset> to scope the pivot to\n   that subtree, so it only lights up on a real submit attempt (or explicit\n   interaction) instead of applying everywhere by default.\n\n   Safe to combine with manual validation: .sf-is-invalid/.sf-is-valid\n   (core/states.css, @layer slashed.states) always win over the rules below\n   regardless of selector specificity, because slashed.states is declared\n   AFTER slashed.forms in the layer order (core/layers.css) — cascade layer\n   order beats specificity. A field you've manually marked .sf-is-invalid\n   (e.g. a server-side error) can't be silently un-coloured by these rules\n   even if the browser considers it natively valid. */\n.sf-live-validate input:user-invalid,\n.sf-live-validate select:user-invalid,\n.sf-live-validate textarea:user-invalid {\n  --sf-field-border-color: var(--sf-color-danger);\n}\n\n.sf-live-validate input:user-valid,\n.sf-live-validate select:user-valid,\n.sf-live-validate textarea:user-valid {\n  --sf-field-border-color: var(--sf-color-success);\n}\n\n/* Numeric inputs */\ninput[type=\"number\"] {\n  font-variant-numeric: var(--sf-font-numeric, tabular-nums);\n}\n\n/* Textarea specifics */\ntextarea {\n  min-block-size: 6rem;\n  resize:         vertical;\n}\n\n@supports (field-sizing: content) {\n  textarea {\n    field-sizing: content;\n  }\n}\n\n/* Select: chevron uses FieldText system color — custom properties don't propagate\n   into data-URI SVG backgrounds. */\nselect {\n  padding-inline-end: calc(var(--sf-space-s) + 1.5em);\n}\n\nselect:not([multiple], [size]) {\n  background-repeat: no-repeat;\n  background-position: right var(--sf-space-s) center;\n  background-size: 1em;\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='FieldText' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M2.5 4.5L6 8l3.5-3.5'/%3E%3C/svg%3E\");\n}\n\n:dir(rtl) select:not([multiple], [size]) {\n  background-position: left var(--sf-space-s) center;\n}\n\n/* Button / submit / reset. Scoped to :where(form, fieldset) so a bare\n   <button> or <input type=\"submit\"/\"reset\"/\"button\"> used elsewhere on\n   the page (a page-builder's hamburger toggle, a modal close control, a\n   third-party widget) is left alone — only controls living inside an\n   actual form get the classless treatment. */\n:where(form, fieldset) button:not([class*=\"sf-\"]),\n:where(form, fieldset) input[type=\"submit\"]:not([class*=\"sf-\"]),\n:where(form, fieldset) input[type=\"reset\"]:not([class*=\"sf-\"]),\n:where(form, fieldset) input[type=\"button\"]:not([class*=\"sf-\"]) {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  gap: var(--sf-space-xs);\n  padding-block: var(--sf-space-xs);\n  padding-inline: var(--sf-space-m);\n  font-size: var(--sf-text-m);\n  font-weight: var(--sf-font-weight-heading);\n  line-height: var(--sf-leading-normal);\n  color: var(--sf-color-text--on-action);\n  background-color: var(--sf-color-action);\n  border: var(--sf-border-width-1) solid transparent;\n  border-radius: var(--sf-radius-m);\n  cursor: pointer;\n  transition: var(--sf-transition-colors);\n  text-decoration: none;\n}\n\n:where(form, fieldset) button:not([class*=\"sf-\"]):hover,\n:where(form, fieldset) input[type=\"submit\"]:not([class*=\"sf-\"]):hover,\n:where(form, fieldset) input[type=\"reset\"]:not([class*=\"sf-\"]):hover,\n:where(form, fieldset) input[type=\"button\"]:not([class*=\"sf-\"]):hover {\n\n  background-color: var(--sf-color-action--hover, var(--sf-color-action));\n}\n\n:where(form, fieldset) button:not([class*=\"sf-\"]):focus-visible,\n:where(form, fieldset) input[type=\"submit\"]:not([class*=\"sf-\"]):focus-visible,\n:where(form, fieldset) input[type=\"reset\"]:not([class*=\"sf-\"]):focus-visible,\n:where(form, fieldset) input[type=\"button\"]:not([class*=\"sf-\"]):focus-visible {\n  outline: var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-color-border--focus);\n  outline-offset: var(--sf-focus-ring-offset);\n}\n\n:where(form, fieldset) button:not([class*=\"sf-\"]):disabled,\n:where(form, fieldset) input[type=\"submit\"]:not([class*=\"sf-\"]):disabled,\n:where(form, fieldset) input[type=\"reset\"]:not([class*=\"sf-\"]):disabled,\n:where(form, fieldset) input[type=\"button\"]:not([class*=\"sf-\"]):disabled {\n  opacity: var(--sf-opacity-disabled);\n  cursor:  not-allowed;\n\n}\n\n/* Checkbox & radio */\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  inline-size:    1.125em;\n  block-size:     1.125em;\n  accent-color:   var(--sf-color-action);\n  cursor:         pointer;\n  vertical-align: middle;\n}\n\n/* File input */\ninput[type=\"file\"] {\n  cursor: pointer;\n}\ninput[type=\"file\"]::file-selector-button {\n  appearance: none;\n  margin-inline-end: var(--sf-space-s);\n  padding-block: var(--sf-space-xs);\n  padding-inline: var(--sf-space-m);\n  font-weight: var(--sf-font-weight-heading);\n  color: var(--sf-color-text--on-action);\n  background-color: var(--sf-color-action);\n  border: var(--sf-border-width-1) solid transparent;\n  border-radius: var(--sf-radius-m);\n  cursor: pointer;\n  transition: var(--sf-transition-colors);\n}\ninput[type=\"file\"]::file-selector-button:hover {\n  background-color: var(--sf-color-action--hover, var(--sf-color-action));\n}\n\n/* Range */\ninput[type=\"range\"] {\n  appearance: none;\n  inline-size: 100%;\n  background: transparent;\n  cursor: pointer;\n}\ninput[type=\"range\"]::-webkit-slider-runnable-track {\n  block-size: var(--sf-border-width-3, 0.25rem);\n  background-color: var(--sf-color-border);\n  border-radius: var(--sf-radius-full);\n}\ninput[type=\"range\"]::-moz-range-track {\n  block-size: var(--sf-border-width-3, 0.25rem);\n  background-color: var(--sf-color-border);\n  border-radius: var(--sf-radius-full);\n}\ninput[type=\"range\"]::-webkit-slider-thumb {\n  appearance: none;\n  inline-size: 1em;\n  block-size: 1em;\n  margin-block-start: calc((var(--sf-border-width-3, 0.25rem) - 1em) / 2);\n  background-color: var(--sf-color-action);\n  border-radius: var(--sf-radius-full);\n}\ninput[type=\"range\"]::-moz-range-thumb {\n  inline-size: 1em;\n  block-size: 1em;\n  background-color: var(--sf-color-action);\n  border: none;\n  border-radius: var(--sf-radius-full);\n}\ninput[type=\"range\"]:focus-visible {\n  outline: var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-color-border--focus);\n  outline-offset: var(--sf-focus-ring-offset);\n}\n\n/* Fieldset & legend */\nfieldset {\n  border: var(--sf-border-width-1) solid var(--sf-color-border--subtle);\n  border-radius: var(--sf-radius-m);\n  padding: var(--sf-space-m);\n}\n\nlegend {\n  font-weight: var(--sf-font-weight-heading);\n  padding-inline: var(--sf-space-xs);\n}\n\n/* Label */\nlabel {\n  display: block;\n  font-weight: var(--sf-font-weight-heading);\n  margin-block-end: var(--sf-space-xs);\n  color: var(--sf-field-text-color, inherit);\n}\n\nlabel:has(:required)::after,\nlabel:has(+ :required)::after,\nlabel:has(+ * :required)::after {\n  content: var(--sf-field-required-marker, \" *\");\n  color: var(--sf-color-danger);\n}\n\n/* ─── optional/components.css ─── */\n/* SLASHED — optional/components.css\n   @layer slashed.components\n   Component class surface: button and card.\n\n   .sf-btn and .sf-card are LIVE since v0.7.0. Further components\n   (badge, tag, alert, avatar, modal, skeleton) are planned — see\n   docs/roadmap.md and issue #384. The framework stays BEM-first and\n   token-first: anything not shipped here is authored as project BEM\n   classes reading SLASHED tokens.\n   Imports optional component tokens. */\n\n\n\n/* ============================================================\n * .sf-btn\n * Interactive call-to-action element. Apply to <button> or <a>.\n * Three orthogonal axes, freely composable:\n *   Colour:   --primary | --secondary | --tertiary | --action |\n *             --base | --neutral | --success | --warning | --info |\n *             --danger   (no modifier = --action)\n *   Style:    (no modifier = fill) | --soft | --outline\n *   Gradient: --gradient (fill + outline; core-4 brand families only —\n *             primary/secondary/tertiary/action; graceful solid no-op\n *             for the other families)\n * Sizes:  --xs | --s | (default m) | --l | --xl\n * Width:  intrinsic by default (like every other framework). --block\n *         forces full width everywhere; --block-cq opts into full width\n *         only inside a query container narrower than 20rem (needs a\n *         container ancestor — the layout primitives or .sf-cq provide\n *         one). No @media breakpoints.\n * States: :disabled / .sf-is-disabled | .sf-is-loading\n *\n * Colour model: every colour variant sets five rule-local custom\n * properties — --sf-btn-color (family base), --sf-btn-color--hover,\n * --sf-btn-on-color (readable foreground), and the --sf-btn-soft-bg /\n * --sf-btn-soft-bg--hover pair (the family's -subtle / -muted alpha\n * aliases) — and the fill / --soft / --outline treatments all derive\n * from them. This keeps the style modifiers orthogonal: they compose\n * with any colour family (e.g. .sf-btn--outline.sf-btn--danger).\n * The default (no colour modifier) is the action family. Semantic\n * hover: brand colours use the --hover token; status colours\n * (success/warning/info/danger) use the direction-aware -strong\n * triplet.\n *\n * Focus: the global core/accessibility.css :focus-visible rule already\n * applies the WCAG ring to every focusable element, so .sf-btn needs no\n * component-level focus outline of its own.\n * ============================================================ */\n.sf-btn {\n  /* Rule-local colour family — variants override these five. */\n  --sf-btn-color:          var(--sf-color-action);\n  --sf-btn-color--hover:   var(--sf-color-action--hover);\n  --sf-btn-on-color:       var(--sf-color-text--on-action);\n  --sf-btn-soft-bg:        var(--sf-color-action-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-action-muted);\n\n  /* Rule-local SIZE tier — the per-size defaults each size modifier tunes.\n     The base (default / m) values live here; .sf-btn--xs/--s/--l/--xl only\n     reassign these *-size tokens, never the public knob. Each public knob\n     (--sf-btn-font-size, --sf-btn-padding-block/-inline, --sf-btn-min-height)\n     is read FIRST in its property below, so a :root override of the knob\n     wins on every size, while an unset knob falls through to the size tier.\n     Each tier's first arg is the matching per-size knob\n     --sf-btn-{size}-{prop} (initial → falls through to that rung's own scale\n     default), so a :root override retunes one rung; for font-size the whole\n     resolved value is then multiplied by --sf-btn-font-scale in the property\n     below. */\n  --sf-btn-font-size--size:      var(--sf-btn-m-font-size, var(--sf-text-m));\n  --sf-btn-padding-block--size:  var(--sf-btn-m-padding-block, var(--sf-space-xs));\n  --sf-btn-padding-inline--size: var(--sf-btn-m-padding-inline, var(--sf-space-m));\n  --sf-btn-min-height--size:     var(--sf-btn-m-min-height, var(--sf-size-m));\n\n  display:          inline-flex;\n  align-items:      center;\n  justify-content:  center;\n  gap:              var(--sf-btn-gap, var(--sf-space-2xs));\n  padding-block:    var(--sf-btn-padding-block, var(--sf-btn-padding-block--size));\n  padding-inline:   var(--sf-btn-padding-inline, var(--sf-btn-padding-inline--size));\n  min-block-size:   var(--sf-btn-min-height, var(--sf-btn-min-height--size));\n  font-family:      inherit;\n  font-size:        calc(var(--sf-btn-font-size, var(--sf-btn-font-size--size)) * var(--sf-btn-font-scale, 1));\n  font-weight:      var(--sf-btn-font-weight, var(--sf-font-weight-interactive));\n  line-height:      var(--sf-leading-tight);\n  text-decoration:  none;\n  white-space:      nowrap;\n  border:           var(--sf-btn-border-width, var(--sf-border-width-1)) solid var(--sf-btn-color);\n  border-radius:    var(--sf-btn-radius);\n  cursor:           pointer;\n  user-select:      none;\n  appearance:       none;\n  transition:       var(--sf-transition-form-field);\n  background:       var(--sf-btn-color);\n  color:            var(--sf-btn-on-color);\n}\n.sf-btn:hover:not(:disabled, .sf-is-disabled, .sf-is-loading) {\n  background:   var(--sf-btn-color--hover);\n  border-color: var(--sf-btn-color--hover);\n}\n\n/* --- Colour families (all 10, 1:1 with the global palette): set the\n       rule-local custom properties only. --action mirrors the default\n       so the colour axis has an explicit name for every family. --- */\n.sf-btn--primary {\n  --sf-btn-color:          var(--sf-color-primary);\n  --sf-btn-color--hover:   var(--sf-color-primary--hover);\n  --sf-btn-on-color:       var(--sf-color-text--on-primary);\n  --sf-btn-soft-bg:        var(--sf-color-primary-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-primary-muted);\n}\n.sf-btn--secondary {\n  --sf-btn-color:          var(--sf-color-secondary);\n  --sf-btn-color--hover:   var(--sf-color-secondary--hover);\n  --sf-btn-on-color:       var(--sf-color-text--on-secondary);\n  --sf-btn-soft-bg:        var(--sf-color-secondary-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-secondary-muted);\n}\n.sf-btn--tertiary {\n  --sf-btn-color:          var(--sf-color-tertiary);\n  --sf-btn-color--hover:   var(--sf-color-tertiary--hover);\n  --sf-btn-on-color:       var(--sf-color-text--on-tertiary);\n  --sf-btn-soft-bg:        var(--sf-color-tertiary-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-tertiary-muted);\n}\n.sf-btn--action {\n  --sf-btn-color:          var(--sf-color-action);\n  --sf-btn-color--hover:   var(--sf-color-action--hover);\n  --sf-btn-on-color:       var(--sf-color-text--on-action);\n  --sf-btn-soft-bg:        var(--sf-color-action-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-action-muted);\n}\n.sf-btn--base {\n  --sf-btn-color:          var(--sf-color-base);\n  --sf-btn-color--hover:   var(--sf-color-base--hover);\n  --sf-btn-on-color:       var(--sf-color-text--on-base);\n  --sf-btn-soft-bg:        var(--sf-color-base-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-base-muted);\n}\n.sf-btn--neutral {\n  --sf-btn-color:          var(--sf-color-neutral);\n  --sf-btn-color--hover:   var(--sf-color-neutral--hover);\n  --sf-btn-on-color:       var(--sf-color-text--on-neutral);\n  --sf-btn-soft-bg:        var(--sf-color-neutral-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-neutral-muted);\n}\n.sf-btn--success {\n  --sf-btn-color:          var(--sf-color-success);\n  --sf-btn-color--hover:   var(--sf-color-success-strong);\n  --sf-btn-on-color:       var(--sf-color-text--on-success);\n  --sf-btn-soft-bg:        var(--sf-color-success-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-success-muted);\n}\n.sf-btn--warning {\n  --sf-btn-color:          var(--sf-color-warning);\n  --sf-btn-color--hover:   var(--sf-color-warning-strong);\n  --sf-btn-on-color:       var(--sf-color-text--on-warning);\n  --sf-btn-soft-bg:        var(--sf-color-warning-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-warning-muted);\n}\n.sf-btn--info {\n  --sf-btn-color:          var(--sf-color-info);\n  --sf-btn-color--hover:   var(--sf-color-info-strong);\n  --sf-btn-on-color:       var(--sf-color-text--on-info);\n  --sf-btn-soft-bg:        var(--sf-color-info-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-info-muted);\n}\n.sf-btn--danger {\n  --sf-btn-color:          var(--sf-color-danger);\n  --sf-btn-color--hover:   var(--sf-color-danger-strong);\n  --sf-btn-on-color:       var(--sf-color-text--on-danger);\n  --sf-btn-soft-bg:        var(--sf-color-danger-subtle);\n  --sf-btn-soft-bg--hover: var(--sf-color-danger-muted);\n}\n\n/* --- Style treatments (compose with any colour family) ---\n   Emphasis ladder, highest → lowest:\n     fill       solid family background (the base .sf-btn)\n     soft       soft TONAL fill — a light wash of the family colour, no\n                border. Lower-emphasis than fill but still reads as a filled\n                button, so it is visually distinct from --outline.\n     outline    transparent with a visible border; fills on hover.\n   --soft reads the family's alpha-alias tokens (--sf-color-{family}-subtle\n   resting, -muted on hover) via the rule-local --sf-btn-soft-bg pair, so\n   the wash has one source of truth in core/tokens.css. Those aliases live\n   behind the relative-color @supports gate, so the resting fill is gated\n   the same way: engines without oklch(from …) degrade soft → bordered\n   instead of dropping a declaration mid-rule. Mirrors the framework-wide\n   gating policy enforced by tests/tier1-p2-coverage.test.js +\n   tests/tier1-p7-oldengine.test.js. */\n\n/* Soft tonal fill. Fallback (no relative color): a bordered treatment so\n   it is never invisible; the tonal wash is layered on inside @supports\n   below. */\n.sf-btn--soft {\n  background:   transparent;\n  color:        var(--sf-btn-color);\n  border-color: var(--sf-btn-color);\n}\n\n@supports (color: oklch(from red l c h)) {\n  /* Tonal fill replaces the fallback border once the alpha-alias tokens\n     (gated on relative color in core/tokens.css) are available. */\n  .sf-btn--soft {\n    background:   var(--sf-btn-soft-bg);\n    color:        var(--sf-btn-color);\n    border-color: transparent;\n  }\n  .sf-btn--soft:hover:not(:disabled, .sf-is-disabled, .sf-is-loading) {\n    background:   var(--sf-btn-soft-bg--hover);\n    border-color: transparent;\n  }\n}\n\n/* Outline: transparent to start, fills with the family colour on hover. */\n.sf-btn--outline {\n  background:   transparent;\n  color:        var(--sf-btn-color);\n  border-color: var(--sf-btn-color);\n}\n.sf-btn--outline:hover:not(:disabled, .sf-is-disabled, .sf-is-loading) {\n  background:   var(--sf-btn-color);\n  color:        var(--sf-btn-on-color);\n  border-color: var(--sf-btn-color);\n}\n\n/* --- Gradient axis (.sf-btn--gradient, composes with colour + style) ---\n   Real modifier for the 4 core brand families — primary / secondary /\n   tertiary / action — driven by the matching --sf-gradient-{family}\n   token. The remaining families (base/neutral/status) have no gradient\n   token yet; for them --gradient resolves to the solid family colour\n   (documented no-op), so composing is always safe. All visual rules sit\n   behind the relative-color @supports gate (the gradient tokens are only\n   defined there); outside it the button renders as its solid fill or\n   outline. --soft wins over --gradient: the tonal wash is the lower-\n   emphasis treatment, so the gradient fill explicitly excludes it. */\n.sf-btn--gradient {\n  --sf-btn-gradient: var(--sf-gradient-action);\n}\n.sf-btn--primary.sf-btn--gradient   { --sf-btn-gradient: var(--sf-gradient-primary); }\n.sf-btn--secondary.sf-btn--gradient { --sf-btn-gradient: var(--sf-gradient-secondary); }\n.sf-btn--tertiary.sf-btn--gradient  { --sf-btn-gradient: var(--sf-gradient-tertiary); }\n.sf-btn--action.sf-btn--gradient    { --sf-btn-gradient: var(--sf-gradient-action); }\n/* Families without a gradient token: solid family colour (no-op). */\n.sf-btn--base.sf-btn--gradient,\n.sf-btn--neutral.sf-btn--gradient,\n.sf-btn--success.sf-btn--gradient,\n.sf-btn--warning.sf-btn--gradient,\n.sf-btn--info.sf-btn--gradient,\n.sf-btn--danger.sf-btn--gradient {\n  --sf-btn-gradient: var(--sf-btn-color);\n}\n\n@supports (color: oklch(from red l c h)) {\n  /* Gradient fill. Border goes transparent so the darkening gradient\n     never fights a solid family-coloured edge. */\n  .sf-btn--gradient:not(.sf-btn--outline, .sf-btn--soft) {\n    background:   var(--sf-btn-gradient);\n    border-color: transparent;\n  }\n  /* Hover: keep the gradient, darken (light mode) / lighten (dark mode)\n     through a translucent overlay — --sf-is-dark is 0 in light, 1 in\n     dark, so the overlay's oklch lightness flips direction-aware. */\n  .sf-btn--gradient:not(.sf-btn--outline, .sf-btn--soft):hover:not(:disabled, .sf-is-disabled, .sf-is-loading) {\n    background:   linear-gradient(\n                    oklch(var(--sf-is-dark) 0 0 / 0.12),\n                    oklch(var(--sf-is-dark) 0 0 / 0.12)\n                  ),\n                  var(--sf-btn-gradient);\n    border-color: transparent;\n  }\n\n  /* Gradient outline: the docs' former copy-paste recipe as a real rule.\n     A masked ::before paints the family gradient in the border ring only\n     (padding-box punched out of border-box). Uses ::before — the loading\n     spinner owns ::after, so both states compose. */\n  .sf-btn--gradient.sf-btn--outline {\n    position:     relative;\n    background:   transparent;\n    color:        var(--sf-btn-color);\n    border-color: transparent;\n  }\n  .sf-btn--gradient.sf-btn--outline::before {\n    content:        \"\";\n    position:       absolute;\n    inset:          0;\n    border-radius:  inherit;\n    padding:        var(--sf-btn-border-width, var(--sf-border-width-1));\n    background:     var(--sf-btn-gradient);\n    /* Punch the padding-box out of the border-box so only the border\n       ring shows. Unprefixed mask is within the browser floor implied\n       by the surrounding relative-color gate. */\n    mask:           linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);\n    mask-composite: exclude;\n    pointer-events: none;\n  }\n  /* Hover mirrors solid --outline: fills, here with the gradient. */\n  .sf-btn--gradient.sf-btn--outline:hover:not(:disabled, .sf-is-disabled, .sf-is-loading) {\n    background:   var(--sf-btn-gradient);\n    color:        var(--sf-btn-on-color);\n    border-color: transparent;\n  }\n}\n\n/* --- Sizes (m is the default; retune the rule-local *-size tier so a\n       :root override of the public knob still wins over the size) ---\n\n   The min-height ladder maps 1:1 onto the --sf-size-* scale rungs: --xs→xs,\n   --s→s, default(m)→m, --l→l, --xl→xl. (Before 0.8.0 the ladder was offset\n   by one rung so the default button cleared the 44px --sf-touch-target\n   floor; that pinned m to --sf-size-l and pushed --l/--xl up. The offset was\n   dropped so the size names read predictably — see docs/migration.md.) The\n   default control is now --sf-size-m (40px), which still clears the WCAG 2.2\n   AA 24px target; consumers who want the 44px AAA touch target back can set\n   `--sf-btn-min-height: var(--sf-touch-target)` globally (exactly 44px, an\n   accessibility anchor independent of the size scale) or reach for\n   `.sf-btn--l` (--sf-size-l, 48px).\n\n   This ladder is honoured on touch devices too: .sf-btn is excluded from the\n   blanket `@media (pointer: coarse)` 44px floor in core/accessibility.css, so\n   the size scale stays visible on phones/tablets instead of every rung\n   collapsing to 44px. The AAA opt-in above restores the floor when wanted. */\n.sf-btn--xs {\n  --sf-btn-padding-block--size:  var(--sf-btn-xs-padding-block, 0.125rem);\n  --sf-btn-padding-inline--size: var(--sf-btn-xs-padding-inline, var(--sf-space-xs));\n  --sf-btn-font-size--size:      var(--sf-btn-xs-font-size, var(--sf-text-xs));\n  --sf-btn-min-height--size:     var(--sf-btn-xs-min-height, var(--sf-size-xs));\n}\n.sf-btn--s {\n  --sf-btn-padding-block--size:  var(--sf-btn-s-padding-block, var(--sf-space-2xs));\n  --sf-btn-padding-inline--size: var(--sf-btn-s-padding-inline, var(--sf-space-s));\n  --sf-btn-font-size--size:      var(--sf-btn-s-font-size, var(--sf-text-s));\n  --sf-btn-min-height--size:     var(--sf-btn-s-min-height, var(--sf-size-s));\n}\n.sf-btn--l {\n  --sf-btn-padding-block--size:  var(--sf-btn-l-padding-block, var(--sf-space-s));\n  --sf-btn-padding-inline--size: var(--sf-btn-l-padding-inline, var(--sf-space-l));\n  --sf-btn-font-size--size:      var(--sf-btn-l-font-size, var(--sf-text-l));\n  --sf-btn-min-height--size:     var(--sf-btn-l-min-height, var(--sf-size-l));\n}\n.sf-btn--xl {\n  --sf-btn-padding-block--size:  var(--sf-btn-xl-padding-block, var(--sf-space-m));\n  --sf-btn-padding-inline--size: var(--sf-btn-xl-padding-inline, var(--sf-space-xl));\n  --sf-btn-font-size--size:      var(--sf-btn-xl-font-size, var(--sf-text-xl));\n  --sf-btn-min-height--size:     var(--sf-btn-xl-min-height, var(--sf-size-xl));\n}\n\n/* --- States --- */\n.sf-btn:disabled,\n.sf-btn.sf-is-disabled {\n  opacity:        var(--sf-opacity-disabled);\n  cursor:         not-allowed;\n  pointer-events: none;\n}\n\n.sf-btn.sf-is-loading {\n  cursor:   wait;\n  position: relative;\n}\n.sf-btn.sf-is-loading > * {\n  visibility: hidden;\n}\n.sf-btn.sf-is-loading::after {\n  content:                  '';\n  position:                 absolute;\n  inset:                    0;\n  margin:                   auto;\n  inline-size:              1em;\n  block-size:               1em;\n  border:                   2px solid currentcolor;\n  border-block-start-color: transparent;\n  border-radius:            var(--sf-radius-full);\n}\n/* Spinner only animates when motion is welcome; otherwise the ring is\n   shown static so the loading state is still visible. */\n@media (prefers-reduced-motion: no-preference) {\n  .sf-btn.sf-is-loading::after {\n    animation: sf-spin var(--sf-duration-slower) linear infinite;\n  }\n}\n\n/* --- Width --- */\n.sf-btn--block {\n  inline-size: 100%;\n}\n\n@container (max-width: 20rem) {\n  .sf-btn--block-cq {\n    inline-size: 100%;\n  }\n}\n\n/* ============================================================\n * .sf-card\n * Padded content container with optional header/body/footer.\n * Modifiers: --bordered (flat, outlined, no shadow) |\n *            --elevated (floating shadow, no border) |\n *            --interactive (pointer + hover/focus lift)\n * Concentric radius: --sf-card-radius-outer on the card,\n * --sf-card-radius on inner elements (mirrors the math in\n * tokens.components.css).\n * Subcomponents: __media (16/9 cover image), __avatar (round),\n * __title (unified heading size). Nested buttons keep their own\n * size — add .sf-btn--s explicitly for a compact card action.\n * ============================================================ */\n.sf-card {\n  /* A card is a block box. When combined with a layout primitive on the same\n     element (.sf-card.sf-stack, .sf-card.sf-grid, …) the primitive's\n     flex/grid display wins, because slashed.layout layers AFTER\n     slashed.components — see core/layers.css. No guard needed. */\n  display:       block;\n  padding:       var(--sf-card-padding, var(--sf-space-l));\n  background:    var(--sf-card-bg, var(--sf-color-surface));\n  border:        var(--sf-card-border-width, var(--sf-border-width-1)) solid var(--sf-card-border-color, var(--sf-color-border));\n  border-radius: var(--sf-card-radius-outer, calc(var(--sf-radius-m) + var(--sf-space-l)));\n  box-shadow:    var(--sf-card-shadow, var(--sf-shadow-s));\n}\n\n/* Card-on-coloured-surface reset (#496).\n   A .sf-card keeps the page/theme surface for its OWN background\n   (--sf-card-bg = --sf-color-surface, which a coloured .sf-surface--* does\n   NOT override — the card stays a light \"elevation\" island above the colour).\n   But the surface auto-contrast cascade (core/macros.css) re-points\n   --sf-color-text / -heading / -border to contrast with the SURFACE colour,\n   and those inherit into the card, computing its title/body/border for the\n   wrong background (e.g. light-on-light). Re-derive the surface-appropriate\n   tokens on the card from the ambient neutral so its content stays legible\n   against its own background, and set `color` so inherited body text is\n   re-established too.\n\n   Activation is gated on the surface's --sf-surface-active flag via a style\n   query — NOT a `.sf-surface .sf-card` descendant selector — so (a) ordinary\n   cards and [data-theme] cards (handled in core/themes.css) are untouched,\n   (b) a consumer's own --sf-color-heading override on a non-surface ancestor\n   is still inherited (the flag is unset there), and (c) the surface class\n   names don't leak into this component file's generated class reference.\n   SL-001: the light-dark() derivations below mirror core/tokens.css's\n   \"Resolved color tokens\" block — keep them in sync if the formulas change. */\n@supports (color: oklch(from red l c h)) {\n  @container style(--sf-surface-active: 1) {\n    .sf-card {\n\n      --sf-color-heading: light-dark(\n        oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h),\n        oklch(from var(--sf-color-neutral)              clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1)    c h));\n      --sf-color-text: var(--sf-color-heading);\n      --sf-color-text--secondary: light-dark(\n        oklch(from var(--sf-color-neutral-source-light) clamp(0.15, calc(l - 0.25 - var(--sf-contrast-bias)), 0.45) c h),\n        oklch(from var(--sf-color-neutral)              clamp(0.55, calc(l + 0.1 + var(--sf-contrast-bias)), 0.90) c h));\n      --sf-color-border: light-dark(\n        oklch(from var(--sf-color-neutral-source-light) clamp(0.70, calc(l + 0.35), 0.95) 0.005 h),\n        oklch(from var(--sf-color-neutral)              clamp(0.25, calc(l - 0.3),  0.55) 0.005 h));\n      --sf-color-border--subtle: light-dark(\n        oklch(from var(--sf-color-neutral-source-light) clamp(0.75, calc(l + 0.4),  0.97) 0.005 h),\n        oklch(from var(--sf-color-neutral)              clamp(0.20, calc(l - 0.38), 0.45) 0.005 h));\n\n      /* Re-seal the :root aliases against the card's restored tokens. */\n      --sf-heading-color:     var(--sf-color-heading);\n      --sf-body-color:        var(--sf-color-text);\n      --sf-card-border-color: var(--sf-color-border);\n\n      /* Body text inherits the `color` property (not a token) from the surface,\n         so re-establish it from the card's restored --sf-color-text. */\n      color: var(--sf-body-color, var(--sf-color-text));\n    }\n  }\n}\n\n.sf-card__header,\n.sf-card__body,\n.sf-card__footer {\n  display: block;\n}\n\n.sf-card__header {\n  padding-block-end: var(--sf-card-gap, var(--sf-space-m));\n  border-block-end:  var(--sf-border-subtle);\n  margin-block-end:  var(--sf-card-gap, var(--sf-space-m));\n}\n\n.sf-card__footer {\n  padding-block-start: var(--sf-card-gap, var(--sf-space-m));\n  border-block-start:  var(--sf-border-subtle);\n  margin-block-start:  var(--sf-card-gap, var(--sf-space-m));\n}\n\n.sf-card__media {\n  display:       block;\n  inline-size:   100%;\n  aspect-ratio:  var(--sf-card-media-ratio, var(--sf-ratio-video));\n  object-fit:    var(--sf-object-fit, cover);\n  border-radius: var(--sf-card-media-radius);\n  overflow:      clip;\n  /* Space before whatever follows (header or body) — media had no gap of\n     its own, so it touched the next element directly. */\n  margin-block-end: var(--sf-card-gap, var(--sf-space-m));\n}\n\n.sf-card__avatar {\n  inline-size:   var(--sf-card-avatar-size, 2.5rem);\n  block-size:    var(--sf-card-avatar-size, 2.5rem);\n  aspect-ratio:  1;\n  object-fit:    cover;\n  border-radius: var(--sf-radius-full);\n  flex-shrink:   0;\n}\n\n.sf-card__title {\n  font-size: var(--sf-card-heading-size, var(--sf-text-xl));\n  color:     var(--sf-color-heading);\n}\n\n/* --- Modifiers --- */\n/* Flat, outlined card: keep the border, drop the shadow. */\n.sf-card--bordered {\n  box-shadow: none;\n}\n\n/* Floating card: lean on the shadow, hide the border. */\n.sf-card--elevated {\n  border-color: transparent;\n  box-shadow:   var(--sf-card-shadow--elevated, var(--sf-shadow-l));\n}\n\n/* Whole-card affordance: pointer + lift on hover/keyboard focus.\n   Pair with .sf-clickable-parent when the entire card is a link. */\n.sf-card--interactive {\n  cursor:     pointer;\n  transition: var(--sf-transition-shadow);\n}\n.sf-card--interactive:hover,\n.sf-card--interactive:focus-within {\n  box-shadow: var(--sf-card-shadow--hover, var(--sf-shadow-l));\n}\n@media (prefers-reduced-motion: no-preference) {\n  .sf-card--interactive {\n    transition: var(--sf-transition-shadow), var(--sf-transition-transform);\n  }\n  .sf-card--interactive:hover,\n  .sf-card--interactive:focus-within {\n    transform: translateY(calc(-1 * var(--sf-space-2xs)));\n  }\n}\n\n/* ─── core/layout.css ─── */\n/* SLASHED — core/layout.css\n   @layer slashed.layout\n   Layout primitives: section, container, stack, cluster, grid, sidebar, switcher, frame.\n   Prefix: .sf-*; local rhythm via --sf-*-gap / sizing tokens.\n   SL-005: every @container query in this file hardcodes its breakpoint\n   instead of referencing a --sf-* token — var() is not allowed inside an\n   @container condition per the CSS spec. This applies framework-wide to\n   every @container site below; not re-explained at each one.\n   SL-005a: those hardcoded breakpoints are expressed in REM, never em.\n   Inside an @container condition a font-relative em resolves against the\n   QUERY CONTAINER's own computed font-size — and under SLASHED's default\n   fluid type that font-size is inherited from body (a clamp() over 100vw,\n   ~16–20px), so an em breakpoint would silently slide with the VIEWPORT and\n   break the \"responds to its own container width, not the viewport\" contract\n   (docs/architecture.md). rem resolves against the ROOT (:root/html stays a\n   fixed 16px; fluid type is applied to body, not html), so the breakpoint is\n   viewport-independent while still honouring user zoom / root-font-size\n   preferences. Note this is the OPPOSITE of the @media convention, where em\n   and rem both resolve against the root — do not copy \"use em for a11y\n   breakpoints\" from @media into @container. (Matches Tailwind, whose\n   container-query breakpoints are rem; cf. issue #497 fluid-cq work.)\n   SL-034: a query container cannot be the subject of its own @container\n   query — conditions only ever match descendants of the nearest ancestor\n   container, never the element that establishes it (self-querying is a\n   silent no-op, not an error). Primitives that need to resize THEMSELVES\n   (.sf-grid-cols-2/3/4/6, .sf-bento) must therefore rely on an ancestor\n   container (.sf-container / .sf-cq / .sf-fluid-cq) rather than declaring\n   `container` on themselves. .sf-grid-cols-1-2 etc. already follow this —\n   they've never declared their own `container` — so they were unaffected.\n   .sf-alternate is a different, unrelated-but-similar-looking pattern: it\n   DOES declare `container` on itself, but only to restyle its CHILDREN\n   (`.sf-alternate > *`), which is not self-querying and is fine. Not\n   re-explained at each site below. */\n\n\n/* Section */\n.sf-section     { padding-block: var(--sf-section-pad); }\n.sf-section--xs { --sf-section-pad: var(--sf-section-pad--xs); }\n.sf-section--s  { --sf-section-pad: var(--sf-section-pad--s); }\n.sf-section--m  { --sf-section-pad: var(--sf-section-pad--m); }\n.sf-section--l  { --sf-section-pad: var(--sf-section-pad--l); }\n.sf-section--xl { --sf-section-pad: var(--sf-section-pad--xl); }\n.sf-section--2xl { --sf-section-pad: var(--sf-section-pad--2xl); }\n\n.sf-section--guttered { padding-inline: var(--sf-gutter); }\n.sf-section--guttered .sf-container { padding-inline: 0; }\n/* .sf-content-grid carries the gutter in its own edge tracks\n   (minmax(gutter,1fr)), not in padding — so unlike .sf-container it can't be\n   de-duplicated by zeroing its padding (it has none). Left alone, the\n   section's padding boxes the grid in: content ends up double-guttered and\n   .sf-full-bleed stops at the padding edge instead of the section edge.\n   Drop the section's own padding so the grid spans edge-to-edge and its\n   tracks provide the single gutter; full-bleed then reaches the true edge.\n   Only when the content grid is the SOLE direct child: dropping the section\n   padding is right for the grid but would strip the gutter from any non-grid\n   sibling (a heading, a plain block) that legitimately relies on it — and\n   those two wants are physically irreconcilable (the gutter *is* the section\n   padding that full-bleed must escape). So we restrict to the unambiguous\n   case; a mixed section keeps its padding and behaves exactly as before this\n   rule existed. Direct-child scope also stops a nested grid deeper in the\n   section from stripping the gutter. */\n.sf-section--guttered:has(> .sf-content-grid):not(:has(> :not(.sf-content-grid))) {\n  padding-inline: 0;\n}\n\n.sf-section-group > .sf-section + .sf-section { padding-block-start: 0; }\n\n/* Header — block padding on the standard spacing scale. Headers usually\n   want lighter vertical rhythm than .sf-section, so these map to\n   --sf-space-* directly. Only block padding is set; any inline gutter\n   (from .sf-section--guttered, a container, or the element itself) is\n   left intact. */\n.sf-header--xs { padding-block: var(--sf-space-xs); }\n.sf-header--s  { padding-block: var(--sf-space-s); }\n.sf-header--m  { padding-block: var(--sf-space-m); }\n.sf-header--l  { padding-block: var(--sf-space-l); }\n.sf-header--xl { padding-block: var(--sf-space-xl); }\n\n/* Collapse modifier */\n.sf-section--collapse:has(+ .sf-section--collapse) {\n  padding-block-end: calc(var(--sf-section-pad) / 2);\n}\n.sf-section--collapse + .sf-section--collapse {\n  padding-block-start: calc(var(--sf-section-pad) / 2);\n}\n\n.sf-divider {\n  inline-size:        100%;\n  border:             none;\n  border-block-start: var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);\n  margin-block:       var(--sf-divider-gap);\n}\n.sf-divider--vertical {\n  inline-size:          auto;\n  border-block-start:   none;\n  border-inline-start:  var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);\n  margin-block:         0;\n  margin-inline:        var(--sf-divider-gap);\n  align-self:           stretch;\n}\n\n.sf-divider--soft   { --sf-divider-color: var(--sf-color-border--subtle); }\n.sf-divider--strong { --sf-divider-color: var(--sf-color-border--strong); }\n.sf-divider--dashed { --sf-divider-style: dashed; }\n.sf-divider--dotted { --sf-divider-style: dotted; }\n\n.sf-divider--gradient {\n  border:        none;\n  block-size:    var(--sf-divider-width);\n  background:    linear-gradient(to right, transparent, var(--sf-divider-color), transparent);\n}\n\n/* Divide — rules between direct children, reusing .sf-divider's tokens.\n   Unlike .sf-divider (a standalone separator element), .sf-divide is\n   applied to the container and needs no extra markup per gap. */\n.sf-divide > * + * {\n  border-block-start: var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);\n}\n.sf-divide--vertical > * + * {\n  border-block-start:  none;\n  border-inline-start: var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);\n}\n\n\n/* Container */\n.sf-container {\n  container:      sf-layout / inline-size;\n  width:          100%;\n  max-width:      var(--sf-container-default);\n  margin-inline:  auto;\n  padding-inline: var(--sf-gutter);\n}\n.sf-container--narrow { max-width: var(--sf-container-narrow); }\n.sf-container--prose  { max-width: var(--sf-container-prose); }\n.sf-container--wide   { max-width: var(--sf-container-wide); }\n.sf-container--full   { max-width: var(--sf-container-full); }\n\n/* .sf-cq: CQ scope without .sf-container's max-width/centering.\n   Use when a CQ-dependent primitive needs a container ancestor but no layout chrome. */\n.sf-cq {\n  container-type: inline-size;\n}\n\n/* Overlay — absolute-fill layout helper for overlays/backdrops. */\n.sf-overlay {\n  position: absolute;\n  inset:    0;\n}\n\n\n/* .sf-fluid-cq: opt a subtree into a CONTAINER-relative fluid scale (issue\n   #497). By default --sf-text-* / --sf-space-* interpolate against 100vw (the\n   viewport); inside .sf-fluid-cq they interpolate against 100cqi (this box's\n   inline size), so type + spacing track the container the way the layout\n   primitives (.sf-grid-cols-*, .sf-content-grid, .sf-bento) already do. Use\n   on nested / narrow contexts (sidebars, cards, 1/3 columns) where a\n   viewport-driven scale would size text as if it spanned the full page.\n\n   Why the tokens are RE-DECLARED (not just --sf-fluid-width flipped): the\n   --sf-text-* / --sf-space-* tokens are computed at :root, so their\n   var(--sf-fluid-width) is substituted there (100vw) and the *resolved*\n   length inherits down — overriding --sf-fluid-width lower in the tree can't\n   retroactively rewrite an already-computed inherited value. The scale is\n   therefore re-declared in-scope so var(--sf-fluid-width) re-resolves to\n   100cqi. It is re-declared on the direct children, not the element itself:\n   a query container's own cq units resolve against its ANCESTOR container, so\n   the re-computation must happen one level in — children compute against\n   .sf-fluid-cq and deeper descendants inherit that resolved value.\n\n   The formulas below are character-identical to their :root twins in\n   core/tokens.css (both read var(--sf-fluid-width)); keep the two copies in\n   sync if the generative formula ever changes (cf. themes.css SL-001). */\n.sf-fluid-cq { container-type: inline-size; }\n.sf-fluid-cq > * {\n    --sf-fluid-width: 100cqi;\n    --sf-text-2xs: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -3) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -3) * 1rem)) * var(--sf-text-scale));\n    --sf-text-xs: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -2) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -2) * 1rem)) * var(--sf-text-scale));\n    --sf-text-s: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -1) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -1) * 1rem)) * var(--sf-text-scale));\n    --sf-text-m: calc(clamp(calc(var(--sf-text-base-min) * 1rem), calc((var(--sf-text-base-max) - var(--sf-text-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * 1rem), calc(var(--sf-text-base-max) * 1rem)) * var(--sf-text-scale));\n    --sf-text-l: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 1) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 1) * 1rem)) * var(--sf-text-scale));\n    --sf-text-xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 2) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 2) * 1rem)) * var(--sf-text-scale));\n    --sf-text-2xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 3) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 3) * 1rem)) * var(--sf-text-scale));\n    --sf-text-3xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 4) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 4) * 1rem)) * var(--sf-text-scale));\n    --sf-text-4xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 5) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 5) * 1rem)) * var(--sf-text-scale));\n    --sf-text-display-s: calc(clamp(calc(var(--sf-text-display-base-min) * 1rem), calc((var(--sf-text-display-base-max) - var(--sf-text-display-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * 1rem), calc(var(--sf-text-display-base-max) * 1rem)) * var(--sf-text-display-scale));\n    --sf-text-display-m: calc(clamp(calc(var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc((var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 1) - var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc(var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 1) * 1rem)) * var(--sf-text-display-scale));\n    --sf-text-display-l: calc(clamp(calc(var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc((var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 2) - var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc(var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 2) * 1rem)) * var(--sf-text-display-scale));\n    --sf-space-2xs: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -3) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -3) * 1rem)) * var(--sf-space-scale));\n    --sf-space-xs: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -2) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -2) * 1rem)) * var(--sf-space-scale));\n    --sf-space-s: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -1) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -1) * 1rem)) * var(--sf-space-scale));\n    --sf-space-m: calc(clamp(calc(var(--sf-space-base-min) * 1rem), calc((var(--sf-space-base-max) - var(--sf-space-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * 1rem), calc(var(--sf-space-base-max) * 1rem)) * var(--sf-space-scale));\n    --sf-space-l: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 1) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 1) * 1rem)) * var(--sf-space-scale));\n    --sf-space-xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 2) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 2) * 1rem)) * var(--sf-space-scale));\n    --sf-space-2xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 3) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 3) * 1rem)) * var(--sf-space-scale));\n    --sf-space-3xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 4) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 4) * 1rem)) * var(--sf-space-scale));\n    --sf-space-4xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 5) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 5) * 1rem)) * var(--sf-space-scale));\n}\n\n\n/* Stack & gap */\n.sf-stack {\n  display:        flex;\n  flex-direction: column;\n  gap:            var(--sf-stack-gap);\n}\n.sf-stack--xs  { gap: var(--sf-space-xs); }\n.sf-stack--s   { gap: var(--sf-space-s); }\n.sf-stack--m   { gap: var(--sf-space-m); }\n.sf-stack--l   { gap: var(--sf-space-l); }\n.sf-stack--xl  { gap: var(--sf-space-xl); }\n.sf-stack--2xl { gap: var(--sf-space-2xl); }\n\n.sf-stack--center  { align-items: center; }\n.sf-stack--end     { align-items: flex-end; }\n.sf-stack--stretch { align-items: stretch; }\n\n.sf-gap { gap: var(--sf-gap); }\n.sf-gap--xs  { gap: var(--sf-space-xs); }\n.sf-gap--s   { gap: var(--sf-space-s); }\n.sf-gap--m   { gap: var(--sf-space-m); }\n.sf-gap--l   { gap: var(--sf-space-l); }\n.sf-gap--xl  { gap: var(--sf-space-xl); }\n.sf-gap--2xl { gap: var(--sf-space-2xl); }\n\n\n/* Box */\n.sf-box {\n  padding: var(--sf-box-padding);\n  outline: var(--sf-box-border-width) solid var(--sf-box-border-color);\n}\n\n\n/* Center */\n.sf-center {\n  box-sizing:      content-box;\n  width:           auto;\n  margin-inline:   auto;\n  max-inline-size: var(--sf-center-max);\n  padding-inline:  var(--sf-center-gutter);\n}\n\n.sf-center--intrinsic {\n  display:        flex;\n  flex-direction: column;\n  align-items:    center;\n}\n\n/* Place-center — the box-neutral centring primitive. Unlike .sf-center (which\n   centres ITSELF as a max-width wrapper) this centres an element's CONTENT on\n   both axes, and unlike the flow primitives' --center modifiers it imposes no\n   row/column/wrap semantics: a plain element becomes a centring box. It is\n   the framework's named form of the community `display:grid; place-items:\n   center` idiom (cf. Tailwind's place-items-center). Give the box a size\n   (min-block-size / height) for the block-axis centring to have room. */\n.sf-place-center {\n  display:     grid;\n  place-items: center;\n}\n\n\n/* Cluster */\n.sf-cluster {\n  display:         flex;\n  flex-wrap:       wrap;\n  gap:             var(--sf-cluster-gap);\n  align-items:     var(--sf-cluster-align);\n  justify-content: var(--sf-cluster-justify);\n}\n.sf-cluster--xs      { gap: var(--sf-space-xs); }\n.sf-cluster--s       { gap: var(--sf-space-s); }\n.sf-cluster--m       { gap: var(--sf-space-m); }\n.sf-cluster--l       { gap: var(--sf-space-l); }\n.sf-cluster--xl      { gap: var(--sf-space-xl); }\n.sf-cluster--2xl     { gap: var(--sf-space-2xl); }\n\n.sf-cluster--no-wrap  { flex-wrap: nowrap; }\n.sf-cluster--center   { justify-content: center; }\n.sf-cluster--end      { justify-content: flex-end; }\n.sf-cluster--between  { justify-content: space-between; }\n\n\n/* Sidebar */\n.sf-sidebar {\n  display:   flex;\n  flex-wrap: wrap;\n  gap:       var(--sf-sidebar-gap);\n}\n\n.sf-sidebar > :first-child {\n  flex-basis: var(--sf-sidebar-width);\n  flex-grow:  1;\n}\n\n.sf-sidebar > :last-child {\n  flex-basis:      0;\n  flex-grow:       999;\n  min-inline-size: var(--sf-sidebar-min-width);\n}\n\n.sf-sidebar--right > :first-child {\n  flex-basis:      0;\n  flex-grow:       999;\n  min-inline-size: var(--sf-sidebar-min-width);\n}\n\n.sf-sidebar--right > :last-child {\n  flex-basis: var(--sf-sidebar-width);\n  flex-grow:  1;\n}\n\n.sf-sidebar--narrow { --sf-sidebar-width: 12rem; }\n.sf-sidebar--wide   { --sf-sidebar-width: 26rem; }\n\n\n/* Switcher */\n.sf-switcher {\n  display:   flex;\n  flex-wrap: wrap;\n  gap:       var(--sf-switcher-gap);\n}\n\n.sf-switcher > * {\n  flex-grow:  1;\n  flex-basis: calc((var(--sf-switcher-threshold) - 100%) * 999);\n}\n\n.sf-switcher--no-wrap  { flex-wrap: nowrap; overflow-x: auto; overflow-inline: auto; }\n.sf-switcher--vertical { flex-direction: column; }\n\n\n/* Grid & icon */\n.sf-grid {\n  display:               grid;\n  grid-template-columns: repeat(auto-fill, minmax(min(var(--sf-grid-min), 100%), 1fr));\n  gap:                   var(--sf-grid-gap);\n}\n\n.sf-grid--fit {\n  grid-template-columns: repeat(auto-fit, minmax(min(var(--sf-grid-min), 100%), 1fr));\n}\n\n.sf-grid--xs { --sf-grid-min: var(--sf-grid-min-xs); }\n.sf-grid--s  { --sf-grid-min: var(--sf-grid-min-s); }\n.sf-grid--m  { --sf-grid-min: var(--sf-grid-min-m); }\n.sf-grid--l  { --sf-grid-min: var(--sf-grid-min-l); }\n.sf-grid--xl { --sf-grid-min: var(--sf-grid-min-xl); }\n.sf-grid--2xl { --sf-grid-min: var(--sf-grid-min-2xl); }\n\n.sf-grid--dense { grid-auto-flow: dense; }\n\n/* Grid-flex — flexbox alternative to .sf-grid for item counts that\n   don't divide evenly: leftover last-row items stretch to fill the\n   row by default, or stay fixed-width and centered with --center.\n   CSS Grid keeps orphans pinned to their track; flex does not. */\n.sf-grid-flex {\n  display:   flex;\n  flex-wrap: wrap;\n  gap:       var(--sf-grid-gap);\n}\n.sf-grid-flex > * {\n  flex: 1 1 min(var(--sf-grid-min), 100%);\n}\n\n.sf-grid-flex--center { justify-content: center; }\n.sf-grid-flex--center > * {\n  flex-grow:  0;\n  flex-basis: min(var(--sf-grid-min), 100%);\n}\n\n.sf-grid-flex--xs  { --sf-grid-min: var(--sf-grid-min-xs); }\n.sf-grid-flex--s   { --sf-grid-min: var(--sf-grid-min-s); }\n.sf-grid-flex--m   { --sf-grid-min: var(--sf-grid-min-m); }\n.sf-grid-flex--l   { --sf-grid-min: var(--sf-grid-min-l); }\n.sf-grid-flex--xl  { --sf-grid-min: var(--sf-grid-min-xl); }\n.sf-grid-flex--2xl { --sf-grid-min: var(--sf-grid-min-2xl); }\n\n.sf-icon {\n  display:        inline-block;\n  inline-size:    var(--sf-icon-size, var(--sf-icon-m));\n  block-size:     var(--sf-icon-size, var(--sf-icon-m));\n  flex-shrink:    0;\n  vertical-align: text-bottom;\n  fill:           currentcolor;\n}\n.sf-icon--xs  { --sf-icon-size: var(--sf-icon-xs); }\n.sf-icon--s   { --sf-icon-size: var(--sf-icon-s); }\n.sf-icon--m   { --sf-icon-size: var(--sf-icon-m); }\n.sf-icon--l   { --sf-icon-size: var(--sf-icon-l); }\n.sf-icon--xl  { --sf-icon-size: var(--sf-icon-xl); }\n.sf-icon--2xl { --sf-icon-size: var(--sf-icon-2xl); }\n\n.sf-icon--boxed {\n  inline-size:    calc(var(--sf-icon-size, var(--sf-icon-m)) + var(--sf-icon-box-pad) * 2);\n  block-size:     calc(var(--sf-icon-size, var(--sf-icon-m)) + var(--sf-icon-box-pad) * 2);\n  padding:        var(--sf-icon-box-pad);\n  border:         var(--sf-icon-box-border);\n  border-radius:  var(--sf-icon-box-radius);\n  background:     var(--sf-icon-box-bg);\n  box-sizing:     border-box;\n}\n\n\n/* Cover */\n.sf-cover {\n  display:        flex;\n  flex-direction: column;\n  min-height:     var(--sf-cover-min-height);\n  padding-block:  var(--sf-cover-padding);\n}\n\n.sf-cover > .sf-cover__center {\n  margin-block: auto;\n}\n\n.sf-cover--min { min-height: 50dvh; }\n\n.sf-cover--max { min-height: 0; max-block-size: 100dvh; }\n.sf-cover--padding-s { padding-block: var(--sf-space-xl); }\n.sf-cover--padding-l { padding-block: var(--sf-space-4xl); }\n\n\n/* Frame */\n.sf-frame {\n  aspect-ratio:    var(--sf-frame-ratio);\n  overflow:        hidden;\n  display:         flex;\n  justify-content: center;\n  align-items:     center;\n}\n\n.sf-frame > img,\n.sf-frame > video {\n  inline-size: 100%;\n  block-size:  100%;\n  object-fit:  cover;\n}\n\n.sf-frame--square   { aspect-ratio: var(--sf-ratio-square); }\n.sf-frame--video    { aspect-ratio: var(--sf-ratio-video); }\n.sf-frame--cinema   { aspect-ratio: var(--sf-ratio-cinema); }\n.sf-frame--portrait { aspect-ratio: var(--sf-ratio-portrait); }\n.sf-frame--4-3      { aspect-ratio: var(--sf-ratio-4-3); }\n.sf-frame--3-2      { aspect-ratio: var(--sf-ratio-3-2); }\n.sf-frame--golden   { aspect-ratio: var(--sf-ratio-golden); }\n\n\n/* Background layer — absolutely-positioned cover media that sits behind a\n   parent's content. The parent is auto-promoted to a positioned, isolated\n   stacking context via :has(), so .sf-bg-layer composes natively under .sf-scrim\n   (background → scrim gradient → content). Works as a bare <img class=\"sf-bg-layer\">\n   or as a wrapper with a nested > img / > video. */\n:where(:has(> .sf-bg-layer)) {\n  position:  relative;\n  isolation: isolate;\n}\n\n.sf-bg-layer {\n  position:        absolute;\n  inset:           var(--sf-bg-layer-inset);\n  inline-size:     calc(100% - 2 * var(--sf-bg-layer-inset));\n  block-size:      calc(100% - 2 * var(--sf-bg-layer-inset));\n  object-fit:      var(--sf-bg-layer-fit);\n  object-position: var(--sf-bg-layer-position);\n  border-radius:   var(--sf-bg-layer-radius);\n  z-index:         var(--sf-bg-layer-z);\n  pointer-events:  none;\n}\n\n.sf-bg-layer > :is(img, video, picture) {\n  inline-size:     100%;\n  block-size:      100%;\n  object-fit:      var(--sf-bg-layer-fit);\n  object-position: var(--sf-bg-layer-position);\n  border-radius:   var(--sf-bg-layer-radius);\n  pointer-events:  none;\n}\n\n.sf-bg-layer > picture > img {\n  inline-size:     100%;\n  block-size:      100%;\n  object-fit:      var(--sf-bg-layer-fit);\n  object-position: var(--sf-bg-layer-position);\n  border-radius:   var(--sf-bg-layer-radius);\n  pointer-events:  none;\n}\n\n\n.sf-reel {\n  display:               flex;\n  block-size:            var(--sf-reel-height);\n  gap:                   var(--sf-reel-gap);\n  overflow-x:                 auto;\n  overflow-inline:            auto;\n  scroll-snap-type:           inline mandatory;\n  scroll-padding-inline:      var(--sf-reel-gap);\n  overscroll-behavior-inline: contain;\n  scrollbar-width:       thin;\n  scrollbar-color:       var(--sf-scrollbar-thumb) var(--sf-scrollbar-track);\n}\n\n.sf-reel::-webkit-scrollbar        { block-size: 6px; }\n.sf-reel::-webkit-scrollbar-track  { background: var(--sf-scrollbar-track); border-radius: var(--sf-radius-full); }\n.sf-reel::-webkit-scrollbar-thumb  { background: var(--sf-scrollbar-thumb); border-radius: var(--sf-radius-full); }\n\n.sf-reel > * {\n  flex:              0 0 var(--sf-reel-item-width);\n  scroll-snap-align: start;\n}\n\n\n/* Physical left (not inset-inline-start): translate() uses the physical axis,\n   so logical + translate breaks centering in RTL layouts. */\n.sf-imposter {\n  position:          absolute;\n  inset-block-start: 50%;\n  left:              50%;\n  translate:         -50% -50%;\n}\n\n.sf-imposter--fixed {\n  position: fixed;\n}\n\n.sf-imposter--contain {\n  max-inline-size: calc(100% - var(--sf-imposter-margin) * 2);\n  max-block-size:  calc(100% - var(--sf-imposter-margin) * 2);\n  overflow:        auto;\n}\n\n\n.sf-alternate {\n  display:   grid;\n  gap:       var(--sf-alternate-gap);\n  container: sf-alternate / inline-size;\n}\n\n.sf-alternate > * {\n  display:     grid;\n  gap:         var(--sf-alternate-inner-gap);\n  align-items: center;\n}\n\n@container sf-alternate (min-width: 48rem) {\n  .sf-alternate > * {\n    grid-template-columns: 1fr 1fr;\n  }\n  .sf-alternate > :nth-child(even) > :first-child { order: 2; }\n  .sf-alternate > :nth-child(even) > :last-child  { order: 1; }\n}\n\n\n.sf-pancake {\n  display:             grid;\n  grid-template-rows:  auto 1fr auto;\n  min-height:          100dvh;\n}\n\n\n.sf-grid-cols-1 {\n  display: grid;\n  gap:     var(--sf-grid-gap);\n}\n\n\n.sf-grid-cols-2, .sf-grid-cols-3, .sf-grid-cols-4, .sf-grid-cols-6 {\n  display: grid;\n  gap:     var(--sf-grid-gap);\n}\n\n@container (min-width: 30rem) {\n  .sf-grid-cols-4 { grid-template-columns: repeat(2, 1fr); }\n  .sf-grid-cols-6 { grid-template-columns: repeat(3, 1fr); }\n}\n\n@container (min-width: 48rem) {\n  .sf-grid-cols-2 { grid-template-columns: repeat(2, 1fr); }\n  .sf-grid-cols-3 { grid-template-columns: repeat(3, 1fr); }\n  .sf-grid-cols-4 { grid-template-columns: repeat(4, 1fr); }\n  .sf-grid-cols-6 { grid-template-columns: repeat(6, 1fr); }\n}\n\n\n.sf-grid-cols-1-2, .sf-grid-cols-2-1,\n.sf-grid-cols-1-3, .sf-grid-cols-3-1 {\n  display: grid;\n  gap:     var(--sf-grid-gap);\n}\n\n@container (min-width: 48rem) {\n  .sf-grid-cols-1-2 { grid-template-columns: 1fr 2fr; }\n  .sf-grid-cols-2-1 { grid-template-columns: 2fr 1fr; }\n  .sf-grid-cols-1-3 { grid-template-columns: 1fr 3fr; }\n  .sf-grid-cols-3-1 { grid-template-columns: 3fr 1fr; }\n}\n\n.sf-equal {\n  column-width: var(--sf-equal-min-col);\n  column-gap:   var(--sf-equal-gap);\n  column-rule:  var(--sf-equal-rule-width) var(--sf-equal-rule-style) var(--sf-equal-rule-color);\n}\n.sf-equal > * { break-inside: avoid; }\n\n.sf-equal--2 { column-count: 2; }\n.sf-equal--3 { column-count: 3; }\n.sf-equal--4 { column-count: 4; }\n.sf-equal--6 { column-count: 6; }\n\n\n.sf-content-grid {\n  display: grid;\n  /* Establish the same NAMED inline-size query container as .sf-container\n     (`sf-layout`), not just an anonymous one. .sf-content-grid is a\n     section-level wrapper that REPLACES .sf-container when you need\n     breakout/full-bleed — but .sf-container carries the CQ scope that\n     .sf-grid-cols-* / .sf-bento rely on, and dropping it silently killed\n     those primitives inside a content grid. Matching the name too means a\n     user's `@container sf-layout (…)` rule keeps matching across the swap, so\n     the two wrappers are genuinely interchangeable (anonymous\n     `@container (…)` queries already matched either — the framework's own\n     primitives use those — but a name-targeted query would not have).\n     Safe re SL-034: .sf-content-grid's own tracks are fixed (they never\n     @container-query themselves), so becoming a query container can't create\n     a self-query. Safe re full-bleed: inline-size containment doesn't change\n     track resolution — the `full` track still reaches the wrapper's edges. */\n  container: sf-layout / inline-size;\n  grid-template-columns:\n    [full-start]\n    minmax(var(--sf-gutter), 1fr)\n    [breakout-start]\n    minmax(0, calc((var(--sf-breakout-width) - var(--sf-content-width)) / 2))\n    [content-start]\n    min(var(--sf-content-width), 100% - var(--sf-gutter) * 2)\n    [content-end]\n    minmax(0, calc((var(--sf-breakout-width) - var(--sf-content-width)) / 2))\n    [breakout-end]\n    minmax(var(--sf-gutter), 1fr)\n    [full-end];\n}\n\n.sf-content-grid > *              { grid-column: content; }\n.sf-content-grid > .sf-breakout   { grid-column: breakout; }\n.sf-content-grid > .sf-full-bleed { grid-column: full; }\n\n.sf-bento {\n  display:               grid;\n  grid-template-columns: repeat(var(--sf-bento-cols, var(--sf-bento-cols-default)), 1fr);\n  grid-auto-rows:        minmax(var(--sf-bento-row, var(--sf-bento-row-default)), auto);\n  grid-auto-flow:        dense;\n  gap:                   var(--sf-bento-gap);\n}\n\n@container (max-width: 29.99rem) {\n  .sf-bento { grid-template-columns: 1fr; }\n}\n\n@container (min-width: 30rem) and (max-width: 47.99rem) {\n  .sf-bento { grid-template-columns: repeat(2, 1fr); }\n}\n\n/* Container column modifiers */\n.sf-bento--2       { --sf-bento-cols: 2; }\n.sf-bento--3       { --sf-bento-cols: 3; }\n.sf-bento--6       { --sf-bento-cols: 6; }\n\n/* Container row height modifiers — named after the --sf-bento-row-* token\n   they set, not just \"tall\"/\"compact\", so they can't be mistaken for the\n   child span modifier below. */\n.sf-bento--row-compact { --sf-bento-row: var(--sf-bento-row-compact); }\n.sf-bento--row-tall    { --sf-bento-row: var(--sf-bento-row-tall); }\n\n/* Child span modifiers — go on an item inside .sf-bento, never on\n   .sf-bento itself. .sf-bento-tall (this item spans 2 rows) is not an\n   alias of .sf-bento--row-tall above (every row in the grid is taller). */\n.sf-bento-wide     { grid-column: span 2; }\n.sf-bento-full     { grid-column: 1 / -1; }\n.sf-bento-tall     { grid-row:    span 2; }\n.sf-bento-featured { grid-column: span 2; grid-row: span 2; }\n\n/* A spanning child can't request more columns than the 1-column mobile\n   grid has, or CSS Grid adds an implicit column to satisfy the span,\n   breaking the single-column layout the query above exists to guarantee.\n   Placed after the modifiers above (equal specificity) so it wins on\n   source order regardless of query-match state. */\n@container (max-width: 29.99rem) {\n  .sf-bento-wide, .sf-bento-featured { grid-column: span 1; }\n}\n\n\n.sf-subgrid      { display: grid; grid-template-columns: subgrid; }\n.sf-subgrid-rows { display: grid; grid-template-rows:    subgrid; }\n\n/* ─── core/macros.css ─── */\n/* SLASHED — core/macros.css\n   @layer slashed.macros\n   Reusable recipes: prose, surface, flow, cards, media, hero, scrims, clamps.\n   Prefix: .sf-*; values resolve through macro tokens. */\n\n\n\n.sf-prose {\n  max-width:     var(--sf-container-prose);\n  overflow-wrap: break-word;\n}\n\n.sf-prose > * + *              { margin-block-start: var(--sf-prose-paragraph); }\n.sf-prose :is(h2, h3, h4, h5, h6) + * { margin-block-start: var(--sf-prose-heading-gap); }\n.sf-prose li + li              { margin-block-start: var(--sf-prose-list-gap); }\n.sf-prose :is(blockquote, pre) { margin-block: var(--sf-prose-block-margin); }\n.sf-prose blockquote           { font-style: italic; padding-inline-start: var(--sf-prose-blockquote-padding); border-inline-start: var(--sf-prose-blockquote-border); }\n.sf-prose img                  { margin-block: var(--sf-prose-media-margin); border-radius: var(--sf-prose-media-radius); }\n.sf-prose :is(ul, ol)          { padding-inline-start: 1.25em; }\n.sf-prose > :is(ul, ol)        { margin-block-end: 0; }\n.sf-prose :is(ul, ol) :is(ul, ol) { margin-block-start: var(--sf-prose-nested-list-gap); }\n.sf-prose ul                   { list-style: disc; }\n.sf-prose ol                   { list-style: decimal; }\n.sf-prose ::marker             { color: var(--sf-prose-marker-color); }\n.sf-prose hr                   { margin-block: var(--sf-prose-hr-margin); }\n.sf-prose figure               { margin-block: var(--sf-prose-figure-margin); }\n.sf-prose figcaption           { font-size: var(--sf-prose-figcaption-size); color: var(--sf-color-text--muted); margin-block-start: var(--sf-prose-list-gap); }\n.sf-prose table                { margin-block: var(--sf-prose-block-margin); display: block; overflow-x: auto; overflow-inline: auto; inline-size: 100%; max-inline-size: 100%; }\n.sf-prose :is(th, td)          { padding: var(--sf-prose-table-pad); }\n.sf-prose video                { margin-block: var(--sf-prose-media-margin); border-radius: var(--sf-prose-media-radius); }\n\n/* Specificity 0-2-1 intentionally beats .sf-prose's 0-2-0 child selectors —\n   documented exception. */\n.sf-prose .sf-not-prose > * + *    { margin-block-start: 0; }\n.sf-prose .sf-not-prose li + li    { margin-block-start: 0; }\n\n.sf-prose .sf-not-prose :is(ul,ol) { list-style: revert; padding-inline-start: revert; }\n.sf-prose .sf-not-prose ::marker   { color: inherit; }\n.sf-prose .sf-not-prose blockquote {\n  margin-block: 0;\n  padding-inline-start: 0;\n  border-inline-start: 0;\n  font-style: normal;\n}\n.sf-prose .sf-not-prose hr         { margin-block: 0; }\n.sf-prose .sf-not-prose img        { margin-block: 0; border-radius: 0; }\n.sf-prose .sf-not-prose figure     { margin-block: 0; }\n.sf-prose .sf-not-prose figcaption { font-size: inherit; color: inherit; margin-block-start: 0; }\n.sf-prose .sf-not-prose table      { margin-block: 0; display: revert; overflow-x: revert; overflow-inline: revert; inline-size: revert; max-inline-size: revert; }\n.sf-prose .sf-not-prose :is(th,td) { padding: revert; }\n.sf-prose .sf-not-prose video      { margin-block: 0; border-radius: 0; }\n\n.sf-flow > * + * {\n  margin-block-start: var(--sf-flow-space);\n}\n\n.sf-truncate {\n  overflow:      hidden;\n  text-overflow: ellipsis;\n  white-space:   nowrap;\n}\n\n.sf-line-clamp-2,\n.sf-line-clamp-3,\n.sf-line-clamp-N {\n  display:            -webkit-box;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- de-facto standard; unprefixed CSS Overflow 4 line-clamp not yet shipped */\n  -webkit-box-orient: vertical;\n  overflow:           hidden;\n}\n\n/* stylelint-disable-next-line property-no-vendor-prefix -- see above */\n.sf-line-clamp-2 { -webkit-line-clamp: 2; }\n/* stylelint-disable-next-line property-no-vendor-prefix -- see above */\n.sf-line-clamp-3 { -webkit-line-clamp: 3; }\n.sf-line-clamp-N {\n  /* stylelint-disable-next-line property-no-vendor-prefix -- see above */\n  -webkit-line-clamp: var(--sf-line-clamp);\n}\n\n.sf-equal-height {\n  display:     flex;\n  align-items: stretch;\n}\n.sf-equal-height > * {\n  block-size: auto;\n  flex:       1 1 auto;\n}\n\n.sf-aspect {\n  aspect-ratio: var(--sf-aspect, 16 / 9);\n}\n\n.sf-scroll-shadow {\n  overflow-y:     auto;\n  overflow-block: auto;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- required for Safari < 15.4 */\n  -webkit-mask-image:\n    linear-gradient(to bottom,\n      transparent 0,\n      black var(--sf-scroll-shadow-size),\n      black calc(100% - var(--sf-scroll-shadow-size)),\n      transparent 100%);\n  mask-image:\n    linear-gradient(to bottom,\n      transparent 0,\n      black var(--sf-scroll-shadow-size),\n      black calc(100% - var(--sf-scroll-shadow-size)),\n      transparent 100%);\n}\n\n.sf-scroll-snap {\n  overflow-y:                auto;\n  overflow-block:            auto;\n  scroll-snap-type:          block mandatory;\n  overscroll-behavior-block: contain;\n}\n.sf-scroll-snap > * {\n  scroll-snap-align: start;\n}\n\n.sf-overflow-fade {\n  overflow: hidden;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- required for Safari < 15.4 */\n  -webkit-mask-image: linear-gradient(\n    to right,\n    black 0,\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n  mask-image: linear-gradient(\n    to right,\n    black 0,\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n}\n\n.sf-overflow-fade--right {\n  overflow: hidden;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- required for Safari < 15.4 */\n  -webkit-mask-image: linear-gradient(\n    to right,\n    black 0,\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n  mask-image: linear-gradient(\n    to right,\n    black 0,\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n}\n\n.sf-overflow-fade--left {\n  overflow: hidden;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- required for Safari < 15.4 */\n  -webkit-mask-image: linear-gradient(\n    to right,\n    transparent 0,\n    black var(--sf-mask-scrim-start),\n    black 100%\n  );\n  mask-image: linear-gradient(\n    to right,\n    transparent 0,\n    black var(--sf-mask-scrim-start),\n    black 100%\n  );\n}\n\n.sf-overflow-fade--top {\n  overflow: hidden;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- required for Safari < 15.4 */\n  -webkit-mask-image: linear-gradient(\n    to bottom,\n    transparent 0,\n    black var(--sf-mask-scrim-start),\n    black 100%\n  );\n  mask-image: linear-gradient(\n    to bottom,\n    transparent 0,\n    black var(--sf-mask-scrim-start),\n    black 100%\n  );\n}\n\n.sf-overflow-fade--bottom {\n  overflow: hidden;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- required for Safari < 15.4 */\n  -webkit-mask-image: linear-gradient(\n    to bottom,\n    black 0,\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n  mask-image: linear-gradient(\n    to bottom,\n    black 0,\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n}\n\n.sf-overflow-fade--block {\n  overflow: hidden;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- required for Safari < 15.4 */\n  -webkit-mask-image: linear-gradient(\n    to bottom,\n    transparent 0,\n    black var(--sf-mask-scrim-start),\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n  mask-image: linear-gradient(\n    to bottom,\n    transparent 0,\n    black var(--sf-mask-scrim-start),\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n}\n\n.sf-overflow-fade--inline {\n  overflow: hidden;\n  /* stylelint-disable-next-line property-no-vendor-prefix -- required for Safari < 15.4 */\n  -webkit-mask-image: linear-gradient(\n    to right,\n    transparent 0,\n    black var(--sf-mask-scrim-start),\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n  mask-image: linear-gradient(\n    to right,\n    transparent 0,\n    black var(--sf-mask-scrim-start),\n    black calc(100% - var(--sf-mask-scrim-end)),\n    transparent 100%\n  );\n}\n\n.sf-no-tap-highlight {\n  /* stylelint-disable-next-line property-no-vendor-prefix -- no unprefixed equivalent */\n  -webkit-tap-highlight-color: transparent;\n}\n\n.sf-surface { background: var(--sf-surface-color); }\n\n.sf-surface--primary   { --sf-surface-color: var(--sf-color-primary);   background: var(--sf-color-primary);   color: var(--sf-color-text--on-primary); }\n.sf-surface--secondary { --sf-surface-color: var(--sf-color-secondary); background: var(--sf-color-secondary); color: var(--sf-color-text--on-secondary); }\n.sf-surface--tertiary  { --sf-surface-color: var(--sf-color-tertiary);  background: var(--sf-color-tertiary);  color: var(--sf-color-text--on-tertiary); }\n.sf-surface--action    { --sf-surface-color: var(--sf-color-action);    background: var(--sf-color-action);    color: var(--sf-color-text--on-action); }\n.sf-surface--neutral   { --sf-surface-color: var(--sf-color-neutral);   background: var(--sf-color-neutral);   color: var(--sf-color-text--on-neutral); }\n.sf-surface--inverse   { --sf-surface-color: var(--sf-color-inverse);   background: var(--sf-color-inverse);   color: var(--sf-color-text--on-inverse); }\n.sf-surface--success   { --sf-surface-color: var(--sf-color-success);   background: var(--sf-color-success);   color: var(--sf-color-text--on-success); }\n.sf-surface--warning   { --sf-surface-color: var(--sf-color-warning);   background: var(--sf-color-warning);   color: var(--sf-color-text--on-warning); }\n.sf-surface--info      { --sf-surface-color: var(--sf-color-info);      background: var(--sf-color-info);      color: var(--sf-color-text--on-info); }\n.sf-surface--danger    { --sf-surface-color: var(--sf-color-danger);    background: var(--sf-color-danger);    color: var(--sf-color-text--on-danger); }\n\n@supports (color: oklch(from red l c h)) and (width: calc(1px * sign(1))) {\n  :is(.sf-surface,\n      .sf-surface--primary, .sf-surface--secondary, .sf-surface--tertiary,\n      .sf-surface--action, .sf-surface--neutral, .sf-surface--inverse,\n      .sf-surface--success, .sf-surface--warning,\n      .sf-surface--info, .sf-surface--danger) {\n\n    --sf-surface-contrast: oklch(from var(--sf-surface-color) clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0 / 1);\n    background: var(--sf-surface-color);\n    color: var(--sf-surface-contrast);\n    --sf-color-text:              var(--sf-surface-contrast);\n    --sf-color-heading:           var(--sf-surface-contrast);\n    --sf-color-link:              oklch(from var(--sf-surface-contrast) l calc(c + 0.08) h);\n    --sf-color-link--hover:       var(--sf-surface-contrast);\n    --sf-color-link--underline:   oklch(from var(--sf-surface-contrast) l c h / 0.5);\n    --sf-color-text--subtle:   oklch(from var(--sf-surface-contrast) l c h / 0.70);\n    --sf-color-text--placeholder: oklch(from var(--sf-surface-contrast) l c h / 0.45);\n    --sf-color-text--disabled:    oklch(from var(--sf-surface-contrast) l c h / 0.30);\n    --sf-color-border:            oklch(from var(--sf-surface-contrast) l c h / 0.20);\n    --sf-color-border--subtle:    oklch(from var(--sf-surface-contrast) l c h / 0.12);\n    --sf-color-border--strong:    oklch(from var(--sf-surface-contrast) l c h / 0.35);\n    --sf-focus-ring-color:        var(--sf-surface-contrast);\n    --sf-caret-color:             var(--sf-surface-contrast);\n\n    --sf-shadow-color:            oklch(from var(--sf-surface-color) var(--sf-shadow-lightness) c h);\n\n    /* :root-only alias-overrides seal their value at the DECLARING element\n       (var() resolves on :root), so a heading/body that reads the alias\n       reads the frozen page value and ignores this surface's re-declared\n       semantic token above — leaving headings dark on a dark surface.\n       Re-declare the aliases here so they re-resolve against THIS surface's\n       adapted --sf-color-heading / --sf-color-text. Same class of bug as the\n       [data-theme] block in themes.css (#496), extended to heading/body. */\n    --sf-heading-color:           var(--sf-color-heading);\n    --sf-body-color:              var(--sf-color-text);\n\n    /* INTERNAL flag (inherits): signals \"inside an auto-contrast surface\" so a\n       nested .sf-card can restore surface-appropriate foreground for its own\n       (non-adapting) background via a style query — see .sf-card in\n       optional/components.css (#496). Not a public hook; read, don't set. */\n    --sf-surface-active:          1;\n  }\n}\n.sf-scrim {\n  position:  relative;\n  isolation: isolate;\n}\n.sf-scrim::before {\n  content:        \"\";\n  position:       absolute;\n  inset:          0;\n  z-index:        0;\n  background:     var(--sf-scrim-gradient);\n  pointer-events: none;\n}\n\n.sf-scrim > :not(img, picture, video, svg, canvas),\n.sf-scrim__content {\n  position: relative;\n  z-index:  1;\n}\n.sf-scrim--top    { --sf-scrim-direction: to bottom; }\n.sf-scrim--bottom { --sf-scrim-direction: to top; }\n.sf-scrim--full   { --sf-scrim-gradient: var(--sf-scrim-color); }\n\n/* Named background surface preset (issue #523). Composes the\n   --sf-surface-bg-* token set (see tokens.macros.css) into one reusable,\n   named background: base colour + image/gradient/pattern, sizing, an\n   optional overlay layered above the image, and an optional animation.\n   Inert until a preset feeds the tokens. The overlay is the first\n   background-image layer so it paints ABOVE the image. */\n.sf-surface-bg {\n  background-color:      var(--sf-surface-bg-color);\n  background-image:      var(--sf-surface-bg-overlay), var(--sf-surface-bg-image);\n  background-size:       var(--sf-surface-bg-size);\n  background-position:   var(--sf-surface-bg-position);\n  background-repeat:     var(--sf-surface-bg-repeat);\n  background-attachment: var(--sf-surface-bg-attachment);\n  animation:             var(--sf-surface-bg-animation);\n}\n\n.sf-text-protect {\n  text-shadow: var(--sf-scrim-text-shadow);\n}\n\n.sf-text-gradient {\n  background-image: var(--sf-gradient-primary);\n  background-clip: text;\n  color: transparent;\n}\n\n.sf-link-external::after {\n  content:         var(--sf-link-external-marker);\n  display:         inline-block;\n  font-size:       0.85em;\n  text-decoration: none;\n}\n/* Alt-text form (accessible name for the glyph) — gated so a UA that\n   rejects the \"value / string\" grammar keeps the plain marker above\n   instead of dropping the whole declaration. */\n@supports (content: \"x\" / \"y\") {\n  .sf-link-external::after {\n    content: var(--sf-link-external-marker) / var(--sf-link-external-label);\n  }\n}\n\n.sf-content-auto {\n  content-visibility:     auto;\n  contain-intrinsic-size: auto var(--sf-content-intrinsic-size, 500px);\n}\n\n.sf-tabular-nums {\n  font-variant-numeric: var(--sf-font-numeric, tabular-nums);\n}\n\n/* filter: drop-shadow() utilities — unlike box-shadow, follows the element's\n   actual alpha shape (SVG icons, PNG cutouts, transparent logos). */\n.sf-drop-shadow-xs { filter: var(--sf-drop-shadow-xs); }\n.sf-drop-shadow-s  { filter: var(--sf-drop-shadow-s); }\n.sf-drop-shadow-m  { filter: var(--sf-drop-shadow-m); }\n.sf-drop-shadow-l  { filter: var(--sf-drop-shadow-l); }\n.sf-drop-shadow-xl { filter: var(--sf-drop-shadow-xl); }\n\n.sf-link--subtle:link,\n.sf-link--subtle:visited {\n  text-decoration-line: none;\n}\n.sf-link--subtle:is(:link, :visited):hover,\n.sf-link--subtle:is(:link, :visited):focus-visible {\n  text-decoration-line:  underline;\n  text-decoration-color: currentcolor;\n}\n\n.sf-link--reverse:link,\n.sf-link--reverse:visited {\n  text-decoration-line: underline;\n}\n.sf-link--reverse:is(:link, :visited):hover,\n.sf-link--reverse:is(:link, :visited):focus-visible {\n  text-decoration-line: none;\n}\n\n/* Overlap recipe — one element intentionally overlapping the previous\n   one (e.g. an image pulled up over the card below it), via a negative\n   logical margin + a raised stacking context. Directional variants are\n   standalone (margins are distinct properties, not a re-pointable knob). */\n.sf-overlap,\n.sf-overlap--down {\n  position: relative;\n  z-index:  var(--sf-z-raised);\n}\n.sf-overlap        { margin-block-start:  calc(-1 * var(--sf-overlap-pull)); }\n.sf-overlap--down  { margin-block-end:    calc(-1 * var(--sf-overlap-pull)); }\n\n/* Card-container recipe — the receiving side of an overlap: an isolated\n   stacking context with block-start padding compensation so in-flow\n   content clears an element intruding from above. The padding knob\n   defaults to the pull knob so one override tunes both. */\n.sf-overlap-host {\n  position:  relative;\n  isolation: isolate;\n  /* var() fallback resolved on this element, not pre-baked at :root —\n     so a local --sf-overlap-pull override (even without setting\n     --sf-overlap-host-pad) is honored (#496-class pitfall). */\n  padding-block-start: var(--sf-overlap-host-pad, var(--sf-overlap-pull));\n}\n\n/* ─── optional/utilities.css ─── */\n/* SLASHED — optional/utilities.css\n   @layer slashed.utilities\n   Static opt-in utility helpers.\n   Prefix: .sf-*; keep dynamic state in .sf-is-* classes.\n\n   Most definitions below are STAGED (commented out) — SLASHED is BEM-first\n   by design and ships only a curated subset of utility classes; uncomment\n   a block to activate it. The visibility, heading, text-size,\n   hover-transform, list-reset, marker-colour, alternate-selection, and\n   sticky blocks are active. */\n\n\n/* Text wrap — per-element override of the global text-wrap defaults\n   (--sf-heading-text-wrap / --sf-body-text-wrap). */\n/* .sf-balance { text-wrap: balance; } */\n/* .sf-pretty  { text-wrap: pretty; } */\n\n/* Object fit / position — per-element control of replaced media (img,\n   video) without touching the global --sf-object-* tokens. */\n/* .sf-object-cover   { object-fit: cover; } */\n/* .sf-object-contain { object-fit: contain; } */\n\n/* .sf-object-top    { object-position: top; } */\n/* .sf-object-center { object-position: center; } */\n/* .sf-object-bottom { object-position: bottom; } */\n\n/* ============================================================\n * VISIBILITY HELPERS (.sf-invisible / .sf-visible)\n * Single-property visibility overrides — not a \"state\" (core/states.css)\n * since neither reacts to anything on its own; toggle from JS to hide\n * something without pulling it out of layout (.sf-invisible), or to\n * force-show an element that inherited visibility:hidden from a parent\n * (.sf-visible). This is the hook docs/roadmap.md's \"reveal on scroll\"\n * pattern targets — pair with an IntersectionObserver in your own code.\n * ============================================================ */\n.sf-invisible { visibility: hidden; }\n.sf-visible   { visibility: visible; }\n\n/* ============================================================\n * HEADING HELPER CLASSES (.sf-h1 – .sf-h6)\n * Heading-level typography on any element without changing\n * document semantics. Carries the typographic scale from the\n * h1–h6 rules in core/base.css, including overflow-wrap; margins\n * are intentionally NOT reset here (a visual class shouldn't clear\n * the caller's spacing the way the base element reset does).\n *   <div class=\"sf-h2\">Visually H2, semantically a div</div>\n * ============================================================ */\n.sf-h1,\n.sf-h2,\n.sf-h3,\n.sf-h4,\n.sf-h5,\n.sf-h6 {\n  font-family:   var(--sf-heading-font-family, var(--sf-font-heading));\n  font-weight:   var(--sf-font-weight-heading);\n  color:         var(--sf-heading-color, var(--sf-color-heading));\n  text-wrap:     var(--sf-heading-text-wrap);\n  overflow-wrap: break-word;\n}\n.sf-h1 { font-size: var(--sf-h1-size); line-height: var(--sf-h1-line-height); font-weight: var(--sf-h1-font-weight); letter-spacing: var(--sf-h1-letter-spacing); max-inline-size: var(--sf-h1-max-width); }\n.sf-h2 { font-size: var(--sf-h2-size); line-height: var(--sf-h2-line-height); font-weight: var(--sf-h2-font-weight); letter-spacing: var(--sf-h2-letter-spacing); max-inline-size: var(--sf-h2-max-width); }\n.sf-h3 { font-size: var(--sf-h3-size); line-height: var(--sf-h3-line-height); font-weight: var(--sf-h3-font-weight); letter-spacing: var(--sf-h3-letter-spacing); max-inline-size: var(--sf-h3-max-width); }\n.sf-h4 { font-size: var(--sf-h4-size); line-height: var(--sf-h4-line-height); font-weight: var(--sf-h4-font-weight); letter-spacing: var(--sf-h4-letter-spacing); max-inline-size: var(--sf-h4-max-width); }\n.sf-h5 { font-size: var(--sf-h5-size); line-height: var(--sf-h5-line-height); font-weight: var(--sf-h5-font-weight); letter-spacing: var(--sf-h5-letter-spacing); max-inline-size: var(--sf-h5-max-width); }\n.sf-h6 { font-size: var(--sf-h6-size); line-height: var(--sf-h6-line-height); font-weight: var(--sf-h6-font-weight); letter-spacing: var(--sf-h6-letter-spacing); max-inline-size: var(--sf-h6-max-width); }\n\n/* ============================================================\n * TEXT-SIZE UTILITIES (.sf-text-2xs – .sf-text-4xl)\n * Apply a full fluid text-size role — size, line-height, weight,\n * tracking, and measure (max-inline-size) — to any element in one\n * class, mirroring the per-size token sets in core/tokens.css.\n *   <p class=\"sf-text-l\">Larger body copy</p>\n * ============================================================ */\n.sf-text-2xs { font-size: var(--sf-text-2xs); line-height: var(--sf-text-2xs-line-height); font-weight: var(--sf-text-2xs-font-weight); letter-spacing: var(--sf-text-2xs-letter-spacing); max-inline-size: var(--sf-text-2xs-max-width); }\n.sf-text-xs  { font-size: var(--sf-text-xs);  line-height: var(--sf-text-xs-line-height);  font-weight: var(--sf-text-xs-font-weight);  letter-spacing: var(--sf-text-xs-letter-spacing);  max-inline-size: var(--sf-text-xs-max-width); }\n.sf-text-s   { font-size: var(--sf-text-s);   line-height: var(--sf-text-s-line-height);   font-weight: var(--sf-text-s-font-weight);   letter-spacing: var(--sf-text-s-letter-spacing);   max-inline-size: var(--sf-text-s-max-width); }\n.sf-text-m   { font-size: var(--sf-text-m);   line-height: var(--sf-text-m-line-height);   font-weight: var(--sf-text-m-font-weight);   letter-spacing: var(--sf-text-m-letter-spacing);   max-inline-size: var(--sf-text-m-max-width); }\n.sf-text-l   { font-size: var(--sf-text-l);   line-height: var(--sf-text-l-line-height);   font-weight: var(--sf-text-l-font-weight);   letter-spacing: var(--sf-text-l-letter-spacing);   max-inline-size: var(--sf-text-l-max-width); }\n.sf-text-xl  { font-size: var(--sf-text-xl);  line-height: var(--sf-text-xl-line-height);  font-weight: var(--sf-text-xl-font-weight);  letter-spacing: var(--sf-text-xl-letter-spacing);  max-inline-size: var(--sf-text-xl-max-width); }\n.sf-text-2xl { font-size: var(--sf-text-2xl); line-height: var(--sf-text-2xl-line-height); font-weight: var(--sf-text-2xl-font-weight); letter-spacing: var(--sf-text-2xl-letter-spacing); max-inline-size: var(--sf-text-2xl-max-width); }\n.sf-text-3xl { font-size: var(--sf-text-3xl); line-height: var(--sf-text-3xl-line-height); font-weight: var(--sf-text-3xl-font-weight); letter-spacing: var(--sf-text-3xl-letter-spacing); max-inline-size: var(--sf-text-3xl-max-width); }\n.sf-text-4xl { font-size: var(--sf-text-4xl); line-height: var(--sf-text-4xl-line-height); font-weight: var(--sf-text-4xl-font-weight); letter-spacing: var(--sf-text-4xl-letter-spacing); max-inline-size: var(--sf-text-4xl-max-width); }\n\n/* ============================================================\n * Z-INDEX UTILITIES (.sf-z-*)\n * Named z-index scale from core/tokens.css. Requires a\n * positioning context (position: relative / absolute / fixed /\n * sticky) to have any effect.\n * ============================================================ */\n/* .sf-z-below    { z-index: var(--sf-z-below); }\n.sf-z-base      { z-index: var(--sf-z-base); }\n.sf-z-raised    { z-index: var(--sf-z-raised); }\n.sf-z-sticky    { z-index: var(--sf-z-sticky); }\n.sf-z-fixed     { z-index: var(--sf-z-fixed); }\n.sf-z-dropdown  { z-index: var(--sf-z-dropdown); }\n.sf-z-overlay   { z-index: var(--sf-z-overlay); }\n.sf-z-modal     { z-index: var(--sf-z-modal); }\n.sf-z-toast     { z-index: var(--sf-z-toast); }\n.sf-z-tooltip   { z-index: var(--sf-z-tooltip); } */\n\n/* ============================================================\n * DECORATIVE ANIMATION UTILITIES (.sf-spin / .sf-ping / etc.)\n * Backed by keyframes in core/motion.css; animation shorthand\n * tokens live in core/tokens.css. Wrapped in reduced-motion\n * media query — elements are invisible/static otherwise.\n *\n * .sf-shimmer: override --sf-shimmer-base and\n * --sf-shimmer-highlight to match your surface if needed.\n * ============================================================ */\n/* @media (prefers-reduced-motion: no-preference) {\n  .sf-spin  { animation: var(--sf-animation-spin); }\n  .sf-ping  { animation: var(--sf-animation-ping); }\n  .sf-blink { animation: var(--sf-animation-blink); }\n  .sf-float { animation: var(--sf-animation-float); }\n  .sf-shimmer {\n    --sf-shimmer-base:      var(--sf-color-inset);\n    --sf-shimmer-highlight: var(--sf-color-raised);\n    background: linear-gradient(\n      90deg,\n      var(--sf-shimmer-base)      0%,\n      var(--sf-shimmer-highlight) 50%,\n      var(--sf-shimmer-base)      100%\n    );\n    background-size: 200% 100%;\n    animation: var(--sf-animation-shimmer);\n  }\n} */\n\n/* ============================================================\n * HOVER-TRANSFORM UTILITIES (.sf-hover-*)\n * Simple, composable hover-triggered transforms — apply directly to\n * any element (card, image, icon, button). Duration/easing reuse the\n * same tokens as --sf-transition-transform (core/tokens.css), but the\n * transition-property targets scale/translate directly: these rules\n * change the `scale` and `translate` properties (CSS Transforms\n * Level 2), which a `transition: transform ...` shorthand does not\n * cover — transform is a distinct property from its scale/translate/\n * rotate components and won't pick up their changes. The global\n * duration kill-switch in core/accessibility.css neutralizes these\n * under prefers-reduced-motion without needing a separate guard here.\n * On a/button/input/select/textarea/summary, core/motion.css's global\n * transition (slashed.motion, layered after slashed.utilities) also\n * covers scale/translate, so --sf-duration-fast wins there instead of\n * --sf-duration-normal — the class selector's higher specificity still\n * keeps these rules in control of *which* properties transition.\n * ============================================================ */\n.sf-hover-grow, .sf-hover-shrink, .sf-hover-float, .sf-hover-sink,\n.sf-hover-slide-start, .sf-hover-slide-end {\n  transition-property:        scale, translate;\n  transition-duration:        var(--sf-duration-normal);\n  transition-timing-function: var(--sf-ease-out);\n}\n.sf-hover-grow:hover    { scale: var(--sf-hover-grow-scale, 1.05); }\n.sf-hover-shrink:hover  { scale: var(--sf-hover-shrink-scale, 0.95); }\n.sf-hover-float:hover   { translate: 0 calc(-1 * var(--sf-hover-lift, 0.25em)); }\n.sf-hover-sink:hover    { translate: 0 var(--sf-hover-lift, 0.25em); }\n.sf-hover-slide-start:hover { translate: calc(-1 * var(--sf-hover-slide, 0.5em)) 0; }\n.sf-hover-slide-end:hover   { translate: var(--sf-hover-slide, 0.5em) 0; }\n/* translate is physical (X axis), but the -start/-end names are logical —\n   flip the horizontal direction under RTL so \"start\"/\"end\" stay correct. */\n:where([dir=\"rtl\"]) .sf-hover-slide-start:hover { translate: var(--sf-hover-slide, 0.5em) 0; }\n:where([dir=\"rtl\"]) .sf-hover-slide-end:hover   { translate: calc(-1 * var(--sf-hover-slide, 0.5em)) 0; }\n\n/* ============================================================\n * LIST RESET (.sf-list-none)\n * Drops marker + inline start-padding in one class, on any\n * <ul>/<ol> (or element with list-style applied).\n * ============================================================ */\n.sf-list-none {\n  list-style: none;\n  padding-inline-start: 0;\n}\n\n/* ============================================================\n * LIST MARKER COLOUR (.sf-marker--*)\n * Colour the ::marker of an arbitrary list. Brand/action families\n * only — for any other colour set `::marker { color }` yourself.\n * The :not(.sf-prose *) guard keeps this utility from reaching into\n * a .sf-prose subtree, which owns its markers via\n * --sf-prose-marker-color (utilities are layered after macros, so\n * without the guard this would win). Covers the element's own marker\n * and descendant list-item markers.\n * ============================================================ */\n.sf-marker--primary :not(.sf-prose *)::marker, .sf-marker--primary:not(.sf-prose *)::marker { color: var(--sf-color-primary); }\n.sf-marker--secondary :not(.sf-prose *)::marker, .sf-marker--secondary:not(.sf-prose *)::marker { color: var(--sf-color-secondary); }\n.sf-marker--tertiary :not(.sf-prose *)::marker, .sf-marker--tertiary:not(.sf-prose *)::marker { color: var(--sf-color-tertiary); }\n.sf-marker--action :not(.sf-prose *)::marker, .sf-marker--action:not(.sf-prose *)::marker { color: var(--sf-color-action); }\n\n/* ============================================================\n * ALTERNATE SELECTION COLOUR (.sf-selection--alt)\n * Overrides the ::selection custom properties (core/base.css) on\n * the element and its descendants, for surfaces where the default\n * selection colours land with poor contrast (e.g. a dark card on a\n * light page). Backed by --sf-color-selection-*--alt (core/tokens.css).\n * ============================================================ */\n.sf-selection--alt {\n  --sf-color-selection-bg:   var(--sf-color-selection-bg--alt);\n  --sf-color-selection-text: var(--sf-color-selection-text--alt);\n}\n\n/* ============================================================\n * STICKY POSITIONING (.sf-sticky)\n * The sticky mechanism — position: sticky at the header-aware\n * --sf-sticky-offset. Offset modifiers (--s/-m/-l) add extra gap\n * on top of that fluid offset. (position: sticky is already\n * conditional by nature, so there is no separate runtime-toggled\n * state class.)\n * ============================================================ */\n.sf-sticky {\n  position: sticky;\n  inset-block-start: var(--sf-sticky-offset, 0);\n  z-index: var(--sf-z-sticky);\n}\n.sf-sticky--s { inset-block-start: calc(var(--sf-sticky-offset, 0) + var(--sf-space-s)); }\n.sf-sticky--m { inset-block-start: calc(var(--sf-sticky-offset, 0) + var(--sf-space-m)); }\n.sf-sticky--l { inset-block-start: calc(var(--sf-sticky-offset, 0) + var(--sf-space-l)); }\n\n/* ============================================================\n * CONTENT-WIDTH UTILITIES (.sf-width-*)\n * Constrain an element to a fraction of the content column\n * (--sf-content-width) and centre it in normal flow. inline-size:100%\n * lets it shrink below the cap on a narrower parent; margin-inline:auto\n * absorbs the leftover space to centre it. The keyword variants map to\n * CSS width keywords: full = 100% uncapped, plus auto / fit-content /\n * min-content / max-content. Logical properties throughout, so they\n * follow the writing mode. Centring assumes normal flow — inside a\n * flex/grid parent, alignment is governed by the container instead.\n *   <div class=\"sf-width-50\">Half the content width, centred</div>\n * ============================================================ */\n.sf-width-10, .sf-width-20, .sf-width-30, .sf-width-40, .sf-width-50,\n.sf-width-60, .sf-width-70, .sf-width-80, .sf-width-90 {\n  inline-size:   100%;\n  margin-inline: auto;\n}\n.sf-width-10 { max-inline-size: calc(var(--sf-content-width) * 0.1); }\n.sf-width-20 { max-inline-size: calc(var(--sf-content-width) * 0.2); }\n.sf-width-30 { max-inline-size: calc(var(--sf-content-width) * 0.3); }\n.sf-width-40 { max-inline-size: calc(var(--sf-content-width) * 0.4); }\n.sf-width-50 { max-inline-size: calc(var(--sf-content-width) * 0.5); }\n.sf-width-60 { max-inline-size: calc(var(--sf-content-width) * 0.6); }\n.sf-width-70 { max-inline-size: calc(var(--sf-content-width) * 0.7); }\n.sf-width-80 { max-inline-size: calc(var(--sf-content-width) * 0.8); }\n.sf-width-90 { max-inline-size: calc(var(--sf-content-width) * 0.9); }\n\n.sf-width-full { inline-size: 100%; max-inline-size: none; }\n.sf-width-auto { inline-size: auto; }\n.sf-width-fit  { inline-size: fit-content; }\n.sf-width-min  { inline-size: min-content; }\n.sf-width-max  { inline-size: max-content; }\n\n/* ============================================================\n * OVERFLOW-DEBUG UTILITY (.sf-debug-overflow)\n * Dev-only diagnostic: apply to <body> (or any container) to outline\n * every descendant, making the element causing horizontal page\n * overflow visually obvious. Not a production utility — remove\n * before shipping.\n * ============================================================ */\n/* .sf-debug-overflow,\n.sf-debug-overflow *,\n.sf-debug-overflow *::before,\n.sf-debug-overflow *::after {\n  outline: 1px solid oklch(0.6 0.25 30 / 0.6);\n} */\n\n/* ─── core/states.css ─── */\n/* SLASHED — core/states.css\n   @layer slashed.states\n   Generic runtime states toggled by JS or ARIA: visibility, interactivity, selection, busy/current.\n   Prefix: .sf-is-*; not utilities or component-specific variants.\n\n   Reach for a native mechanism first — a pseudo-class (:disabled, :read-only,\n   :empty, :user-invalid), a boolean/enumerated attribute ([hidden], [disabled],\n   [readonly]), or an ARIA state ([aria-busy], [aria-current], [aria-expanded],\n   [aria-selected], [aria-pressed]) — since the browser (and assistive tech)\n   already understands it for free. Add a .sf-is-* class only for states with\n   no native equivalent, or ones this file's own tokens/consumers need as a\n   hook (see docs/states.md). See docs/states.md § \"Prefer native state\" for\n   the full rationale and the [hidden] precedent that got .sf-is-hidden\n   removed in favour of the attribute it duplicated. */\n\n\n/* No visibility classes here: .sf-is-hidden duplicated [hidden] (removed —\n   core/reset.css hardens that attribute identically). .sf-invisible /\n   .sf-visible moved to optional/utilities.css as single-property helpers\n   (same call as Bulma's is-hidden/is-invisible living under \"helpers\",\n   not component/state docs) — still the hook docs/roadmap.md's\n   reveal-on-scroll pattern targets, just renamed and relocated. */\n\n/* -- INTERACTIVITY --\n   No .sf-is-readonly here: it duplicated :read-only for real form controls,\n   and its pointer-events:none blocked text selection that a genuinely\n   read-only field should still allow — reach for :read-only, or\n   [aria-readonly] on a non-native widget, instead. */\n\n/* cursor: not-allowed inherits to children with pointer-events: auto —\n   intentional, part of the .sf-is-disabled API surface. */\n.sf-is-disabled {\n  opacity:        var(--sf-opacity-disabled);\n  pointer-events: none;\n\n  cursor:         not-allowed;\n  user-select:    none;\n}\n\n/* -- LOADING / ASYNC FEEDBACK -- */\n\n.sf-is-loading {\n  color:          transparent !important;\n  pointer-events: none;\n  position:       relative;\n}\n\n.sf-is-loading > * {\n  opacity: 0 !important;\n}\n\n.sf-is-loading::after {\n  content:             \"\";\n  position:            absolute;\n  inset-block-start:   50%;\n  inset-inline-start:  50%;\n  inline-size:         1em;\n  block-size:          1em;\n  margin-block-start:  -0.5em;\n  margin-inline-start: -0.5em;\n  border:        var(--sf-border-width-2) solid var(--sf-color-border--strong);\n  border-block-start-color: var(--sf-color-action);\n  border-radius: var(--sf-radius-full);\n\n  animation: var(--sf-animation-spin);\n}\n\n/* No .sf-is-busy / .sf-is-pending here: both were a couple of\n   property-value declarations (cursor:progress, plus opacity for\n   pending's \"optimistic UI\" dimming) with no consumer and no native gap\n   they filled — [aria-busy=\"true\"] covers the semantic, and the visual\n   is two lines to hand-roll in your own component CSS if you want it. */\n\n/* Shimmer loading placeholder (was .sf-is-skeleton pre-Unreleased; renamed so\n   \"skeleton\" names only the planned .sf-skeleton component, not a state —\n   see docs/migration.md and roadmap.md #575). The class name now mirrors its\n   driving token, --sf-animation-shimmer. */\nimg.sf-is-shimmer,\n.sf-is-shimmer img {\n  opacity: 0 !important;\n}\n\n.sf-is-shimmer {\n  color:           transparent !important;\n  background:      linear-gradient(\n                     90deg,\n                     var(--sf-color-inset) 25%,\n                     var(--sf-color-raised) 50%,\n                     var(--sf-color-inset) 75%\n                   );\n  background-size: 200% 100%;\n  animation: var(--sf-animation-shimmer);\n  border-radius:   var(--sf-radius-s);\n  pointer-events:  none;\n  user-select:     none;\n}\n\n/* -- SELECTED / HIGHLIGHTED --\n   No .sf-is-active / .sf-is-open / .sf-is-collapsed / .sf-is-expanded /\n   .sf-is-current / .sf-is-pressed here: these only ever set an\n   inheritable --sf-is-* custom property for a hypothetical consumer\n   calc() to branch on, with zero consumer anywhere in this codebase or\n   its demo. Speculative \"might be useful one day\" surface, removed —\n   see docs/states.md § \"Prefer native state\". Reach for [aria-current],\n   [aria-expanded], [aria-pressed] as the styling hook instead; .sf-is-\n   selected / .sf-is-highlighted below cover the two cases (selection,\n   transient emphasis) that still need their own visual. */\n\n.sf-is-selected {\n  background-color: var(--sf-color-bg--selected);\n}\n\n.sf-is-highlighted {\n  background-color: var(--sf-color-bg--focus);\n}\n\n/* -- VALIDATION / FEEDBACK --\n   No .sf-is-danger here: identical implementation to .sf-is-invalid/\n   .sf-is-error (both only ever wrote --sf-field-*, so it never worked as\n   the \"destructive-action context\" its own docs described outside a form\n   field) and, per docs/migration.md, visual variants belong in your own\n   component CSS anyway. Use .sf-is-invalid/.sf-is-error, or your own\n   `--danger` variant class, instead. */\n\n.sf-is-valid,\n.sf-is-success {\n  --sf-field-border-color: var(--sf-color-success);\n  --sf-field-text-color:   var(--sf-color-success-strong);\n}\n\n.sf-is-invalid,\n.sf-is-error {\n  --sf-field-border-color: var(--sf-color-danger);\n  --sf-field-text-color:   var(--sf-color-danger-strong);\n}\n\n.sf-is-warning {\n  --sf-field-border-color: var(--sf-color-warning);\n  --sf-field-text-color:   var(--sf-color-warning-strong);\n}\n\n.sf-is-info {\n  --sf-field-border-color: var(--sf-color-info);\n  --sf-field-text-color:   var(--sf-color-info-strong);\n}\n\n/* -- DRAG & DROP -- */\n\n.sf-is-dragging {\n  opacity: var(--sf-opacity-muted);\n  cursor:  grabbing;\n}\n\n.sf-is-drop-target {\n  outline:        var(--sf-focus-ring-width) dashed var(--sf-color-action);\n  outline-offset: var(--sf-focus-ring-offset);\n}\n\n.sf-is-draggable {\n  cursor: grab;\n}\n\n/* -- EMPTY STATE -- */\n\n.sf-is-empty:empty {\n  display: none;\n}\n\n/* KEYFRAMES (used by states above) */\n\n/* ─── core/themes.css ─── */\n/* SLASHED — core/themes.css\n   @layer slashed.themes\n   Light/dark activation, scoped theme color inheritance, LumLocker, and scheme-aware color adjustments.\n   Uses data-theme, .sf-theme-light/.sf-theme-dark aliases, and token overrides. */\n\n\n@media (prefers-color-scheme: dark) {\n  :root:not([data-theme]) {\n    color-scheme: dark;\n    --sf-is-dark: 1;\n  }\n}\n\n:is([data-theme=\"light\"], .sf-theme-light) { color-scheme: light; --sf-is-dark: 0; }\n:is([data-theme=\"dark\"], .sf-theme-dark)  { color-scheme: dark;  --sf-is-dark: 1; }\n\n:where([data-theme]:not(:root, html), .sf-theme-light:not(:root, html), .sf-theme-dark:not(:root, html)) {\n  background-color: var(--sf-color-bg);\n  color:            var(--sf-color-text);\n\n  /* Component-layer and :root-only alias tokens that merely alias a themed\n     core token (no light/dark branching of their own, e.g. --sf-card-bg:\n     var(--sf-color-surface)) are declared once in :root (tokens.css /\n     optional/tokens.components.css). Without a redeclaration here, that\n     var() substitutes using :root's OWN --sf-color-surface/-heading/-text\n     at computed-value time and the result inherits down frozen — a nested\n     data-theme section further in never gets a chance to re-substitute it,\n     breaking the \"data-theme works on any element\" guarantee\n     (docs/theming.md) for .sf-card and for heading/body colour (#496).\n     Re-declaring the aliases here, at the same non-root scope, forces a\n     fresh substitution against this section's own (possibly overridden)\n     --sf-color-surface / -border / -heading / -text. */\n  --sf-card-bg:           var(--sf-color-surface);\n  --sf-card-border-color: var(--sf-color-border);\n  --sf-heading-color:     var(--sf-color-heading);\n  --sf-body-color:        var(--sf-color-text);\n}\n\n/* LumLocker: locks 4 brand colors to a fixed OKLCH L — --sf-lumlocker in\n   light, --sf-lumlocker-dark (default calc(1.18 - L), the mirror around the\n   light/dark background midpoint) in dark, so contrast against the surface\n   holds in both themes. Neutral/base excluded — forcing them to a brand L\n   breaks their semantic role. */\n@supports (color: oklch(from red l c h)) {\n:root[data-lumlocker] {\n  --sf-color-primary: light-dark(\n    oklch(from var(--sf-color-primary-source-light) var(--sf-lumlocker) c h),\n    oklch(from var(--sf-color-primary-source-dark, var(--sf-color-primary-source-light)) var(--sf-lumlocker-dark) c h)\n  );\n  --sf-color-secondary: light-dark(\n    oklch(from var(--sf-color-secondary-source-light) var(--sf-lumlocker) c h),\n    oklch(from var(--sf-color-secondary-source-dark, var(--sf-color-secondary-source-light)) var(--sf-lumlocker-dark) c h)\n  );\n  --sf-color-tertiary: light-dark(\n    oklch(from var(--sf-color-tertiary-source-light) var(--sf-lumlocker) c h),\n    oklch(from var(--sf-color-tertiary-source-dark, var(--sf-color-tertiary-source-light)) var(--sf-lumlocker-dark) c h)\n  );\n  --sf-color-action: light-dark(\n    oklch(from var(--sf-color-action-source-light) var(--sf-lumlocker) c h),\n    oklch(from var(--sf-color-action-source-dark, var(--sf-color-action-source-light)) var(--sf-lumlocker-dark) c h)\n  );\n}\n\n:root[data-lumlocker] :is([data-theme=\"dark\"], .sf-theme-dark) {\n  --sf-color-primary:   oklch(from var(--sf-color-primary-source-dark,   var(--sf-color-primary-source-light))   var(--sf-lumlocker-dark) c h);\n  --sf-color-secondary: oklch(from var(--sf-color-secondary-source-dark, var(--sf-color-secondary-source-light)) var(--sf-lumlocker-dark) c h);\n  --sf-color-tertiary:  oklch(from var(--sf-color-tertiary-source-dark,  var(--sf-color-tertiary-source-light))  var(--sf-lumlocker-dark) c h);\n  --sf-color-action:    oklch(from var(--sf-color-action-source-dark,    var(--sf-color-action-source-light))    var(--sf-lumlocker-dark) c h);\n}\n:root[data-lumlocker] :is([data-theme=\"light\"], .sf-theme-light) {\n  --sf-color-primary:   oklch(from var(--sf-color-primary-source-light)   var(--sf-lumlocker) c h);\n  --sf-color-secondary: oklch(from var(--sf-color-secondary-source-light) var(--sf-lumlocker) c h);\n  --sf-color-tertiary:  oklch(from var(--sf-color-tertiary-source-light)  var(--sf-lumlocker) c h);\n  --sf-color-action:    oklch(from var(--sf-color-action-source-light)    var(--sf-lumlocker) c h);\n}\n}\n\n/* SECTION-LEVEL THEMING */\n/* light-dark() bakes at :root declaration time; re-declarations on [data-theme]\n   elements are required for section-level theming to work.\n   SL-001: the clamp() derivation formula below is the same one used inside\n   tokens.css's \"Resolved color tokens — auto-switch via light-dark()\"\n   block (search core/tokens.css for that comment) — duplicated here, not\n   shared, because this file needs flat values outside light-dark().\n   Keep both copies in sync if the formula ever changes. */\n@supports (color: oklch(from red l c h)) {\n\n      :root {\n    --sf-color-primary-source-dark:   oklch(from var(--sf-color-primary-source-light)   clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n    --sf-color-secondary-source-dark: oklch(from var(--sf-color-secondary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n    --sf-color-tertiary-source-dark:  oklch(from var(--sf-color-tertiary-source-light)  clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n    --sf-color-action-source-dark:    oklch(from var(--sf-color-action-source-light)    clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n    --sf-color-neutral-source-dark:   oklch(from var(--sf-color-neutral-source-light)   clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n    --sf-color-base-source-dark:      oklch(from var(--sf-color-base-source-light)      clamp(0.16, calc(1.18 - l),        0.24) calc(c * 0.5) h);\n    --sf-color-success-source-dark:   oklch(from var(--sf-color-success-source-light)   clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n    --sf-color-warning-source-dark:   oklch(from var(--sf-color-warning-source-light)   clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n    --sf-color-info-source-dark:      oklch(from var(--sf-color-info-source-light)      clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n    --sf-color-danger-source-dark:    oklch(from var(--sf-color-danger-source-light)    clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h);\n  }\n\n      :is([data-theme=\"dark\"], .sf-theme-dark) {\n\n    --sf-color-primary:   var(--sf-color-primary-source-dark);\n    --sf-color-secondary: var(--sf-color-secondary-source-dark);\n    --sf-color-tertiary:  var(--sf-color-tertiary-source-dark);\n    --sf-color-action:    var(--sf-color-action-source-dark);\n    --sf-color-neutral:   var(--sf-color-neutral-source-dark);\n    --sf-color-base:      var(--sf-color-base-source-dark);\n    --sf-color-surface:   var(--sf-color-base);\n\n    --sf-color-bg:      oklch(from var(--sf-color-base) calc(l + 0.02) c h);\n    --sf-color-inset:   oklch(from var(--sf-color-base) calc(l - 0.02) c h);\n    --sf-color-raised:  oklch(from var(--sf-color-base) calc(l + 0.04) c h);\n    --sf-color-overlay: oklch(from var(--sf-color-base) l c h / 0.9);\n    --sf-color-inverse: oklch(from var(--sf-color-base) calc(1 - l) c h);\n\n    --sf-color-success: var(--sf-color-success-source-dark);\n    --sf-color-warning: var(--sf-color-warning-source-dark);\n    --sf-color-info:    var(--sf-color-info-source-dark);\n    --sf-color-danger:  var(--sf-color-danger-source-dark);\n\n    --sf-color-text:              oklch(from var(--sf-color-neutral) clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1)    c h);\n    --sf-color-text--subtle:   oklch(from var(--sf-color-neutral) clamp(0.55, calc(l + 0.1 + var(--sf-contrast-bias)), 0.90) c h);\n    --sf-color-text--placeholder: oklch(from var(--sf-color-neutral) clamp(0.35, calc(l - 0.1),  0.65) c h);\n    --sf-color-text--disabled:    oklch(from var(--sf-color-neutral) clamp(0.25, calc(l - 0.2),  0.55) c h);\n    --sf-color-text--inverse:     oklch(from var(--sf-color-neutral) clamp(0.05, calc(l - 0.4),  0.35) c h);\n    --sf-color-heading:           oklch(from var(--sf-color-neutral) clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1)    c h);\n\n    --sf-color-border:         oklch(from var(--sf-color-neutral) clamp(0.25, calc(l - 0.3),  0.55) 0.005 h);\n    --sf-color-border--subtle: oklch(from var(--sf-color-neutral) clamp(0.20, calc(l - 0.38), 0.45) 0.005 h);\n    --sf-color-border--strong: oklch(from var(--sf-color-neutral) clamp(0.38, calc(l - 0.1),  0.65) 0.02  h);\n\n    --sf-color-link:          oklch(from var(--sf-color-action) clamp(0.68, l, 1) c h);\n    --sf-color-link--hover:   oklch(from var(--sf-color-action) clamp(0, max(l + 0.10, 0.68), 1) c h);\n    --sf-color-link--active:  oklch(from var(--sf-color-action) clamp(0, max(l + 0.15, 0.74), 1) c h);\n    --sf-color-link--visited: oklch(from var(--sf-color-action) clamp(0.68, l, 1) c calc(h + 60));\n\n    --sf-color-selection-bg: oklch(from var(--sf-color-action-source-dark) clamp(0.62, calc(0.93 - l * 0.4), 0.78) c h / 0.55);\n\n    --sf-color-success-strong: oklch(from var(--sf-color-success) clamp(0.70, calc(l + 0.15), 1) c h);\n    --sf-color-warning-strong: oklch(from var(--sf-color-warning) clamp(0.70, calc(l + 0.05), 1) c h);\n    --sf-color-info-strong:    oklch(from var(--sf-color-info)    clamp(0.70, calc(l + 0.15), 1) c h);\n    --sf-color-danger-strong:  oklch(from var(--sf-color-danger)  clamp(0.70, calc(l + 0.15), 1) c h);\n\n    /* :root-only aliases from tokens.css — var() resolves on the declaring\n       element, so without these re-declarations a nested [data-theme]\n       section inherits the :root-resolved (wrong-scheme) values (#496). */\n    --sf-color-code-bg:        var(--sf-color-inset);\n    --sf-color-bg--disabled:   var(--sf-color-inset);\n    --sf-color-link--disabled: var(--sf-color-text--disabled);\n    --sf-scrollbar-thumb:      var(--sf-color-neutral);\n    /* Non-sign() fallback: keeps inline code readable in engines with\n       oklch(from) but not sign() — the sign()-gated auto-contrast block\n       below overrides this with a proper per-background contrast calc\n       wherever sign() is supported. */\n    --sf-color-code-text:      var(--sf-color-text);\n  }\n\n      :is([data-theme=\"light\"], .sf-theme-light) {\n\n    --sf-color-primary:   var(--sf-color-primary-source-light);\n    --sf-color-secondary: var(--sf-color-secondary-source-light);\n    --sf-color-tertiary:  var(--sf-color-tertiary-source-light);\n    --sf-color-action:    var(--sf-color-action-source-light);\n    --sf-color-neutral:   var(--sf-color-neutral-source-light);\n    --sf-color-base:      var(--sf-color-base-source-light);\n    --sf-color-surface:   var(--sf-color-base);\n\n    --sf-color-bg:      oklch(from var(--sf-color-base) calc(l + 0.02) c h);\n    --sf-color-inset:   oklch(from var(--sf-color-base) calc(l - 0.02) c h);\n    --sf-color-raised:  oklch(from var(--sf-color-base) calc(l + 0.04) c h);\n    --sf-color-overlay: oklch(from var(--sf-color-base) l c h / 0.9);\n    --sf-color-inverse: oklch(from var(--sf-color-base) calc(1 - l) c h);\n\n    --sf-color-success: var(--sf-color-success-source-light);\n    --sf-color-warning: var(--sf-color-warning-source-light);\n    --sf-color-info:    var(--sf-color-info-source-light);\n    --sf-color-danger:  var(--sf-color-danger-source-light);\n\n    --sf-color-text:              oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h);\n    --sf-color-text--subtle:   oklch(from var(--sf-color-neutral-source-light) clamp(0.15, calc(l - 0.25 - var(--sf-contrast-bias)), 0.45) c h);\n    --sf-color-text--placeholder: oklch(from var(--sf-color-neutral-source-light) clamp(0.45, calc(l + 0.15), 0.75) c h);\n    --sf-color-text--disabled:    oklch(from var(--sf-color-neutral-source-light) clamp(0.55, calc(l + 0.25), 0.82) c h);\n    --sf-color-text--inverse:     oklch(from var(--sf-color-neutral-source-light) clamp(0.85, calc(l + 0.4),  0.98) c h);\n    --sf-color-heading:           oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h);\n\n    --sf-color-border:         oklch(from var(--sf-color-neutral-source-light) clamp(0.70, calc(l + 0.35), 0.95) 0.005 h);\n    --sf-color-border--subtle: oklch(from var(--sf-color-neutral-source-light) clamp(0.75, calc(l + 0.4),  0.97) 0.005 h);\n    --sf-color-border--strong: oklch(from var(--sf-color-neutral-source-light) clamp(0.55, calc(l + 0.1),  0.85) 0.02  h);\n\n    --sf-color-link:          oklch(from var(--sf-color-action) clamp(0, min(l - 0.07, 0.48), 1) c h);\n    --sf-color-link--hover:   oklch(from var(--sf-color-action) clamp(0, min(l - 0.15, 0.40), 1) c h);\n    --sf-color-link--active:  oklch(from var(--sf-color-action) clamp(0, min(l - 0.21, 0.34), 1) c h);\n    --sf-color-link--visited: oklch(from var(--sf-color-action) clamp(0, min(l - 0.07, 0.48), 1) c calc(h + 60));\n\n    --sf-color-selection-bg: oklch(from var(--sf-color-action-source-light) l c h / 0.28);\n\n    --sf-color-success-strong: oklch(from var(--sf-color-success-source-light) calc(l - 0.15) c h);\n    --sf-color-warning-strong: oklch(from var(--sf-color-warning-source-light) calc(l - 0.25) c h);\n    --sf-color-info-strong:    oklch(from var(--sf-color-info-source-light)    calc(l - 0.1)  c h);\n    --sf-color-danger-strong:  oklch(from var(--sf-color-danger-source-light)  calc(l - 0.1)  c h);\n\n    /* :root-only aliases — see the matching note in the dark block (#496). */\n    --sf-color-code-bg:        var(--sf-color-inset);\n    --sf-color-bg--disabled:   var(--sf-color-inset);\n    --sf-color-link--disabled: var(--sf-color-text--disabled);\n    --sf-scrollbar-thumb:      var(--sf-color-neutral);\n    /* Non-sign() fallback — see matching note in the dark block (#496). */\n    --sf-color-code-text:      var(--sf-color-text);\n  }\n\n}\n\n@supports (color: oklch(from red l c h)) and (width: calc(1px * sign(1))) {\n  :is([data-theme=\"dark\"], .sf-theme-dark) {\n    --sf-color-text--on-primary:   oklch(from var(--sf-color-primary)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-secondary: oklch(from var(--sf-color-secondary) clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-tertiary:  oklch(from var(--sf-color-tertiary)  clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-action:    oklch(from var(--sf-color-action)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-neutral:   oklch(from var(--sf-color-neutral)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-success:   oklch(from var(--sf-color-success)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-warning:   oklch(from var(--sf-color-warning)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-info:      oklch(from var(--sf-color-info)      clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-danger:    oklch(from var(--sf-color-danger)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-inverse:   oklch(from var(--sf-color-inverse)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    /* Auto-contrast code text re-derived in-scope so it tracks the\n       per-scope --sf-color-code-bg above (#496). Same formula as\n       core/tokens.css — keep in sync. */\n    --sf-color-code-text:          oklch(from var(--sf-color-code-bg)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n  }\n  :is([data-theme=\"light\"], .sf-theme-light) {\n    --sf-color-text--on-primary:   oklch(from var(--sf-color-primary)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-secondary: oklch(from var(--sf-color-secondary) clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-tertiary:  oklch(from var(--sf-color-tertiary)  clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-action:    oklch(from var(--sf-color-action)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-neutral:   oklch(from var(--sf-color-neutral)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-success:   oklch(from var(--sf-color-success)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-warning:   oklch(from var(--sf-color-warning)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-info:      oklch(from var(--sf-color-info)      clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-danger:    oklch(from var(--sf-color-danger)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    --sf-color-text--on-inverse:   oklch(from var(--sf-color-inverse)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n    /* See matching note in the dark block (#496). */\n    --sf-color-code-text:          oklch(from var(--sf-color-code-bg)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);\n  }\n}\n\n/* OPT-IN THEME CROSS-FADE */\n.sf-theme-transition {\n  transition:\n    --sf-color-primary   var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-secondary var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-tertiary  var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-action    var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-neutral   var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-base      var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-success   var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-warning   var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-info      var(--sf-theme-transition-duration) var(--sf-ease-out),\n    --sf-color-danger    var(--sf-theme-transition-duration) var(--sf-ease-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .sf-theme-transition { transition: none; }\n}\n\n/* ─── core/motion.css ─── */\n/* SLASHED — core/motion.css\n   @layer slashed.motion\n   Global transitions, view transitions, keyframes, and motion helpers.\n   Respects prefers-reduced-motion and --sf-motion-scale. */\n\n\n@media (prefers-reduced-motion: no-preference) {\n\n  html {\n    scroll-behavior: smooth;\n  }\n\n  a, button, input, select, textarea, summary {\n    transition-property:\n      color, background-color, border-color, text-decoration-color,\n      fill, stroke, opacity, box-shadow, transform, scale, translate,\n      filter, backdrop-filter;\n    transition-duration:        var(--sf-duration-fast);\n    transition-timing-function: var(--sf-ease-out);\n  }\n\n  @supports (view-transition-name: none) {\n    ::view-transition-old(root),\n    ::view-transition-new(root) {\n      animation-duration:        var(--sf-duration-normal);\n      animation-timing-function: var(--sf-ease-out);\n    }\n  }\n\n  \n  .sf-fade-in        { animation: var(--sf-animation-fade-in); }\n  .sf-fade-out       { animation: var(--sf-animation-fade-out); }\n  .sf-slide-in-up    { animation: var(--sf-animation-slide-in-up); }\n  .sf-slide-in-down  { animation: var(--sf-animation-slide-in-down); }\n  .sf-slide-in-left  { animation: var(--sf-animation-slide-in-left); }\n  .sf-slide-in-right { animation: var(--sf-animation-slide-in-right); }\n  .sf-scale-up       { animation: var(--sf-animation-scale-up); }\n  .sf-scale-down     { animation: var(--sf-animation-scale-down); }\n\n  \n  /* animation-duration set unconditionally: without it, engines without\n     animation-timeline snap to end state at 0s. */\n  .sf-entrance--fade,\n  .sf-entrance--fade-up,\n  .sf-entrance--fade-down,\n  .sf-entrance--fade-left,\n  .sf-entrance--fade-right,\n  .sf-entrance--scale-up {\n    animation-duration:        var(--sf-duration-slow);\n    animation-timing-function: var(--sf-ease-out);\n    animation-fill-mode:       both;\n  }\n  @supports (animation-timeline: view()) {\n    .sf-entrance--fade,\n    .sf-entrance--fade-up,\n    .sf-entrance--fade-down,\n    .sf-entrance--fade-left,\n    .sf-entrance--fade-right,\n    .sf-entrance--scale-up {\n      animation-fill-mode: forwards;\n      animation-timeline: view();\n      animation-range:    var(--sf-scroll-timeline-range-start, entry 0%)\n                          var(--sf-scroll-timeline-range-end,   cover 30%);\n    }\n  }\n  .sf-entrance--fade        { animation-name: sf-fade-in; }\n  .sf-entrance--fade-up     { animation-name: sf-slide-in-up; }\n  .sf-entrance--fade-down   { animation-name: sf-slide-in-down; }\n  .sf-entrance--fade-left   { animation-name: sf-slide-in-left; }\n  .sf-entrance--fade-right  { animation-name: sf-slide-in-right; }\n  .sf-entrance--scale-up    { animation-name: sf-scale-up; }\n\n\n  /* Exit counterpart of .sf-entrance--*: fires as the element scrolls\n     out of view. Every declaration below lives inside @supports —\n     unlike entrance (where a non-scroll fallback still ends visible),\n     an unconditional exit animation would leave content permanently\n     hidden on engines without animation-timeline: view() support, so\n     there is deliberately no fallback declaration outside @supports. */\n  @supports (animation-timeline: view()) {\n    .sf-exit--fade,\n    .sf-exit--fade-up,\n    .sf-exit--fade-down,\n    .sf-exit--fade-left,\n    .sf-exit--fade-right,\n    .sf-exit--scale-down {\n      animation-duration:        var(--sf-duration-slow);\n      animation-timing-function: var(--sf-ease-in);\n      animation-fill-mode:       both;\n      animation-timeline: view();\n      animation-range:    var(--sf-scroll-timeline-range-exit-start, cover 70%)\n                          var(--sf-scroll-timeline-range-exit-end,   exit 100%);\n    }\n    .sf-exit--fade        { animation-name: sf-fade-out; }\n    .sf-exit--fade-up     { animation-name: sf-slide-out-up; }\n    .sf-exit--fade-down   { animation-name: sf-slide-out-down; }\n    .sf-exit--fade-left   { animation-name: sf-slide-out-left; }\n    .sf-exit--fade-right  { animation-name: sf-slide-out-right; }\n    .sf-exit--scale-down  { animation-name: sf-scale-down; }\n  }\n\n  /* Stagger — choreography, not the animation itself. Put .sf-stagger on a\n     PARENT; every direct child gets an incrementing animation-delay so a\n     time-based entrance (.sf-fade-in / .sf-slide-in-*) plays in sequence.\n     Children WITHOUT an animation just carry an inert delay (no-op), so you\n     opt in per child with no need to exclude anything. Pairs with time-based\n     animations only — the .sf-entrance / .sf-exit families are scroll-driven\n     (their rhythm is animation-range, not animation-delay).\n\n     One formula, one knob (--sf-stagger-step); the two paths below only\n     differ in how --sf-stagger-i (the child's index) is set. */\n  .sf-stagger > * {\n    animation-delay: calc(\n      var(--sf-stagger-i, 0) * var(--sf-stagger-step, 75ms) * var(--sf-motion-scale, 1)\n    );\n  }\n\n  /* Modern path: real, unbounded index straight from the DOM position. */\n  @supports (animation-delay: calc(sibling-index() * 1ms)) {\n    .sf-stagger > * { --sf-stagger-i: calc(sibling-index() - 1); }\n  }\n\n  /* Fallback (no sibling-index()): a bounded :nth-child ramp reusing the same\n     formula. The default is the plateau value, so the 9th child onward shares\n     the last rung's delay instead of growing without limit — 8 rungs cover a\n     4-column grid's first two visible rows. Split into @supports not(...) so\n     the modern override above wins cleanly without a specificity fight\n     (:nth-child would otherwise out-specify the sibling-index rule). */\n  @supports not (animation-delay: calc(sibling-index() * 1ms)) {\n    .sf-stagger > *              { --sf-stagger-i: 8; }\n    .sf-stagger > *:nth-child(1) { --sf-stagger-i: 0; }\n    .sf-stagger > *:nth-child(2) { --sf-stagger-i: 1; }\n    .sf-stagger > *:nth-child(3) { --sf-stagger-i: 2; }\n    .sf-stagger > *:nth-child(4) { --sf-stagger-i: 3; }\n    .sf-stagger > *:nth-child(5) { --sf-stagger-i: 4; }\n    .sf-stagger > *:nth-child(6) { --sf-stagger-i: 5; }\n    .sf-stagger > *:nth-child(7) { --sf-stagger-i: 6; }\n    .sf-stagger > *:nth-child(8) { --sf-stagger-i: 7; }\n  }\n\n}\n\n@keyframes sf-fade-in   { from { opacity: 0; } to { opacity: 1; } }\n@keyframes sf-fade-out  { from { opacity: 1; } to { opacity: 0; } }\n@keyframes sf-slide-in-up    { from { opacity: 0; translate: 0 1rem;  } to { opacity: 1; translate: 0 0; } }\n@keyframes sf-slide-in-down  { from { opacity: 0; translate: 0 -1rem; } to { opacity: 1; translate: 0 0; } }\n@keyframes sf-slide-in-left  { from { opacity: 0; translate: 1rem 0;  } to { opacity: 1; translate: 0 0; } }\n@keyframes sf-slide-in-right { from { opacity: 0; translate: -1rem 0; } to { opacity: 1; translate: 0 0; } }\n@keyframes sf-scale-up   { from { opacity: 0; scale: 0.92; } to { opacity: 1; scale: 1; } }\n@keyframes sf-scale-down { from { opacity: 1; scale: 1; } to { opacity: 0; scale: 0.92; } }\n\n@keyframes sf-slide-out-up    { from { opacity: 1; translate: 0 0; } to { opacity: 0; translate: 0 -1rem; } }\n@keyframes sf-slide-out-down  { from { opacity: 1; translate: 0 0; } to { opacity: 0; translate: 0 1rem;  } }\n@keyframes sf-slide-out-left  { from { opacity: 1; translate: 0 0; } to { opacity: 0; translate: -1rem 0; } }\n@keyframes sf-slide-out-right { from { opacity: 1; translate: 0 0; } to { opacity: 0; translate: 1rem 0;  } }\n\n@keyframes sf-spin    { to { rotate: 360deg; } }\n@keyframes sf-shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } }\n\n@keyframes sf-ping  { 75%, 100% { scale: 2; opacity: 0; } }\n@keyframes sf-blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }\n@keyframes sf-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -0.5rem; } }\n\n\n@supports (@property --x { syntax: \"<color>\"; inherits: false; initial-value: white; }) {\n  @keyframes sf-color-pulse {\n    0%   { --sf-color-primary-source-light: var(--sf-color-primary-source-light); }\n    50%  { --sf-color-primary-source-light: oklch(from var(--sf-color-primary-source-light) clamp(0, calc(l + 0.25), 0.9) c h); }\n    100% { --sf-color-primary-source-light: var(--sf-color-primary-source-light); }\n  }\n\n  @media (prefers-reduced-motion: no-preference) {\n    .sf-color-pulse {\n      animation: var(--sf-animation-color-pulse);\n    }\n  }\n}\n\n@supports (transition-behavior: allow-discrete) {\n  dialog, [popover] {\n    transition: var(--sf-transition-overlay);\n  }\n}\n\n/* ─── core/accessibility.css ─── */\n/* SLASHED — core/accessibility.css\n   @layer slashed.accessibility\n   Focus rings, screen-reader helpers, skip links, and reduced-friction a11y utilities.\n   Prefix: .sf-* plus native focus selectors. */\n\n\n/* Focus */\n:focus:not(:focus-visible) {\n  outline: none;\n}\n\n:focus-visible {\n  outline:        var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-focus-ring-color) !important;\n  outline-offset: var(--sf-focus-ring-offset) !important;\n}\n\n/* .sf-focus-shadow: replaces outline ring with box-shadow ring; !important required\n   to take over the hardened :focus-visible outline (WCAG 2.4.7 still met). */\n.sf-focus-shadow:focus-visible {\n  outline:    none                         !important;\n  box-shadow: var(--sf-focus-ring-shadow)  !important;\n}\n\n/* forced-colors: box-shadow vanishes — restore outline ring for WCAG 2.4.7\n   in Windows High Contrast. */\n@media (forced-colors: active) {\n  .sf-focus-shadow:focus-visible {\n    outline:        var(--sf-focus-ring-width) solid !important;\n    outline-offset: var(--sf-focus-ring-offset) !important;\n    box-shadow:     none !important;\n  }\n}\n\n/* Reduced motion. Token override helps components that read */\n@media (prefers-reduced-motion: reduce) {\n  :root {\n    --sf-duration-instant: 0.01ms;\n    --sf-duration-fast:    0.01ms;\n    --sf-duration-normal:  0.01ms;\n    --sf-duration-slow:    0.01ms;\n    --sf-duration-slower:  0.01ms;\n  }\n\n  *,\n  *::before,\n  *::after {\n    animation-duration:        0.01ms !important;\n    animation-iteration-count: 1      !important;\n    transition-duration:       0.01ms !important;\n    scroll-behavior:           auto   !important;\n  }\n}\n\n.no-motion,\n.no-motion *,\n.no-motion *::before,\n.no-motion *::after {\n  animation-duration:        0.01ms !important;\n  animation-iteration-count: 1      !important;\n  transition-duration:       0.01ms !important;\n  scroll-behavior:           auto   !important;\n}\n\n/* High contrast */\n@media (prefers-contrast: more) {\n  :root {\n    --sf-focus-ring-width: 3px;\n\n    --sf-contrast-bias: 0.06;\n  }\n\n  hr {\n    border-block-start-width: var(--sf-border-width-2);\n  }\n}\n\n@media (prefers-reduced-transparency: reduce) {\n  ::backdrop {\n    background-color: var(--sf-color-neutral);\n    opacity:          1;\n  }\n}\n\n/* Reduced data */\n@media (prefers-reduced-data: reduce) {\n  :root {\n    --sf-shadow-strength: 0;\n    --sf-blur: 0px;\n  }\n}\n\n/* Minimum touch targets — a backstop for genuinely bare, unstyled controls.\n   The floor targets only controls that carry NO class at all. The moment a\n   control has any class it is considered *owned* — by SLASHED itself (.sf-btn\n   owns a deliberate XS–XL size ladder via --sf-btn-min-height / --sf-size-*\n   rungs), by the author, or by a third-party widget (a page-builder hamburger\n   toggle, a plugin control) — and its sizing belongs to whoever put that class\n   there, not to this blanket rule.\n\n   Why so conservative: a blanket floor on *every* button/control silently\n   overrode its owners. It collapsed .sf-btn's whole size ladder to one height\n   on touch, and it stretched narrow custom widgets (e.g. a hamburger icon\n   button) to 44px on BOTH axes — at a specificity higher than a single class,\n   so the owner couldn't even override it without !important. Element-level\n   selectors that reach for someone else's markup are the \"too aggressive base\n   style\" trap; scoping the floor to classless controls keeps it from ever\n   touching markup the framework doesn't own. It extends the \"un-styled\n   element\" idiom already used for `a:not([class])` in base.\n\n   \"Un-styled\" here means *no effective class* — no class attribute at all, OR\n   an empty one (`class=\"\"`), which templating/component renderers routinely\n   emit for a control the author never styled. Both keep the floor. The test\n   is written `:not([class]:not([class=\"\"]))` — read it as \"not (has a\n   non-empty class)\": it excludes only controls carrying a real class token.\n   (A whitespace-only `class=\" \"` is treated as owned; that pathological case\n   isn't worth widening the selector for.) `:where()` keeps the element list\n   at zero specificity so the whole rule stays a low, easily-reasoned weight.\n\n   Bare `<button>text</button>` and un-classed native controls — almost always\n   the author's own quick markup — keep the WCAG 2.5.5 44px floor on both axes.\n   To opt a control OUT, give it any class. To put the floor back ON an owned\n   control, add the .sf-touch-target opt-in class below, set its own\n   min-block/inline-size, or on .sf-btn use\n   `--sf-btn-min-height: var(--sf-touch-target)`. */\n@media (pointer: coarse) {\n  :where(\n    button,\n    input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"],\n    select, summary,\n    input[type=\"checkbox\"], input[type=\"radio\"]\n  ):not([class]:not([class=\"\"])) {\n    min-block-size:  var(--sf-touch-target);\n    min-inline-size: var(--sf-touch-target);\n  }\n}\n\n/* .sf-touch-target — the explicit opt-IN counterpart to the class-less floor\n   above. Because the automatic floor deliberately never touches a control\n   that carries a class, put this class on any control you own (a button with\n   your own class, a third-party widget you can add a class to) to guarantee\n   the WCAG 2.5.5 44px minimum hit area on both axes. Unlike the automatic\n   floor it is NOT gated to a coarse pointer — an explicit opt-in is\n   predictable everywhere. Size follows --sf-touch-target, so a wrapper (or\n   the element itself) can retune it locally.\n\n     <button class=\"my-menu-toggle sf-touch-target\" aria-label=\"Menu\">…</button>\n\n   It sets ONLY the two min-size properties — deliberately no `display` — so it\n   never strips a native affordance (e.g. a <summary>'s list-item marker, a\n   control's baseline alignment). It therefore expects a target whose display\n   already honours min-inline-size: buttons and native form controls\n   (inline-block/flex) do. On a purely inline element (a bare <a>) add your own\n   `display: inline-flex` (or inline-block) alongside it.\n\n   No !important: it's a single class (specificity 0,1,0), so your own\n   component rule can still override it when a specific control needs to opt\n   back out. */\n.sf-touch-target {\n  min-block-size:  var(--sf-touch-target);\n  min-inline-size: var(--sf-touch-target);\n}\n\n/* Disabled states */\n[disabled],\n[aria-disabled=\"true\"] {\n  cursor:  not-allowed;\n  opacity: var(--sf-opacity-disabled);\n}\n\n/* Screen-reader-only. Atomic contract: partial override either exposes hidden content\n   or hides intended content — all-or-nothing, whole set hardened. */\n.sr-only,\n.sr-only-focusable:not(:focus, :focus-within) {\n  position:    absolute            !important;\n  width:       1px                 !important;\n  height:      1px                 !important;\n  padding:     0                   !important;\n  margin:      -1px                !important;\n  overflow:    hidden              !important;\n  overflow:    clip                !important;\n  clip-path:   inset(50%)          !important;\n  white-space: nowrap              !important;\n  border:      0                   !important;\n}\n\n/* Skip link */\n.skip-link {\n  position:          absolute;\n  inset-block-start: -100%;\n  inset-inline-start: var(--sf-space-m);\n  z-index:           var(--sf-z-tooltip);\n  padding:           var(--sf-space-s) var(--sf-space-m);\n  background:        var(--sf-color-bg);\n  color:             var(--sf-color-text);\n  border:            var(--sf-border-width-1) solid var(--sf-color-border);\n  border-radius:     var(--sf-radius-m);\n  transition:        inset-block-start var(--sf-duration-fast) var(--sf-ease-out);\n}\n.skip-link:focus {\n  inset-block-start: var(--sf-space-m);\n}\n\n/* Focus-parent */\n\n.sf-focus-parent:focus-within {\n  outline:        var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-focus-ring-color);\n  outline-offset: var(--sf-focus-ring-offset);\n}\n\n/* Clickable-parent */\n/* Perf note (SL-002): the two selector groups below each combine multiple\n   :has()-bearing branches, forcing subtree re-evaluation on DOM mutation\n   inside .sf-clickable-parent. Fine for typical card/list-item usage; avoid\n   applying this class to large (100+ node) grids or lists without profiling\n   first. */\n.sf-clickable-parent {\n  --sf-clickable-overlay-z: 1;\n  position: relative;\n  cursor:   pointer;\n}\n\n.sf-clickable-parent:not(:has([data-overlay-link], .sf-clickable-parent__overlay)) a:where(:any-link)::after,\n.sf-clickable-parent [data-overlay-link]::after,\n.sf-clickable-parent .sf-clickable-parent__overlay::after {\n  content:        \"\";\n  position:       absolute;\n  inset:          0;\n  z-index:        var(--sf-clickable-overlay-z);\n  pointer-events: auto;\n}\n\n.sf-clickable-parent :is(\n  button, input, textarea, select,\n  summary, video, audio,\n  [role=\"button\"], [data-no-overlay]\n),\n.sf-clickable-parent:has([data-overlay-link]) a:where(:any-link):not([data-overlay-link]),\n.sf-clickable-parent:has(.sf-clickable-parent__overlay) a:where(:any-link):not(.sf-clickable-parent__overlay),\n.sf-clickable-parent:not(:has([data-overlay-link], .sf-clickable-parent__overlay)) a:where(:any-link):not(:first-of-type) {\n  position: relative;\n  z-index:  calc(var(--sf-clickable-overlay-z) + 1);\n}\n\n.sf-clickable-parent:focus-within {\n  outline:        var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-focus-ring-color);\n  outline-offset: var(--sf-focus-ring-offset);\n}\n\n/* Forced colors (Windows High Contrast). Outline-based focus */\n@media (forced-colors: active) {\n  :root {\n    --sf-focus-ring-color: Highlight;\n  }\n\n  :focus-visible {\n    outline-color: Highlight !important;\n  }\n\n  :where(*) {\n    box-shadow:  none;\n    text-shadow: none;\n  }\n\n  input,\n  select,\n  textarea {\n    border: var(--sf-border-width-1) solid;\n  }\n\n  button,\n  input[type=\"submit\"],\n  input[type=\"reset\"],\n  input[type=\"button\"] {\n    border-color: ButtonBorder !important;\n  }\n\n  .sf-text-gradient {\n    background-image:         none !important;\n    /* stylelint-disable-next-line property-no-vendor-prefix */\n    -webkit-background-clip:  unset !important;\n    background-clip:          unset !important;\n    color:                    CanvasText !important;\n  }\n\n  .sf-is-loading::after {\n    border-color:             ButtonText !important;\n    border-block-start-color: Highlight !important;\n  }\n}\n\n/* ─── core/print.css ─── */\n/* SLASHED — core/print.css\n   @layer slashed.print\n   Print-only visibility, page defaults, ink-saving resets, and URL disclosure.\n   Prefix: .print-* for explicit print helpers. */\n\n\n\n.print-only {\n  display: none;\n}\n\n@media print {\n\n  /* --sf-print-page-size / -margin are read here so a :root override retunes\n     the printed page box. Each fallback equals the historical literal, so the\n     default print render is unchanged. Verified in Chromium that var() is\n     substituted inside @page descriptors; engines lacking general custom-\n     property substitution in @page fall back to the literal. */\n  @page {\n\n    size:   var(--sf-print-page-size, a4) portrait;\n    margin: var(--sf-print-page-margin, 2cm);\n  }\n\n  body {\n    font-size: var(--sf-print-base-size, 11pt);\n  }\n\n  *,\n  *::before,\n  *::after {\n    box-shadow:  none;\n    text-shadow: none;\n  }\n\n  a[href]:not([href^=\"#\"], [href^=\"javascript:\" i], [href^=\"mailto:\" i], [href^=\"tel:\" i], .sf-link-external)::after {\n    content:    \" (\" attr(href) \")\";\n    font-size:  90%;\n    word-break: break-all;\n  }\n\n  abbr[title]::after {\n    content: \" (\" attr(title) \")\";\n  }\n\n  img, svg, canvas, figure, table, pre, blockquote {\n    break-inside: avoid;\n\n  }\n\n  thead {\n    display: table-header-group;\n  }\n\n  tr {\n    break-inside: avoid;\n  }\n\n  h1, h2, h3, h4, h5, h6 {\n    break-after: avoid;\n\n  }\n\n  /* Fluid --sf-h*-size tokens resolve via 100vw clamp()s, which have no\n     reliable meaning on a print page box. Pin print heading sizes to\n     static pt values instead. */\n  h1 { font-size: 24pt; }\n  h2 { font-size: 20pt; }\n  h3 { font-size: 16pt; }\n  h4 { font-size: 14pt; }\n  h5 { font-size: 12pt; }\n  h6 { font-size: 11pt; }\n\n  p {\n    orphans: 3;\n    widows:  3;\n  }\n\n  pre, blockquote {\n    border:  var(--sf-border-width-1) solid var(--sf-color-border--strong);\n    padding: var(--sf-space-s);\n  }\n\n  nav, aside, button, input, select, textarea,\n  audio, video, dialog, [popover], .no-print {\n    display: none !important;\n  }\n\n  .print-only {\n    display: revert !important;\n  }\n\n  details { display: block; }\n  details > summary { display: none !important; }\n  details > :not(summary) { display: block; }\n\n  \n  .print-color-exact,\n  .print-color-exact * {\n    print-color-adjust:         exact !important;\n    -webkit-print-color-adjust: exact !important;\n  }\n\n  .print-no-color,\n  .print-no-color *,\n  .print-no-color *::before,\n  .print-no-color *::after {\n    background:  transparent !important;\n    color:       CanvasText  !important;\n  }\n\n}\n"],"names":[]}