/*
 * Klyp shared app stylesheet — on-brand building blocks for funky apps.
 * Self-hosted Plus Jakarta Sans (same face as the feed shell) so apps match the app-store type system AND
 * still load instantly offline (woff2 vendored under /apps/fonts, precached by the SW).
 * Include with: <link rel="stylesheet" href="/apps/klyp-app.css">
 */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal; font-weight: 200 800; font-display: swap;
  src: url("/apps/fonts/jakarta.woff2") format("woff2");
}
/* TYPE VOICES (2026-08-02). Identity cannot depend on fonts we HOPE the device has — measured via CDP
   getPlatformFontsForNode: `ui-rounded` fell through to plain system SF, and "Roboto Condensed" was not
   installed at all, so two worlds' declared voices were fiction. Only a face we SHIP is a face we have.
   Both below are SIL OFL. Latin subset, variable weight — one file covers the whole range. */
/* THE FACE LIBRARY (2026-08-03, founder: "it should be researched on which fonts work fantastically
   well on which archetype"). Ten self-hosted OFL faces, each chosen FOR a material — a ledger wants a
   typewriter, a scoreboard wants condensed numerals, a circus wants a fat slab. @font-face is LAZY: the
   browser fetches a family only when a glyph actually renders in it, so declaring all ten costs an app
   nothing unless it uses one. Each app pays for its own 1-2 faces, not the library. */
@font-face { font-family:"Space Mono"; font-style:normal; font-weight:400 700; font-display:swap;
  src:url("/apps/fonts/space-mono.woff2") format("woff2"); }
@font-face { font-family:"Big Shoulders"; font-style:normal; font-weight:100 900; font-display:swap;
  src:url("/apps/fonts/big-shoulders.woff2") format("woff2"); }
@font-face { font-family:"Alfa Slab One"; font-style:normal; font-weight:400; font-display:swap;
  src:url("/apps/fonts/alfa-slab.woff2") format("woff2"); }
@font-face { font-family:"Bricolage Grotesque"; font-style:normal; font-weight:200 800; font-display:swap;
  src:url("/apps/fonts/bricolage.woff2") format("woff2"); }
@font-face { font-family:"Playfair Display"; font-style:normal; font-weight:400 900; font-display:swap;
  src:url("/apps/fonts/playfair.woff2") format("woff2"); }
@font-face { font-family:"Fraunces"; font-style:normal; font-weight:100 900; font-display:swap;
  src:url("/apps/fonts/fraunces.woff2") format("woff2"); }
@font-face { font-family:"Anton"; font-style:normal; font-weight:400; font-display:swap;
  src:url("/apps/fonts/anton.woff2") format("woff2"); }
@font-face {
  font-family: "Space Grotesk"; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url("/apps/fonts/space-grotesk.woff2") format("woff2");
}
@font-face {
  font-family: "Nunito"; font-style: normal; font-weight: 200 1000; font-display: swap;
  src: url("/apps/fonts/nunito.woff2") format("woff2");
}
@font-face { /* latin-ext (accented creator/app names) */
  font-family: "Plus Jakarta Sans";
  font-style: normal; font-weight: 200 800; font-display: swap;
  src: url("/apps/fonts/jakarta-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
:root {
  /* SHARED SAFE-TOP: the reserved band the host top chrome floats over — post the
     2026-07 tab-bar redesign that's ONE row: streak chip (left, bottom ≈ inset+46px)
     and coin jar (right, bottom ≈ inset+52px); search/daily/rank live in the bottom
     tab bar now. 64px = jar worst-case + 12px breathing (was 92px for the retired
     two-row pill stack — every app gets ~28px of its screen back). Any app whose
     content sits at the top MUST pad with this — one source of truth. */
  --klyp-safe-top: calc(env(safe-area-inset-top) + 64px);
  /* SHARED SAFE-BOTTOM: the reserved strip the host bottom chrome (the ~58px nav /
     coin-jar / progress bar) floats over. Mirrors --klyp-safe-top. Full-bleed apps
     pad their play-zone with this (via .klyp-stage) so nothing tappable hides under
     the bottom strip. Additive: existing apps ignore it. */
  --klyp-safe-bottom: calc(58px + env(safe-area-inset-bottom));
  --cream: #FEFAF6;
  --cream-2: #F5EDE4;
  --coral: #E07A5F;
  --coral-dark: #C4593F;
  --teal: #7BA7BC;
  --purple: #9B72CF;
  --gold: #F2CC8F;
  --green: #81B29A;
  --ink: #1A1816; /* warm-black — aligned to the feed's canonical --text-primary (was #2D2A26, the deprecated ink) */
  /* The subtitle token. A FIXED grey (#6B6560) regardless of the app's ground — so on a dark world it
     measured 1.6-3.7:1 and read as "text isn't visible" (founder, 2026-08-03). Derive it from the app's
     OWN ink instead, so it is always a legible step below the title on every ground. */
  --ink-2: color-mix(in oklch, var(--ks-ink, #6B6560) 82%, transparent);
  --ink-3: #9B948D;
  --line: #E8DFD5;
  /* serif is RESERVED for the result-card score reveal only (.df-score) — the one editorial flourish; every
     other heading/number/body is Plus Jakarta Sans, matching the feed shell (founder call 2026-07-15). */
  --serif: Georgia, "Times New Roman", serif;
  --sans: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
/* FRAMED-BY-THE-FEED (L15): the feed insets the app iframe below the top band and above the identity strip
   (globals.css --top-h/--strip-h), so the host ALREADY clears the chrome. Re-applying the full safe bands
   INSIDE the frame double-counts them → a big empty void above (and below) every app (the 64px shoved
   margin:auto content down so the top void dwarfed the bottom). klyp.js tags <html> .klyp-framed only for
   the feed's <iframe class="klyp-app-frame"> (NOT standalone /a/<slug> or previews), so here we collapse the
   bands to a small SYMMETRIC breathing gap. The notch is the host band's job now, so no env().
   We deliberately KEEP the shared .k-wrap { margin:auto }: in a scrolling flex column that is the correct
   "centre-if-it-fits, top-anchor-and-scroll-if-it-doesn't" behaviour (auto-margins split free space when
   content fits → centred; collapse to 0 when it overflows → top-aligned + scrollable, never top-clipped
   unlike justify-content:center). With the padding fixed, that reads exactly right. */
html.klyp-framed {
  --klyp-safe-top: 12px;
  --klyp-safe-bottom: 12px;
}
/* #5 — when a framed app OVERFLOWS (a utility taller than the middle), show a slim right scrollbar so
   "there's more" is discoverable. Only renders when actually scrollable (overflow-y:auto). Reliable on
   Chromium/Android; iOS keeps its overlay bar (best-effort). Non-scrolling apps show no track. */
html.klyp-framed body { scrollbar-width: thin; scrollbar-color: rgba(120,120,130,0.5) transparent; }
html.klyp-framed body::-webkit-scrollbar { width: 4px; }
html.klyp-framed body::-webkit-scrollbar-thumb { background: rgba(120,120,130,0.5); border-radius: 999px; }
/* V1a FIT FLOOR — the floor-below-the-floor: when a locked-layout app would need <0.7 scale to fit
   (unreadable), klyp.js unlocks BODY scroll instead so every control stays reachable. Body only —
   html stays non-scrolling (the L9 single-scroller law; a second scroll container freezes Android). */
html.klyp-fit-scroll body { overflow-y: auto !important; height: auto !important; min-height: 100%; }
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; height: 100%; }

/* ── Attract-mode preview: keep the feed swipeable ──────────────────────────
   While the host is auto-demoing this app (body.klyp-attracting, toggled by the SDK),
   force every element to allow vertical pan so a swipe-up/down still reaches the host
   feed — apps lock their play surface to touch-action:none for gameplay, which
   otherwise eats the swipe during the preview (the "can't scroll while demo plays"
   bug). The SDK's tap-vs-drag detector still starts the game on a clean tap. */
body.klyp-attracting,
body.klyp-attracting * { touch-action: pan-y !important; }

/* During the host auto-demo the HOST renders the name + one-line "what to do"
   (the .klyp-attract-label, positioned correctly BELOW the top chrome). Hide the
   app's own standard header (.k-h1/.k-sub) while attracting so the name isn't
   doubled and never sits tucked under the streak/daily/rank pills. The demo itself
   shows the play + score; the app's header returns the moment real play starts.
   (Apps that self-name via Klyp.attract(...,{named:true}) keep their own header.) */
body.klyp-attracting .k-h1,
body.klyp-attracting .k-sub { visibility: hidden; }

/* ── Attract-demo "scorecard" flash (shared by every auto-demo app) ─────────────
   When the demo finishes a round it flashes the score on a real CARD, not a flat
   wash: an OPAQUE blurred backdrop (so the playfield never bleeds through — was the
   tap-speed "TAP! shows behind the score" bug) + a glassy rounded panel with a big
   serif score in the app's accent. Each app only sets `--df-accent` (its score
   colour) + wraps its emoji/score/sub in `.df-card`. Markup:
     <div class="demo-flash" id="demoFlash"><div class="df-card">
        <div class="df-emoji">🫧</div><div class="df-score">0 popped</div>
        <div class="df-sub">now make a friend beat it 😏</div></div></div> */
.demo-flash {
  position: fixed; inset: 0; z-index: 9;
  display: flex; align-items: center; justify-content: center; padding: 24px;
  pointer-events: none; opacity: 0; transition: opacity .26s ease;
  background: radial-gradient(120% 90% at 50% 40%, rgba(10, 14, 20, .80), rgba(5, 7, 11, .95));
  -webkit-backdrop-filter: blur(7px) saturate(1.1); backdrop-filter: blur(7px) saturate(1.1);
}
.demo-flash.show { opacity: 1; }
.df-card {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 26px 34px; border-radius: 26px; min-width: min(70vw, 270px);
  background: linear-gradient(168deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, .035));
  border: 1px solid rgba(255, 255, 255, .16);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(255, 255, 255, .14);
}
.demo-flash.show .df-card { animation: dfPop .36s cubic-bezier(.2, .9, .3, 1.25) both; }
@keyframes dfPop { 0% { transform: scale(.8); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
.df-emoji { font-size: 2.4rem; line-height: 1; filter: drop-shadow(0 6px 16px rgba(0, 0, 0, .5)); }
.df-score {
  font-family: var(--serif), Georgia, serif; font-weight: 800; line-height: .98;
  font-size: 3.5rem; letter-spacing: -.02em; color: var(--df-accent, #fff);
  text-shadow: 0 2px 18px rgba(0, 0, 0, .45);
}
.df-sub {
  margin-top: 4px; padding-top: 12px; width: 100%;
  border-top: 1px solid rgba(255, 255, 255, .14);
  font-size: .9rem; font-weight: 600; color: rgba(255, 255, 255, .74);
}
/* LIGHT WORLDS (contrast audit 2026-08-02): the glass card was authored when every app was dark —
   white-on-white the day DIORAMA/PAPER/EDITORIAL/REGISTER/APPLIANCE reached the feed. On a light
   ground the card goes opaque white with ink text. */
body[class*="ks-arch-diorama"] .df-card, body[class*="ks-arch-paper"] .df-card, body[class*="ks-arch-editorial"] .df-card, body[class*="ks-arch-register"] .df-card, body[class*="ks-arch-appliance"] .df-card {
  background: #FFFFFF; border-color: rgba(23, 21, 28, .14);
  box-shadow: 0 24px 60px rgba(23, 21, 28, .28), inset 0 1px 0 rgba(255, 255, 255, .9);
}
body[class*="ks-arch-diorama"] .df-sub, body[class*="ks-arch-paper"] .df-sub, body[class*="ks-arch-editorial"] .df-sub, body[class*="ks-arch-register"] .df-sub, body[class*="ks-arch-appliance"] .df-sub {
  color: rgba(23, 21, 28, .72); border-top-color: rgba(23, 21, 28, .12);
}
body[class*="ks-arch-diorama"] .df-score, body[class*="ks-arch-paper"] .df-score, body[class*="ks-arch-editorial"] .df-score, body[class*="ks-arch-register"] .df-score, body[class*="ks-arch-appliance"] .df-score {
  text-shadow: none;
}

body {
  font-family: var(--sans);
  color: var(--ink);
  background: var(--cream);
  display: flex;
  flex-direction: column;
  min-height: 100%;
  /* Top pad clears the HOST chrome (streak chip · daily/standings pill · search · coin jar), which
     floats over the top of every app iframe. We declare --klyp-safe-top for exactly this but the body
     was only padding ~20px — so flow-layout apps (word-guess, quizzes, tools) rendered their header
     UNDER the chrome. Use the var. Full-bleed canvas games position fixed/absolute → unaffected. */
  padding: var(--klyp-safe-top) 20px max(20px, env(safe-area-inset-bottom));
  overflow-x: hidden;
  /* tall apps stay fully reachable on small screens */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* Android: don't let the app's own body-scroll rubber-band inside the (cross-origin) feed iframe — that
     bounce reads as jank and swallows the residual swipe. iOS momentum is unaffected. */
  overscroll-behavior-y: none;
}
.k-wrap {
  width: 100%;
  max-width: 460px;
  margin: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
  text-align: center;
}
.k-emoji { font-size: 3rem; line-height: 1; }
/* SWEEP-2 LESS-IS-MORE (2026-07-28): the app's own start screen is where type gets LARGE (the
   "taste") — host chrome stays standard. Title up 1.9→2.2rem, tighter; the hook is visually capped
   at 3 lines on a narrow measure so it reads as a HOOK, not a rules paragraph (full rules belong
   in-game). Category faces via the host's ?kind= tag: game = Jakarta energy (default), toy =
   rounded friendliness (system SF-Rounded on iOS; falls back to Jakarta elsewhere — zero bytes). */
.k-h1 { font-family: var(--sans); font-weight: 800; font-size: 2.2rem; margin: 0; letter-spacing: -0.03em; line-height: 1.05; text-wrap: balance; }
html.k-kind-toy .k-h1 { font-family: ui-rounded, "SF Pro Rounded", var(--sans); letter-spacing: -0.02em; }
.k-sub { color: var(--ink-2); margin: 0 auto; font-size: 1.02rem; line-height: 1.45; max-width: 32ch; text-align: center;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.k-big { font-family: var(--sans); font-weight: 800; font-size: 3.4rem; line-height: 1; letter-spacing: -0.02em; color: var(--coral); margin: 6px 0; }
.k-label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.14em; color: var(--ink-3); }

.k-input, .k-textarea {
  width: 100%; font: inherit; color: var(--ink); background: #fff;
  border: 1px solid var(--line); border-radius: 14px; padding: 14px; outline: none;
  /* 16px keeps mobile browsers from zooming the page when a field is focused;
     scroll-margin leaves room so the SDK can scroll it clear of the keyboard. */
  font-size: 16px;
  scroll-margin: 90px;
}
.k-input:focus, .k-textarea:focus { border-color: var(--coral); }
.k-textarea { min-height: 130px; resize: none; font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 16px; }

.k-btn {
  font: inherit; font-weight: 800; border: none; cursor: pointer;
  background: var(--coral); color: #fff; padding: 14px 22px; border-radius: 999px;
  font-size: 1.02rem; transition: transform 0.12s cubic-bezier(.34,1.56,.64,1), filter 0.15s;
}
.k-btn:active { transform: scale(0.96); }
.k-btn:hover { filter: brightness(1.04); }
.k-btn.ghost { background: transparent; color: var(--ink-2); border: 1px solid var(--line); }
.k-btn.wa { background: #25D366; }
.k-btn:disabled { opacity: 0.45; cursor: default; }

.k-row { display: flex; gap: 10px; }
.k-row > * { flex: 1; }

.k-card {
  background: #fff; border: 1px solid var(--line); border-radius: 22px;
  padding: 22px 18px; box-shadow: 0 16px 40px rgba(45,42,38,0.12); text-align: center;
}
.k-watermark { font-size: 0.62rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-3); margin-top: 14px; }

/* big choice buttons (this-or-that) */
.k-choice {
  font: inherit; font-weight: 800; font-size: 1.25rem; cursor: pointer;
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: 22px; padding: 28px 16px; transition: transform 0.1s cubic-bezier(.34,1.56,.64,1), border-color 0.12s;
}
.k-choice:active { transform: scale(0.95); border-color: var(--coral); }

/* FILL-THE-BLANK without the OS keyboard (D22): answer TILES (.k-slots/.k-slot) up top + a compact tappable
   LETTER BANK (.k-bank/.k-chip) below. Tap a chip to fill the next blank; tap a filled tile to clear. Keeps
   the whole game ON SCREEN (no keyboard eating half the viewport, no buried board). A choice pad, NOT a QWERTY. */
.k-slots { display: flex; flex-wrap: wrap; justify-content: center; gap: 7px; }
.k-slot {
  width: 40px; height: 48px; display: grid; place-items: center;
  font: 800 1.4rem/1 var(--sans); color: var(--ink);
  background: #fff; border: 1.5px solid var(--line); border-radius: 12px;
}
.k-slot.on { border-color: var(--coral); box-shadow: 0 0 0 3px color-mix(in srgb, var(--coral) 22%, transparent); } /* active blank */
.k-slot.fixed { background: var(--cream-2); border-style: dashed; color: var(--ink-2); }  /* a pre-revealed letter */
.k-slot.gap { border: none; background: none; width: 14px; }                              /* a space between words */
.k-bank { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.k-chip {
  min-width: 42px; height: 46px; padding: 0 10px; font: inherit; font-weight: 800; font-size: 1.15rem;
  color: var(--ink); background: #fff; border: 1px solid var(--line); border-radius: 12px; cursor: pointer;
  box-shadow: 0 4px 12px rgba(45,42,38,0.08); transition: transform 0.1s cubic-bezier(.34,1.56,.64,1), opacity 0.12s;
}
.k-chip:active { transform: scale(0.9); }
.k-chip:disabled, .k-chip.used { opacity: 0.32; pointer-events: none; }

.k-fade { animation: kfade 0.4s ease both; }
@keyframes kfade { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.k-hidden { display: none !important; }

/* ── Deterministic play-zone contract (opt-in; premium full-bleed apps) ──────────
   A full-screen app puts ALL of its play content inside `.klyp-stage` and its HUD in
   `.klyp-hud`. The stage auto-pads the host's top + bottom chrome bands so nothing is
   ever hidden under or colliding with the host UI — one source of truth instead of each
   app guessing the safe insets. Deliberately CLASS-based (not a bare `#stage` id rule):
   several live apps already use `id="stage"` for other things, so an id rule would
   silently restyle them. Apps opt in with the class; everyone else is untouched. */
.klyp-stage {
  position: absolute; inset: 0;
  padding-top: var(--klyp-safe-top);
  padding-bottom: var(--klyp-safe-bottom);
}
/* Top-centre HUD slot — score/timer/combo live here, clear of the top chrome corners
   (host streak/daily cluster top-left, search/mute top-right). Non-interactive by
   default so taps fall through to the play surface underneath. */
/* STRUCTURAL HUD CLEARANCE (I11 "BrainFill" learning): when an app has a populated, POSITIONED hud, the
   platform reserves the hud band — stage content starts below it automatically. klyp.js adds the html class
   on load. Before this, every generated app had to hand-tune headroom and models kept getting it wrong on
   short screens (the grid crept up into the hearts/score row). Now the layer makes the mistake impossible. */
.klyp-has-hud .klyp-stage { padding-top: calc(var(--klyp-safe-top) + 54px); }

.klyp-hud {
  position: absolute; left: 0; right: 0; top: var(--klyp-safe-top);
  display: flex; justify-content: center; align-items: flex-start; gap: 34px;
  padding: 6px 18px; z-index: 5; pointer-events: none;
  font-variant-numeric: tabular-nums;
}
/* Canonical inner scroller for tall (list/quiz/result) apps that use the
   html,body{overflow:hidden} + inner-scroll pattern. 39 live apps hand-roll this and
   near-universally forget the BOTTOM safe band (audit 2026-07-03: last row hides under
   the 58px bottom chrome). Use this class on the scroller instead of hand-rolling:
   it pads both chrome bands and keeps momentum scrolling. (Prefer plain body-scroll
   for new apps — L9 — this helper is for the existing inner-scroll cohort.) */
.klyp-scroll {
  width: 100%; height: 100%;
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: none; /* Android: no rubber-band inside the iframe (reads as jank) */
  padding-top: var(--klyp-safe-top);
  padding-bottom: var(--klyp-safe-bottom);
  box-sizing: border-box;
}

/* ── NO blanket body-scroll "rescue" here — it was the regression. ───────────────────────────────────────
   We briefly forced `body{overflow-y:auto !important}` + `body > *{flex-shrink:0}` on EVERY app to rescue the
   handful of CONTENT apps that mistakenly declare `html,body{overflow:hidden}`. But that blanket override was
   worse than the disease: it forced a competing body scroller onto apps that INTENTIONALLY lock the viewport —
   games with `touch-action:none` playfields (orbit, trace-race…) and apps that own their scroll via an inner
   `#scroll`/`#main` element (cosmos, compliment-inbox…). The result on Android was the "can only scroll by
   grabbing the tiny strip at the very bottom" bug (the touch-action:none surface eats the drag everywhere
   else). The base `body{overflow-y:auto}` above is the ONLY shared scroller; apps that need it get it by NOT
   declaring their own overflow:hidden (like every working content app: this-or-that, discount, wrong-answers).
   The few content apps that wrongly locked overflow are fixed AT SOURCE (their own `overflow:hidden` →
   `overflow-x:hidden`), so games and inner-scroller apps are never touched. */

/* Un-shrink direct body children so a tall content wrapper actually overflows the fixed-height flex body and
   the base `body{overflow-y:auto}` can scroll it (without this the flex column shrinks the wrapper to fit →
   nothing overflows → dead scroll). This is HARMLESS to the apps the overflow-rescue broke: a game's
   `#wrap{flex:1}` still grows to fill (no overflow, body stays overflow:hidden → not scrollable), and an
   inner-scroller's `#scroll{height:100%}` stays exactly 100% — neither becomes body-scrollable, so there is
   no "grab from the bottom" surface. It only matters for a real content app whose wrapper is taller than the
   screen. Defers to intentional `flex:1` (non-!important). */
body > * { flex-shrink: 0; }


/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   §K · THE KLYP SURFACE KIT  — merged into this file on purpose, 2026-07-29.
   ═══════════════════════════════════════════════════════════════════════════════════════════════
   WHY IT LIVES HERE AND NOT IN ITS OWN FILE:
   the stylesheet link is emitted INDEPENDENTLY by 13 skeletons, 4 V1 templates, the rescue app, 3
   prompt exemplars, deterministicFix, and remix's ensureSharedCss — and ~20 test harnesses inline
   this file's bytes to audit layout faithfully. Adding a SECOND link would mean editing every one of
   those nodes and would guarantee a lane where the kit silently is not applied (which is exactly the
   class of bug this kit exists to end). One file ⇒ every existing app, every lane, every harness and
   every one of the 237 built-ins gets the kit with zero new wiring, one cache entry and no extra
   round-trip. `ks-` was grep-verified free before naming.
   Purely ADDITIVE: new classes, and every custom property is --ks-* namespaced. Nothing above changes.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
/*
 * KLYP SURFACE KIT v1 — the 2026 component + layout library.
 * ===========================================================
 * Host-served and PRECACHEd, so EVERY class here costs an app ZERO bytes of its 80KB budget.
 *
 * WHY THIS FILE EXISTS
 *   Our generative lane was given ~186KB of PROSE describing how to draw a button, a card, a HUD and
 *   an end screen — and then re-derived all of it, from scratch, on every build. That is the documented
 *   cause of "AI slop": a model asked to do creative direction AND implementation in one pass reverts to
 *   the median of its training data (Inter, indigo gradient, centred hero, three 1px-bordered cards).
 *   Prose cannot fix distributional convergence. PARTS can. Lovable's UI reliability comes from shadcn/ui
 *   — the model never writes a button, it arranges one. This file is that library for mini-apps.
 *
 * THE 2026 REFERENCES (researched, not invented)
 *   · iOS 26 "Liquid Glass": translucency, lensing, specular highlights, adaptive depth.
 *     THE RULE MOST PEOPLE GET WRONG, and the one that keeps this from becoming slop:
 *     glass belongs ONLY to the floating control layer above content — never to content itself.
 *   · Material 3 Expressive: SPRINGS (stiffness/damping) replace duration+easing as the motion model;
 *     an expressive scheme with visible overshoot; a shape system with morphing; "emphasized" type
 *     variants for louder editorial hierarchy.
 *
 * HARD RULES (violating any of these is what 2010 looks like)
 *   1. NO literal colour anywhere. Every value derives from --ks-bg / --ks-accent / --ks-ink.
 *   2. NO `ease`, `ease-out`, or bare cubic-bezier. Motion uses the spring tokens (real spring curves
 *      expressed as CSS linear(), which is what M3's spring model actually is).
 *   3. NO 1px grey border as the default card treatment. Depth comes from tonal surface + a specular
 *      top edge, the way real materials work.
 *   4. Numerals are tabular and optically sized. A score that reflows as it counts is a 2010 tell.
 *   5. Glass on the control layer only. Content is opaque.
 *
 * PREFIX: ks-  (grep-verified free across public/apps and globals.css)
 * Pairs with klyp-app.css (safe areas, stage, feed contract) — this file never redefines those.
 */

/* ── 0 · ANIMATABLE CUSTOM PROPERTIES ─────────────────────────────────────────────────────────
   Registering makes these interpolable, which is what lets a highlight sweep or a bloom animate
   without a repaint of the whole layer. */
@property --ks-sheen { syntax: "<percentage>"; inherits: false; initial-value: 0%; }
@property --ks-bloom { syntax: "<number>";     inherits: false; initial-value: 0; }
@property --ks-fill  { syntax: "<percentage>"; inherits: false; initial-value: 0%; }

:root {
  /* ── THEME BRIDGE ──────────────────────────────────────────────────────────────────────────────
     The codegen directive already instructs every app to define --bg / --surface / --accent /
     --accent2 / --ink / --dim. Aliasing them here means kit components theme themselves with no
     extra work — an app that follows the existing contract gets a correctly-coloured kit for free.
     DELIBERATE EXCEPTION — --ink is NOT aliased. This stylesheet defines `--ink: #1A1816` (a warm
     BLACK) for the host's cream chrome, so `var(--ink, #fff)` would resolve to dark ink on a dark
     app: invisible text on every screen. --ks-ink therefore defaults to white (correct for the
     modal dark case) and MUST be set explicitly by any light-polarity app. The publish contract
     enforces that (ks_ink_missing) rather than trusting anyone to remember. */
  --ks-bg: var(--bg, #101014);
  --ks-accent: var(--accent, #b4ff39);
  --ks-accent-2: var(--accent2, var(--ks-accent));

  /* ── SHAPE (M3 Expressive shape scale) ── */
  --ks-r-xs: 8px;
  --ks-r-sm: 12px;
  --ks-r-md: 18px;
  --ks-r-lg: 26px;
  --ks-r-xl: 36px;
  --ks-r-pill: 999px;
  /* Superellipse / squircle. corner-shape is progressive: browsers without it get the radius, which
     is a graceful downgrade rather than a broken shape. */
  --ks-squircle: superellipse(1.8);

  /* ── SPRING MOTION (M3 Expressive) ──
     A spring is not a duration+curve; it is stiffness and damping. CSS linear() expresses the actual
     sampled spring, which is why these overshoot correctly instead of faking a bounce with an
     out-back bezier. Three schemes: snap (crisp UI), bounce (expressive/celebratory), settle (calm). */
  --ks-spring-snap: linear(0, 0.32 7.3%, 0.63 14.9%, 0.86 22.6%, 1.02 30.6%, 1.07 38.9%, 1.06 47.6%,
                            1.02 56.8%, 0.99 66.4%, 0.99 76.5%, 1);
  --ks-spring-bounce: linear(0, 0.24 5.4%, 0.62 11.5%, 1.11 20.4%, 1.24 25.2%, 1.27 30.5%, 1.19 37%,
                              1.02 45.5%, 0.95 51.4%, 0.94 57.6%, 1.0 70.9%, 1.02 79.4%, 1);
  --ks-spring-settle: linear(0, 0.14 6.6%, 0.44 14.4%, 0.72 22.6%, 0.89 30%, 0.97 37.9%, 1.01 47.4%,
                              1.01 58.5%, 1);
  --ks-t-instant: 90ms;
  --ks-t-quick: 220ms;
  --ks-t-move: 420ms;
  --ks-t-grand: 720ms;

  /* ── SURFACE + MATERIAL ──
     Tonal surfaces derived from the app's own bg and accent, in OKLCH so lightness steps are
     perceptually even rather than the muddy sRGB mixes that read as "cheap gradient". */
  /* Steps are deliberately wide. The first proof render used 92/85/78 and the answer options on a
     dark pack were unreadable — a surface only 8% off the background is a rectangle, not a control.
     A tappable surface must be visibly *on* the page, not a whisper against it. */
  --ks-surface-1: color-mix(in oklch, var(--ks-bg, #101014) 88%, var(--ks-ink, #fff) 12%);
  --ks-surface-2: color-mix(in oklch, var(--ks-bg, #101014) 79%, var(--ks-ink, #fff) 21%);
  --ks-surface-3: color-mix(in oklch, var(--ks-bg, #101014) 72%, var(--ks-accent, #b4ff39) 16%);
  --ks-tint: color-mix(in oklch, var(--ks-accent, #b4ff39) 14%, transparent);
  --ks-tint-strong: color-mix(in oklch, var(--ks-accent, #b4ff39) 26%, transparent);
  --ks-hairline: color-mix(in oklch, var(--ks-ink, #fff) 12%, transparent);
  /* The specular top edge — the single detail that reads as "material" rather than "div". */
  --ks-specular: color-mix(in oklch, var(--ks-ink, #fff) 26%, transparent);
  /* Semantic danger — a token, not a literal, so an app can retheme it and the kit keeps its
     own no-literal-colour rule. oklch keeps it perceptually stable against any accent. */
  --ks-danger: var(--danger, oklch(0.63 0.23 25));

  /* ── INK ── */
  --ks-ink-1: var(--ks-ink, #fff);
  --ks-ink-2: color-mix(in oklch, var(--ks-ink, #fff) 84%, transparent);
  --ks-ink-3: color-mix(in oklch, var(--ks-ink, #fff) 62%, transparent);

  /* ── DEPTH ── adaptive, tinted by the accent, never flat black drop-shadows. */
  --ks-lift-1: 0 1px 2px color-mix(in oklch, var(--ks-bg, #000) 60%, transparent),
               0 4px 14px color-mix(in oklch, var(--ks-bg, #000) 40%, transparent);
  --ks-lift-2: 0 2px 6px color-mix(in oklch, var(--ks-bg, #000) 55%, transparent),
               0 14px 40px color-mix(in oklch, var(--ks-bg, #000) 45%, transparent);
  --ks-glow: 0 0 0 1px var(--ks-tint), 0 8px 30px color-mix(in oklch, var(--ks-accent, #b4ff39) 26%, transparent);

  /* ── TYPE ── display / title / body / label, each with an emphasized variant. */
  /* THE FONT WE ALREADY PAY FOR (2026-08-02). klyp-app.css @font-faces Plus Jakarta Sans at the top and
     the feed shell uses it via --sans (founder call 2026-07-15) — but the APP kit's default stack started
     at system-ui, so every generated app DOWNLOADED Jakarta and then rendered in Roboto (Android) / SF
     (iOS). The platform default is also the AI-slop default; this is the single biggest reason our apps
     read samey on type. Costs nothing: the face is already fetched and precached. */
  --ks-font: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --ks-font-round: ui-rounded, "SF Pro Rounded", system-ui, sans-serif;
  --ks-font-mono: ui-monospace, "SF Mono", "Roboto Mono", "Droid Sans Mono", Menlo, monospace;
  /* TYPE VOICES (2026-08-02). Founder: "do we have fixed font choices for an archetype as well?" — we
     did, but only in NAME: 11 of 17 worlds declared no font and inherited the same sans, and the two
     that did (ui-rounded / ui-serif) are iOS-ONLY keywords, so on Android — our majority device — those
     worlds silently collapsed to Roboto, i.e. the platform default, i.e. the generic look. Each genus
     below names an Android-real family so the voice survives the trip. */
  --ks-font-serif: ui-serif, "New York", Georgia, "Noto Serif", "Droid Serif", serif;
  --ks-font-cond: "Roboto Condensed", "SF Pro Display", "Helvetica Neue Condensed", ui-sans-serif, system-ui, sans-serif;
  --ks-font-display: "Plus Jakarta Sans", -apple-system, "SF Pro Display", system-ui, Roboto, sans-serif;
  --ks-step: 1.28;                    /* modular scale ratio */
  --ks-text-1: 0.78rem;
  --ks-text-2: 1rem;
  --ks-text-3: 1.28rem;
  /* FLUID DISPLAY SCALE (L-2026-08-16). These were FIXED rems, so a 43px headline was 43px whether it
     had 340px of a phone or 300px of the feed box — "Chai Compatibility" then ate two enormous lines and
     ~40% of the screen. Each app is its own document inside the frame, so `vw` here IS the app's real
     width: 372px → ~30px display, and it still opens up to the old size on a roomy screen. The founder's
     note after the clip fix was simply "still too big", which is what a fixed scale always is somewhere. */
  --ks-text-4: clamp(1.15rem, 4.9vw, 1.64rem);
  --ks-text-5: clamp(1.4rem, 6.2vw, 2.1rem);
  --ks-text-6: clamp(1.55rem, 8vw, 2.7rem);
  --ks-text-7: clamp(3rem, 15vw, 4.6rem);

  /* ── SPACE ── */
  --ks-1: 4px; --ks-2: 8px; --ks-3: 12px; --ks-4: 16px; --ks-5: 24px; --ks-6: 32px; --ks-7: 48px;
  --ks-tap: 48px;                     /* minimum tap target — above the 44px floor, on purpose */
  --ks-thumb: 34vh;                   /* the bottom band a thumb reaches without a regrip */
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   1 · MATERIAL — the floating control layer, and ONLY that layer.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
.ks-glass,
.ks-glass-thick {
  position: relative;
  background: color-mix(in oklch, var(--ks-surface-2) 62%, transparent);
  backdrop-filter: blur(18px) saturate(1.7);
  -webkit-backdrop-filter: blur(18px) saturate(1.7);
  border-radius: var(--ks-r-lg);
  corner-shape: var(--ks-squircle);
  box-shadow: inset 0 1px 0 var(--ks-specular), var(--ks-lift-1);
  isolation: isolate;
}
.ks-glass-thick { backdrop-filter: blur(30px) saturate(1.9); -webkit-backdrop-filter: blur(30px) saturate(1.9); }

/* The specular sweep — a highlight that travels the top edge on entrance. This is the "lensing"
   cue from Liquid Glass, reduced to something a 4G phone can actually paint. */
.ks-glass::after,
.ks-glass-thick::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(105deg, transparent calc(var(--ks-sheen) - 18%),
              color-mix(in oklch, var(--ks-ink-1) 16%, transparent) var(--ks-sheen),
              transparent calc(var(--ks-sheen) + 18%));
  mix-blend-mode: plus-lighter; opacity: 0.9;
}
.ks-sheen-on { animation: ks-sheen var(--ks-t-grand) var(--ks-spring-settle) 1 both; }
@keyframes ks-sheen { from { --ks-sheen: -20%; } to { --ks-sheen: 120%; } }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   2 · TYPE — hierarchy by weight AND size AND tracking, never by size alone.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
.ks-display, .ks-title, .ks-body, .ks-label { font-family: var(--ks-font); color: var(--ks-ink-1); margin: 0; }
/* No synthesized weights anywhere: a missing 800 must fall back to a REAL 700, never a smeared fake. */
body[class*="ks-arch-"] { font-synthesis-weight: none; font-synthesis-style: none; }

.ks-display {
  font-size: var(--ks-text-6); font-weight: var(--ks-weight-display, 800); line-height: 0.98;
  letter-spacing: var(--ks-track-display, -0.035em); text-transform: var(--ks-caps-display, none); text-wrap: balance;
  font-optical-sizing: auto;
  /* L-2026-08-15 — A CLIPPED HEADLINE. `text-wrap: balance` chooses nice line breaks but will NOT break
     a long WORD, so "Chai Compatibility" rendered as "Chai Compatib" and ran off a 372px screen. The
     founder caught it in a screenshot that 52/52 green matrix cells had passed, because the layout audit
     only measured CONTROLS for clipping — it measured tappability, not legibility. A title is the first
     word a creator reads and the thing they screenshot; it may wrap, it may hyphenate, it may never clip. */
  max-width: 100%; overflow-wrap: break-word; hyphens: auto;
}
.ks-display.ks-emph {                                  /* M3 "emphasized" — editorial, louder */
  font-weight: 900; letter-spacing: -0.05em; text-transform: none;
  background: linear-gradient(180deg, var(--ks-ink-1), color-mix(in oklch, var(--ks-ink-1) 62%, var(--ks-accent)));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.ks-title { font-size: var(--ks-text-4); font-weight: calc(var(--ks-weight-display, 800) - 50); letter-spacing: -0.02em; line-height: 1.12; text-wrap: balance; max-width: 100%; overflow-wrap: break-word; hyphens: auto; }
.ks-body  { font-size: var(--ks-text-2); font-weight: var(--ks-weight-body, 450); line-height: 1.45; color: var(--ks-ink-2); text-wrap: pretty; max-width: 34ch; }
.ks-label {
  font-size: var(--ks-text-1); font-weight: 650; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ks-ink-3);
}

/* THE NUMERAL — tabular, optically sized, and it does NOT reflow as it counts. */
.ks-numeral {
  font-family: var(--ks-font); font-size: var(--ks-text-7); font-weight: var(--ks-weight-display, 800);
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1, "ss01" 1;
  letter-spacing: -0.045em; line-height: 0.9; color: var(--ks-ink-1);
  display: inline-block; font-optical-sizing: auto;
}
.ks-numeral.ks-accent { color: var(--ks-accent); }
.ks-numeral.ks-bump { animation: ks-bump var(--ks-t-quick) var(--ks-spring-bounce) 1; }
@keyframes ks-bump { from { transform: scale(1); } 40% { transform: scale(1.14); } to { transform: scale(1); } }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   3 · COMPONENTS
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* — BUTTON — three intents. Press is a spring, not a scale-and-hope. */
.ks-btn {
  appearance: none; border: 0; cursor: pointer; font-family: var(--ks-font);
  /* THE NARROW-PHONE LAW. A flex/grid item defaults to `min-width:auto`, which means it REFUSES to
     shrink below its content — so a long label ("Let fate decide 🎲") computed to 471px inside a
     300px slot and overflowed the screen. Caught by probing at the REAL feed box (372×597), not the
     standalone 390×844 everything had been QA'd against. min-width:0 lets it shrink; the label wraps. */
  min-width: 0; max-width: 100%;
  min-height: var(--ks-tap); padding: 0 var(--ks-5);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--ks-2);
  font-size: var(--ks-text-3); font-weight: 700; letter-spacing: -0.01em;
  border-radius: var(--ks-r-pill); corner-shape: var(--ks-squircle);
  background: var(--ks-accent); color: var(--ks-bg);
  box-shadow: inset 0 1px 0 color-mix(in oklch, #fff 34%, transparent), var(--ks-lift-1);
  transition: transform var(--ks-t-instant) var(--ks-spring, var(--ks-spring-snap)),
              box-shadow var(--ks-t-quick) var(--ks-spring, var(--ks-spring-snap)),
              filter var(--ks-t-instant) linear;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.ks-btn:active { transform: scale(0.94); box-shadow: inset 0 1px 0 color-mix(in oklch, #fff 20%, transparent); }
.ks-btn.ks-ghost {
  background: color-mix(in oklch, var(--ks-ink-1) 8%, transparent); color: var(--ks-ink-1);
  box-shadow: inset 0 0 0 1px var(--ks-hairline);
}
.ks-btn.ks-glass-btn {
  background: color-mix(in oklch, var(--ks-surface-2) 55%, transparent); color: var(--ks-ink-1);
  backdrop-filter: blur(16px) saturate(1.6); -webkit-backdrop-filter: blur(16px) saturate(1.6);
  box-shadow: inset 0 1px 0 var(--ks-specular), var(--ks-lift-1);
}
.ks-btn.ks-xl { min-height: 62px; font-size: var(--ks-text-4); padding: 0 var(--ks-6); }
/* A disabled CTA here does not mean "forbidden" — it means "not ready yet" (the creator has not typed an
   option). It is the FIRST thing a user sees on most apps, so it must read as WAITING, not broken.
   Blanket `opacity:.4` faded label and fill together and collapsed their contrast (measured 1.1-2.5:1;
   the founder read it as "text isn't visible"). Keep the LABEL at near-full ink; mute only the FILL. */
.ks-btn:disabled {
  pointer-events: none;
  background: color-mix(in oklch, var(--ks-bg) 84%, var(--ks-ink) 9%) !important;
  background-image: none !important;
  color: color-mix(in oklch, var(--ks-ink) 94%, transparent) !important;
  -webkit-text-fill-color: color-mix(in oklch, var(--ks-ink) 94%, transparent) !important;
  border: 1px solid color-mix(in oklch, var(--ks-ink) 22%, transparent) !important;
  box-shadow: none !important;
  text-shadow: none !important;
  filter: none;
}
/* Secondary/outline controls ("+ add") painted their label in the ACCENT, which on several grounds is a
   3:1 decorative colour, not a text colour. Accent keeps the border; the label takes ink. */
.ks-btn.ks-ghost, .ks-ghost-btn, .ks-btn-2 {
  color: var(--ks-ink) !important; -webkit-text-fill-color: var(--ks-ink) !important;
}

/* — CARD — opaque content surface. NOT glass, NOT a 1px grey box. Depth via tone + specular edge. */
.ks-card {
  background: var(--ks-surface-1);
  border-radius: var(--ks-r-lg); corner-shape: var(--ks-squircle);
  padding: var(--ks-5);
  box-shadow: inset 0 1px 0 color-mix(in oklch, var(--ks-ink-1) 9%, transparent), var(--ks-lift-1);
}
.ks-card.ks-raised { background: var(--ks-surface-2); box-shadow: inset 0 1px 0 var(--ks-specular), var(--ks-lift-2); }
.ks-card.ks-tinted { background: var(--ks-surface-3); box-shadow: inset 0 1px 0 var(--ks-specular), var(--ks-glow); }

/* — OPTION — a TAPPABLE row. Distinct from .ks-card on purpose: a card is something you read, an
   option is something you hit. Conflating them is why the first proof render had answer lists that
   looked like disabled text. Full-width, thumb-height, and it moves when pressed. */
.ks-option {
  display: flex; align-items: center; gap: var(--ks-3);
  width: 100%; min-height: 58px; padding: var(--ks-3) var(--ks-4);
  min-width: 0; max-width: 100%;   /* the narrow-phone law — see .ks-btn */
  background: var(--ks-surface-2); color: var(--ks-ink-1);
  border: 0; cursor: pointer; text-align: left;
  border-radius: var(--ks-r-md); corner-shape: var(--ks-squircle);
  font-family: var(--ks-font); font-size: var(--ks-text-3); font-weight: 620; line-height: 1.25;
  box-shadow: inset 0 1px 0 color-mix(in oklch, var(--ks-ink-1) 13%, transparent),
              inset 0 0 0 1px var(--ks-hairline);
  transition: transform var(--ks-t-instant) var(--ks-spring-snap),
              background var(--ks-t-quick) linear, box-shadow var(--ks-t-quick) linear;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.ks-option:active { transform: scale(0.975); }
.ks-option.ks-right { background: var(--ks-surface-3); box-shadow: var(--ks-glow); }
.ks-option.ks-wrong { opacity: 0.5; }
.ks-option .ks-key {                                   /* the A/B/C/D affordance */
  flex: 0 0 auto; width: 30px; height: 30px; display: grid; place-items: center;
  border-radius: var(--ks-r-sm); background: color-mix(in oklch, var(--ks-ink-1) 12%, transparent);
  font-size: var(--ks-text-1); font-weight: 800; color: var(--ks-ink-2);
}

/* — FIELD / INPUT — the one component the first port revealed was missing. Verdict, picker and roast
   all take typed input, and each had hand-rolled its own bordered box with its own focus colour. */
.ks-field { display: grid; gap: var(--ks-1); text-align: left; }
.ks-field > label {
  font-size: var(--ks-text-1); font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ks-ink-3); padding-left: var(--ks-1);
}
.ks-input {
  width: 100%; min-height: var(--ks-tap); padding: 0 var(--ks-4);
  font-family: var(--ks-font); font-size: 16px; font-weight: 650;  /* 16px: never trigger iOS zoom */
  color: var(--ks-ink-1); background: color-mix(in oklch, var(--ks-ink-1) 8%, transparent);
  border: 0; border-radius: var(--ks-r-md); corner-shape: var(--ks-squircle);
  box-shadow: inset 0 0 0 1.5px var(--ks-hairline);
  -webkit-user-select: text; user-select: text; outline: none;
  transition: box-shadow var(--ks-t-quick) var(--ks-spring-snap);
}
.ks-input::placeholder { color: var(--ks-ink-3); font-weight: 550; }
.ks-input:focus { box-shadow: inset 0 0 0 2px var(--ks-accent), var(--ks-glow); }
.ks-input.ks-miss { box-shadow: inset 0 0 0 2px var(--ks-danger); animation: ks-shake 320ms var(--ks-spring-snap); }

/* — TILE — the grid unit (board cells, cards to flip). */
.ks-tile {
  aspect-ratio: 1; display: grid; place-items: center;
  background: var(--ks-surface-2); color: var(--ks-ink-1);
  border-radius: var(--ks-r-md); corner-shape: var(--ks-squircle);
  font-size: var(--ks-text-4); font-weight: 700; border: 0; cursor: pointer;
  box-shadow: inset 0 1px 0 color-mix(in oklch, var(--ks-ink-1) 10%, transparent);
  transition: transform var(--ks-t-instant) var(--ks-spring-snap), background var(--ks-t-quick) linear;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.ks-tile:active { transform: scale(0.93); }
.ks-tile.ks-on { background: var(--ks-accent); color: var(--ks-bg); box-shadow: var(--ks-glow); }
.ks-tile.ks-off { opacity: 0.34; pointer-events: none; }

/* — CHOICE ROW — the this-or-that primitive, sized for the thumb arc. */
.ks-choice {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--ks-2);
  flex: 1; min-height: 132px; padding: var(--ks-4);
  min-width: 0; max-width: 100%;   /* the narrow-phone law — see .ks-btn */
  background: var(--ks-surface-2); color: var(--ks-ink-1); border: 0; cursor: pointer;
  border-radius: var(--ks-r-lg); corner-shape: var(--ks-squircle);
  font-family: var(--ks-font); font-size: var(--ks-text-3); font-weight: 700; text-align: center;
  box-shadow: inset 0 1px 0 color-mix(in oklch, var(--ks-ink-1) 10%, transparent), var(--ks-lift-1);
  transition: transform var(--ks-t-quick) var(--ks-spring-bounce), box-shadow var(--ks-t-quick) linear;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.ks-choice:active { transform: scale(0.96); }
.ks-choice.ks-picked { box-shadow: var(--ks-glow); background: var(--ks-surface-3); }

/* — HUD — floating control layer. Glass lives HERE and nowhere else. */
.ks-hud {
  position: fixed; top: calc(var(--klyp-safe-top, 0px) + var(--ks-3)); left: 50%; translate: -50% 0;
  z-index: 40; display: flex; align-items: center; gap: var(--ks-4);
  padding: var(--ks-2) var(--ks-4); min-height: 42px;
  border-radius: var(--ks-r-pill);
  background: color-mix(in oklch, var(--ks-surface-2) 58%, transparent);
  backdrop-filter: blur(20px) saturate(1.8); -webkit-backdrop-filter: blur(20px) saturate(1.8);
  box-shadow: inset 0 1px 0 var(--ks-specular), var(--ks-lift-1);
  font-variant-numeric: tabular-nums;
}
.ks-hud-stat { display: flex; align-items: baseline; gap: var(--ks-1); }
/* A stat with no value yet hides itself, label and all — an orphaned "STREAK" next to nothing reads
   as a bug. Restores automatically the moment the value lands. */
.ks-hud-stat:has(> b:empty) { display: none; }
.ks-hud-stat b { font-size: var(--ks-text-3); font-weight: 800; color: var(--ks-ink-1); }
.ks-hud-stat span { font-size: 0.68rem; font-weight: 650; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ks-ink-3); }

/* — METER — the one pressure indicator. Exactly one per app. */
.ks-meter {
  height: 6px; width: 100%; border-radius: var(--ks-r-pill); overflow: hidden;
  background: color-mix(in oklch, var(--ks-ink-1) 12%, transparent);
}
.ks-meter > i {
  display: block; height: 100%; width: var(--ks-fill, 100%);
  background: linear-gradient(90deg, var(--ks-accent), var(--ks-accent-2, var(--ks-accent)));
  border-radius: inherit; transition: width var(--ks-t-quick) linear;
}
.ks-meter.ks-danger > i { background: color-mix(in oklch, var(--ks-accent) 45%, var(--ks-danger)); }

/* — RING — the circular timer/progress. */
.ks-ring { width: 56px; aspect-ratio: 1; display: grid; place-items: center; position: relative; }
.ks-ring::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(var(--ks-accent) var(--ks-fill, 0%), color-mix(in oklch, var(--ks-ink-1) 12%, transparent) 0);
  mask: radial-gradient(farthest-side, transparent calc(100% - 5px), #000 calc(100% - 4px));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 5px), #000 calc(100% - 4px));
}
.ks-ring > b { font-size: var(--ks-text-2); font-weight: 800; font-variant-numeric: tabular-nums; }

/* — CHIP — */
.ks-chip {
  display: inline-flex; align-items: center; gap: var(--ks-1);
  min-height: 44px; min-width: 44px; padding: 0 var(--ks-4); border: 0; cursor: pointer;
  min-width: 0; max-width: 100%;   /* the narrow-phone law — see .ks-btn */
  border-radius: var(--ks-r-pill);
  background: color-mix(in oklch, var(--ks-ink-1) 9%, transparent); color: var(--ks-ink-1);
  font-family: var(--ks-font); font-size: var(--ks-text-2); font-weight: 650;
  transition: transform var(--ks-t-instant) var(--ks-spring-snap);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.ks-chip:active { transform: scale(0.9); }
.ks-chip.ks-on { background: var(--ks-accent); color: var(--ks-bg); }

/* — BADGE / PILL — */
.ks-badge {
  display: inline-flex; align-items: center; gap: var(--ks-1);
  /* A badge hugs its text. Inside a grid/flex slot the default stretch turned it into a full-width
     bar in the first proof — a pill that spans the screen is not a pill. */
  width: fit-content; justify-self: start; align-self: center; flex: 0 0 auto;
  padding: 3px var(--ks-3); border-radius: var(--ks-r-pill);
  background: var(--ks-tint); color: var(--ks-accent);
  font-size: var(--ks-text-1); font-weight: 700; letter-spacing: 0.04em;
}

/* — SHEET — the bottom overlay. Control layer, so: glass. */
.ks-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  padding: var(--ks-5) var(--ks-5) calc(var(--klyp-safe-bottom, 0px) + var(--ks-5));
  border-radius: var(--ks-r-xl) var(--ks-r-xl) 0 0;
  background: color-mix(in oklch, var(--ks-surface-2) 78%, transparent);
  backdrop-filter: blur(30px) saturate(1.8); -webkit-backdrop-filter: blur(30px) saturate(1.8);
  box-shadow: inset 0 1px 0 var(--ks-specular), 0 -20px 60px color-mix(in oklch, var(--ks-bg) 55%, transparent);
  animation: ks-rise var(--ks-t-move) var(--ks-spring-snap) both;
}
@keyframes ks-rise { from { transform: translateY(101%); } to { transform: translateY(0); } }

/* — PAYOFF / END CARD — the screenshot moment. Content, so opaque; the flourish is the bloom. */
.ks-payoff {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: var(--ks-3);
  padding: var(--ks-6) var(--ks-5); text-align: center;
  background: var(--ks-surface-1);
  border-radius: var(--ks-r-xl); corner-shape: var(--ks-squircle);
  box-shadow: inset 0 1px 0 var(--ks-specular), var(--ks-lift-2);
  overflow: hidden;
  animation: ks-payoff-in var(--ks-t-grand) var(--ks-spring-bounce) both;
}
.ks-payoff::before {                                   /* the accent bloom behind the number */
  content: ""; position: absolute; inset: -40% -20% auto -20%; height: 76%;
  background: radial-gradient(ellipse at 50% 0%, var(--ks-tint-strong), transparent 68%);
  pointer-events: none;
}
.ks-payoff > * { position: relative; }
@keyframes ks-payoff-in { from { transform: scale(0.9) translateY(14px); opacity: 0; } to { transform: none; opacity: 1; } }

/* — TOAST — */
.ks-toast {
  position: fixed; left: 50%; bottom: calc(var(--klyp-safe-bottom, 0px) + var(--ks-7)); translate: -50% 0;
  z-index: 70; padding: var(--ks-3) var(--ks-5); border-radius: var(--ks-r-pill);
  background: color-mix(in oklch, var(--ks-surface-2) 72%, transparent);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  box-shadow: inset 0 1px 0 var(--ks-specular), var(--ks-lift-1);
  font-size: var(--ks-text-2); font-weight: 650; color: var(--ks-ink-1);
  animation: ks-rise var(--ks-t-quick) var(--ks-spring-snap) both;
}

/* — RAIL — horizontal scroller (edge-to-edge, snapping). */
.ks-rail-x {
  display: flex; gap: var(--ks-3); overflow-x: auto; scroll-snap-type: x mandatory;
  padding-inline: var(--ks-4); margin-inline: calc(var(--ks-4) * -1);
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.ks-rail-x::-webkit-scrollbar { display: none; }
.ks-rail-x > * { scroll-snap-align: center; flex: 0 0 auto; }

/* — SLOT / BANK (tap-to-answer, no OS keyboard) — */
.ks-slots { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--ks-2); }
.ks-slot {
  min-width: 38px; height: 48px; display: grid; place-items: center;
  border-radius: var(--ks-r-sm); corner-shape: var(--ks-squircle);
  background: color-mix(in oklch, var(--ks-ink-1) 7%, transparent);
  box-shadow: inset 0 0 0 1px var(--ks-hairline);
  font-size: var(--ks-text-3); font-weight: 750; font-variant-numeric: tabular-nums;
}
.ks-slot.ks-on { box-shadow: var(--ks-glow); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   4 · LAYOUT TEMPLATES — the "many templates".
   Each is a named arrangement of SLOTS. An app marks regions with data-ks="hud|board|primary|
   secondary|payoff|caption" and the template positions them. Swapping the template class is the
   whole change — no markup edit, no model call, and no way to break the logic.
   Every template is portrait-first and reserves the feed's safe bands.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
/* THE SPINE — flex column, not a fixed grid.
   Learned from the first proof render: a grid with a hard row count breaks the moment a slot is
   absent or a slot (the HUD) is position:fixed and therefore out of flow. Every frame that used
   `grid-template-rows: auto 1fr auto` with a fixed HUD produced BOTH of our own audit's named
   defects at once — `top-collision` (board painted under the floating HUD) and
   `layout-bad:dead-bottom` (content packed to the top, a third of the screen empty).
   A flex column with a growing board slot cannot produce either: absent slots simply do not exist,
   and the board always absorbs the free space. */
[class*="ks-lay-"] {
  display: flex; flex-direction: column; box-sizing: border-box;
  /* COOPERATE WITH `body`, DON'T RE-SOLVE IT. body (above) is ALREADY a flex column that has applied
     --klyp-safe-top / --klyp-safe-bottom as padding. The first port used `height:100dvh` PLUS the safe
     vars again, so the template was inset twice and hung past the screen — the double-safe-top void,
     measured at 342x450 as a start screen whose midpoint sat at 319 instead of 225.
     `flex:1` fills the body's content box exactly, at any viewport, with no second inset and no dvh. */
  flex: 1 1 auto; min-height: 0; width: 100%;
  padding: 0 var(--ks-4);
  gap: var(--ks-4); align-items: center;
  container-type: inline-size;
}
/* HUD CLEARANCE — a floating HUD is out of flow, so the layout must reserve its band or the first
   in-flow slot paints underneath it. Structural, not advisory. */
[class*="ks-lay-"]:has(> .ks-hud), [class*="ks-lay-"]:has(.ks-hud) {
  padding-top: 62px;
}
[class*="ks-lay-"] > [data-ks] { width: 100%; max-width: 520px; flex: 0 1 auto; min-height: 0; }
/* The board is the elastic slot: it takes the slack so nothing packs to the top. */
[class*="ks-lay-"] > [data-ks="board"] { flex: 1 1 auto; min-height: 0; display: grid; place-content: center;
  /* The track must not size to max-content, or a long child (a CTA label) widens it past the slot and
     off the screen — `min-width:0` on the child cannot save it once the TRACK is the thing overflowing. */
  grid-template-columns: minmax(0, 1fr); }
/* Belt and braces: nothing inside a slot may exceed it, whatever the slot's display type. */
[class*="ks-lay-"] > [data-ks] > * { max-width: 100%; }
/* START-SCREEN TAGLINE CLAMP (2026-08-04, founder: "text overlapping & too much text"). The board slot
   has min-height:0 so the SLOT shrinks — but its text does not, and a long model-written tagline paints
   straight over the primary band (badge + CTA). Measured on a real audit build at 342x450: a 4-line
   tagline collided with the params badge. Two lines is the reading budget of a start screen; the sheet
   is host-served, so every live app heals on next load. Scoped to #start ONLY — story/quiz reading text
   in #play uses the same .ks-body class and must never clamp. */
#start [data-ks="board"] .ks-body {
  /* Standard `line-clamp` computes display as flow-root (CSS Overflow 4) — the -webkit-box display
     games are unnecessary. What DID slice glyphs mid-line was the board grid squeezing this element to
     ~1.4 lines; min-height pins the box to exactly the two lines the clamp promises. */
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; line-clamp:2;
  overflow:hidden; min-height:calc(2 * 1.45em); max-height:calc(2 * 1.45em);
}
[class*="ks-lay-"] > [data-ks="caption"] { color: var(--ks-ink-3); }
/* Every slot a template declares must be POSITIONED here, or an app marks a region the stylesheet
   ignores and it silently falls back to flow order. `hud` (in-flow variant — distinct from the fixed
   .ks-hud control bar) and `secondary` were declared by templates with no rule; the coverage test
   caught it before any app could. */
[class*="ks-lay-"] > [data-ks="hud"] { display: grid; gap: var(--ks-1); justify-items: center; text-align: center; }
[class*="ks-lay-"] > [data-ks="secondary"] { display: grid; gap: var(--ks-2); }
/* The primary slot is the action band — it lives in the thumb arc by default. */
[class*="ks-lay-"] > [data-ks="primary"] { display: grid; gap: var(--ks-3); }
/* SLOT-IMPLIED LAYOUT: a slot must lay itself out correctly from the attribute alone. The proof
   render caught the payoff slot flowing its label and numeral INLINE because the demo carried the
   data-ks but not the .ks-payoff class. A contract that only works when you remember a second class
   is a contract that will be got wrong — by a creator, by a model, and by me. */
[class*="ks-lay-"] > [data-ks="payoff"] {
  display: flex; flex-direction: column; align-items: center; gap: var(--ks-3); text-align: center;
}

/* 1 — HERO STACK: one enormous numeral, everything else deferential. Reflex, aim, timing. */
/* ═══ SURFACE ARCHETYPES (2026-07-31 · SURFACE_ARCHETYPES.md · Phase A: PAPER + CONSOLE) ═══════════
   The sameness fix: the SUBJECT dictates the SURFACE. An archetype re-grounds the whole app through the
   SAME tokens every kit component already reads — so contrast, material and components stay coherent and
   the composition gates keep holding. Keyed on a body class stamped by the engine (new builds only).

   PAPER — from String-a-Story: typewriter mono on warm paper, highlight-marked tagline, flat squared
   actions. The engine's first LIGHT world. */
body[class*="ks-arch-paper"] {
  --ks-bg:#F3F1EA; --ks-ink:#22201C; --ks-accent:#B3372B; --ks-accent-2:#1F6FB2;
  --bg:#F3F1EA; --ink:#22201C; --acc:#B3372B; --accent:#B3372B; --accent2:#1F6FB2;
  --dim:color-mix(in oklch,#22201C 55%,transparent);
  --ks-font:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --ks-weight-display:700; --ks-caps-display:none; --ks-track-display:0;
  /* the archetype's MATERIAL colours, declared as tokens so components stay literal-free (the kit law) */
  --ksa-mark:#E7A5A0; --ksa-cta:#F2D479; --ksa-edge:#22201C;
  background:var(--ks-bg); color:var(--ks-ink);
}
html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-paper"]::before, html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-paper"]::after { display:none; } /* no grain/vignette — paper IS the material */
body[class*="ks-arch-paper"] .ks-badge { background:transparent; border:none; color:var(--dim); letter-spacing:.12em; text-transform:uppercase; font-size:.72rem; }
body[class*="ks-arch-paper"] main#start .ks-body,
body[class*="ks-arch-paper"] main#start p { background:var(--ksa-mark); padding:2px 6px; box-decoration-break:clone; -webkit-box-decoration-break:clone; line-height:1.9; }
/* The pack's display treatment (gradient text-fill, tinted glows, translucent dims) was authored for
   DARK grounds and renders near-invisible on paper — ink beats decoration here, the typewriter way.
   ALL screens, not just #start: the founder's first real PAPER build shipped with a pale end-screen
   headline and a 55%-alpha vibe line on cream ("white on white, not visible"). Ink is a body-wide law. */
body[class*="ks-arch-paper"] :is(h1, h2, h3, .ks-display, .ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink);
  text-shadow:none; filter:none;
}
body[class*="ks-arch-paper"] { --dim:color-mix(in srgb, var(--ksa-edge) 64%, var(--ks-bg)); }
body[class*="ks-arch-paper"] :is(.vibe, .count, .k-sub, .ks-body, .msg, p) { color:var(--ksa-edge); }
body[class*="ks-arch-paper"] main#start .ks-body,
body[class*="ks-arch-paper"] main#start p { color:var(--ksa-edge); }
body[class*="ks-arch-paper"] .ks-btn { border-radius:0; border:2px solid var(--ksa-edge); background:var(--ksa-cta); color:var(--ksa-edge); font-weight:700; box-shadow:3px 3px 0 var(--ksa-edge); }
body[class*="ks-arch-paper"] .ks-btn:active { transform:translate(2px,2px); box-shadow:1px 1px 0 var(--ksa-edge); }

/* CONSOLE — from Morse Code Pal / Drum Machine: instrument panel. Mono CAPS, tick-bar labels, hairline
   wells, ONE signal colour doing all the talking. */
body[class*="ks-arch-console"] {
  --ks-bg:#0B1220; --ks-ink:#C7D3E4; --ks-accent:#FF6B4A; --ks-accent-2:#7AD7FF;
  --bg:#0B1220; --ink:#C7D3E4; --acc:#FF6B4A; --accent:#FF6B4A; --accent2:#7AD7FF;
  --dim:color-mix(in oklch,#C7D3E4 55%,transparent);
  --ks-font:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --ks-weight-display:700; --ks-caps-display:uppercase; --ks-track-display:.14em;
  --ksa-scan:rgba(140,170,210,.05);
  background:var(--ks-bg); color:var(--ks-ink);
  background-image:repeating-linear-gradient(0deg,transparent 0 23px,var(--ksa-scan) 23px 24px);
}
body[class*="ks-arch-console"] .ks-badge {
  background:transparent; border:none; color:var(--ks-ink); font-size:.68rem; letter-spacing:.24em;
  text-transform:uppercase; display:inline-flex; align-items:center; gap:8px;
}
body[class*="ks-arch-console"] .ks-badge::before { content:""; width:3px; height:12px; background:var(--ks-accent); }
body[class*="ks-arch-console"] .ks-display { letter-spacing:.06em; }
body[class*="ks-arch-console"] .ks-btn {
  border-radius:10px; background:transparent; border:1px solid var(--ks-accent); color:var(--ks-accent);
  letter-spacing:.2em; text-transform:uppercase; font-weight:700;
}
body[class*="ks-arch-console"] .ks-btn:active { background:color-mix(in oklch,var(--ks-accent) 18%,transparent); }

/* POSTER — from Vector Run: flat saturated ground + blueprint grid, chunky OUTLINED caps, sticker-fat
   buttons. The arcade voice of our own usage leaders (tap-speed, penalty, knife-hit…). */
body[class*="ks-arch-poster"] {
  --ks-bg:#1B54C4; --ks-ink:#FFFFFF; --ks-accent:#FFD400; --ks-accent-2:#3ECF6A;
  --bg:#1B54C4; --ink:#FFFFFF; --acc:#FFD400; --accent:#FFD400; --accent2:#3ECF6A;
  --dim:color-mix(in oklch,#FFFFFF 62%,transparent);
  --ksa-edge:#07162E; --ksa-grid:rgba(255,255,255,.10);
  --ks-weight-display:900; --ks-caps-display:uppercase; --ks-track-display:.1em;
  background:var(--ks-bg); color:var(--ks-ink);
  background-image:linear-gradient(var(--ksa-grid) 1px,transparent 1px),linear-gradient(90deg,var(--ksa-grid) 1px,transparent 1px);
  background-size:96px 96px;
}
html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-poster"]::before, html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-poster"]::after { display:none; } /* the grid IS the field */
body[class*="ks-arch-poster"] .ks-display, body[class*="ks-arch-poster"] h1 {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-accent);
  -webkit-text-stroke:2px var(--ksa-edge); paint-order:stroke fill;
  text-shadow:3px 3px 0 var(--ksa-edge); letter-spacing:.06em;
}
body[class*="ks-arch-poster"] .ks-badge { background:transparent; border:none; color:var(--ks-accent); letter-spacing:.22em; text-transform:uppercase; font-weight:800; font-size:.7rem; text-shadow:1px 1px 0 var(--ksa-edge); }
body[class*="ks-arch-poster"] .ks-btn {
  background:var(--ks-accent-2); color:var(--ksa-edge); border:3px solid var(--ksa-edge); border-radius:16px;
  font-weight:900; text-transform:uppercase; letter-spacing:.08em; box-shadow:0 5px 0 var(--ksa-edge);
}
body[class*="ks-arch-poster"] .ks-btn:active { transform:translateY(3px); box-shadow:0 2px 0 var(--ksa-edge); }

/* VOID — from Neon Mix: a pure black canvas where the TUTORIAL TEXT is the start screen and everything
   that paints, glows. For our precision/canvas toys (perfect-circle, steady-hand, fluids). */
body[class*="ks-arch-void"] {
  --ks-bg:#050507; --ks-ink:#B8C0CA; --ks-accent:#FF3B30; --ks-accent-2:#FFD60A;
  --bg:#050507; --ink:#B8C0CA; --acc:#FF3B30; --accent:#FF3B30; --accent2:#FFD60A;
  --dim:color-mix(in oklch,#B8C0CA 45%,transparent);
  --ks-weight-display:600; --ks-caps-display:uppercase; --ks-track-display:.22em;
  background:var(--ks-bg); color:var(--ks-ink);
}
html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-void"]::before, html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-void"]::after { display:none; } /* the void is the material */
/* VOID's title deliberately recedes so the glowing signal owns the screen — but at --dim (45% ink) it
   measured 2.6:1 and rendered DIMMER THAN ITS OWN SUBTITLE (founder: "at many places I see issues in
   seeing the content"). --ks-ink-2 keeps it understated at 72% while restoring the hierarchy. */
body[class*="ks-arch-void"] .ks-display, body[class*="ks-arch-void"] h1 {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink-1);
  font-size:var(--ks-text-5) !important; letter-spacing:.22em; opacity:.92;
}
body[class*="ks-arch-void"] .ks-badge { background:transparent; border:none; color:var(--dim); letter-spacing:.3em; font-size:.64rem; }
body[class*="ks-arch-void"] .ks-btn {
  background:transparent; color:var(--ks-accent); border:2px solid var(--ks-accent); border-radius:999px;
  box-shadow:0 0 14px color-mix(in oklch,var(--ks-accent) 55%,transparent), inset 0 0 10px color-mix(in oklch,var(--ks-accent) 25%,transparent);
  letter-spacing:.18em; text-transform:uppercase; font-weight:700;
}

/* REGISTER — the ledger/sarkari-form world (coverage audit: 21 tool apps had NO archetype). Railway
   ticket, bank challan: every Indian user has held this document. Stamped header, ruled rows, tabular
   mono numbers, one ink + one stamp red. LIGHT. */
body[class*="ks-arch-register"] {
  --ks-bg:#F7F6F1; --ks-ink:#26231E; --ks-accent:#C03A2B; --ks-accent-2:#1E5A8A;
  --bg:#F7F6F1; --ink:#26231E; --acc:#C03A2B; --accent:#C03A2B; --accent2:#1E5A8A;
  --ksa-edge:#26231E; --ksa-rule:rgba(38,35,30,.14);
  --dim:color-mix(in srgb,#26231E 60%,#F7F6F1);
  --ks-font:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --ks-weight-display:700; --ks-caps-display:uppercase; --ks-track-display:.1em;
  background:var(--ks-bg); color:var(--ks-ink);
  background-image:repeating-linear-gradient(0deg,transparent 0 27px,var(--ksa-rule) 27px 28px);
  font-variant-numeric:tabular-nums;
}
html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-register"]::before, html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-register"]::after { display:none; }
body[class*="ks-arch-register"] :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink); text-shadow:none;
  border-top:2px solid var(--ksa-edge); border-bottom:2px solid var(--ksa-edge); padding:6px 0; display:inline-block;
}
body[class*="ks-arch-register"] :is(.vibe,.count,.k-sub,.ks-body,p) { color:var(--ksa-edge); }
body[class*="ks-arch-register"] .ks-badge {
  background:transparent; border:1.5px solid var(--ks-accent); color:var(--ks-accent); border-radius:3px;
  letter-spacing:.18em; text-transform:uppercase; font-size:.66rem; padding:4px 10px; transform:rotate(-1.2deg);
}
body[class*="ks-arch-register"] .ks-btn {
  border-radius:4px; background:transparent; border:2px solid var(--ks-accent); color:var(--ks-accent);
  text-transform:uppercase; letter-spacing:.14em; font-weight:700; box-shadow:none;
}
body[class*="ks-arch-register"] .ks-btn:active { background:color-mix(in srgb,var(--ks-accent) 12%,transparent); }

/* APPLIANCE — the LIGHT half of the founder's Drum Machine reference (30 generator apps were naked).
   Cream plastic hardware: extruded panels, a chunky dispense button. A generator IS a machine. */
body[class*="ks-arch-appliance"] {
  --ks-bg:#EDEAE3; --ks-ink:#2B2823; --ks-accent:#F08A24; --ks-accent-2:#3D8F7A;
  --bg:#EDEAE3; --ink:#2B2823; --acc:#F08A24; --accent:#F08A24; --accent2:#3D8F7A;
  --ksa-hi:rgba(255,255,255,.85); --ksa-lo:rgba(43,40,35,.16); --ksa-btn-ink:#FFFFFF;
  --dim:color-mix(in srgb,#2B2823 58%,#EDEAE3);
  --ks-weight-display:800; --ks-caps-display:none; --ks-track-display:-.01em;
  background:var(--ks-bg); color:var(--ks-ink);
}
html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-appliance"]::before, html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-appliance"]::after { display:none; }
body[class*="ks-arch-appliance"] :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink); text-shadow:none;
}
body[class*="ks-arch-appliance"] :is(.vibe,.count,.k-sub,.ks-body,p) { color:var(--dim); }
body[class*="ks-arch-appliance"] .ks-badge {
  background:var(--ks-bg); border:none; color:var(--dim); border-radius:8px; font-size:.68rem;
  letter-spacing:.14em; text-transform:uppercase; padding:5px 12px;
  box-shadow:inset 2px 2px 5px var(--ksa-lo), inset -2px -2px 5px var(--ksa-hi);
}
body[class*="ks-arch-appliance"] .ks-btn {
  background:var(--ks-accent); color:var(--ksa-btn-ink); border:none; border-radius:14px; font-weight:800;
  box-shadow:0 5px 0 color-mix(in srgb,var(--ks-accent) 55%,var(--ks-ink)), 0 8px 16px var(--ksa-lo), inset 0 1px 0 var(--ksa-hi);
}
body[class*="ks-arch-appliance"] .ks-btn:active { transform:translateY(4px); box-shadow:0 1px 0 color-mix(in srgb,var(--ks-accent) 55%,var(--ks-ink)); }

/* STADIUM — floodlit pitch, jersey numerals, flipboard scoreboard. gully-cricket is usage #6; POSTER
   had the arcade energy but not the SPORTS identity. */
body[class*="ks-arch-stadium"] {
  --ks-bg:#0E3B24; --ks-ink:#F2F7F0; --ks-accent:#F2E641; --ks-accent-2:#FF8A3C;
  --bg:#0E3B24; --ink:#F2F7F0; --acc:#F2E641; --accent:#F2E641; --accent2:#FF8A3C;
  --ksa-chalk:rgba(242,247,240,.28); --ksa-slab:#092417; --ksa-flood:rgba(242,230,65,.10);
  --dim:color-mix(in srgb,#F2F7F0 62%,transparent);
  --ks-weight-display:900; --ks-caps-display:uppercase; --ks-track-display:.04em;
  background:var(--ks-bg); color:var(--ks-ink);
  background-image:radial-gradient(120% 55% at 50% -8%, var(--ksa-flood), transparent 60%),
    repeating-linear-gradient(90deg, transparent 0 46px, rgba(0,0,0,.10) 46px 92px);
}
body[class*="ks-arch-stadium"] :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink);
  font-style:italic; letter-spacing:.02em; text-shadow:2px 2px 0 rgba(0,0,0,.35);
}
body[class*="ks-arch-stadium"] .ks-badge {
  background:var(--ksa-slab); border:none; color:var(--ks-accent); border-radius:6px;
  font-variant-numeric:tabular-nums; letter-spacing:.2em; text-transform:uppercase; font-size:.66rem; padding:6px 12px;
  box-shadow:inset 0 -2px 0 rgba(0,0,0,.5);
}
body[class*="ks-arch-stadium"] [data-ks="board"] { border:2px dashed var(--ksa-chalk); border-radius:18px; }
body[class*="ks-arch-stadium"] .ks-btn {
  background:var(--ks-accent); color:var(--ksa-slab); border:none; border-radius:12px; font-weight:900;
  font-style:italic; text-transform:uppercase; letter-spacing:.06em; box-shadow:0 4px 0 rgba(0,0,0,.4);
}
body[class*="ks-arch-stadium"] .ks-btn:active { transform:translateY(3px); box-shadow:0 1px 0 rgba(0,0,0,.4); }

/* CARNIVAL — the mela stall: bunting, a ticket-stub badge, stall-stripe CTA. compliment-roulette (the
   founder's worst remix) failed hardest for lack of exactly this world. */
body[class*="ks-arch-carnival"] {
  --ks-bg:#7A1E2C; --ks-ink:#FFF4E4; --ks-accent:#FFC93C; --ks-accent-2:#4FB0A5;
  --bg:#7A1E2C; --ink:#FFF4E4; --acc:#FFC93C; --accent:#FFC93C; --accent2:#4FB0A5;
  --ksa-stripe:rgba(255,244,228,.16); --ksa-edge:#40101A;
  --dim:color-mix(in srgb,#FFF4E4 66%,transparent);
  --ks-weight-display:800; --ks-caps-display:none; --ks-track-display:0;
  background:var(--ks-bg); color:var(--ks-ink);
  background-image:radial-gradient(90% 40% at 50% 108%, rgba(0,0,0,.28), transparent 60%),
    repeating-linear-gradient(45deg, transparent 0 26px, var(--ksa-stripe) 26px 27px);
}
body[class*="ks-arch-carnival"] :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-accent);
  text-shadow:0 2px 0 var(--ksa-edge);
}
body[class*="ks-arch-carnival"] .ks-badge {
  background:transparent; color:var(--ks-ink); border:1.5px dashed var(--ks-ink); border-radius:2px;
  letter-spacing:.16em; text-transform:uppercase; font-size:.66rem; padding:5px 14px;
}
body[class*="ks-arch-carnival"] .ks-btn {
  background:var(--ks-accent); color:var(--ksa-edge); border:2px solid var(--ksa-edge); border-radius:999px;
  font-weight:900; box-shadow:0 4px 0 var(--ksa-edge);
}
body[class*="ks-arch-carnival"] .ks-btn:active { transform:translateY(3px); box-shadow:0 1px 0 var(--ksa-edge); }

/* DIORAMA — from Terrarium Trap: near-white illustrated calm, tiny living things, soft rounded chrome.
   The gentle world: breathing apps, slow toys, small sims. LIGHT #4. */
body[class*="ks-arch-diorama"] {
  --ks-bg:#F6F5F1; --ks-ink:#33302A; --ks-accent:#3E7C4F; --ks-accent-2:#C97B4A;
  --bg:#F6F5F1; --ink:#33302A; --acc:#3E7C4F; --accent:#3E7C4F; --accent2:#C97B4A;
  --ksa-soil:#7A5C43; --ksa-card:#FFFFFF;
  --dim:color-mix(in srgb,#33302A 55%,#F6F5F1);
  --ks-weight-display:700; --ks-caps-display:none; --ks-track-display:-.01em;
  background:var(--ks-bg); color:var(--ks-ink);
  background-image:linear-gradient(0deg, color-mix(in srgb, var(--ksa-soil) 22%, transparent) 0 6px, transparent 6px);
  background-repeat:no-repeat; background-position:bottom;
}
body[class*="ks-arch-diorama"] :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink); text-shadow:none;
}
body[class*="ks-arch-diorama"] :is(.vibe,.count,.k-sub,.ks-body,p) { color:var(--dim); }
body[class*="ks-arch-diorama"] .ks-badge { background:var(--ksa-card); border:1px solid color-mix(in srgb,var(--ks-ink) 12%,transparent); color:var(--dim); border-radius:999px; font-size:.7rem; padding:5px 12px; box-shadow:0 2px 8px color-mix(in srgb,var(--ks-ink) 8%,transparent); }
body[class*="ks-arch-diorama"] .ks-btn { background:var(--ks-accent); color:var(--ksa-card); border:none; border-radius:999px; font-weight:700; box-shadow:0 3px 10px color-mix(in srgb,var(--ks-accent) 35%,transparent); }

/* OBSERVATORY — from Gravity Sandbox: deep space, one glowing body, watch it evolve. Subject-bound to the
   cosmos. */
body[class*="ks-arch-observatory"] {
  --ks-bg:#05060C; --ks-ink:#D8DEF0; --ks-accent:#F5B940; --ks-accent-2:#8A7CFF;
  --bg:#05060C; --ink:#D8DEF0; --acc:#F5B940; --accent:#F5B940; --accent2:#8A7CFF;
  --ksa-star:rgba(216,222,240,.5);
  --dim:color-mix(in srgb,#D8DEF0 55%,transparent);
  --ks-weight-display:500; --ks-caps-display:uppercase; --ks-track-display:.2em;
  background:var(--ks-bg); color:var(--ks-ink);
  background-image:radial-gradient(1.5px 1.5px at 18% 22%, var(--ksa-star) 50%, transparent 51%),
    radial-gradient(1px 1px at 72% 12%, var(--ksa-star) 50%, transparent 51%),
    radial-gradient(1.2px 1.2px at 84% 58%, var(--ksa-star) 50%, transparent 51%),
    radial-gradient(1px 1px at 34% 76%, var(--ksa-star) 50%, transparent 51%),
    radial-gradient(1.4px 1.4px at 55% 38%, var(--ksa-star) 50%, transparent 51%);
}
body[class*="ks-arch-observatory"] :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink);
  letter-spacing:.12em; text-shadow:0 0 24px color-mix(in srgb,var(--ks-accent) 30%,transparent);
}
body[class*="ks-arch-observatory"] .ks-badge { background:transparent; border:1px solid color-mix(in srgb,var(--ks-ink) 25%,transparent); color:var(--dim); border-radius:999px; letter-spacing:.24em; text-transform:uppercase; font-size:.62rem; padding:5px 12px; }
body[class*="ks-arch-observatory"] .ks-btn { background:transparent; color:var(--ks-accent); border:1.5px solid var(--ks-accent); border-radius:999px; letter-spacing:.16em; text-transform:uppercase; font-weight:600; box-shadow:0 0 18px color-mix(in srgb,var(--ks-accent) 35%,transparent); }

/* FELT — from UNO Showdown: the game table. Deep felt, chunky white-stroked objects, a chip badge, a
   white pill CTA with real weight. A table between two people is the exact metaphor for 2-player. */
body[class*="ks-arch-felt"] {
  --ks-bg:#0D3529; --ks-ink:#EDF6F0; --ks-accent:#E9A519; --ks-accent-2:#B3372B;
  --bg:#0D3529; --ink:#EDF6F0; --acc:#E9A519; --accent:#E9A519; --accent2:#B3372B;
  --ksa-card:#FFFFFF; --ksa-shadow:rgba(0,0,0,.4);
  --dim:color-mix(in srgb,#EDF6F0 66%,transparent);
  --ks-font:var(--ks-font-round);
  --ks-weight-display:900; --ks-caps-display:none; --ks-track-display:-.02em;
  background:var(--ks-bg) radial-gradient(120% 90% at 50% 0%, color-mix(in srgb,var(--ks-ink) 7%,transparent), transparent 62%);
  color:var(--ks-ink);
}
body[class*="ks-arch-felt"] :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink);
  text-shadow:0 3px 0 var(--ksa-shadow);
}
body[class*="ks-arch-felt"] .ks-badge { background:color-mix(in srgb,var(--ks-ink) 12%,transparent); border:none; color:var(--ks-ink); border-radius:999px; font-weight:700; font-size:.72rem; padding:6px 14px; }
body[class*="ks-arch-felt"] .ks-btn { background:var(--ksa-card); color:var(--ks-bg); border:none; border-radius:999px; font-weight:900; box-shadow:0 5px 0 var(--ksa-shadow); }
body[class*="ks-arch-felt"] .ks-btn:active { transform:translateY(4px); box-shadow:0 1px 0 var(--ksa-shadow); }
body[class*="ks-arch-felt"] .ks-choice, body[class*="ks-arch-felt"] .k-choice { border:3px solid var(--ksa-card); box-shadow:0 4px 10px var(--ksa-shadow); border-radius:12px; font-weight:800; }

/* EDITORIAL — from Daily Journal: serif display on white, tinted soft cards, italic grace. LIGHT #5,
   and the world that finally gives VERDICT a voice beyond the register. */
body[class*="ks-arch-editorial"] {
  --ks-bg:#FCFBF8; --ks-ink:#1C1A17; --ks-accent:#C05B2E; --ks-accent-2:#6A5FA8;
  --bg:#FCFBF8; --ink:#1C1A17; --acc:#C05B2E; --accent:#C05B2E; --accent2:#6A5FA8;
  --ksa-tint:#F6EFE6; --ksa-line:#E8E2D7;
  --dim:color-mix(in srgb,#1C1A17 52%,#FCFBF8);
  --ks-font:var(--ks-font-serif);
  --ks-weight-display:600; --ks-caps-display:none; --ks-track-display:0;
  background:var(--ks-bg); color:var(--ks-ink);
}
html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-editorial"]::before, html:not([data-klyp-bgphoto]):not([data-klyp-bgframe]) body[class*="ks-arch-editorial"]::after { display:none; }
body[class*="ks-arch-editorial"] :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink); text-shadow:none;
  line-height:1.12;
}
body[class*="ks-arch-editorial"] :is(.vibe,.count,.k-sub,.ks-body,p) { color:var(--dim); font-style:italic; }
body[class*="ks-arch-editorial"] .ks-badge { background:transparent; border:none; border-top:1px solid var(--ksa-line); border-bottom:1px solid var(--ksa-line); color:var(--dim); border-radius:0; letter-spacing:.22em; text-transform:uppercase; font-size:.62rem; font-family:ui-sans-serif,system-ui,sans-serif; padding:6px 2px; }
body[class*="ks-arch-editorial"] .ks-btn { background:var(--ks-ink); color:var(--ks-bg); border:none; border-radius:6px; font-weight:600; font-family:ui-sans-serif,system-ui,sans-serif; letter-spacing:.04em; }
body[class*="ks-arch-editorial"] .ks-choice, body[class*="ks-arch-editorial"] .k-choice { background:var(--ksa-tint); border:1px solid var(--ksa-line); border-radius:14px; }

/* STAGE — from 20 Questions: a dark theatre for ONE character. Mono eyebrow, a prop with real presence
   (the hero slot at full size, glowing), a single gold CTA. The placeholder teaches the game. */
body[class*="ks-arch-stage"] {
  --ks-bg:#170F2B; --ks-ink:#EDE6FA; --ks-accent:#C9A24C; --ks-accent-2:#8A7CFF;
  --bg:#170F2B; --ink:#EDE6FA; --acc:#C9A24C; --accent:#C9A24C; --accent2:#8A7CFF;
  --ksa-glow:rgba(160,120,255,.45); --ksa-slab:#1A1230;
  --dim:color-mix(in srgb,#EDE6FA 58%,transparent);
  --ks-weight-display:700; --ks-caps-display:none; --ks-track-display:0;
  background:var(--ks-bg) radial-gradient(90% 70% at 50% 20%, color-mix(in srgb,var(--ks-accent-2) 16%,transparent), transparent 70%);
  color:var(--ks-ink);
}
body[class*="ks-arch-stage"] main#start .hero { filter:drop-shadow(0 6px 22px var(--ksa-glow)); font-size:clamp(3rem,16cqw,4.6rem) !important; }
body[class*="ks-arch-stage"] .ks-badge { background:transparent; border:none; color:var(--dim); font-family:ui-monospace,Menlo,monospace; letter-spacing:.28em; text-transform:uppercase; font-size:.62rem; }
body[class*="ks-arch-stage"] :is(h1,h2,h3,.ks-display,.ks-title) { background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink); }
body[class*="ks-arch-stage"] .ks-btn { background:var(--ks-accent); color:var(--ksa-slab); border:none; border-radius:12px; font-weight:800; letter-spacing:.12em; text-transform:uppercase; }

/* CANVAS — from Pixel Scan: the artwork IS the app. Chrome dissolves to a whisper; one hint line. */
body[class*="ks-arch-canvas"] {
  --ks-bg:#0A0C10; --ks-ink:#C8D2DE; --ks-accent:#7AD7FF; --ks-accent-2:#FF69B4;
  --bg:#0A0C10; --ink:#C8D2DE; --acc:#7AD7FF; --accent:#7AD7FF; --accent2:#FF69B4;
  --dim:color-mix(in srgb,#C8D2DE 50%,transparent);
  --ks-weight-display:400; --ks-caps-display:none; --ks-track-display:.06em;
  background:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-canvas"] :is(h1,h2,h3,.ks-display,.ks-title) { background:none !important; -webkit-text-fill-color:currentColor; color:var(--dim); font-size:var(--ks-text-4) !important; font-weight:400; }
body[class*="ks-arch-canvas"] .ks-badge { display:none; }   /* the canvas needs no eyebrow */
body[class*="ks-arch-canvas"] .ks-btn { background:color-mix(in srgb,var(--ks-ink) 8%,transparent); color:var(--ks-ink); border:1px solid color-mix(in srgb,var(--ks-ink) 22%,transparent); border-radius:999px; font-weight:600; backdrop-filter:blur(6px); }

/* TOYBOX — EXTRACTED from block-drop (our own founder-praised best): deep navy #1b2340, ink #EAF0FF, and
   the chunky 7-hue piece family at matched lightness that accentFamily was mined from. Objects are thick,
   soft-shadowed, ROUND-CORNERED — a box of pieces, not a document. */
body[class*="ks-arch-toybox"] {
  --ks-bg:#1B2340; --ks-ink:#EAF0FF; --ks-accent:#4BC4E8; --ks-accent-2:#FFB454;
  --bg:#1B2340; --ink:#EAF0FF; --acc:#4BC4E8; --accent:#4BC4E8; --accent2:#FFB454;
  --ksa-p1:#E84B3C; --ksa-p2:#8B6BE8; --ksa-p3:#F06AA8; --ksa-p4:#5FD48A; --ksa-p5:#FFCE5A;
  --ksa-well:#141A30; --ksa-btn-ink:#10203A; --ksa-btn-shade:color-mix(in srgb, var(--ks-accent) 45%, var(--ksa-well));
  --dim:color-mix(in srgb,#EAF0FF 62%,transparent);
  --ks-weight-display:800; --ks-caps-display:none; --ks-track-display:-.01em;
  background:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-toybox"] :is(h1,h2,h3,.ks-display,.ks-title) { background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink); }
body[class*="ks-arch-toybox"] .ks-badge { background:var(--ksa-well); border:none; color:var(--ks-accent); border-radius:10px; font-weight:700; font-size:.7rem; padding:6px 12px; }
body[class*="ks-arch-toybox"] [data-ks="board"] { background:var(--ksa-well); border-radius:16px; box-shadow:inset 0 2px 10px rgba(0,0,0,.4); }
body[class*="ks-arch-toybox"] .ks-btn { background:var(--ks-accent); color:var(--ksa-btn-ink); border:none; border-radius:14px; font-weight:800; box-shadow:0 4px 0 var(--ksa-btn-shade); }
body[class*="ks-arch-toybox"] .ks-btn:active { transform:translateY(3px); box-shadow:0 1px 0 var(--ksa-btn-shade); }

/* ═══ GLASS — Apple's Liquid Glass, honestly approximated (2026-08-02, founder ask).
   Apple's own definition is LENSING, not blur: the material "dynamically bends, shapes and
   concentrates light" (WWDC25). The faithful version needs backdrop-filter:url(#svg) with
   feDisplacementMap — Chromium-only AND fill-rate murder on an Adreno 610, which is the exact
   device our audience carries. So the DEFAULT here is the cheap, honest read: a bright top edge
   (light entering), a dark bottom edge (light leaving), an inner specular sweep and a real
   shadow — ~0 cost, no blur. The true lensing is layered on ONLY behind @supports where the
   device can pay for it. Apple's own rules kept: glass is the CONTROL layer, never glass-on-glass,
   never tint everything. */
body[class*="ks-arch-glass"] {
  --ks-bg:#EAF0F7; --ks-ink:#0E1219; --ks-accent:#0A6CFF; --ks-accent-2:#12C2A0;
  --bg:#EAF0F7; --ink:#0E1219; --acc:#0A6CFF; --accent:#0A6CFF; --accent2:#12C2A0;
  --dim:color-mix(in oklch,#0E1219 55%,transparent);
  --ks-weight-display:800; --ks-track-display:-.035em;
  --ksg-edge:rgba(255,255,255,.96); --ksg-under:rgba(12,26,54,.22);
  --ksg-warm:#FF4D8D; --ksg-sun:#FFB020; --ksg-top:#FFFFFF; --ksg-bottom:#E6EDF6;
  background:var(--ks-bg); color:var(--ks-ink);
  /* GLASS NEEDS SOMETHING TO BEND. Apple's material only reads as glass because vivid content sits
     BEHIND it; over a pale wash it is just frosted white — which is exactly why v1 looked flat. These
     are saturated colour bodies, deliberately larger than the panels that float over them. */
  background-image:
    radial-gradient(58% 42% at 14% 6%,  color-mix(in oklch,var(--ks-accent) 62%,transparent), transparent 68%),
    radial-gradient(52% 40% at 96% 14%, color-mix(in oklch,var(--ksg-warm) 52%,transparent), transparent 70%),
    radial-gradient(64% 46% at 78% 96%, color-mix(in oklch,var(--ks-accent-2) 58%,transparent), transparent 72%),
    radial-gradient(46% 34% at 30% 82%, color-mix(in oklch,var(--ksg-sun) 44%,transparent), transparent 70%),
    linear-gradient(180deg,var(--ksg-top),var(--ksg-bottom));
  background-attachment:fixed;
}
/* The floating control layer. Apple's rules kept: glass belongs to controls, never to content, and two
   glass surfaces never stack. Default is BLUR-FREE (an Adreno 610 cannot pay for full-screen sampling):
   a bright top edge where light enters, a dark bottom edge where it leaves, and a real cast shadow. */
body[class*="ks-arch-glass"] .ks-card,
body[class*="ks-arch-glass"] .ks-panel {
  position:relative;
  background:linear-gradient(180deg, rgba(255,255,255,.78), rgba(255,255,255,.46));
  border:1px solid rgba(255,255,255,.85);
  border-radius:24px;
  box-shadow:
    inset 0 1.5px 0 var(--ksg-edge),
    inset 0 -1px 0 rgba(255,255,255,.34),
    inset 0 0 22px rgba(255,255,255,.30),
    0 12px 34px var(--ksg-under),
    0 2px 6px rgba(12,26,54,.10);
  color:var(--ks-ink);
}
/* The specular sweep — the single detail that reads as GLASS rather than as a white box. */
body[class*="ks-arch-glass"] .ks-card::after,
body[class*="ks-arch-glass"] .ks-panel::after,
body[class*="ks-arch-glass"] .ks-btn::after {
  content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  background:linear-gradient(115deg, rgba(255,255,255,.55) 0%, rgba(255,255,255,0) 38%, rgba(255,255,255,0) 68%, rgba(255,255,255,.28) 100%);
}
/* THE PRIMARY ACTION IS FILLED, NOT GLASS. Apple fills the primary control and keeps glass for the
   surfaces around it; making every button glass erases hierarchy — which is exactly why v1 read flat. */
body[class*="ks-arch-glass"] .ks-btn {
  position:relative; overflow:hidden;
  background:linear-gradient(180deg, color-mix(in oklch,var(--ks-accent) 92%,var(--ksg-top)), var(--ks-accent));
  border:1px solid color-mix(in oklch,var(--ks-accent) 70%,black);
  border-radius:22px; font-weight:800; letter-spacing:-.015em;
  color:var(--ksg-top); -webkit-text-fill-color:var(--ksg-top);
  box-shadow:
    inset 0 1.5px 0 rgba(255,255,255,.55),
    inset 0 -2px 6px color-mix(in oklch,var(--ks-accent) 60%,black),
    0 10px 26px color-mix(in oklch,var(--ks-accent) 42%,transparent),
    0 2px 6px rgba(12,26,54,.18);
}
body[class*="ks-arch-glass"] .ks-btn:active { transform:scale(.972); box-shadow:inset 0 1.5px 0 rgba(255,255,255,.5), 0 3px 10px color-mix(in oklch,var(--ks-accent) 40%,transparent); }
/* secondary / ghost controls keep the glass */
body[class*="ks-arch-glass"] :is(.ks-btn.ks-ghost, .ks-ghost-btn, .ks-btn-2) {
  background:linear-gradient(180deg, rgba(255,255,255,.78), rgba(255,255,255,.46));
  border:1px solid rgba(255,255,255,.85); color:var(--ks-ink); -webkit-text-fill-color:var(--ks-ink);
  box-shadow:inset 0 1.5px 0 var(--ksg-edge), 0 8px 22px var(--ksg-under);
}
body[class*="ks-arch-glass"] .ks-badge {
  background:rgba(255,255,255,.66); border:1px solid rgba(255,255,255,.9); border-radius:999px;
  color:color-mix(in oklch,var(--ks-ink) 82%,transparent);
  box-shadow:0 4px 14px rgba(12,26,54,.12), inset 0 1px 0 rgba(255,255,255,.9);
  font-size:.66rem; font-weight:700; letter-spacing:.16em; text-transform:uppercase;
}
/* Where the device can afford it, sample the vivid ground for real. */
@supports (backdrop-filter: blur(12px)) {
  body[class*="ks-arch-glass"] .ks-card,
  body[class*="ks-arch-glass"] .ks-panel {
    -webkit-backdrop-filter:blur(20px) saturate(1.9);
    backdrop-filter:blur(20px) saturate(1.9);
    background:linear-gradient(180deg, rgba(255,255,255,.52), rgba(255,255,255,.22));
  }
}
@media (prefers-reduced-transparency: reduce) {
  body[class*="ks-arch-glass"] .ks-card,
  body[class*="ks-arch-glass"] .ks-panel {
    -webkit-backdrop-filter:none; backdrop-filter:none; background:rgba(255,255,255,.94);
  }
}
/* THE LIGHT-GROUND INK LAW — every light world must restate it (PAPER learned this the hard way:
   "white on white, not visible"). Skeleton display type ships a gradient fill tuned for DARK grounds. */
body[class*="ks-arch-glass"] :is(h1, h2, h3, .ks-display, .ks-title) {
  background:none !important; -webkit-text-fill-color:currentColor; color:var(--ks-ink);
  text-shadow:0 1px 0 rgba(255,255,255,.6); filter:none;
}
body[class*="ks-arch-glass"] :is(.vibe, .count, .k-sub, .ks-body, .msg, p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent); }

/* ═══ PRISM — real depth on a 2D budget (2026-08-02, founder ask for 3D).
   three.js is dead on arrival here (79 KB gzip before a line of app code, and Chromium canvas
   collapses on draw calls long before pixels). CSS 3D is the honest 3D for a ₹14k Android: the
   compositor does perspective/rotate on the GPU with zero JS per frame. This world gives every
   skeleton a stage with real Z — cards that flip and tilt, layers that part. Motion is the point,
   so it fully surrenders to prefers-reduced-motion. */
body[class*="ks-arch-prism"] {
  --ks-bg:#0C0A18; --ks-ink:#F0ECFF; --ks-accent:#8B7BFF; --ks-accent-2:#4BE0D0;
  --bg:#0C0A18; --ink:#F0ECFF; --acc:#8B7BFF; --accent:#8B7BFF; --accent2:#4BE0D0;
  --dim:color-mix(in oklch,#F0ECFF 55%,transparent);
  --ks-weight-display:800; --ks-track-display:.02em;
  background:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(85% 55% at 50% -10%, color-mix(in oklch,var(--ks-accent) 34%,transparent), transparent 65%),
    radial-gradient(70% 50% at 90% 108%, color-mix(in oklch,var(--ks-accent-2) 26%,transparent), transparent 70%);
  perspective:1100px; perspective-origin:50% 42%;
}
body[class*="ks-arch-prism"] .ks-stage,
body[class*="ks-arch-prism"] main { transform-style:preserve-3d; }
body[class*="ks-arch-prism"] .ks-card,
body[class*="ks-arch-prism"] .ks-panel {
  background:linear-gradient(165deg, rgba(255,255,255,.10), rgba(255,255,255,.03));
  border:1px solid rgba(255,255,255,.14); border-radius:20px;
  transform:rotateX(6deg) translateZ(0);
  box-shadow:0 24px 50px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.16);
  transition:transform var(--ks-t-slow, .35s) var(--ks-spring-settle);
}
body[class*="ks-arch-prism"] .ks-card:active { transform:rotateX(0deg) translateZ(28px); }
body[class*="ks-arch-prism"] .ks-btn {
  background:var(--ks-accent); color:var(--ks-bg); border:none; border-radius:16px; font-weight:800;
  box-shadow:0 6px 0 color-mix(in oklch,var(--ks-accent) 55%,black), 0 14px 28px rgba(0,0,0,.5);
  transform:translateZ(20px);
}
body[class*="ks-arch-prism"] .ks-btn:active { transform:translateZ(6px) translateY(4px); box-shadow:0 2px 0 color-mix(in oklch,var(--ks-accent) 55%,black); }

/* ═══ THE VOICE RING — per-APP type identity inside a world ════════════════════════════════════════
   Founder 2026-08-02: "every created app will have its own identity." A world sets the material; the
   VOICE sets the type. Each archetype allows 2-3 of these, and the app's own seed picks one, so two
   apps in the same world never share a face. Stamped as `ks-voice-*` beside `ks-arch-*`. */
body[class*="ks-voice-"] .ks-display, body[class*="ks-voice-"] .ks-title { font-family: var(--ksv-face, var(--ks-font)); }
body[class*="ks-voice-"] .ks-badge { font-family: var(--ksv-caption, var(--ks-font)); }

body.ks-voice-humanist { --ksv-face:"Plus Jakarta Sans", system-ui, sans-serif; --ksv-caption:"Plus Jakarta Sans", system-ui, sans-serif; }
body.ks-voice-humanist .ks-display { letter-spacing:-.03em; font-weight:800; }

body.ks-voice-geometric { --ksv-face:"Space Grotesk", "Plus Jakarta Sans", system-ui, sans-serif; --ksv-caption:var(--ks-font-mono); }
body.ks-voice-geometric .ks-display { letter-spacing:-.015em; font-weight:700; }
body.ks-voice-geometric .ks-badge { letter-spacing:.2em; text-transform:uppercase; font-size:.66rem; }

body.ks-voice-rounded { --ksv-face:"Nunito", "Plus Jakarta Sans", system-ui, sans-serif; --ksv-caption:"Nunito", system-ui, sans-serif; }
body.ks-voice-rounded .ks-display { letter-spacing:-.02em; font-weight:900; }

body.ks-voice-mono { --ksv-face:var(--ks-font-mono); --ksv-caption:var(--ks-font-mono); }
body.ks-voice-mono .ks-display { letter-spacing:.02em; font-weight:700; }
body.ks-voice-mono .ks-badge { letter-spacing:.22em; text-transform:uppercase; font-size:.64rem; }

body.ks-voice-serif { --ksv-face:var(--ks-font-serif); --ksv-caption:var(--ks-font-mono); }
body.ks-voice-serif .ks-display { letter-spacing:-.012em; font-weight:700; }
body.ks-voice-serif .ks-badge { letter-spacing:.2em; text-transform:uppercase; font-size:.64rem; }

body.ks-voice-marquee { --ksv-face:"Space Grotesk", "Plus Jakarta Sans", system-ui, sans-serif; --ksv-caption:var(--ks-font-mono); }
body.ks-voice-marquee .ks-display { text-transform:uppercase; letter-spacing:.045em; font-weight:700; }
body.ks-voice-marquee .ks-badge { letter-spacing:.24em; text-transform:uppercase; font-size:.62rem; }

body[class*="ks-arch-prism"] .ks-badge { background:rgba(255,255,255,.10); border:1px solid rgba(255,255,255,.18); border-radius:999px; color:var(--ks-ink); }
/* Direct properties, not tokens: the theme ring writes --ks-track-display INLINE on the element, so a
   stylesheet token can never win (this is why CONSOLE sets letter-spacing directly too). Uppercase
   condensed needs POSITIVE tracking — the inherited -0.035em jammed "CHAI ROULETTE" into one word. */
body[class*="ks-arch-prism"] :is(h1, h2, h3, .ks-display, .ks-title) {
  color:var(--ks-ink);
}
body[class*="ks-arch-prism"] .ks-badge {
  font-family:var(--ks-font-mono); font-size:.64rem; letter-spacing:.24em; text-transform:uppercase; font-weight:600;
}
@media (prefers-reduced-motion: reduce) {
  body[class*="ks-arch-prism"] { perspective:none; }
  body[class*="ks-arch-prism"] .ks-card,
  body[class*="ks-arch-prism"] .ks-panel,
  body[class*="ks-arch-prism"] .ks-btn { transform:none; transition:none; }
}


/* LIGHT-WORLD FORM INK/* LIGHT-WORLD FORM INK/* LIGHT-WORLD FORM INK/* LIGHT-WORLD FORM INK/* LIGHT-WORLD FORM INK (2026-08-01). The register render shipped ghosted fields — "YOU" / "type a
   name…" barely visible: labels and inputs kept the PACK's translucent pale ink over a light ground, and
   the contrast gate could not convict them (translucent paint → no verdict, an honest skip that is also a
   blind spot, recorded in contrastGate.ts). On every LIGHT archetype, form ink derives from the world. */
body[class*="ks-arch-paper"], body[class*="ks-arch-register"], body[class*="ks-arch-appliance"], body[class*="ks-arch-editorial"], body[class*="ks-arch-diorama"] {
  & :is(label, .ks-label, legend) { color:var(--dim); }
  & :is(input, textarea, select) { color:var(--ks-ink); border-color:color-mix(in srgb, var(--ks-ink) 30%, transparent); background:color-mix(in srgb, var(--ks-ink) 4%, transparent); }
  & ::placeholder { color:color-mix(in srgb, var(--ks-ink) 45%, transparent); }
}
/* Appliance CTA: dark ink on the orange key, the way hardware labels its buttons — white-on-orange read
   washed at feed size. */
body[class*="ks-arch-appliance"] .ks-btn { color:var(--ks-ink); }

/* ONE replay affordance in the feed/* ONE replay affordance in the feed/* ONE replay affordance in the feed (2026-08-01). The host paints its own "Play again" pill over the
   card after game_end; an ARCHETYPE app's own #again button then reads as a second, colliding CTA — the
   founder's "2 play agains" screenshot, a dark pill sitting on a yellow paper button. Scoped to archetype
   bodies (new builds only): live classics keep their layouts; standalone keeps #again everywhere. */
html.klyp-framed body[class*="ks-arch-"] #again { display:none; }

/* START-SCREEN PRESENCE (2026-07-31, the composition ratchet). Measured at the real feed box: story and
   tradeoff start screens sat as a small centred group with 29-34% of the screen empty above AND below —
   97 of 208 matrix cells, the founder's "2010 emptiness" as a number. The board is the elastic slot and
   `place-content:center` pools all its slack around the group. On the START screen only, spread the
   board's rows across the slack instead: first content rises, the group breathes, the CTA stays anchored.
   Scoped by id so PLAY and END screens (which reuse these layouts, and where a spread would wreck a
   chat column or a scorecard) are untouched — the glass-surface lesson: never change the layout of what
   you decorate, and never let a start-screen fix leak into a play surface. */
main#start[class*="ks-lay-"] > [data-ks="board"] { place-content: space-evenly; }
main#start[class*="ks-lay-"] { justify-content: space-evenly; }
/* The hero mark earns its slot: at body size it read as a stray character between badge and title. */
main#start[class*="ks-lay-"] .hero { font-size: clamp(2.6rem, 14cqw, 4rem); line-height: 1; }

.ks-lay-hero { text-align: center; }

/* 2 — THUMB DECK: board floats up top, all controls in the bottom third where a thumb lives. */
.ks-lay-thumb > [data-ks="primary"] { padding-top: var(--ks-4); }

/* 3 — SPLIT DUEL: two equal halves. This-or-that, versus, compare. */
.ks-lay-duel { padding-inline: var(--ks-3); }
.ks-lay-duel > [data-ks="primary"] { flex: 1 1 auto; display: flex; gap: var(--ks-3); align-items: stretch; }
.ks-lay-duel > [data-ks="primary"] > * { flex: 1; }

/* 4 — SPLIT STACK: the same duel, stacked. Better for long option text. */
.ks-lay-duel-v > [data-ks="primary"] { flex: 1 1 auto; display: flex; flex-direction: column; gap: var(--ks-3); }
.ks-lay-duel-v > [data-ks="primary"] > * { flex: 1; }

/* 5 — EDITORIAL LEFT: asymmetric, type-led, left-ragged. Verdicts, reveals, results. */
.ks-lay-editorial { align-items: flex-start; text-align: left; }
.ks-lay-editorial > [data-ks="board"] { place-content: center start; gap: var(--ks-4); }
.ks-lay-editorial .ks-body { margin-inline: 0; }

/* 6 — BENTO: a modular grid of unequal cells. Dashboards, stat reveals, multi-part results. */
.ks-lay-bento > [data-ks="board"] {
  display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--ks-3);
  place-content: center stretch; align-content: center;
}
.ks-lay-bento > [data-ks="board"] > * { grid-column: span 3; }
.ks-lay-bento > [data-ks="board"] > *:first-child { grid-column: span 6; }
.ks-lay-bento > [data-ks="board"] > *:nth-child(4) { grid-column: span 2; }
.ks-lay-bento > [data-ks="board"] > *:nth-child(5) { grid-column: span 4; }

/* 7 — BOARD GRID: an n×n play field. Memory, lights-out, whack, tap-the-tile. */
.ks-lay-board > [data-ks="board"] {
  display: grid; grid-template-columns: repeat(var(--ks-cols, 4), 1fr); gap: var(--ks-2);
  place-content: center; align-content: center;
  width: min(100%, 92cqw, 460px); aspect-ratio: 1; margin-inline: auto;
}
.ks-lay-board > [data-ks="board"] > * { aspect-ratio: 1; }

/* 8 — LIST SCROLL: a scrolling body between a pinned prompt and a pinned action. */
.ks-lay-list > [data-ks="board"] {
  overflow-y: auto; display: grid; gap: var(--ks-3); align-content: start; place-content: start stretch;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
}

/* 9 — CARD STACK: one focal card, siblings peeking behind. Swipe, flip, reveal. */
.ks-lay-stack > [data-ks="board"] { place-items: center; perspective: 1200px; }
.ks-lay-stack > [data-ks="board"] > * { grid-area: 1 / 1; }
.ks-lay-stack > [data-ks="board"] > *:nth-child(2) { transform: translateY(16px) scale(0.94); opacity: 0.45; }
.ks-lay-stack > [data-ks="board"] > *:nth-child(3) { transform: translateY(30px) scale(0.88); opacity: 0.22; }

/* 10 — FULL CANVAS: the escape hatch. The core draws freely inside a bounded region. */
.ks-lay-canvas { padding: 0; gap: 0; }
/* The board GROWS and is itself a column, so a child that says `flex:1` (an arena, a <canvas>) can
   actually fill it. As `display:block` the board grew but its child could not — launch's arena
   measured zero height and every shot missed by construction. */
.ks-lay-canvas > [data-ks="board"] { max-width: none; width: 100%;
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; position: relative; }

/* 11 — CENTRE ORB: a single breathing focal object. Ambient, calm, hold-to-charge. */
.ks-lay-orb { text-align: center; }
.ks-lay-orb > [data-ks="board"] { place-items: center; }

/* 12 — TOP TICKER: the score is the headline, the play area sits below. Endless, arcade. */
.ks-lay-ticker > [data-ks="hud"] { display: grid; justify-items: center; gap: 0; }

/* 13 — VERSUS: two numbers face off. Duels, comparisons, you-vs-them. */
.ks-lay-versus > [data-ks="board"] {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--ks-3);
  place-content: center stretch;
}
.ks-lay-versus [data-ks-vs] { font-size: var(--ks-text-3); font-weight: 800; color: var(--ks-ink-3); }

/* 14 — POSTER: the full-bleed shareable. Big type on an accent field. Worth screenshotting. */
.ks-lay-poster { text-align: center; padding-inline: var(--ks-6); justify-content: center; }
/* In poster mode the payoff IS the page: no card. The bloom must also stop being clipped to the
   card's radius — `overflow:hidden` + the inherited radius drew a faint rounded box edge across the
   most shareable screen we have. */
.ks-lay-poster > [data-ks="payoff"] {
  background: none; box-shadow: none; padding: 0; overflow: visible; border-radius: 0;
}
.ks-lay-poster > [data-ks="payoff"]::before {
  inset: -40% -45% auto -45%; height: 105%; border-radius: 50%; filter: blur(6px);
}

/* 15 — QUESTION FOCUS: the prompt is the hero, answers sit in the thumb arc. Trivia, polls.
   The board ANCHORS TO THE BOTTOM of its slack, not the centre: with it centred, the question floated
   mid-screen and left a void between prompt and answers that read as a layout bug rather than as
   breathing room. Anchored, the space collects above the question and the pair reads as one block. */
.ks-lay-question { justify-content: center; }
/* The prompt and its answers are ONE block, centred as a pair. Letting the board absorb the slack put
   the question mid-screen with a void beneath it; anchoring it to the bottom just moved the void above.
   Content-sized board + a centred column balances the space on both sides, which is what "the prompt is
   the hero and the answers are in reach" actually looks like. */
.ks-lay-question > [data-ks="board"] { text-align: center; flex: 0 1 auto; place-content: center; padding-bottom: var(--ks-4); }
.ks-lay-question > [data-ks="primary"] { gap: var(--ks-2); }

/* 16 — RAIL FOCUS: a horizontal rail of options under a focal region. Pickers, browsers. */
.ks-lay-rail { overflow-x: clip; }
.ks-lay-rail > [data-ks="primary"] { overflow: visible; }

/* 17 — SPLIT MEDIA: a graphic half and a content half. Photo-led choice, taste tests. */
.ks-lay-media { gap: var(--ks-5); }
.ks-lay-media > [data-ks="board"] { border-radius: var(--ks-r-xl); overflow: hidden; }

/* 18 — LADDER: a vertical progression the player climbs. Streaks, levels, tiers. */
.ks-lay-ladder > [data-ks="board"] { display: grid; gap: var(--ks-2); align-content: center; place-content: center stretch; }

/* 19 — KEYPAD: a board up top, an input pad below. Word games, guessing, code entry. */
.ks-lay-keypad > [data-ks="primary"] { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--ks-2); }

/* 20 — MINIMAL: one line, one control, nothing else. Tools, single-answer, the honest utility. */
.ks-lay-minimal { text-align: center; gap: var(--ks-6); justify-content: center; }
/* The board must NOT absorb slack here: "minimal" centres the whole stack as one group. With the
   base `flex:1` the group drifted to the bottom of a short viewport (skeletonLayout caught it at
   342x450: midpoint 385 vs 225). Content-sized slots + justify-content:center is the honest centre. */
.ks-lay-minimal > [data-ks] { flex: 0 1 auto; }
.ks-lay-minimal > [data-ks="board"] { display: grid; place-content: center; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   5 · MOTION PRIMITIVES — entrances that read as craft. All spring-driven.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
.ks-in       { animation: ks-in var(--ks-t-move) var(--ks-spring, var(--ks-spring-snap)) both; }
.ks-in-up    { animation: ks-in-up var(--ks-t-move) var(--ks-spring, var(--ks-spring-snap)) both; }
.ks-in-pop   { animation: ks-in-pop var(--ks-t-move) var(--ks-spring-bounce) both; }
@keyframes ks-in     { from { opacity: 0; } to { opacity: 1; } }
@keyframes ks-in-up  { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes ks-in-pop { from { opacity: 0; transform: scale(0.86); } to { opacity: 1; transform: none; } }

/* Stagger — set --ks-i on children for an ordered cascade. */
.ks-stagger > * { animation: ks-in-up var(--ks-t-move) var(--ks-spring, var(--ks-spring-snap)) both;
                  animation-delay: calc(var(--ks-i, 0) * 55ms); }
.ks-stagger > *:nth-child(1) { --ks-i: 0; } .ks-stagger > *:nth-child(2) { --ks-i: 1; }
.ks-stagger > *:nth-child(3) { --ks-i: 2; } .ks-stagger > *:nth-child(4) { --ks-i: 3; }
.ks-stagger > *:nth-child(5) { --ks-i: 4; } .ks-stagger > *:nth-child(6) { --ks-i: 5; }

.ks-breathe { animation: ks-breathe 3.4s var(--ks-spring-settle) infinite alternate; }
@keyframes ks-breathe { from { transform: scale(1); } to { transform: scale(1.045); } }

.ks-shake { animation: ks-shake 320ms var(--ks-spring-snap); }
@keyframes ks-shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-7px); }
                      50% { transform: translateX(6px); } 75% { transform: translateX(-3px); } }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   6 · BACKDROPS — the background is never a flat fill. Three tokenised fields, all cheap to paint.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
.ks-bg-grid   { background:
  linear-gradient(var(--ks-hairline) 1px, transparent 1px) 0 0 / 100% 34px,
  linear-gradient(90deg, var(--ks-hairline) 1px, transparent 1px) 0 0 / 34px 100%,
  radial-gradient(90% 60% at 50% 0%, var(--ks-tint), transparent 60%),
  var(--ks-bg); }
/* ── MATERIAL: the layer that stops an app reading as text on a gradient (L-2026-08-17) ───────────
   Founder, three times: "looks like 2010 / an MS Word project from 2008" — and after type and colour
   were fixed it STILL read that way. The reason, found by looking rather than reasoning: the kit already
   ships glass, lift, specular and springs, and a START SCREEN USES NONE OF THEM. Content sat as naked
   text on a flat two-stop gradient. There was no SURFACE, and naked text on a flat field is exactly what
   a Word document is.

   Two additions, both free of markup changes so every existing app gets them:
   1 · GRAIN + DEPTH on every field. A pure CSS gradient is the tell of an AI-generated page; real
       products carry noise, a light source, and a vignette that keeps the eye centred.
   2 · A MATERIAL STACK on the start screen's board slot — translucent, blurred, hairline-lit, elevated —
       so the title group sits ON something. `:has()` targets only a board that holds a heading, which is
       the start/end composition; a PLAY board (grid, arena, canvas) is untouched.
   Kept subtle per the founder's taste: "people like subtle things… size is always medium." */
body[class*="ks-bg-"]::after {
  content: ""; position: fixed; inset: 0; pointer-events: none;
  /* Grain via an inline SVG turbulence — no asset, no request, ~200 bytes. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  opacity: .055; mix-blend-mode: overlay; z-index: -1;
}
body[class*="ks-bg-"]::before {
  content: ""; position: fixed; inset: 0; pointer-events: none;
  /* One light source top-left + a vignette. Depth, not decoration. */
  background:
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink-1)), transparent 70%);
  z-index: -1;
}
/* NOTE: the decoration sits BEHIND content via z-index:-1 rather than promoting every child with
   `body > * { position: relative }`. That first attempt gave each direct child a new containing block,
   which moved absolutely-positioned game layers and took the matrix to 36/52 with v-overflow. Decoration
   must never change the layout of the thing it decorates. */

/* THE START/END SURFACE — ATTEMPTED AND WITHDRAWN (L-2026-08-17).
   Giving the heading board a glass surface took the matrix 52/52 → 36/52 with `v-overflow` on 16 cells,
   and removing its padding did not help: the material itself is not the cost, the composition is. A start
   or end screen is already vertically tight inside a 597px feed box (card's end screen sits right at the
   limit), so introducing ANY surface there needs the screens re-composed for it — a real design pass, not
   a stylesheet addition. Withdrawn rather than shipped at 36/52. The FIELD material below stays: it is
   free, needs no markup, and is the half of the "2008 background" the founder actually named. */


/* ── THE FIELDS ────────────────────────────────────────────────────────────────────────────────
   Two corrections, both learned by looking:
   1. Accent-tinted radial GLOW blobs read 2010. Gone. These are flat, hard-edged colour blocking —
      riso, editorial bands, one huge arc — which is what actually reads 2026.
   2. But a field is ATMOSPHERE, not a poster layer. The first flat pass put 40% of the screen under
      solid accent and left the form in a dark void, and riso's diagonal cut straight through the
      inputs. So every field is now confined to the TOP BAND and resolves to the base colour by ~46%,
      where the controls live. Bold where the hero is; quiet where the thumb is. */

/* Hard diagonal split, resolving before the controls. */
.ks-bg-duotone { background:
  linear-gradient(163deg,
    color-mix(in oklch, var(--ks-accent) 26%, transparent) 0 15%,
    color-mix(in oklch, var(--ks-accent) 9%, transparent) 15% 27%,
    transparent 27%),
  var(--ks-bg); }

/* One enormous off-canvas circle behind the hero. */
.ks-bg-arc { background:
  radial-gradient(circle at 50% -54%,
    color-mix(in oklch, var(--ks-accent) 26%, transparent) 0 52%, transparent 52.4%),
  var(--ks-bg); }

/* Editorial bands — all above the fold. */
.ks-bg-bands { background:
  linear-gradient(180deg,
    color-mix(in oklch, var(--ks-accent) 22%, transparent) 0 11%,
    transparent 11% 19%,
    color-mix(in oklch, var(--ks-accent) 40%, transparent) 19% 21%,
    transparent 21%),
  var(--ks-bg); }

/* Print halftone, fading out before the controls. */
.ks-bg-halftone { background:
  linear-gradient(180deg, oklch(0 0 0 / 0) 0 20%, var(--ks-bg) 32%),
  radial-gradient(color-mix(in oklch, var(--ks-accent) 62%, transparent) 1.4px, transparent 1.5px) 0 0 / 13px 13px,
  var(--ks-bg); }

/* Riso: two off-register planes, kept ABOVE the play area so no band crosses a control. */
.ks-bg-riso { background:
  linear-gradient(180deg, oklch(0 0 0 / 0) 0 18%, var(--ks-bg) 30%),
  linear-gradient(112deg, transparent 0 30%, color-mix(in oklch, var(--ks-accent-2, var(--ks-accent)) 26%, transparent) 30% 62%, transparent 62%),
  linear-gradient(112deg, transparent 0 26%, color-mix(in oklch, var(--ks-accent) 30%, transparent) 26% 58%, transparent 58%),
  var(--ks-bg); }

/* Flat dark with ONE hard light edge — the restrained option, for fast play surfaces. */
.ks-bg-noir { background:
  linear-gradient(200deg, color-mix(in oklch, var(--ks-accent) 44%, var(--ks-bg)) 0 2.5px, transparent 2.5px),
  linear-gradient(180deg, color-mix(in oklch, var(--ks-bg) 88%, var(--ks-accent)), var(--ks-bg) 46%); }

/* A bold accent field for the hero, knocked out to base for everything below it. */
.ks-bg-pop { background:
  linear-gradient(180deg,
    color-mix(in oklch, var(--ks-accent) 30%, transparent) 0 14%,
    color-mix(in oklch, var(--ks-accent) 6%, transparent) 22%,
    transparent 30%),
  var(--ks-bg); }

.ks-bg-horizon { background:
  linear-gradient(180deg, transparent 40%, color-mix(in oklch, var(--ks-accent) 58%, transparent) 41.2%, transparent 42.6%),
  linear-gradient(180deg, color-mix(in oklch, var(--ks-bg) 84%, oklch(0 0 0)), var(--ks-bg) 48%); }

.ks-bg-veil { background:
  linear-gradient(160deg, color-mix(in oklch, var(--ks-accent) 20%, transparent) 0 16%, transparent 44%),
  linear-gradient(20deg, color-mix(in oklch, var(--ks-accent-2, var(--ks-accent)) 20%, transparent) 0 14%, transparent 38%),
  var(--ks-bg); }

/* Grain — the finish that stops a gradient reading as "AI gradient". */
.ks-grain::before {
  content: ""; position: fixed; inset: 0; z-index: 1; pointer-events: none; opacity: 0.05;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   7 · ACCESSIBILITY + RESILIENCE
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  .ks-in, .ks-in-up, .ks-in-pop, .ks-stagger > *, .ks-breathe, .ks-shake,
  .ks-payoff, .ks-sheet, .ks-toast, .ks-sheen-on, .ks-numeral.ks-bump {
    animation: none !important; transition-duration: 1ms !important;
  }
}
/* Colour is never the only signal: a chosen state carries a ring AND a mark.
   Scoped to CHOICE surfaces only — an active input slot is a cursor, not a confirmation, and the
   first proof render put ticks inside every empty letter slot. */
.ks-choice.ks-picked::after, .ks-chip.ks-on::after { content: "✓"; font-size: 0.7em; opacity: 0.9; margin-left: 0.35em; }
.ks-tile { position: relative; }
.ks-tile.ks-on::after { content: "✓"; position: absolute; top: 4px; right: 6px; font-size: 0.6em; opacity: 0.85; }
/* An active slot reads as a caret, not a tick. */
.ks-slot.ks-on { box-shadow: var(--ks-glow); }
.ks-slot.ks-on::after {
  content: ""; width: 2px; height: 46%; background: var(--ks-accent); border-radius: 2px;
  animation: ks-caret 1.1s steps(1) infinite;
}
@keyframes ks-caret { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }

/* Focus is visible and follows the accent. */
:where(.ks-btn, .ks-tile, .ks-choice, .ks-chip):focus-visible {
  outline: 3px solid var(--ks-accent); outline-offset: 3px;
}

/* backdrop-filter is not universal on low-end Android webviews: fall back to an opaque surface so a
   glass control never becomes an unreadable transparent smear. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ks-glass, .ks-glass-thick, .ks-hud, .ks-sheet, .ks-toast, .ks-btn.ks-glass-btn {
    background: var(--ks-surface-2);
  }
}


/* ═══ THE FACE RING — the type half of a set. One class per family; a set names the face it wants. */
body[class*="ks-face-"] :is(.ks-display,.ks-title) { font-family:var(--ksf-face, var(--ks-font)); }
body[class*="ks-face-"] .ks-badge { font-family:var(--ksf-caption, var(--ks-font)); }
body.ks-face-jakarta      { --ksf-face:"Plus Jakarta Sans",system-ui,sans-serif; --ksf-caption:"Plus Jakarta Sans",system-ui,sans-serif; }
body.ks-face-jakarta .ks-display { letter-spacing:-.03em; font-weight:800; }
body.ks-face-grotesk      { --ksf-face:"Space Grotesk","Plus Jakarta Sans",sans-serif; --ksf-caption:"Space Mono",ui-monospace,monospace; }
body.ks-face-grotesk .ks-display { letter-spacing:-.015em; font-weight:700; }
body.ks-face-nunito       { --ksf-face:"Nunito","Plus Jakarta Sans",sans-serif; --ksf-caption:"Nunito",system-ui,sans-serif; }
body.ks-face-nunito .ks-display { letter-spacing:-.02em; font-weight:900; }
body.ks-face-mono         { --ksf-face:"Space Mono",ui-monospace,monospace; --ksf-caption:"Space Mono",ui-monospace,monospace; }
body.ks-face-mono .ks-display { letter-spacing:-.01em; font-weight:700; }
body.ks-face-mono .ks-badge { letter-spacing:.2em; text-transform:uppercase; font-size:.64rem; }
body.ks-face-shoulders    { --ksf-face:"Big Shoulders","Space Grotesk",sans-serif; --ksf-caption:"Space Mono",ui-monospace,monospace; }
body.ks-face-shoulders .ks-display { text-transform:uppercase; letter-spacing:.02em; font-weight:800; }
body.ks-face-shoulders .ks-badge { letter-spacing:.22em; text-transform:uppercase; font-size:.62rem; }
body.ks-face-slab         { --ksf-face:"Alfa Slab One","Playfair Display",serif; --ksf-caption:"Nunito",system-ui,sans-serif; }
body.ks-face-slab .ks-display { letter-spacing:-.005em; font-weight:400; }
body.ks-face-bricolage    { --ksf-face:"Bricolage Grotesque","Plus Jakarta Sans",sans-serif; --ksf-caption:"Bricolage Grotesque",system-ui,sans-serif; }
body.ks-face-bricolage .ks-display { letter-spacing:-.025em; font-weight:800; }
body.ks-face-playfair     { --ksf-face:"Playfair Display",Georgia,serif; --ksf-caption:"Space Mono",ui-monospace,monospace; }
body.ks-face-playfair .ks-display { letter-spacing:-.012em; font-weight:800; }
body.ks-face-playfair .ks-badge { letter-spacing:.2em; text-transform:uppercase; font-size:.62rem; }
body.ks-face-fraunces     { --ksf-face:"Fraunces",Georgia,serif; --ksf-caption:"Space Mono",ui-monospace,monospace; }
body.ks-face-fraunces .ks-display { letter-spacing:-.015em; font-weight:800; }
body.ks-face-anton        { --ksf-face:"Anton","Big Shoulders",sans-serif; --ksf-caption:"Space Mono",ui-monospace,monospace; }
body.ks-face-anton .ks-display { text-transform:uppercase; letter-spacing:.01em; font-weight:400; }
body.ks-face-anton .ks-badge { letter-spacing:.22em; text-transform:uppercase; font-size:.62rem; }

/* ===== KS-SET BLOCK (generated by scripts/gen-set-css.mts — do not hand-edit) =====
   Three complete looks per world: a type voice + a palette + an element character, paired by hand so
   the combination is coherent by construction. The app's seed picks one → siblings, never clones. */
body[class*="ks-arch-glass"].ks-set-1 { /* Arctic · jakarta · light */
  --ks-bg:#EAF0F7; --ks-ink:#0E1219; --ks-accent:#0A6CFF; --ks-accent-2:#12C2A0;
  --bg:#EAF0F7; --ink:#0E1219; --acc:#0A6CFF; --accent:#0A6CFF; --accent2:#12C2A0;
  --dim:color-mix(in oklch,#0E1219 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-glass"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-glass"].ks-set-2 { /* Coral · grotesk · light */
  --ks-bg:#F0C3AE; --ks-ink:#24140C; --ks-accent:#A82E0E; --ks-accent-2:#6B4400;
  --bg:#F0C3AE; --ink:#24140C; --acc:#A82E0E; --accent:#A82E0E; --accent2:#6B4400;
  --dim:color-mix(in oklch,#24140C 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-glass"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-glass"].ks-set-3 { /* Onyx · nunito · dark */
  --ks-bg:#12161D; --ks-ink:#F2F6FB; --ks-accent:#7ABBFF; --ks-accent-2:#5CE0BE;
  --bg:#12161D; --ink:#F2F6FB; --acc:#7ABBFF; --accent:#7ABBFF; --accent2:#5CE0BE;
  --dim:color-mix(in oklch,#F2F6FB 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 34%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 30%,transparent), transparent 70%);
}
body[class*="ks-arch-glass"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-glass"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-glass"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-prism"].ks-set-1 { /* Violet · grotesk · dark */
  --ks-bg:#0C0A18; --ks-ink:#F0ECFF; --ks-accent:#A594FF; --ks-accent-2:#4BE0D0;
  --bg:#0C0A18; --ink:#F0ECFF; --acc:#A594FF; --accent:#A594FF; --accent2:#4BE0D0;
  --dim:color-mix(in oklch,#F0ECFF 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-prism"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-prism"].ks-set-1::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 40%,transparent) 0 1px, transparent 1px 3px);
  opacity:0.07; mix-blend-mode:normal;
}
body[class*="ks-arch-prism"].ks-set-1::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-prism"].ks-set-2 { /* Ember · shoulders · dark */
  --ks-bg:#2C1006; --ks-ink:#FFEDE4; --ks-accent:#FF8A4D; --ks-accent-2:#FFC93D;
  --bg:#2C1006; --ink:#FFEDE4; --acc:#FF8A4D; --accent:#FF8A4D; --accent2:#FFC93D;
  --dim:color-mix(in oklch,#FFEDE4 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-prism"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-prism"].ks-set-2::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px), repeating-linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px);
  opacity:0.055; mix-blend-mode:normal;
}
body[class*="ks-arch-prism"].ks-set-2::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-prism"].ks-set-3 { /* Ice · bricolage · light */
  --ks-bg:#E9EEF7; --ks-ink:#0C1220; --ks-accent:#2255C8; --ks-accent-2:#00776A;
  --bg:#E9EEF7; --ink:#0C1220; --acc:#2255C8; --accent:#2255C8; --accent2:#00776A;
  --dim:color-mix(in oklch,#0C1220 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 46%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 40%,transparent), transparent 70%);
}
body[class*="ks-arch-prism"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-prism"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-prism"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-paper"].ks-set-1 { /* Manuscript · mono · light */
  --ks-bg:#F3F1EA; --ks-ink:#241F1A; --ks-accent:#9C2E23; --ks-accent-2:#6B5C48;
  --bg:#F3F1EA; --ink:#241F1A; --acc:#9C2E23; --accent:#9C2E23; --accent2:#6B5C48;
  --dim:color-mix(in oklch,#241F1A 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-paper"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-paper"].ks-set-1::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-paper"].ks-set-1::before {
  background:
    radial-gradient(circle at 0 50%, transparent 0 5px, color-mix(in oklch,var(--ks-ink) 16%,transparent) 5px 5.8px, transparent 5.8px) left / 12px 18px repeat-y, radial-gradient(circle at 100% 50%, transparent 0 5px, color-mix(in oklch,var(--ks-ink) 16%,transparent) 5px 5.8px, transparent 5.8px) right / 12px 18px repeat-y,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-paper"].ks-set-2 { /* Blueprint · fraunces · light */
  --ks-bg:#C4D5E6; --ks-ink:#0E1C2A; --ks-accent:#123C7A; --ks-accent-2:#3B5B78;
  --bg:#C4D5E6; --ink:#0E1C2A; --acc:#123C7A; --accent:#123C7A; --accent2:#3B5B78;
  --dim:color-mix(in oklch,#0E1C2A 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-paper"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-paper"].ks-set-2::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px), repeating-linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px);
  opacity:0.055; mix-blend-mode:normal;
}
body[class*="ks-arch-paper"].ks-set-2::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-paper"].ks-set-3 { /* Carbon · playfair · dark */
  --ks-bg:#23211C; --ks-ink:#F2EDE0; --ks-accent:#E0A03C; --ks-accent-2:#B09070;
  --bg:#23211C; --ink:#F2EDE0; --acc:#E0A03C; --accent:#E0A03C; --accent2:#B09070;
  --dim:color-mix(in oklch,#F2EDE0 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 34%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 30%,transparent), transparent 70%);
}
body[class*="ks-arch-paper"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-paper"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-paper"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-paper"].ks-set-3::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-paper"].ks-set-3::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-editorial"].ks-set-1 { /* Broadsheet · playfair · light */
  --ks-bg:#FCFBF8; --ks-ink:#14110D; --ks-accent:#A94B24; --ks-accent-2:#5A5245;
  --bg:#FCFBF8; --ink:#14110D; --acc:#A94B24; --accent:#A94B24; --accent2:#5A5245;
  --dim:color-mix(in oklch,#14110D 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-editorial"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-editorial"].ks-set-1::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-editorial"].ks-set-1::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-editorial"].ks-set-2 { /* Kraft · fraunces · light */
  --ks-bg:#DCCDB4; --ks-ink:#241C10; --ks-accent:#8A3A16; --ks-accent-2:#5C4A2E;
  --bg:#DCCDB4; --ink:#241C10; --acc:#8A3A16; --accent:#8A3A16; --accent2:#5C4A2E;
  --dim:color-mix(in oklch,#241C10 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-editorial"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-editorial"].ks-set-2::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-editorial"].ks-set-2::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-editorial"].ks-set-3 { /* Noir · jakarta · dark */
  --ks-bg:#141009; --ks-ink:#F5EFE2; --ks-accent:#E0A33C; --ks-accent-2:#9A8A70;
  --bg:#141009; --ink:#F5EFE2; --acc:#E0A33C; --accent:#E0A33C; --accent2:#9A8A70;
  --dim:color-mix(in oklch,#F5EFE2 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 34%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 30%,transparent), transparent 70%);
}
body[class*="ks-arch-editorial"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-editorial"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-editorial"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-editorial"].ks-set-3::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-register"].ks-set-1 { /* Challan · mono · light */
  --ks-bg:#F7F6F1; --ks-ink:#1C1A16; --ks-accent:#A62E21; --ks-accent-2:#6B6458;
  --bg:#F7F6F1; --ink:#1C1A16; --acc:#A62E21; --accent:#A62E21; --accent2:#6B6458;
  --dim:color-mix(in oklch,#1C1A16 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-register"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-register"].ks-set-1::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px), repeating-linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px);
  opacity:0.055; mix-blend-mode:normal;
}
body[class*="ks-arch-register"].ks-set-1::before {
  background:
    radial-gradient(circle at 0 50%, transparent 0 5px, color-mix(in oklch,var(--ks-ink) 16%,transparent) 5px 5.8px, transparent 5.8px) left / 12px 18px repeat-y, radial-gradient(circle at 100% 50%, transparent 0 5px, color-mix(in oklch,var(--ks-ink) 16%,transparent) 5px 5.8px, transparent 5.8px) right / 12px 18px repeat-y,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-register"].ks-set-2 { /* Ledger · fraunces · light */
  --ks-bg:#BCD2B4; --ks-ink:#0E170E; --ks-accent:#17512A; --ks-accent-2:#3E5A45;
  --bg:#BCD2B4; --ink:#0E170E; --acc:#17512A; --accent:#17512A; --accent2:#3E5A45;
  --dim:color-mix(in oklch,#0E170E 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-register"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-register"].ks-set-2::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px), repeating-linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px);
  opacity:0.055; mix-blend-mode:normal;
}
body[class*="ks-arch-register"].ks-set-2::before {
  background:
    radial-gradient(circle at 0 50%, transparent 0 5px, color-mix(in oklch,var(--ks-ink) 16%,transparent) 5px 5.8px, transparent 5.8px) left / 12px 18px repeat-y, radial-gradient(circle at 100% 50%, transparent 0 5px, color-mix(in oklch,var(--ks-ink) 16%,transparent) 5px 5.8px, transparent 5.8px) right / 12px 18px repeat-y,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-register"].ks-set-3 { /* Carbon · jakarta · dark */
  --ks-bg:#201E19; --ks-ink:#F0EBDD; --ks-accent:#D89A45; --ks-accent-2:#A89272;
  --bg:#201E19; --ink:#F0EBDD; --acc:#D89A45; --accent:#D89A45; --accent2:#A89272;
  --dim:color-mix(in oklch,#F0EBDD 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 34%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 30%,transparent), transparent 70%);
}
body[class*="ks-arch-register"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-register"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-register"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-register"].ks-set-3::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-register"].ks-set-3::before {
  background:
    radial-gradient(circle at 0 50%, transparent 0 5px, color-mix(in oklch,var(--ks-ink) 16%,transparent) 5px 5.8px, transparent 5.8px) left / 12px 18px repeat-y, radial-gradient(circle at 100% 50%, transparent 0 5px, color-mix(in oklch,var(--ks-ink) 16%,transparent) 5px 5.8px, transparent 5.8px) right / 12px 18px repeat-y,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-appliance"].ks-set-1 { /* Cream · nunito · light */
  --ks-bg:#EDEAE3; --ks-ink:#1A1815; --ks-accent:#C46A10; --ks-accent-2:#2F6274;
  --bg:#EDEAE3; --ink:#1A1815; --acc:#C46A10; --accent:#C46A10; --accent2:#2F6274;
  --dim:color-mix(in oklch,#1A1815 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-appliance"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-appliance"].ks-set-1::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-appliance"].ks-set-2 { /* Teal · jakarta · light */
  --ks-bg:#AFCFCB; --ks-ink:#0B1A19; --ks-accent:#0A5566; --ks-accent-2:#8A4A00;
  --bg:#AFCFCB; --ink:#0B1A19; --acc:#0A5566; --accent:#0A5566; --accent2:#8A4A00;
  --dim:color-mix(in oklch,#0B1A19 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-appliance"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-appliance"].ks-set-2::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px), repeating-linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px);
  opacity:0.055; mix-blend-mode:normal;
}
body[class*="ks-arch-appliance"].ks-set-2::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-appliance"].ks-set-3 { /* Charcoal · bricolage · dark */
  --ks-bg:#1E2124; --ks-ink:#EDF0F2; --ks-accent:#F0A032; --ks-accent-2:#5AB6C8;
  --bg:#1E2124; --ink:#EDF0F2; --acc:#F0A032; --accent:#F0A032; --accent2:#5AB6C8;
  --dim:color-mix(in oklch,#EDF0F2 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 34%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 30%,transparent), transparent 70%);
}
body[class*="ks-arch-appliance"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-appliance"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-appliance"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-diorama"].ks-set-1 { /* Terrarium · nunito · light */
  --ks-bg:#F6F5F1; --ks-ink:#16211A; --ks-accent:#2F6B41; --ks-accent-2:#A56C2A;
  --bg:#F6F5F1; --ink:#16211A; --acc:#2F6B41; --accent:#2F6B41; --accent2:#A56C2A;
  --dim:color-mix(in oklch,#16211A 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-diorama"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-diorama"].ks-set-1::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-diorama"].ks-set-2 { /* Dusk · fraunces · light */
  --ks-bg:#B9C8D6; --ks-ink:#0F1A24; --ks-accent:#1F4E75; --ks-accent-2:#8A4E1A;
  --bg:#B9C8D6; --ink:#0F1A24; --acc:#1F4E75; --accent:#1F4E75; --accent2:#8A4E1A;
  --dim:color-mix(in oklch,#0F1A24 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-diorama"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-diorama"].ks-set-3 { /* Night · jakarta · dark */
  --ks-bg:#16211C; --ks-ink:#E8F0E9; --ks-accent:#5FC183; --ks-accent-2:#D8A24C;
  --bg:#16211C; --ink:#E8F0E9; --acc:#5FC183; --accent:#5FC183; --accent2:#D8A24C;
  --dim:color-mix(in oklch,#E8F0E9 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 34%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 30%,transparent), transparent 70%);
}
body[class*="ks-arch-diorama"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-diorama"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-diorama"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-diorama"].ks-set-3::after {
  background-image:radial-gradient(1.6px 1.6px at 20% 30%, var(--ks-accent), transparent), radial-gradient(1.4px 1.4px at 70% 20%, var(--ks-accent-2), transparent), radial-gradient(1.8px 1.8px at 40% 75%, var(--ks-accent), transparent), radial-gradient(1.3px 1.3px at 85% 62%, var(--ks-accent-2), transparent);
  opacity:0.42; mix-blend-mode:normal;
}
body[class*="ks-arch-console"].ks-set-1 { /* Amber · mono · dark */
  --ks-bg:#0B1220; --ks-ink:#C7D3E4; --ks-accent:#FF6B4A; --ks-accent-2:#7AD7FF;
  --bg:#0B1220; --ink:#C7D3E4; --acc:#FF6B4A; --accent:#FF6B4A; --accent2:#7AD7FF;
  --dim:color-mix(in oklch,#C7D3E4 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-console"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-console"].ks-set-1::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 40%,transparent) 0 1px, transparent 1px 3px);
  opacity:0.07; mix-blend-mode:normal;
}
body[class*="ks-arch-console"].ks-set-1::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-console"].ks-set-2 { /* Phosphor · grotesk · dark */
  --ks-bg:#04160B; --ks-ink:#B8F0C8; --ks-accent:#35E07A; --ks-accent-2:#F0D060;
  --bg:#04160B; --ink:#B8F0C8; --acc:#35E07A; --accent:#35E07A; --accent2:#F0D060;
  --dim:color-mix(in oklch,#B8F0C8 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-console"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-console"].ks-set-2::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 40%,transparent) 0 1px, transparent 1px 3px);
  opacity:0.07; mix-blend-mode:normal;
}
body[class*="ks-arch-console"].ks-set-2::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-console"].ks-set-3 { /* Bone · shoulders · light */
  --ks-bg:#D8DCE0; --ks-ink:#12171C; --ks-accent:#B03A22; --ks-accent-2:#25607A;
  --bg:#D8DCE0; --ink:#12171C; --acc:#B03A22; --accent:#B03A22; --accent2:#25607A;
  --dim:color-mix(in oklch,#12171C 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 46%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 40%,transparent), transparent 70%);
}
body[class*="ks-arch-console"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-console"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-console"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-console"].ks-set-3::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px), repeating-linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px);
  opacity:0.055; mix-blend-mode:normal;
}
body[class*="ks-arch-console"].ks-set-3::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-poster"].ks-set-1 { /* Vector · anton · dark */
  --ks-bg:#1B54C4; --ks-ink:#FFFFFF; --ks-accent:#FFD400; --ks-accent-2:#FF9EB4;
  --bg:#1B54C4; --ink:#FFFFFF; --acc:#FFD400; --accent:#FFD400; --accent2:#FF9EB4;
  --dim:color-mix(in oklch,#FFFFFF 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-poster"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-poster"].ks-set-1::after {
  background-image:radial-gradient(color-mix(in oklch,var(--ks-ink) 60%,transparent) 22%, transparent 23%);
  background-size:6px 6px;
  opacity:0.075; mix-blend-mode:normal;
}
body[class*="ks-arch-poster"].ks-set-1::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-poster"].ks-set-2 { /* Riso · shoulders · dark */
  --ks-bg:#16161A; --ks-ink:#F5F2E8; --ks-accent:#FF4D2E; --ks-accent-2:#2ED3B0;
  --bg:#16161A; --ink:#F5F2E8; --acc:#FF4D2E; --accent:#FF4D2E; --accent2:#2ED3B0;
  --dim:color-mix(in oklch,#F5F2E8 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-poster"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-poster"].ks-set-2::after {
  background-image:radial-gradient(color-mix(in oklch,var(--ks-ink) 60%,transparent) 22%, transparent 23%);
  background-size:6px 6px;
  opacity:0.075; mix-blend-mode:normal;
}
body[class*="ks-arch-poster"].ks-set-2::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-poster"].ks-set-3 { /* Newsprint · bricolage · light */
  --ks-bg:#EFE9DC; --ks-ink:#161410; --ks-accent:#C42020; --ks-accent-2:#1B54C4;
  --bg:#EFE9DC; --ink:#161410; --acc:#C42020; --accent:#C42020; --accent2:#1B54C4;
  --dim:color-mix(in oklch,#161410 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 46%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 40%,transparent), transparent 70%);
}
body[class*="ks-arch-poster"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-poster"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-poster"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-poster"].ks-set-3::after {
  background-image:radial-gradient(color-mix(in oklch,var(--ks-ink) 60%,transparent) 22%, transparent 23%);
  background-size:6px 6px;
  opacity:0.075; mix-blend-mode:normal;
}
body[class*="ks-arch-poster"].ks-set-3::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-void"].ks-set-1 { /* Ember · grotesk · dark */
  --ks-bg:#050507; --ks-ink:#F5F0EA; --ks-accent:#FF3B30; --ks-accent-2:#FFB020;
  --bg:#050507; --ink:#F5F0EA; --acc:#FF3B30; --accent:#FF3B30; --accent2:#FFB020;
  --dim:color-mix(in oklch,#F5F0EA 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-void"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-void"].ks-set-1::after {
  background-image:radial-gradient(1.2px 1.2px at 18% 24%, var(--ks-ink), transparent), radial-gradient(1px 1px at 72% 12%, var(--ks-ink), transparent), radial-gradient(1.4px 1.4px at 44% 68%, var(--ks-ink), transparent), radial-gradient(1px 1px at 86% 54%, var(--ks-ink), transparent), radial-gradient(1.1px 1.1px at 28% 88%, var(--ks-ink), transparent);
  opacity:0.5; mix-blend-mode:normal;
}
body[class*="ks-arch-void"].ks-set-2 { /* Ion · mono · dark */
  --ks-bg:#04101C; --ks-ink:#DDEBFF; --ks-accent:#00D4FF; --ks-accent-2:#7B5CFF;
  --bg:#04101C; --ink:#DDEBFF; --acc:#00D4FF; --accent:#00D4FF; --accent2:#7B5CFF;
  --dim:color-mix(in oklch,#DDEBFF 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-void"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-void"].ks-set-2::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 40%,transparent) 0 1px, transparent 1px 3px);
  opacity:0.07; mix-blend-mode:normal;
}
body[class*="ks-arch-void"].ks-set-3 { /* Whiteout · shoulders · light */
  --ks-bg:#F2F4F7; --ks-ink:#0A0A0C; --ks-accent:#E02418; --ks-accent-2:#2A5BE0;
  --bg:#F2F4F7; --ink:#0A0A0C; --acc:#E02418; --accent:#E02418; --accent2:#2A5BE0;
  --dim:color-mix(in oklch,#0A0A0C 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 46%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 40%,transparent), transparent 70%);
}
body[class*="ks-arch-void"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-void"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-void"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-stage"].ks-set-1 { /* Velvet · playfair · dark */
  --ks-bg:#170F2B; --ks-ink:#F2E9DC; --ks-accent:#D4AD55; --ks-accent-2:#D06AAA;
  --bg:#170F2B; --ink:#F2E9DC; --acc:#D4AD55; --accent:#D4AD55; --accent2:#D06AAA;
  --dim:color-mix(in oklch,#F2E9DC 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-stage"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-stage"].ks-set-1::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-stage"].ks-set-1::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-stage"].ks-set-2 { /* Curtain · fraunces · dark */
  --ks-bg:#3A1018; --ks-ink:#F7E8E2; --ks-accent:#EE7A6A; --ks-accent-2:#D4AD55;
  --bg:#3A1018; --ink:#F7E8E2; --acc:#EE7A6A; --accent:#EE7A6A; --accent2:#D4AD55;
  --dim:color-mix(in oklch,#F7E8E2 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-stage"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-stage"].ks-set-2::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-stage"].ks-set-2::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-stage"].ks-set-3 { /* Alabaster · nunito · dark */
  --ks-bg:#2B2118; --ks-ink:#F7EFE2; --ks-accent:#E8B96A; --ks-accent-2:#C08AB8;
  --bg:#2B2118; --ink:#F7EFE2; --acc:#E8B96A; --accent:#E8B96A; --accent2:#C08AB8;
  --dim:color-mix(in oklch,#F7EFE2 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-stage"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-stage"].ks-set-3::before {
  background:
    linear-gradient(color-mix(in oklch,var(--ks-ink) 46%,transparent), color-mix(in oklch,var(--ks-ink) 46%,transparent)) top 10px left 0 / 100% 1px no-repeat, linear-gradient(color-mix(in oklch,var(--ks-ink) 22%,transparent), color-mix(in oklch,var(--ks-ink) 22%,transparent)) top 14px left 0 / 100% 1px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-felt"].ks-set-1 { /* Table · nunito · dark */
  --ks-bg:#0D3529; --ks-ink:#F0EDE0; --ks-accent:#E9A519; --ks-accent-2:#F0765A;
  --bg:#0D3529; --ink:#F0EDE0; --acc:#E9A519; --accent:#E9A519; --accent2:#F0765A;
  --dim:color-mix(in oklch,#F0EDE0 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-felt"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-felt"].ks-set-1::after {
  background-image:repeating-linear-gradient(45deg, color-mix(in oklch,var(--ks-ink) 30%,transparent) 0 1px, transparent 1px 4px), repeating-linear-gradient(-45deg, color-mix(in oklch,var(--ks-ink) 30%,transparent) 0 1px, transparent 1px 4px);
  opacity:0.06; mix-blend-mode:normal;
}
body[class*="ks-arch-felt"].ks-set-1::before {
  background:
    linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 6px, transparent 6px 12px) top 13px left / 12px 1px repeat-x, linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 6px, transparent 6px 12px) bottom 13px left / 12px 1px repeat-x,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-felt"].ks-set-2 { /* Night · bricolage · dark */
  --ks-bg:#141E3C; --ks-ink:#EDEEF5; --ks-accent:#F07A57; --ks-accent-2:#5ADCA8;
  --bg:#141E3C; --ink:#EDEEF5; --acc:#F07A57; --accent:#F07A57; --accent2:#5ADCA8;
  --dim:color-mix(in oklch,#EDEEF5 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-felt"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-felt"].ks-set-2::after {
  background-image:repeating-linear-gradient(45deg, color-mix(in oklch,var(--ks-ink) 30%,transparent) 0 1px, transparent 1px 4px), repeating-linear-gradient(-45deg, color-mix(in oklch,var(--ks-ink) 30%,transparent) 0 1px, transparent 1px 4px);
  opacity:0.06; mix-blend-mode:normal;
}
body[class*="ks-arch-felt"].ks-set-2::before {
  background:
    linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 6px, transparent 6px 12px) top 13px left / 12px 1px repeat-x, linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 6px, transparent 6px 12px) bottom 13px left / 12px 1px repeat-x,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-felt"].ks-set-3 { /* Sand · fraunces · light */
  --ks-bg:#E4D9C2; --ks-ink:#1E1710; --ks-accent:#9A4A18; --ks-accent-2:#2F6B54;
  --bg:#E4D9C2; --ink:#1E1710; --acc:#9A4A18; --accent:#9A4A18; --accent2:#2F6B54;
  --dim:color-mix(in oklch,#1E1710 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 46%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 40%,transparent), transparent 70%);
}
body[class*="ks-arch-felt"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-felt"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-felt"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-felt"].ks-set-3::after {
  background-image:repeating-linear-gradient(45deg, color-mix(in oklch,var(--ks-ink) 30%,transparent) 0 1px, transparent 1px 4px), repeating-linear-gradient(-45deg, color-mix(in oklch,var(--ks-ink) 30%,transparent) 0 1px, transparent 1px 4px);
  opacity:0.06; mix-blend-mode:normal;
}
body[class*="ks-arch-felt"].ks-set-3::before {
  background:
    linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 6px, transparent 6px 12px) top 13px left / 12px 1px repeat-x, linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 6px, transparent 6px 12px) bottom 13px left / 12px 1px repeat-x,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-carnival"].ks-set-1 { /* Mela · slab · dark */
  --ks-bg:#7A1E2C; --ks-ink:#FFF3E0; --ks-accent:#FFC93C; --ks-accent-2:#5EDBC6;
  --bg:#7A1E2C; --ink:#FFF3E0; --acc:#FFC93C; --accent:#FFC93C; --accent2:#5EDBC6;
  --dim:color-mix(in oklch,#FFF3E0 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-carnival"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-carnival"].ks-set-1::after {
  background-image:radial-gradient(1.6px 1.6px at 20% 30%, var(--ks-accent), transparent), radial-gradient(1.4px 1.4px at 70% 20%, var(--ks-accent-2), transparent), radial-gradient(1.8px 1.8px at 40% 75%, var(--ks-accent), transparent), radial-gradient(1.3px 1.3px at 85% 62%, var(--ks-accent-2), transparent);
  opacity:0.42; mix-blend-mode:normal;
}
body[class*="ks-arch-carnival"].ks-set-1::before {
  background:
    linear-gradient(135deg, var(--ks-accent) 25%, transparent 25.5%) top left / 26px 16px repeat-x, linear-gradient(-135deg, var(--ks-accent-2) 25%, transparent 25.5%) top left / 26px 16px repeat-x,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-carnival"].ks-set-2 { /* Bunting · bricolage · dark */
  --ks-bg:#1E2A6E; --ks-ink:#FFF0E6; --ks-accent:#FF8FB0; --ks-accent-2:#FFD24D;
  --bg:#1E2A6E; --ink:#FFF0E6; --acc:#FF8FB0; --accent:#FF8FB0; --accent2:#FFD24D;
  --dim:color-mix(in oklch,#FFF0E6 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-carnival"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-carnival"].ks-set-2::after {
  background-image:radial-gradient(1.6px 1.6px at 20% 30%, var(--ks-accent), transparent), radial-gradient(1.4px 1.4px at 70% 20%, var(--ks-accent-2), transparent), radial-gradient(1.8px 1.8px at 40% 75%, var(--ks-accent), transparent), radial-gradient(1.3px 1.3px at 85% 62%, var(--ks-accent-2), transparent);
  opacity:0.42; mix-blend-mode:normal;
}
body[class*="ks-arch-carnival"].ks-set-2::before {
  background:
    linear-gradient(135deg, var(--ks-accent) 25%, transparent 25.5%) top left / 26px 16px repeat-x, linear-gradient(-135deg, var(--ks-accent-2) 25%, transparent 25.5%) top left / 26px 16px repeat-x,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-carnival"].ks-set-3 { /* Candyfloss · nunito · light */
  --ks-bg:#F7E4EE; --ks-ink:#2A0E1C; --ks-accent:#C42A6B; --ks-accent-2:#1F7A8C;
  --bg:#F7E4EE; --ink:#2A0E1C; --acc:#C42A6B; --accent:#C42A6B; --accent2:#1F7A8C;
  --dim:color-mix(in oklch,#2A0E1C 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 46%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 40%,transparent), transparent 70%);
}
body[class*="ks-arch-carnival"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-carnival"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-carnival"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-carnival"].ks-set-3::after {
  background-image:radial-gradient(color-mix(in oklch,var(--ks-ink) 60%,transparent) 22%, transparent 23%);
  background-size:6px 6px;
  opacity:0.075; mix-blend-mode:normal;
}
body[class*="ks-arch-carnival"].ks-set-3::before {
  background:
    linear-gradient(135deg, var(--ks-accent) 25%, transparent 25.5%) top left / 26px 16px repeat-x, linear-gradient(-135deg, var(--ks-accent-2) 25%, transparent 25.5%) top left / 26px 16px repeat-x,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-stadium"].ks-set-1 { /* Floodlight · shoulders · dark */
  --ks-bg:#0E3B24; --ks-ink:#F2F7EE; --ks-accent:#F2E641; --ks-accent-2:#5AC8F5;
  --bg:#0E3B24; --ink:#F2F7EE; --acc:#F2E641; --accent:#F2E641; --accent2:#5AC8F5;
  --dim:color-mix(in oklch,#F2F7EE 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-stadium"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-stadium"].ks-set-1::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px), repeating-linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px);
  opacity:0.055; mix-blend-mode:normal;
}
body[class*="ks-arch-stadium"].ks-set-1::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-stadium"].ks-set-2 { /* Clay · anton · dark */
  --ks-bg:#5A2416; --ks-ink:#FBF0E6; --ks-accent:#F2A03D; --ks-accent-2:#8FE06A;
  --bg:#5A2416; --ink:#FBF0E6; --acc:#F2A03D; --accent:#F2A03D; --accent2:#8FE06A;
  --dim:color-mix(in oklch,#FBF0E6 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-stadium"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-stadium"].ks-set-2::after {
  background-image:repeating-linear-gradient(45deg, color-mix(in oklch,var(--ks-ink) 30%,transparent) 0 1px, transparent 1px 4px), repeating-linear-gradient(-45deg, color-mix(in oklch,var(--ks-ink) 30%,transparent) 0 1px, transparent 1px 4px);
  opacity:0.06; mix-blend-mode:normal;
}
body[class*="ks-arch-stadium"].ks-set-2::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-stadium"].ks-set-3 { /* Away · mono · dark */
  --ks-bg:#1B2A46; --ks-ink:#EDF3FB; --ks-accent:#FF9E3D; --ks-accent-2:#6FE0A8;
  --bg:#1B2A46; --ink:#EDF3FB; --acc:#FF9E3D; --accent:#FF9E3D; --accent2:#6FE0A8;
  --dim:color-mix(in oklch,#EDF3FB 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-stadium"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-stadium"].ks-set-3::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-toybox"].ks-set-1 { /* Blocks · bricolage · dark */
  --ks-bg:#1B2340; --ks-ink:#EAF0FF; --ks-accent:#4BC4E8; --ks-accent-2:#FF7FAA;
  --bg:#1B2340; --ink:#EAF0FF; --acc:#4BC4E8; --accent:#4BC4E8; --accent2:#FF7FAA;
  --dim:color-mix(in oklch,#EAF0FF 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-toybox"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-toybox"].ks-set-1::after {
  background-image:radial-gradient(1.6px 1.6px at 20% 30%, var(--ks-accent), transparent), radial-gradient(1.4px 1.4px at 70% 20%, var(--ks-accent-2), transparent), radial-gradient(1.8px 1.8px at 40% 75%, var(--ks-accent), transparent), radial-gradient(1.3px 1.3px at 85% 62%, var(--ks-accent-2), transparent);
  opacity:0.42; mix-blend-mode:normal;
}
body[class*="ks-arch-toybox"].ks-set-2 { /* Candy · nunito · dark */
  --ks-bg:#3A1148; --ks-ink:#FCEBFA; --ks-accent:#FF7AD1; --ks-accent-2:#4FE0C4;
  --bg:#3A1148; --ink:#FCEBFA; --acc:#FF7AD1; --accent:#FF7AD1; --accent2:#4FE0C4;
  --dim:color-mix(in oklch,#FCEBFA 55%,transparent);
  --ks-radius:999px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-toybox"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:999px; }
body[class*="ks-arch-toybox"].ks-set-2::after {
  background-image:radial-gradient(color-mix(in oklch,var(--ks-ink) 60%,transparent) 22%, transparent 23%);
  background-size:6px 6px;
  opacity:0.075; mix-blend-mode:normal;
}
body[class*="ks-arch-toybox"].ks-set-3 { /* Circuit · grotesk · dark */
  --ks-bg:#0F1A1F; --ks-ink:#E4F2F0; --ks-accent:#3DE0B0; --ks-accent-2:#FFB84D;
  --bg:#0F1A1F; --ink:#E4F2F0; --acc:#3DE0B0; --accent:#3DE0B0; --accent2:#FFB84D;
  --dim:color-mix(in oklch,#E4F2F0 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-toybox"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-toybox"].ks-set-3::after {
  background-image:repeating-linear-gradient(0deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px), repeating-linear-gradient(90deg, color-mix(in oklch,var(--ks-ink) 34%,transparent) 0 1px, transparent 1px 22px);
  opacity:0.055; mix-blend-mode:normal;
}
body[class*="ks-arch-toybox"].ks-set-3::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-observatory"].ks-set-1 { /* DeepField · grotesk · dark */
  --ks-bg:#05060C; --ks-ink:#E8ECF8; --ks-accent:#F5B940; --ks-accent-2:#7B93FF;
  --bg:#05060C; --ink:#E8ECF8; --acc:#F5B940; --accent:#F5B940; --accent2:#7B93FF;
  --dim:color-mix(in oklch,#E8ECF8 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-observatory"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-observatory"].ks-set-1::after {
  background-image:radial-gradient(1.2px 1.2px at 18% 24%, var(--ks-ink), transparent), radial-gradient(1px 1px at 72% 12%, var(--ks-ink), transparent), radial-gradient(1.4px 1.4px at 44% 68%, var(--ks-ink), transparent), radial-gradient(1px 1px at 86% 54%, var(--ks-ink), transparent), radial-gradient(1.1px 1.1px at 28% 88%, var(--ks-ink), transparent);
  opacity:0.5; mix-blend-mode:normal;
}
body[class*="ks-arch-observatory"].ks-set-2 { /* Nebula · mono · dark */
  --ks-bg:#1C0730; --ks-ink:#F0E6FA; --ks-accent:#C77AFF; --ks-accent-2:#3DD6E0;
  --bg:#1C0730; --ink:#F0E6FA; --acc:#C77AFF; --accent:#C77AFF; --accent2:#3DD6E0;
  --dim:color-mix(in oklch,#F0E6FA 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-observatory"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-observatory"].ks-set-2::after {
  background-image:radial-gradient(1.2px 1.2px at 18% 24%, var(--ks-ink), transparent), radial-gradient(1px 1px at 72% 12%, var(--ks-ink), transparent), radial-gradient(1.4px 1.4px at 44% 68%, var(--ks-ink), transparent), radial-gradient(1px 1px at 86% 54%, var(--ks-ink), transparent), radial-gradient(1.1px 1.1px at 28% 88%, var(--ks-ink), transparent);
  opacity:0.5; mix-blend-mode:normal;
}
body[class*="ks-arch-observatory"].ks-set-3 { /* Dawn · shoulders · light */
  --ks-bg:#DCE4EE; --ks-ink:#0A1020; --ks-accent:#2A4A9C; --ks-accent-2:#A65A1A;
  --bg:#DCE4EE; --ink:#0A1020; --acc:#2A4A9C; --accent:#2A4A9C; --accent2:#A65A1A;
  --dim:color-mix(in oklch,#0A1020 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 46%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 40%,transparent), transparent 70%);
}
body[class*="ks-arch-observatory"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-observatory"].ks-set-3 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-observatory"].ks-set-3 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-canvas"].ks-set-1 { /* Studio · jakarta · dark */
  --ks-bg:#0A0C10; --ks-ink:#EDF2F7; --ks-accent:#7AD7FF; --ks-accent-2:#FF8FD6;
  --bg:#0A0C10; --ink:#EDF2F7; --acc:#7AD7FF; --accent:#7AD7FF; --accent2:#FF8FD6;
  --dim:color-mix(in oklch,#EDF2F7 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-canvas"].ks-set-1 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-canvas"].ks-set-1::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
body[class*="ks-arch-canvas"].ks-set-2 { /* Graphite · bricolage · light */
  --ks-bg:#D5D5D2; --ks-ink:#131313; --ks-accent:#8A6A00; --ks-accent-2:#1F6B52;
  --bg:#D5D5D2; --ink:#131313; --acc:#8A6A00; --accent:#8A6A00; --accent2:#1F6B52;
  --dim:color-mix(in oklch,#131313 55%,transparent);
  --ks-radius:4px;
  background-color:var(--ks-bg); color:var(--ks-ink);
  background-image:
    radial-gradient(62% 44% at 16% 4%, color-mix(in oklch,var(--ks-accent) 46%,transparent), transparent 68%),
    radial-gradient(58% 42% at 92% 96%, color-mix(in oklch,var(--ks-accent-2) 40%,transparent), transparent 70%);
}
body[class*="ks-arch-canvas"].ks-set-2 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:4px; }
body[class*="ks-arch-canvas"].ks-set-2 :is(h1,h2,h3,.ks-display,.ks-title) {
  background:none !important; -webkit-text-fill-color:var(--ks-ink) !important; color:var(--ks-ink) !important; text-shadow:none; filter:none;
}
body[class*="ks-arch-canvas"].ks-set-2 :is(.vibe,.count,.k-sub,.ks-body,.msg,p) { color:color-mix(in oklch,var(--ks-ink) 78%,transparent) !important; }
body[class*="ks-arch-canvas"].ks-set-2::after {
  background-image:radial-gradient(color-mix(in oklch,var(--ks-ink) 60%,transparent) 22%, transparent 23%);
  background-size:6px 6px;
  opacity:0.075; mix-blend-mode:normal;
}
body[class*="ks-arch-canvas"].ks-set-2::before {
  background:
    linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) top 12px left 12px / 1px 14px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 14px 1px no-repeat, linear-gradient(var(--ks-accent),var(--ks-accent)) bottom 12px right 12px / 1px 14px no-repeat,
    radial-gradient(120% 80% at 18% -10%, color-mix(in oklch, var(--ks-accent) 13%, transparent), transparent 62%),
    radial-gradient(130% 100% at 50% 108%, color-mix(in oklch, var(--ks-bg) 82%, var(--ks-ink)), transparent 70%);
}
body[class*="ks-arch-canvas"].ks-set-3 { /* Wash · grotesk · dark */
  --ks-bg:#123038; --ks-ink:#E8F4F2; --ks-accent:#5AE0C0; --ks-accent-2:#FFA070;
  --bg:#123038; --ink:#E8F4F2; --acc:#5AE0C0; --accent:#5AE0C0; --accent2:#FFA070;
  --dim:color-mix(in oklch,#E8F4F2 55%,transparent);
  --ks-radius:18px;
  background-color:var(--ks-bg); color:var(--ks-ink);
}
body[class*="ks-arch-canvas"].ks-set-3 :is(.ks-card,.ks-panel,.ks-btn) { border-radius:18px; }
body[class*="ks-arch-canvas"].ks-set-3::after {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.62' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E");
  opacity:0.085; mix-blend-mode:overlay;
}
/* ===== END KS-SET BLOCK ===== */
