/*
 * Koder Design — base layout
 *
 * AAA contrast palette, light + dark via [data-theme]. Per-spec content
 * (preset previews) lives in presets.css and is loaded only on style
 * pages so other kinds stay lean.
 */

/* ════════════════════════════════════════════════════════════════════
 * Vendored from `engines/sdk/koder_web_kit/koder-web-kit.css`
 *
 *   - canonical source of truth: koder_web_kit (commit 68863379f2+)
 *   - design-RFC-002 Camada 2/3, ratified 2026-05-12 (D1 + D2 = core)
 *   - design-gen is a static-site generator that produces self-
 *     contained dist/, so we vendor-inline rather than HTTP-import.
 *
 * Keep in sync: when koder_web_kit/responsive.css changes, this block
 * must mirror it.  A drift-detection CI hook is tracked in #003
 * (slice 2).  Per-class doc lives in the SDK file — this is a
 * sync target, not the source.
 *
 * Note: `--kds-bp-*` CSS vars live in the consolidated `:root` block
 * lower in this file (with `--kds-topbar-height`), not here — the
 * token extractor (internal/tokens/extract.go) grabs the FIRST
 * `:root {}` it finds, so we can't shadow the `--kdr-*` palette.
 * ════════════════════════════════════════════════════════════════════ */

/* SDK-VENDORED-BEGIN — rules between this marker and SDK-VENDORED-END
   are scanned by cmd/responsive-drift-check against
   engines/sdk/koder_web_kit/koder-web-kit.css. Drift fails CI. Move a
   rule OUT of this block when it's local to design-gen (utility that
   doesn't belong in the shared SDK). #021 introduced the sentinels. */
.kds-hide-below-sm,
.kds-hide-below-md,
.kds-hide-below-lg { display: none; }

@media (min-width: 640px)  { .kds-hide-below-sm { display: revert; } }
@media (min-width: 900px)  { .kds-hide-below-md { display: revert; } }
@media (min-width: 1280px) { .kds-hide-below-lg { display: revert; } }

@media (min-width: 640px)  { .kds-hide-above-sm { display: none; } }
@media (min-width: 900px)  { .kds-hide-above-md { display: none; } }
@media (min-width: 1280px) { .kds-hide-above-lg { display: none; } }

.kds-stack-below-md {
  display: flex;
  flex-direction: row;
  gap: 16px;
  flex-wrap: wrap;
}
@media (max-width: 899px) {
  .kds-stack-below-md { flex-direction: column; }
}

.kds-grid-auto {
  display: grid;
  gap: var(--kds-grid-gap, 16px);
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(var(--kds-grid-min, 280px), 100%), 1fr)
  );
}

/* SDK-VENDORED-END — see SDK-VENDORED-BEGIN above. */
/* End vendored block. ════════════════════════════════════════════════ */

/* Typography — canonical Koder Design System implementation.
   Spec: meta/docs/stack/specs/fonts/typography.kmd
   Wave 1: Inter (sans) + JetBrains Mono (mono), both self-hosted OFL.
   font-display: swap mitigates FOIT. Preloaded by layout.templ. Per
   policies/self-hosted-first.kmd G1, no Google Fonts CDN. */
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/inter-latin-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/assets/fonts/jetbrains-mono-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* KDS-022 (2026-05-13) — compare-mode classes share the token block
   with :root so we can wrap any subtree in `.themed-light` to force
   light tokens locally (mirror logic for dark below). Used by the
   uistyle detail page's "Compare modes" feature (side-by-side
   light|dark preset preview) without changing the global theme. */
/* Ticket #047 — Theme switch transition. Cross-fades tokens on
   theme toggle once data-theme-ready flips on the first frame
   (gated so the initial paint doesn't animate). Reduced-motion
   collapses to 0ms. */
:root[data-theme-ready="true"] *,
:root[data-theme-ready="true"] *::before,
:root[data-theme-ready="true"] *::after {
  transition: background-color 200ms cubic-bezier(0.2, 0, 0, 1),
              color 200ms cubic-bezier(0.2, 0, 0, 1),
              border-color 200ms cubic-bezier(0.2, 0, 0, 1),
              box-shadow 200ms cubic-bezier(0.2, 0, 0, 1),
              fill 200ms cubic-bezier(0.2, 0, 0, 1),
              stroke 200ms cubic-bezier(0.2, 0, 0, 1);
}
@media (prefers-reduced-motion: reduce) {
  :root[data-theme-ready="true"] *,
  :root[data-theme-ready="true"] *::before,
  :root[data-theme-ready="true"] *::after {
    transition-duration: 0ms;
  }
}

:root,
.themed-light {
  /* Typography roles — canonical KDS variables per
     meta/docs/stack/specs/fonts/typography.kmd. Components MUST
     resolve every font-family through these (no hard-coded typeface
     names) so Wave-2/3 typeface swaps are one-line edits. */
  --kds-font-sans:    'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --kds-font-mono:    'JetBrains Mono', ui-monospace, "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace;
  --kds-font-display: var(--kds-font-sans);
  --kds-font-serif:   ui-serif, Georgia, "Times New Roman", serif;

  /* Tell the UA which color scheme our form controls expect. Without
     this, native <button>/<input>/<select> in OS-dark-mode browsers
     paint with system "ButtonText" white even when our CSS sets an
     explicit dark color (the inactive theme toggle "Escuro" was
     becoming nearly invisible in light mode for this reason). */
  color-scheme: light;

  --kdr-bg: #ffffff;
  --kdr-surface: #f5f5f7;
  --kdr-surface-2: #eaeaee;
  --kdr-text: #161616;
  --kdr-text-muted: #4b4b4b;
  --kdr-accent: #1f3a93;
  --kdr-accent-on: #ffffff;
  --kdr-border: #d4d4d9;
  --kdr-focus: #0f3bd6;
  --kdr-radius-sm: 6px;
  --kdr-radius-md: 10px;
  --kdr-radius-lg: 16px;
  --kdr-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.10), 0 2px 6px rgba(0, 0, 0, 0.06);
  --kdr-fs-base: 16px;
  font-size: var(--kdr-fs-base);

  /* Motion tokens — per meta/docs/stack/specs/themes/motion/easing-duration.kmd
     R1/R2 + physics.kmd R4 (springs as linear() approximation). Material 3
     Expressive parity wave 1 (tools/design-gen#020). Concrete defaults are
     the material3 baseline; presets may override (terminal_classic /
     brutalist set durations to 0ms per spec R4.5). */
  --kds-motion-duration-instant: 50ms;
  --kds-motion-duration-fast: 150ms;
  --kds-motion-duration-medium: 250ms;
  --kds-motion-duration-slow: 400ms;
  --kds-motion-duration-long: 600ms;

  --kds-motion-easing-standard:    cubic-bezier(0.2, 0, 0, 1);
  --kds-motion-easing-decelerate:  cubic-bezier(0, 0, 0, 1);
  --kds-motion-easing-accelerate:  cubic-bezier(0.3, 0, 1, 1);
  --kds-motion-easing-emphasize:   cubic-bezier(0.2, 0, 0, 1);
  --kds-motion-easing-linear:      linear;

  /* Spring tokens — linear() approximations precomputed from
     SpringDescription(stiffness, dampingRatio, mass). physics.kmd R4.1/R4.2.
     Browsers without linear() support fall back to ease-out via @supports. */
  --kds-motion-spring-spatial-fast:    linear(0, 0.49, 0.85, 1.0);
  --kds-motion-spring-spatial-default: linear(0, 0.18, 0.56, 0.85, 0.98, 1.0);
  --kds-motion-spring-spatial-slow:    linear(0, 0.06, 0.24, 0.55, 0.83, 0.97, 1.0);
  --kds-motion-spring-effect-fast:     linear(0, 0.73, 0.96, 1.0);
  --kds-motion-spring-effect-default:  linear(0, 0.42, 0.84, 0.97, 1.0);
  --kds-motion-spring-effect-slow:     linear(0, 0.19, 0.55, 0.85, 0.97, 1.0);
}

@supports not (transition-timing-function: linear(0, 1)) {
  :root, .themed-light, :root[data-theme="dark"] {
    --kds-motion-spring-spatial-fast:    cubic-bezier(0.16, 1, 0.3, 1);
    --kds-motion-spring-spatial-default: cubic-bezier(0.16, 1, 0.3, 1);
    --kds-motion-spring-spatial-slow:    cubic-bezier(0.22, 1, 0.36, 1);
    --kds-motion-spring-effect-fast:     cubic-bezier(0.4, 0, 0.2, 1);
    --kds-motion-spring-effect-default:  cubic-bezier(0.4, 0, 0.2, 1);
    --kds-motion-spring-effect-slow:     cubic-bezier(0.4, 0, 0.2, 1);
  }
}

/* Global reduced-motion gate — per motion/physics.kmd R1. Collapses
   every animation to 0ms, freezes infinite loops, and disables
   scroll-behavior. Local reduced-motion blocks elsewhere in this
   file remain as defense-in-depth. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ─── Page-level View Transitions API ──────────────────────────────
   Cross-document opt-in lives in <meta name="view-transition"
   content="same-origin"> (layout.templ). When Chrome 126+ navigates
   between pages, it captures old/new snapshots and fades them via the
   ::view-transition-* pseudos below. Per motion/transitions.kmd R3
   page-level table: same-surface tab switch → cross-fade (fast).
   Browsers without support: zero regression — they navigate normally
   (no fade), and the @supports check is implicit (the pseudos are
   silently ignored). */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--kds-motion-duration-medium, 250ms);
  animation-timing-function: var(--kds-motion-easing-standard, ease);
}
::view-transition-old(root) {
  animation-name: kds-vt-fade-out;
}
::view-transition-new(root) {
  animation-name: kds-vt-fade-in;
}
@keyframes kds-vt-fade-out { to { opacity: 0; } }
@keyframes kds-vt-fade-in  { from { opacity: 0; } }

/* Reduced-motion: VT runs but is instant (the global block above
   collapses the duration; we also guard explicitly here so the
   pseudo selector — which is not matched by `*` — still snaps). */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0.01ms !important;
  }
}

/* Container transform pattern — per motion/transitions.kmd R1 row 4
   ("Card → detail page (shared element)"). Apply `.kds-vt-container`
   to a card and its detail-page hero with matching view-transition-name
   to get the morph automatically (browser handles the rest).
   Example use:
     <a class="card kds-vt-container" style="view-transition-name: card-42">…</a>
     <h1 class="hero kds-vt-container" style="view-transition-name: card-42">…</h1> */
.kds-vt-container {
  view-transition-name: var(--kds-vt-name, auto);
}
::view-transition-group(*) {
  animation-duration: var(--kds-motion-duration-slow, 400ms);
  animation-timing-function: var(--kds-motion-easing-emphasize, ease);
}

/* Shared-axis pattern — per motion/transitions.kmd R1 row 5 ("Stepwise
   nav — onboarding, wizard"). Apply `.kds-axis-x` or `.kds-axis-y` to
   the entry-point body class to swap the default fade for an axial
   slide. Only honored when --kds-axis-direction is set per-navigation
   (forward = positive translate, back = negative). The variables are
   surfaced for JS to flip on history.back(). */
body.kds-axis-x ::view-transition-old(root) {
  animation: kds-axis-x-out var(--kds-motion-duration-medium, 250ms) var(--kds-motion-easing-accelerate, ease) both;
}
body.kds-axis-x ::view-transition-new(root) {
  animation: kds-axis-x-in var(--kds-motion-duration-medium, 250ms) var(--kds-motion-easing-decelerate, ease) both;
}
@keyframes kds-axis-x-out {
  to { opacity: 0; transform: translateX(calc(var(--kds-axis-direction, 1) * -30px)); }
}
@keyframes kds-axis-x-in {
  from { opacity: 0; transform: translateX(calc(var(--kds-axis-direction, 1) * 30px)); }
}

/* Scoped to `:root[data-theme="dark"]` (not the wider
   `[data-theme="dark"]`) so that elements which legitimately carry a
   data-theme attribute for unrelated reasons — notably the Settings
   drawer theme-toggle buttons (`<button data-theme="dark">`) — don't
   accidentally redefine the CSS theme tokens on themselves. Before
   the scope tightening, the inactive "Escuro" button in light mode
   had `--kdr-text: #f1f1f4` (dark theme value) re-defined locally
   and its label rendered near-white over a near-white background. */
:root[data-theme="dark"],
.themed-dark {
  color-scheme: dark;
  --kdr-bg: #0d0f12;
  --kdr-surface: #14171c;
  --kdr-surface-2: #1c2027;
  --kdr-text: #f1f1f4;
  --kdr-text-muted: #b9bcc4;
  --kdr-accent: #8ab4ff;
  --kdr-accent-on: #0d0f12;
  --kdr-border: #2a2f37;
  --kdr-focus: #b8d1ff;
  --kdr-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.4);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--kds-font-sans);
  background: var(--kdr-bg);
  color: var(--kdr-text);
  line-height: 1.5;
  /* #149 S8 — leave room for the fixed topbar (56px). */
  padding-top: 56px;
}

/* When the mobile sidebar is open, lock body scroll so the page below
   the scrim doesn't move underneath. The class is toggled on <html>
   by sidebarToggleScript so iOS Safari respects the lock. */
html.koder-sidebar-open,
html.koder-sidebar-open body {
  overflow: hidden;
}

/* Anchor-scroll offset: every heading and anchor-targetable element
   inside main.page needs scroll-margin-top equal to the fixed topbar
   height + breathing room. Without this, navigating from the
   "Nesta página" ToC scrolls the target heading underneath the topbar
   (the user clicks "6 — MUST…" and lands at the section body, with
   the heading hidden behind the topbar). 2026-05-11 fix.

   Use :is() so the rule stays short; descendant scope to main.page
   so the same selector doesn't accidentally affect headings inside
   the sidebar/topbar widgets. */
main.page :is(h1, h2, h3, h4, h5, h6, [id]) {
  scroll-margin-top: calc(var(--kds-topbar-height) + 24px);
}

a {
  color: var(--kdr-accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

a:focus-visible,
button:focus-visible,
select:focus-visible,
input:focus-visible {
  outline: 3px solid var(--kdr-focus);
  outline-offset: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── Top bar + lateral sidebar (#149 S8, 2026-05-11) ────────────────
   Replaces the previous flat top-nav (13 sections + 5 facets in a
   single horizontal row) with a minimal fixed top bar and a lateral
   sidebar. Resolves the overflow trap the old top-nav fell into on
   1080p viewports and accommodates future section growth without
   another visual overhaul. Mobile collapses the sidebar behind a
   hamburger overlay (data-state="open").
   Constants:
   --kds-topbar-height: 56px  (kept in sync with body padding-top)
   --kds-sidebar-width: 248px (desktop) / 280px (mobile overlay)
   ───────────────────────────────────────────────────────────────── */

:root {
  --kds-topbar-height: 56px;
  --kds-sidebar-width: 248px;
  /* Responsive breakpoints — vendored from koder_web_kit per
     design-RFC-002 D1 (2026-05-12). The utility classes that consume
     these live higher up in the file (vendored block); the values
     themselves live here so they sit in the same `:root` as the
     other `--kds-*` vars.  Avoid drift with koder_web_kit. */
  --kds-bp-xs: 360px;
  --kds-bp-sm: 640px;
  --kds-bp-md: 900px;
  --kds-bp-lg: 1280px;
  --kds-bp-xl: 1640px;
}

.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--kds-topbar-height);
  display: flex;
  align-items: center;
  gap: 12px;
  /* env(safe-area-inset-*) reserves landscape notch / Dynamic Island
     padding so the last control isn't clipped by the device cutout.
     specs/app-layout/safe-area.kmd § Web. */
  padding-left:  max(20px, env(safe-area-inset-left));
  padding-right: max(20px, env(safe-area-inset-right));
  box-sizing: border-box;
  background: color-mix(in srgb, var(--kdr-bg) 88%, transparent);
  -webkit-backdrop-filter: saturate(150%) blur(8px);
  backdrop-filter: saturate(150%) blur(8px);
  border-bottom: 1px solid var(--kdr-border);
  z-index: 30;
}

.topbar .brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  text-decoration: none;
  color: var(--kdr-text);
  flex-shrink: 0;
}

.topbar .brand-mark {
  display: inline-flex;
  width: 28px; height: 28px;
  align-items: center;
  justify-content: center;
}
.topbar .brand-mark svg {
  width: 100%;
  height: 100%;
  display: block;
}

.topbar .controls {
  margin-left: auto;
  display: flex;
  gap: 12px;
  align-items: center;
  flex-shrink: 0;
}
/* Mobile portrait: tighten the topbar so 6+ controls fit inside 360-
   400 dp viewports without the trailing gear icon clipping the right
   edge. Tested at 360 / 390 / 412 dp. */
@media (max-width: 600px) {
  .topbar {
    gap: 8px;
    padding-left:  max(12px, env(safe-area-inset-left));
    padding-right: max(12px, env(safe-area-inset-right));
  }
  .topbar .controls { gap: 6px; }
  /* Hide the trailing version badge / selector on narrow phones —
     they're nice-to-have, never load-bearing, and otherwise eat space
     the functional controls need. */
  .topbar .version-badge { display: none; }
  .topbar .version-selector { display: none; }
  /* Hide the brand wordmark text — the diamond mark icon carries
     enough identity at narrow widths. GitHub / Vercel / Linear all do
     this. Frees ~80px so the trailing gear ⚙ stops clipping at 390-
     412 dp viewports per visual-regression-tdds.kmd R7 item (3).
     Frees enough budget that the ambient-pause control can stay
     visible alongside search + theme toggle + gear. */
  .topbar .brand-name { display: none; }
}

/* Hamburger button — visible only on narrow viewports. The three
   <span> stacks become an X when sidebar is open (state lives on
   #koder-sidebar [data-state], read by the toggle JS). */
.sidebar-toggle {
  display: none;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  background: transparent;
  color: var(--kdr-text);
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
}
.sidebar-toggle:hover { background: var(--kdr-surface); }
.sidebar-toggle-icon {
  display: inline-flex;
  flex-direction: column;
  gap: 4px;
  width: 16px;
}
.sidebar-toggle-icon > span {
  display: block;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
  transition:
    transform var(--kds-motion-duration-fast) var(--kds-motion-easing-emphasize),
    opacity var(--kds-motion-duration-fast) var(--kds-motion-easing-standard);
}

/* Sidebar — desktop: fixed left rail under the topbar.
   2026-05-21 mobile fix: 100vh is the *largest* viewport height
   (without browser URL bar). On Chrome / Safari mobile the URL bar
   slides in during scroll-up and overlaps the last drawer item.
   Fall back to 100vh first for older browsers, then 100dvh — the
   dynamic viewport height that shrinks when the URL bar enters.
   Also reserve env(safe-area-inset-bottom) for the iOS home
   indicator. specs/app-layout/safe-area.kmd § web vars. */
.sidebar {
  position: fixed;
  top: var(--kds-topbar-height);
  left: 0;
  width: var(--kds-sidebar-width);
  height: calc(100vh - var(--kds-topbar-height));
  height: calc(100dvh - var(--kds-topbar-height));
  overflow-y: auto;
  overflow-x: hidden;
  padding: 20px 12px calc(32px + env(safe-area-inset-bottom, 0px));
  background: var(--kdr-bg);
  border-right: 1px solid var(--kdr-border);
  z-index: 20;
  /* Subtle overlay scrollbar — defined as a shared pattern across the
     sidebar and the page-toc sticky rail so both rails feel like one
     visual system (no chunky OS-default chrome breaking the aesthetic).
     See the matching rules below for `.page-toc` too. Cross-browser
     via Firefox's `scrollbar-*` props + WebKit's ::-webkit-scrollbar
     pseudos. */
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--kdr-text) 14%, transparent) transparent;
}
.sidebar::-webkit-scrollbar,
.page-toc::-webkit-scrollbar {
  width: 8px;
}
.sidebar::-webkit-scrollbar-track,
.page-toc::-webkit-scrollbar-track {
  background: transparent;
}
.sidebar::-webkit-scrollbar-thumb,
.page-toc::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--kdr-text) 14%, transparent);
  border-radius: 4px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.sidebar:hover::-webkit-scrollbar-thumb,
.page-toc:hover::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--kdr-text) 28%, transparent);
  background-clip: padding-box;
}
.sidebar::-webkit-scrollbar-thumb:hover,
.sidebar::-webkit-scrollbar-thumb:active,
.page-toc::-webkit-scrollbar-thumb:hover,
.page-toc::-webkit-scrollbar-thumb:active {
  background: color-mix(in srgb, var(--kdr-accent) 60%, transparent);
  background-clip: padding-box;
}
.sidebar:hover,
.page-toc:hover {
  scrollbar-color: color-mix(in srgb, var(--kdr-text) 28%, transparent) transparent;
}
/* page-toc needs Firefox `scrollbar-*` props on its own selector
   because the .sidebar rule above doesn't reach it. */
.page-toc {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--kdr-text) 14%, transparent) transparent;
}
.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.sidebar-section { display: flex; flex-direction: column; gap: 2px; }
/* design-RFC-003 Phase 6 — stronger visual break between SEÇÕES and
   FACETS so the user reads them as distinct taxonomies, not a single
   sequential list. Applied to every sidebar-section after the first;
   the parent .sidebar-nav uses gap:24px which gives breathing room. */
.sidebar-section + .sidebar-section {
  border-top: 1px solid var(--kdr-border);
  padding-top: 16px;
  margin-top: 4px;
}
.sidebar-section-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--kdr-text-muted);
  margin: 0 0 6px;
  padding: 0 10px;
  font-weight: 600;
}
.sidebar-link {
  display: block;
  padding: 7px 10px;
  border-radius: 6px;
  text-decoration: none;
  color: var(--kdr-text);
  font-size: 14px;
  line-height: 1.3;
  transition:
    background var(--kds-motion-duration-fast) var(--kds-motion-easing-standard),
    color var(--kds-motion-duration-fast) var(--kds-motion-easing-standard);
}
.sidebar-link:hover {
  background: var(--kdr-surface);
  color: var(--kdr-text);
}
.sidebar-link--active,
.sidebar-link[aria-current="page"] {
  background: color-mix(in srgb, var(--kdr-accent) 14%, transparent);
  color: var(--kdr-accent);
  font-weight: 600;
}
.sidebar-link:focus-visible {
  outline: 2px solid var(--kdr-focus);
  outline-offset: 1px;
}

/* Sidebar grouping — Sections collapse into 4 groups via native
   <details>/<summary> so the rail fits in a small viewport without
   scrolling. The group containing the active page receives the
   `open` attribute server-side (navGroupActive helper) so the user
   sees the path to where they are on first paint. Other groups
   start collapsed; user can expand any of them. State is per-page,
   not persisted — clicking a link reloads with that link's group
   open. */
.sidebar-group {
  display: block;
  margin: 0;
}
.sidebar-group + .sidebar-group {
  margin-top: 2px;
}
.sidebar-group-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 6px;
  color: var(--kdr-text);
  font-size: 14px;
  line-height: 1.3;
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition:
    background var(--kds-motion-duration-fast) var(--kds-motion-easing-standard),
    color var(--kds-motion-duration-fast) var(--kds-motion-easing-standard);
}
.sidebar-group-summary::-webkit-details-marker { display: none; }
.sidebar-group-summary::marker { content: ""; }
.sidebar-group-summary:hover {
  background: var(--kdr-surface);
}
.sidebar-group-summary:focus-visible {
  outline: 2px solid var(--kdr-focus);
  outline-offset: 1px;
}
.sidebar-group-chevron {
  display: inline-flex;
  width: 12px;
  height: 12px;
  align-items: center;
  justify-content: center;
  color: var(--kdr-text-muted);
  font-size: 10px;
  transition: transform var(--kds-motion-duration-fast) var(--kds-motion-spring-spatial-default);
  flex-shrink: 0;
}
.sidebar-group[open] > .sidebar-group-summary .sidebar-group-chevron {
  transform: rotate(90deg);
  color: var(--kdr-text);
}
.sidebar-group-label {
  flex: 1;
  min-width: 0;
}
.sidebar-group-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 2px 0 6px;
}
/* The UA stylesheet hides non-summary children of a closed <details>
   via `details:not([open]) > :not(summary) { display: none }` — but
   the `display: flex` rule above wins on specificity-by-origin, which
   leaks the children of every closed group. Restore the closed-state
   hide explicitly so only groups containing the active page expand. */
.sidebar-group:not([open]) > .sidebar-group-body {
  display: none;
}
/* Indent the children so the hierarchy is visible. The chevron+gap
   in the summary is ~20px, so match it on the children. */
.sidebar-group-body .sidebar-link {
  padding-left: 30px;
  font-size: 13.5px;
}

/* ── Sticky Command Bar + Tree sidebar (2026-05-16) ─────────────────
   Refactor of the sidebar to a doc-site DNA closer to Stripe/Vercel:
   - Inline search field at the very top (opens the same modal, but
     styled as an input so it reads like part of the rail, not a
     separate widget).
   - Flat titled sections — uppercase muted header + flat link list,
     no <details>/chevron/disclosure. Density over chrome.
   - Active link uses a small accent dot on the left edge instead of
     a pill background. The active section title also reads bolder
     when the current page lives under it (active-trail signal).
   The previous collapsible-group styling above is kept but no
   longer rendered by the templ — left in CSS in case a future
   page needs it. */

/* Inline search at top of sidebar — styled like an input field even
   though it's a <button> that opens the existing modal. */
.sidebar-search {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 0 0 16px;
  padding: 8px 10px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  color: var(--kdr-text-muted);
  font: inherit;
  font-size: 13px;
  cursor: text;
  text-align: left;
  transition: background 120ms ease, border-color 120ms ease;
}
.sidebar-search:hover {
  background: color-mix(in srgb, var(--kdr-surface) 70%, var(--kdr-bg));
  border-color: color-mix(in srgb, var(--kdr-text) 24%, transparent);
}
.sidebar-search:focus-visible {
  outline: 2px solid var(--kdr-focus);
  outline-offset: 1px;
}
.sidebar-search-icon {
  flex-shrink: 0;
  color: var(--kdr-text-muted);
  font-size: 18px;
  line-height: 1;
  font-weight: 700;
}
.sidebar-search-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar-search-kbd {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  padding: 2px 6px;
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: 4px;
  color: var(--kdr-text-muted);
  flex-shrink: 0;
}

/* Flat titled section — uppercase muted header + flat link list. */
.sidebar-section--titled {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
/* Override the heavy SEÇÕES↔FACETS border separator between flat
   sections — switch to a quiet gap so the rail reads as one column
   of equal-weight sections instead of a stacked accordion. */
.sidebar-section--titled + .sidebar-section--titled {
  border-top: none;
  padding-top: 0;
  margin-top: 20px;
}
/* Active-trail title — when a child page is current, the section
   header reads bolder so the user finds their location at a glance
   even without the dot indicator on the active leaf. */
.sidebar-section--has-active > .sidebar-section-title {
  color: var(--kdr-text);
}
/* Body inherits the flex layout from .sidebar-group-body; just
   tighten the indent for the new flat style. */
.sidebar-section--titled > .sidebar-group-body .sidebar-link {
  padding-left: 22px;
  font-size: 13.5px;
}

/* Active link — drop the pill background, use a 4px accent dot on
   the left edge. Refined doc-site look (Stripe/Vercel). The base
   .sidebar-link rule sets position:static; promote to relative so
   the absolutely-positioned dot anchors correctly. */
.sidebar-link { position: relative; }
.sidebar-link--active,
.sidebar-link[aria-current="page"] {
  background: transparent;
  color: var(--kdr-accent);
  font-weight: 600;
}
.sidebar-link--active::before,
.sidebar-link[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 8px;
  top: 50%;
  width: 4px;
  height: 4px;
  margin-top: -2px;
  background: var(--kdr-accent);
  border-radius: 50%;
}
/* Indented (in-group) active links — shift the dot right so it
   aligns with the text indent rather than the section padding. */
.sidebar-section--titled > .sidebar-group-body .sidebar-link--active::before,
.sidebar-section--titled > .sidebar-group-body .sidebar-link[aria-current="page"]::before {
  left: 12px;
}

/* (2026-05-16) The standalone overview link override above this point
   was removed when "Primeiros passos" moved into a proper INÍCIO/Intro
   SidebarGroup — every sidebar link now lives inside a titled section,
   so the .sidebar-section--titled > .sidebar-group-body .sidebar-link
   rule already covers leaf indent + active dot positioning. */

/* The topbar still ships its own search trigger as a fallback for
   ≤900px viewports where the sidebar is collapsed behind the
   hamburger — at desktop widths the inline sidebar field is the
   primary affordance, so hide the topbar copy. */
@media (min-width: 901px) {
  .topbar #koder-search-trigger { display: none; }
}
@media (max-width: 900px) {
  .sidebar-search { display: none; }
}

/* Scrim — only visible/clickable when the mobile sidebar is open. */
.sidebar-scrim {
  position: fixed;
  inset: var(--kds-topbar-height) 0 0 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms ease;
  z-index: 19;
}

@media (max-width: 900px) {
  .sidebar-toggle { display: inline-flex; }

  /* On mobile the sidebar slides in from the left. data-state="open"
     is toggled by sidebarToggleScript. */
  .sidebar {
    width: 280px;
    transform: translateX(-105%);
    transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
  }
  .sidebar[data-state="open"] {
    transform: translateX(0);
  }
  .sidebar[data-state="open"] ~ .sidebar-scrim,
  .sidebar-scrim:has(~ .sidebar[data-state="open"]) {
    opacity: 1;
    pointer-events: auto;
  }
  /* Fallback when :has is not supported on older browsers: pair the
     scrim activation directly to a html.koder-sidebar-open class
     toggled by the same JS. */
  html.koder-sidebar-open .sidebar-scrim {
    opacity: 1;
    pointer-events: auto;
  }
}

/* Facet landing page styling — used by FacetPage template for the 4
   non-Visual facet landings. Reuses existing surface/spacing tokens. */
.facet-empty,
.facet-specs,
.facet-other {
  margin: 32px 0;
}
.facet-empty p,
.facet-other ul {
  color: var(--kdr-text-muted);
}
.facet-spec-list {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
}
.facet-spec-item {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 16px 18px;
}
.facet-spec-link {
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-decoration: none;
  color: var(--kdr-text);
}
.facet-spec-link:hover .facet-spec-name {
  color: var(--kdr-accent);
}
.facet-spec-name {
  font-weight: 600;
}
.facet-spec-path {
  font-size: 12px;
  color: var(--kdr-text-muted);
}
.facet-spec-summary {
  margin: 8px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--kdr-text);
}
.facet-other-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  list-style: none;
  padding: 0;
}
.facet-other-list a {
  color: var(--kdr-accent);
  text-decoration: none;
}
.facet-other-list a:hover {
  text-decoration: underline;
}

.theme-toggle {
  width: 34px; height: 34px;
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  font-size: 18px;
  cursor: pointer;
}

.theme-toggle:hover { background: var(--kdr-surface-2); }

/* ── Page shell ──────────────────────────────────────────── */

main.page {
  /* #149 S8 — leave space for the fixed sidebar on desktop.
     The sidebar is 248px wide and starts at left: 0; main is
     pushed right with margin-left. Horizontal padding gives
     breathing room from sidebar's right border and the viewport's
     right edge — bumped to 48px (#149 close follow-up) because at
     viewport widths ≤ 1448 the auto-margin would collapse to 0
     and the hero's split panel would butt the viewport. The
     e2e suite (tests/e2e/margins_test.go) enforces ≥ 32px gap.

     2026-05-13: max-width bumped from 1200 → 1800 (fluid via
     clamp) pra reduzir void em monitores wide (>1600px). Owner
     reportou que em 2560+ a tela ficava com ~50% espaço vazio.
     Hero/grids internos não overflow — eles já têm seus próprios
     max-widths (lede 720, grid columns auto-distribute). */
  max-width: 1800px;
  margin: 0 auto;
  padding: 32px 48px 64px;
  margin-left: var(--kds-sidebar-width);
}

/* Once the viewport is wide enough to fit sidebar + max-content +
   breathing room on both sides, recenter main inside its column.
   Pages without a right-side ToC center within the post-sidebar
   area (between sidebar's right edge and viewport's right edge)
   so wide monitors don't show a large void on the right.
   Pages with .has-toc stay left-anchored because their right
   column is filled by the ToC grid.
   Bumped breakpoint from 1640 → 2200 (matches new max-width 1800
   + sidebar 248 + padding 2×48 = 2144, +56 breathing). */
@media (min-width: 2200px) {
  main.page {
    margin-right: auto;
  }
  main.page:not(.has-toc),
  body:has(main.page:not(.has-toc)) .page-footer {
    margin-left: calc(
      var(--kds-sidebar-width) +
      (100vw - var(--kds-sidebar-width) - 1800px) / 2
    );
  }
  body:has(main.page:not(.has-toc)) .page-footer {
    max-width: 1800px;
    margin-right: auto;
  }
}

/* Wide-monitor sidebar typography (2026-05-16).
   On wide monitors (≥1600px) the sidebar reads small relative to the
   available canvas — fixed 14px links/group-summaries and 11px section
   titles were sized for laptops and don't grow on a 1800/2160/2560
   wide screen. Bump in two steps: 1600 (workstation) and 2200
   (matching the existing centering breakpoint). Mobile / tablet /
   standard-desktop (≤1599px) stay untouched.
   The matching hero-tagline override lives below near the lp-hero
   block so it wins the cascade over the base clamp. */
@media (min-width: 1600px) {
  .sidebar-link,
  .sidebar-group-summary { font-size: 15px; }
  .sidebar-section-title { font-size: 12px; }
}
@media (min-width: 2200px) {
  .sidebar-link,
  .sidebar-group-summary { font-size: 16px; }
  .sidebar-section-title { font-size: 13px; }
}

/* Footer also sits beside the sidebar on desktop. */
.page-footer {
  margin-left: var(--kds-sidebar-width);
  padding-left: 48px;
  padding-right: 48px;
}

@media (max-width: 900px) {
  main.page,
  .page-footer {
    margin-left: 0;
    padding-left: 20px;
    padding-right: 20px;
  }
}

.hero h1 {
  font-size: clamp(28px, 4vw, 40px);
  margin: 0 0 12px;
  letter-spacing: -0.01em;
}

.lede {
  font-size: 18px;
  color: var(--kdr-text-muted);
  /* Responsive max-width: scales modestly on wide monitors to avoid
     the lede looking orphaned next to grid content (tiles, cards) that
     spans the full content area. 720px floor preserves readability on
     narrow screens; 55% target tracks container; 960px cap (~80ch at
     18px) stays inside the readable typography range. Owner-reported
     2026-05-16 ultra-wide display incident. */
  max-width: clamp(720px, 55%, 960px);
  margin: 0 0 16px;
}

.cta {
  display: inline-block;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  padding: 10px 18px;
  border-radius: var(--kdr-radius-md);
  text-decoration: none;
  font-weight: 600;
}

.cta:focus-visible {
  outline-color: var(--kdr-focus);
}

.kinds h2 { margin-top: 48px; }

.kind-list {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 8px;
}

.kind-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--kdr-surface);
  padding: 10px 14px;
  border-radius: var(--kdr-radius-sm);
  border: 1px solid var(--kdr-border);
}

.pill {
  display: inline-block;
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--kdr-surface-2);
  color: var(--kdr-text);
  text-transform: lowercase;
  font-weight: 600;
}

.pill-ui-style { background: #1f3a93; color: #fff; }
.pill-pattern  { background: #2e7d32; color: #fff; }
.pill-icon     { background: #ad1457; color: #fff; }
.pill-theme    { background: #6a1b9a; color: #fff; }
.pill-voice    { background: #ef6c00; color: #fff; }
.pill-spec-doc { background: #455a64; color: #fff; }
.pill-app-layout { background: #00695c; color: #fff; }

.spec-name { color: var(--kdr-text-muted); }

.breadcrumb {
  font-size: 14px;
  color: var(--kdr-text-muted);
  margin-bottom: 10px;
  display: flex;
  gap: 8px;
  align-items: center;
}

.breadcrumb a {
  color: var(--kdr-accent);
  text-decoration: none;
}

/* ── Style index grid ────────────────────────────────────── */

.preset-grid {
  /* KDS-022 follow-up (2026-05-13): listing page é 1 preset por linha
     com forms nos 2 temas side-by-side. Single column desktop, stack
     mobile. Owner reportou que 2-col grid era apertado pra mostrar
     light+dark per card. */
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  margin: 16px 0 32px;
}

.preset-card {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.preset-card-head {
  padding: 12px 16px;
  background: var(--kdr-surface-2);
  border-bottom: 1px solid var(--kdr-border);
}

.preset-card-head h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.preset-card-head h3 a {
  color: var(--kdr-text);
  text-decoration: none;
}

.preset-card-head h3 a:hover {
  text-decoration: underline;
}

.preset-meta {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--kdr-text-muted);
  font-family: var(--kds-font-mono);
}

.badge-default {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  padding: 2px 6px;
  border-radius: 4px;
  letter-spacing: 0.04em;
}

.preset-switcher {
  margin-top: 12px;
  display: flex;
  gap: 10px;
  align-items: center;
}

.preset-switcher select {
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 6px 10px;
  font: inherit;
  min-width: 220px;
}

.spec-summary {
  background: var(--kdr-surface);
  border-left: 3px solid var(--kdr-accent);
  padding: 10px 14px;
  margin: 12px 0;
  color: var(--kdr-text-muted);
}

/* ── Component samples ───────────────────────────────────── */

.components-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
  width: 100%;
  max-width: 720px;
}

.components-card {
  background: var(--bg, #fff);
  border-radius: var(--radius-md, 8px);
  padding: 14px;
  border: 1px solid rgba(0, 0, 0, 0.08);
  color: var(--on-surface, #111);
}

.components-card h4 {
  margin: 0 0 10px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--on-surface, #111);
}

.components-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* Stack form elements inside a components-card with consistent gap */
.components-card label,
.components-card input,
.components-card select,
.components-card .form-check,
.components-card .toggle-switch {
  display: block;
  width: 100%;
  margin-top: 8px;
}
.components-card label:first-child,
.components-card input:first-child {
  margin-top: 0;
}
.components-card .form-check,
.components-card .toggle-switch {
  width: auto;
  cursor: pointer;
}

.dialog-sample {
  background: var(--surface-variant, #f0f0f5);
  padding: 12px;
  border-radius: var(--radius-sm, 6px);
}

/* Containers section layout */
.components-card .card + .card,
.components-card .alert + .alert,
.components-card .accordion-item + .accordion-item {
  margin-top: 6px;
}
.components-card .badge + .badge { margin-left: 4px; }
.components-card .tab-list { margin-top: 0; }
.components-card .tab-content {
  font-size: 13px;
  color: var(--label-color, #5e6772);
  padding: 4px 0;
}

/* ── Theme detail page ───────────────────────────────────── */

.theme-token-grid {
  display: grid;
  grid-template-columns: minmax(160px, max-content) 1fr 1fr 2fr;
  gap: 0;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
  margin: 16px 0 32px;
  background: var(--kdr-surface);
}

.theme-token-row {
  display: contents;
}

.theme-token-row > * {
  padding: 10px 14px;
  border-bottom: 1px solid var(--kdr-border);
  display: flex;
  align-items: center;
  gap: 10px;
}

.theme-token-grid > .theme-token-row:last-of-type > * {
  border-bottom: 0;
}

.theme-token-head > * {
  background: var(--kdr-surface-2);
  font-weight: 600;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  /* Header cells centered both axes (#149 close follow-up, owner
     request 2026-05-11). align-items: center comes from the parent
     `.theme-token-row > *` flex; justify-content + text-align cover
     the horizontal axis. */
  justify-content: center;
  text-align: center;
}

/* First-column TOKEN badge — before the templ rewrite the <code>
   element WAS the grid cell with `width: fit-content`, which sized
   the cell to the badge width and clipped the row border-bottom
   under it (row dividers looked invisible in the TOKEN column). Now
   `.theme-token-name` is the full-width cell, with <code> inside as
   an inline badge that doesn't constrain the cell. */
.theme-token-name > code {
  font-family: var(--kds-font-mono);
  background: var(--kdr-surface-2);
  padding: 2px 6px;
  border-radius: 4px;
}

.swatch {
  font-family: var(--kds-font-mono);
  font-size: 13px;
}

.swatch-chip {
  display: inline-block;
  width: 20px;
  height: 20px;
  border-radius: 4px;
  border: 1px solid rgba(0, 0, 0, 0.15);
  flex: none;
}

.theme-rules,
.theme-audit {
  margin: 8px 0 24px;
  padding-left: 24px;
  line-height: 1.6;
}

.theme-rules li,
.theme-audit li {
  margin-bottom: 8px;
  /* The rules/audit copy embeds inline expressions like
     `matchMedia(...).addEventListener("change", …)` that have no
     natural break points. Without overflow-wrap the li's intrinsic
     min-content propagates past viewport — caused /themes/ to be
     50px over @ 320 (the theme-rules section was the propagation
     source, not the visible <code> in <pre> below it). #003 slice 6. */
  overflow-wrap: anywhere;
}

main.page pre {
  background: var(--kdr-surface);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
  overflow-x: auto;
  font-family: var(--kds-font-mono);
  font-size: 13px;
  line-height: 1.55;
  margin: 8px 0 24px;
}

main.page pre code {
  font: inherit;
  color: inherit;
  background: transparent;
  padding: 0;
}

/* ── Component index + detail ────────────────────────────── */

.component-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 16px;
  margin: 16px 0 32px;
}

.component-tile {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.component-tile-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.component-tile h3 {
  font-size: 15px;
  margin: 0;
  font-weight: 600;
}

.component-tile h3 a {
  color: var(--kdr-text);
  text-decoration: none;
}

.component-tile h3 a:hover {
  text-decoration: underline;
}

.component-tile-spec {
  font-size: 12px;
  color: var(--kdr-text-muted);
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  font-family: var(--kds-font-mono);
}

.component-tile-spec a {
  color: var(--kdr-accent);
  text-decoration: none;
}

.component-tile-group {
  background: var(--kdr-surface-2);
  padding: 1px 6px;
  border-radius: 999px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 10px;
  color: var(--kdr-text);
}

.component-tile-desc {
  font-size: 14px;
  color: var(--kdr-text-muted);
  margin: 0;
  line-height: 1.5;
}

.badge {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 4px;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.badge-ratified   { background: #155724; color: #ffffff; }
.badge-documented { background: #1f3a93; color: #ffffff; }
.badge-proposed   { background: #5d4037; color: #ffffff; }

[data-theme="dark"] .badge-ratified   { background: #2e7d32; color: #ffffff; }
[data-theme="dark"] .badge-documented { background: #5b6dd0; color: #ffffff; }
[data-theme="dark"] .badge-proposed   { background: #8d6e63; color: #ffffff; }

.component-legend {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 12px 18px;
  margin: 8px 0 24px;
  align-items: baseline;
}

.component-legend dt { margin: 0; }
.component-legend dd { margin: 0; color: var(--kdr-text-muted); }

.component-availability {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 6px 16px;
  margin: 8px 0 24px;
}

.component-availability dt {
  margin: 0;
  font-weight: 600;
}

.component-availability dd {
  margin: 0;
  font-family: var(--kds-font-mono);
}

.related-list {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 8px;
}

.related-list li {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 8px 12px;
  font-size: 14px;
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.related-list li a {
  color: var(--kdr-accent);
  text-decoration: none;
  font-weight: 500;
}

.related-list small {
  color: var(--kdr-text-muted);
}

/* ── Component demo mocks ────────────────────────────────── */

.demo-card {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 24px;
  width: min(620px, 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  color: var(--kdr-text);
}

.demo-caption {
  font-size: 13px;
  color: var(--kdr-text-muted);
  margin: 0;
  text-align: center;
  max-width: 540px;
}

/* auth-button demo */
.auth-button {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border-radius: 999px;
  padding: 10px 20px;
  font-weight: 600;
  font-size: 15px;
}

.auth-button-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  background: var(--kdr-accent-on);
  color: var(--kdr-accent);
  border-radius: 6px;
  font-size: 13px;
  font-weight: 700;
}

/* title-bar demo */
.demo-window {
  width: 100%;
}

.demo-titlebar {
  display: flex;
  align-items: center;
  background: var(--kdr-surface-2);
  border: 1px solid var(--kdr-border);
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  padding: 8px 12px;
  font-size: 13px;
}

.demo-titlebar-title {
  font-weight: 600;
}

.demo-titlebar-free {
  flex: 1;
  height: 24px;
  margin: 0 12px;
  background: repeating-linear-gradient(45deg, transparent 0 6px, rgba(0,0,0,0.06) 6px 8px);
  border-radius: 4px;
}

[data-theme="dark"] .demo-titlebar-free {
  background: repeating-linear-gradient(45deg, transparent 0 6px, rgba(255,255,255,0.08) 6px 8px);
}

.demo-window-buttons { display: flex; gap: 6px; }
.demo-window-buttons .wb {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px; height: 22px;
  border-radius: 4px;
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  font-size: 12px;
}

.demo-window-body {
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: 0 0 8px 8px;
  padding: 16px;
  width: 100%;
  font-size: 14px;
  color: var(--kdr-text-muted);
}

/* safe-scaffold demo */
.demo-phone {
  width: 220px;
  height: 360px;
  background: var(--kdr-bg);
  border: 2px solid var(--kdr-border);
  border-radius: 28px;
  padding: 6px 10px;
  display: grid;
  grid-template-rows: 28px 1fr 24px;
}

.demo-status,
.demo-gestures {
  background: var(--kdr-surface-2);
  border-radius: 6px;
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--kdr-text-muted);
}

.demo-app {
  background: var(--kdr-surface);
  margin: 4px 0;
  border-radius: 12px;
  padding: 14px;
  border: 1px dashed var(--kdr-border);
  display: flex;
  align-items: center;
  justify-content: center;
}

.demo-app-content {
  font-size: 13px;
  color: var(--kdr-text);
  text-align: center;
}

/* back-scope demo */
.demo-stack {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.demo-stack-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.demo-stack-label {
  background: var(--kdr-surface-2);
  border-radius: 6px;
  padding: 6px 12px;
  font-size: 14px;
  border: 1px solid var(--kdr-border);
}

.demo-stack-active {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border-color: var(--kdr-accent);
}

.demo-stack-arrow {
  color: var(--kdr-text-muted);
}

.demo-stack-key {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--kdr-text-muted);
}

kbd {
  font-family: var(--kds-font-mono);
  background: var(--kdr-surface-2);
  border: 1px solid var(--kdr-border);
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: 2px 6px;
  font-size: 12px;
}

/* error-banner demo */
.demo-error {
  width: 100%;
  display: grid;
  grid-template-columns: 32px 1fr;
  gap: 12px;
  background: #fff4f4;
  border: 1px solid #d63838;
  border-radius: var(--kdr-radius-md);
  padding: 12px 14px;
  color: #2a0606;
}

[data-theme="dark"] .demo-error {
  background: #3a1414;
  color: #ffe7e7;
  border-color: #ff6b6b;
}

.demo-error-icon {
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: #d63838;
  color: #ffffff;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.demo-error p {
  margin: 4px 0;
  font-size: 14px;
}

.demo-error small {
  color: inherit;
}

/* theme-toggle demo */
.demo-toggle-row {
  display: flex;
  align-items: center;
  gap: 14px;
}

.demo-toggle-pane {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: var(--kdr-radius-md);
  border: 1px solid var(--kdr-border);
  font-size: 14px;
}

.demo-toggle-light {
  background: #ffffff;
  color: #161616;
}

.demo-toggle-dark {
  background: #0d0f12;
  color: #f1f1f4;
  border-color: #2a2f37;
}

.demo-toggle-btn {
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border: none;
  font-size: 18px;
  cursor: pointer;
}

/* ── Component demos: 2.2-bis batch ──────────────────────── */

/* user-badge */
.user-badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  padding: 4px 14px 4px 4px;
  color: var(--kdr-text);
}

.user-badge-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 999px;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  font-weight: 700;
}

.user-badge-name {
  font-weight: 500;
}

.user-badge-arrow {
  color: var(--kdr-text-muted);
  font-size: 12px;
}

/* auth-gate */
.auth-gate {
  width: 100%;
  max-width: 420px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 28px 24px;
  text-align: center;
}

.auth-gate-lock {
  display: inline-block;
  font-size: 32px;
  margin-bottom: 8px;
}

.auth-gate h4 {
  margin: 6px 0 4px;
  font-size: 18px;
}

.auth-gate p {
  color: var(--kdr-text-muted);
  margin: 0 0 20px;
  font-size: 14px;
}

.auth-gate .auth-button {
  margin: 0 auto;
}

/* settings-tile shared by reporter, voice, settings */
.settings-tile {
  width: 100%;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
}

.settings-tile-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--kdr-border);
}

.settings-tile-row:last-child {
  border-bottom: 0;
}

.settings-tile-row > div {
  flex: 1;
}

.settings-tile-row strong {
  display: block;
  font-size: 14px;
  color: var(--kdr-text);
}

.settings-tile-row p {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--kdr-text-muted);
  line-height: 1.4;
}

.settings-tile-row select {
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 4px 8px;
  font: inherit;
  color: var(--kdr-text);
}

.settings-tile-row-disabled {
  opacity: 0.55;
}

.switch {
  display: inline-flex;
  align-items: center;
  width: 40px;
  height: 22px;
  background: var(--kdr-surface-2);
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  padding: 1px;
  flex: none;
}

.switch-thumb {
  display: inline-block;
  width: 18px;
  height: 18px;
  background: var(--kdr-bg);
  border-radius: 999px;
  border: 1px solid var(--kdr-border);
  transition: transform 120ms;
}

.switch-on .switch-thumb {
  transform: translateX(18px);
}

.switch-on {
  background: var(--kdr-accent);
  border-color: var(--kdr-accent);
}

.switch-on .switch-thumb {
  background: var(--kdr-accent-on);
  border-color: var(--kdr-accent-on);
}

/* reporter button */
.report-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--kdr-surface);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  font: inherit;
  cursor: pointer;
}

.report-button:hover {
  background: var(--kdr-surface-2);
}

/* update-banner */
.update-banner {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--kdr-surface-2);
  border-left: 4px solid var(--kdr-accent);
  border-radius: var(--kdr-radius-md);
  padding: 12px 16px;
}

.update-banner strong {
  display: block;
  font-size: 14px;
}

.update-banner p {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--kdr-text-muted);
}

.btn-update {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border: none;
  border-radius: var(--kdr-radius-sm);
  padding: 8px 14px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

/* l10n switcher pillgroup */
.l10n-pillgroup {
  display: inline-flex;
  background: var(--kdr-surface-2);
  border-radius: 999px;
  padding: 4px;
  gap: 4px;
}

.l10n-pill {
  font-family: var(--kds-font-mono);
  font-size: 13px;
  padding: 6px 14px;
  border-radius: 999px;
  color: var(--kdr-text);
  background: transparent;
}

.l10n-pill-active {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  font-weight: 600;
}

/* ui-style mini grid */
.ui-style-mini-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  width: 100%;
  max-width: 400px;
}

.ui-style-mini {
  display: flex;
  flex-direction: column;
  background: var(--kdr-surface);
  border: 2px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 10px;
  gap: 8px;
}

.ui-style-mini-active {
  border-color: var(--kdr-accent);
}

.ui-style-mini-bar {
  display: block;
  width: 100%;
  height: 28px;
  border-radius: var(--kdr-radius-sm);
}

.ui-style-mini-name {
  font-family: var(--kds-font-mono);
  font-size: 12px;
  color: var(--kdr-text-muted);
}

/* cache-purge dialog */
.cache-purge-dialog {
  width: 100%;
  max-width: 420px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 18px;
  box-shadow: var(--kdr-shadow-1);
}

.cache-purge-dialog h4 {
  margin: 0 0 12px;
  font-size: 16px;
}

.cache-purge-list {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  font-size: 14px;
}

.cache-purge-list li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 0;
  color: var(--kdr-text);
}

.cache-purge-list small {
  margin-left: auto;
  color: var(--kdr-text-muted);
  font-family: var(--kds-font-mono);
  font-size: 12px;
}

.cache-purge-dialog .actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.cache-purge-dialog .btn-secondary,
.cache-purge-dialog .btn-primary {
  border-radius: var(--kdr-radius-sm);
  padding: 6px 14px;
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  border: 1px solid var(--kdr-border);
}

.cache-purge-dialog .btn-secondary {
  background: var(--kdr-surface);
  color: var(--kdr-text);
}

.cache-purge-dialog .btn-primary {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border-color: var(--kdr-accent);
}

/* download-button */
.download-button {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border-radius: var(--kdr-radius-md);
  padding: 14px 20px;
  text-decoration: none;
}

.download-icon {
  font-size: 28px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--kdr-accent-on);
  color: var(--kdr-accent);
}

.download-button strong {
  display: block;
  font-size: 15px;
  margin-bottom: 2px;
}

.download-button small {
  font-size: 12px;
  opacity: 0.85;
}

/* ── Pattern index + detail ──────────────────────────────── */

.pattern-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: 16px;
  margin: 16px 0 32px;
}

.pattern-tile {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.pattern-tile-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.pattern-tile h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.pattern-tile h3 a {
  color: var(--kdr-text);
  text-decoration: none;
}

.pattern-tile h3 a:hover {
  text-decoration: underline;
}

.pattern-tile-spec {
  font-size: 12px;
  color: var(--kdr-text-muted);
  margin: 0;
  font-family: var(--kds-font-mono);
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.pattern-tile-summary {
  font-size: 14px;
  color: var(--kdr-text-muted);
  margin: 0;
  line-height: 1.5;
}

.badge-pattern-errors    { background: #c0392b; color: #ffffff; }
.badge-pattern-i18n      { background: #16a085; color: #ffffff; }
.badge-pattern-navigation { background: #2980b9; color: #ffffff; }
.badge-pattern-identity  { background: #8e44ad; color: #ffffff; }

[data-theme="dark"] .badge-pattern-errors    { background: #e74c3c; }
[data-theme="dark"] .badge-pattern-i18n      { background: #1abc9c; }
[data-theme="dark"] .badge-pattern-navigation { background: #3498db; }
[data-theme="dark"] .badge-pattern-identity  { background: #9b59b6; }

.pattern-triggers {
  list-style: none;
  padding: 0;
  margin: 8px 0 24px;
  display: grid;
  gap: 6px;
}

.pattern-triggers li {
  background: var(--kdr-surface);
  border-left: 3px solid var(--kdr-accent);
  padding: 8px 12px;
  border-radius: 0 var(--kdr-radius-sm) var(--kdr-radius-sm) 0;
  font-size: 14px;
}

.pattern-body {
  margin: 8px 0 24px;
  line-height: 1.65;
  color: var(--kdr-text);
}

.pattern-body h2 {
  font-size: 22px;
  margin: 36px 0 12px;
  border-bottom: 1px solid var(--kdr-border);
  padding-bottom: 6px;
}

.pattern-body h3 {
  font-size: 17px;
  margin: 28px 0 8px;
}

.pattern-body h4 {
  font-size: 15px;
  margin: 20px 0 8px;
  color: var(--kdr-text-muted);
}

.pattern-body p {
  margin: 0 0 14px;
}

.pattern-body ul,
.pattern-body ol {
  margin: 0 0 14px;
  padding-left: 24px;
}

.pattern-body li {
  margin: 4px 0;
}

.pattern-body code {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 3px;
  padding: 1px 6px;
  font-family: var(--kds-font-mono);
  font-size: 0.9em;
  /* Long mono tokens (e.g. `koder.voice.koder-eye.recordPCM`) inside
     list items push the page wider than the viewport on narrow phones.
     overflow-wrap: anywhere lets the browser split at any character;
     mirrors the same fix already applied to .lp-hero-split-spec-code.
     #003 slice 5 — was responsible for /voice/ 41px overflow @ 320. */
  overflow-wrap: anywhere;
}

.pattern-body pre {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
  overflow-x: auto;
  /* max-width / min-width: 0 keep <pre> within parent flow on narrow
     viewports so its internal scrollbar (overflow-x: auto above)
     handles wide code lines instead of pushing the document wider.
     #003 slice 5 — /themes/ was 50px over @ 320 because the inline
     <pre> grew to fit a 671px <code> sibling of <script> snippet. */
  max-width: 100%;
  min-width: 0;
  font-family: var(--kds-font-mono);
  font-size: 13px;
  line-height: 1.55;
  margin: 8px 0 18px;
}

.pattern-body pre code {
  background: transparent;
  border: 0;
  padding: 0;
}

.pattern-body blockquote {
  border-left: 4px solid var(--kdr-accent);
  background: var(--kdr-surface);
  margin: 12px 0;
  padding: 8px 14px;
  color: var(--kdr-text-muted);
}

/* .md-table-wrap wraps every markdown-emitted <table> via the
   renderMarkdown post-processor in internal/kinds/pattern.go. Keeps
   wide tables (Wake-word error map, etc.) inside their own horizontal
   scroll container instead of widening the page. #003 slice 5. */
.md-table-wrap {
  overflow-x: auto;
  max-width: 100%;
  margin: 12px 0;
}
.md-table-wrap > table {
  margin: 0;
}

.pattern-body table {
  border-collapse: collapse;
  margin: 12px 0;
  font-size: 14px;
  width: 100%;
}

.pattern-body th,
.pattern-body td {
  border: 1px solid var(--kdr-border);
  padding: 8px 12px;
  text-align: left;
}

.pattern-body th {
  background: var(--kdr-surface-2);
  font-weight: 600;
}

.pattern-refs {
  list-style: none;
  padding: 0;
  margin: 8px 0 24px;
  display: grid;
  gap: 6px;
}

.pattern-refs li {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 6px 12px;
  font-size: 14px;
}

/* ── Flows ───────────────────────────────────────────────── */

.flow-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: 16px;
  margin: 16px 0 32px;
}

.flow-tile {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.flow-tile-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.flow-tile h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.flow-tile h3 a {
  color: var(--kdr-text);
  text-decoration: none;
}

.flow-tile h3 a:hover {
  text-decoration: underline;
}

.flow-tile-meta {
  font-size: 12px;
  color: var(--kdr-text-muted);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-family: var(--kds-font-mono);
}

.flow-tile-meta a {
  color: var(--kdr-accent);
  text-decoration: none;
}

.badge-flow-onboarding { background: #1f3a93; color: #ffffff; }
.badge-flow-auth        { background: #2980b9; color: #ffffff; }
.badge-flow-update      { background: #16a085; color: #ffffff; }
.badge-flow-errors      { background: #c0392b; color: #ffffff; }
.badge-flow-nav         { background: #6a1b9a; color: #ffffff; }
.badge-flow-voice       { background: #ef6c00; color: #ffffff; }
.badge-flow-i18n        { background: #00695c; color: #ffffff; }
.badge-flow-layout      { background: #455a64; color: #ffffff; }

[data-theme="dark"] .badge-flow-onboarding { background: #5b6dd0; }
[data-theme="dark"] .badge-flow-auth        { background: #3498db; }
[data-theme="dark"] .badge-flow-update      { background: #1abc9c; }
[data-theme="dark"] .badge-flow-errors      { background: #e74c3c; }
[data-theme="dark"] .badge-flow-nav         { background: #9b59b6; }
[data-theme="dark"] .badge-flow-voice       { background: #ff9800; }
[data-theme="dark"] .badge-flow-i18n        { background: #26a69a; }
[data-theme="dark"] .badge-flow-layout      { background: #78909c; }

/* Step diagram */
.flow-steps {
  list-style: none;
  padding: 0;
  margin: 16px 0 32px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
}

.flow-step {
  display: grid;
  grid-template-columns: 60px 1fr;
  gap: 16px;
  position: relative;
  padding-bottom: 12px;
}

.flow-step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 999px;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  font-weight: 700;
  font-size: 18px;
  font-family: var(--kds-font-mono);
  flex: none;
}

.flow-step-body {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
}

.flow-step-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}

.flow-step-head h3 {
  margin: 0 0 6px;
  font-size: 16px;
  font-weight: 600;
}

.flow-step-body p {
  margin: 4px 0;
  color: var(--kdr-text-muted);
  font-size: 14px;
  line-height: 1.55;
}

.flow-step-spec {
  margin-top: 6px !important;
  font-family: var(--kds-font-mono);
  font-size: 12px !important;
}

.flow-step-spec a {
  color: var(--kdr-accent);
  text-decoration: none;
}

.flow-step-arrow {
  grid-column: 1;
  width: 48px;
  text-align: center;
  font-size: 22px;
  color: var(--kdr-text-muted);
  line-height: 1;
  padding: 4px 0;
}

.actor {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 4px;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.actor-user   { background: #1f3a93; color: #ffffff; }
.actor-app    { background: #155724; color: #ffffff; }
.actor-sdk    { background: #5d4037; color: #ffffff; }
.actor-server { background: #4527a0; color: #ffffff; }

[data-theme="dark"] .actor-user   { background: #5b6dd0; }
[data-theme="dark"] .actor-app    { background: #2e7d32; }
[data-theme="dark"] .actor-sdk    { background: #8d6e63; }
[data-theme="dark"] .actor-server { background: #7e57c2; }

.flow-pitfalls {
  list-style: none;
  padding: 0;
  margin: 8px 0 24px;
  display: grid;
  gap: 8px;
}

.flow-pitfalls li {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 10px;
  background: var(--kdr-surface);
  border-left: 3px solid #c0392b;
  border-radius: 0 var(--kdr-radius-sm) var(--kdr-radius-sm) 0;
  padding: 10px 14px;
  font-size: 14px;
  line-height: 1.5;
}

[data-theme="dark"] .flow-pitfalls li {
  border-left-color: #e74c3c;
}

.pit-mark {
  color: #c0392b;
  font-size: 18px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

[data-theme="dark"] .pit-mark { color: #ff8a80; }

/* ── Anti-patterns ───────────────────────────────────────── */

.anti-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
  margin: 16px 0 8px;
  font-size: 13px;
}

.anti-toc a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  text-decoration: none;
  color: var(--kdr-text);
  background: var(--kdr-surface);
}

.anti-toc a:hover {
  background: var(--kdr-surface-2);
}

.anti-list {
  display: grid;
  gap: 28px;
  margin: 24px 0 32px;
}

.anti-card {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 18px 20px;
  scroll-margin-top: calc(var(--kds-topbar-height) + 24px); /* compensate fixed topbar for anchor scroll */
}

.anti-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.anti-card-head h3 {
  margin: 0 0 4px;
  font-size: 18px;
  font-weight: 600;
}

.anti-card-spec {
  margin: 4px 0 12px;
  font-size: 12px;
  color: var(--kdr-text-muted);
  font-family: var(--kds-font-mono);
}

.anti-card-spec a {
  color: var(--kdr-accent);
  text-decoration: none;
}

.badge-anti-desktop  { background: #6a1b9a; color: #ffffff; }
.badge-anti-i18n     { background: #00695c; color: #ffffff; }
.badge-anti-errors   { background: #c0392b; color: #ffffff; }
.badge-anti-layout   { background: #455a64; color: #ffffff; }
.badge-anti-auth     { background: #2980b9; color: #ffffff; }
.badge-anti-theme    { background: #ad1457; color: #ffffff; }
.badge-anti-nav      { background: #1f3a93; color: #ffffff; }
.badge-anti-voice    { background: #ef6c00; color: #ffffff; }
.badge-anti-url      { background: #5d4037; color: #ffffff; }
.badge-anti-storage  { background: #4527a0; color: #ffffff; }

[data-theme="dark"] .badge-anti-desktop  { background: #9b59b6; }
[data-theme="dark"] .badge-anti-i18n     { background: #26a69a; }
[data-theme="dark"] .badge-anti-errors   { background: #e74c3c; }
[data-theme="dark"] .badge-anti-layout   { background: #78909c; }
[data-theme="dark"] .badge-anti-auth     { background: #3498db; }
[data-theme="dark"] .badge-anti-theme    { background: #ec407a; }
[data-theme="dark"] .badge-anti-nav      { background: #5b6dd0; }
[data-theme="dark"] .badge-anti-voice    { background: #ff9800; }
[data-theme="dark"] .badge-anti-url      { background: #8d6e63; }
[data-theme="dark"] .badge-anti-storage  { background: #7e57c2; }

.anti-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin: 8px 0 16px;
}

@media (max-width: 639px) { /* #003 slice 4 (2026-05-14): aligned to canonical sm (640px); was 760px */
  .anti-pair { grid-template-columns: 1fr; }
}

.anti-side {
  display: flex;
  flex-direction: column;
}

.anti-side-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 8px;
  font-size: 14px;
}

.anti-side-head small {
  color: var(--kdr-text-muted);
  font-size: 12px;
  margin-left: 4px;
}

.anti-bad .anti-side-head { color: #c0392b; }
.anti-good .anti-side-head { color: #155724; }

[data-theme="dark"] .anti-bad .anti-side-head { color: #ff8a80; }
[data-theme="dark"] .anti-good .anti-side-head { color: #69f0ae; }

.anti-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
}

.anti-mark-bad {
  background: #c0392b;
  color: #ffffff;
}

.anti-mark-good {
  background: #155724;
  color: #ffffff;
}

[data-theme="dark"] .anti-mark-bad { background: #e74c3c; }
[data-theme="dark"] .anti-mark-good { background: #2e7d32; }

.anti-code {
  margin: 0;
  background: var(--kdr-surface-2);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 12px 14px;
  font-family: var(--kds-font-mono);
  font-size: 12.5px;
  line-height: 1.55;
  overflow-x: auto;
  white-space: pre;
  color: var(--kdr-text);
  flex: 1;
}

.anti-bad .anti-code {
  border-left: 3px solid #c0392b;
}

.anti-good .anti-code {
  border-left: 3px solid #155724;
}

[data-theme="dark"] .anti-bad .anti-code  { border-left-color: #e74c3c; }
[data-theme="dark"] .anti-good .anti-code { border-left-color: #2e7d32; }

.anti-why {
  margin: 4px 0 0;
  padding: 12px 14px;
  background: var(--kdr-surface-2);
  border-radius: var(--kdr-radius-sm);
  font-size: 14px;
  line-height: 1.55;
}

.anti-why strong {
  margin-right: 6px;
  color: var(--kdr-accent);
}

/* ── Icons ───────────────────────────────────────────────── */

.icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
  margin: 16px 0 32px;
}

.icon-tile {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
  transition: border-color 100ms;
}

.icon-tile:hover { border-color: var(--kdr-accent); }

.icon-tile-link {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: var(--kdr-text);
}

.icon-tile-canvas {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(180deg, var(--kdr-surface-2), var(--kdr-surface));
  height: 160px;
  padding: 16px;
}

.icon-tile-canvas svg {
  width: auto;
  height: 100px;
  max-width: 100%;
}

.icon-tile-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px 4px;
}

.icon-tile-head h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
}

.icon-tile-tag {
  margin: 0 14px 14px;
  font-size: 13px;
  color: var(--kdr-text-muted);
  line-height: 1.5;
}

.badge-icon-dev        { background: #1f3a93; color: #ffffff; }
.badge-icon-horizontal { background: #16a085; color: #ffffff; }
.badge-icon-vertical   { background: #ad1457; color: #ffffff; }
.badge-icon-foundation { background: #6d4c41; color: #ffffff; }
.badge-icon-ai         { background: #8e24aa; color: #ffffff; }
.badge-icon-media      { background: #d84315; color: #ffffff; }
.badge-icon-crypto     { background: #00695c; color: #ffffff; }
.badge-icon-kodec      { background: #c62828; color: #ffffff; }
.badge-icon-lang       { background: #283593; color: #ffffff; }
.badge-icon-sdk        { background: #4527a0; color: #ffffff; }
.badge-icon-compress   { background: #ef6c00; color: #ffffff; }
.badge-icon-net        { background: #1565c0; color: #ffffff; }
.badge-icon-data       { background: #2e7d32; color: #ffffff; }
.badge-icon-observe    { background: #00838f; color: #ffffff; }
.badge-icon-linux      { background: #455a64; color: #ffffff; }

[data-theme="dark"] .badge-icon-dev        { background: #5b6dd0; }
[data-theme="dark"] .badge-icon-horizontal { background: #1abc9c; }
[data-theme="dark"] .badge-icon-vertical   { background: #ec407a; }
[data-theme="dark"] .badge-icon-foundation { background: #a1887f; }
[data-theme="dark"] .badge-icon-ai         { background: #ce93d8; color: #1a0d24; }
[data-theme="dark"] .badge-icon-media      { background: #ff8a65; color: #1a0d05; }
[data-theme="dark"] .badge-icon-crypto     { background: #4db6ac; color: #002a25; }
[data-theme="dark"] .badge-icon-kodec      { background: #ef5350; }
[data-theme="dark"] .badge-icon-lang       { background: #7986cb; }
[data-theme="dark"] .badge-icon-sdk        { background: #9575cd; }
[data-theme="dark"] .badge-icon-compress   { background: #ffb74d; color: #2a1700; }
[data-theme="dark"] .badge-icon-net        { background: #64b5f6; color: #0a1a2c; }
[data-theme="dark"] .badge-icon-data       { background: #81c784; color: #0a2a0d; }
[data-theme="dark"] .badge-icon-observe    { background: #4dd0e1; color: #003035; }
[data-theme="dark"] .badge-icon-linux      { background: #90a4ae; color: #0d1a20; }

.icon-placeholder {
  font-family: var(--kds-font-mono);
  font-size: 14px;
  color: var(--kdr-text-muted);
  letter-spacing: 0.04em;
}

.icon-master-stage {
  background: linear-gradient(180deg, var(--kdr-surface-2), var(--kdr-surface));
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 8px 0 12px;
  min-height: 280px;
}

.icon-master-stage svg {
  width: auto;
  height: 240px;
  max-width: 100%;
}

.icon-master-caption {
  color: var(--kdr-text-muted);
  font-size: 14px;
  margin: 0 0 24px;
}

.icon-matrix {
  display: grid;
  grid-template-columns: minmax(160px, max-content) max-content 1fr;
  gap: 0;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
  margin: 12px 0 16px;
  background: var(--kdr-surface);
}

.icon-matrix-row { display: contents; }

.icon-matrix-row > * {
  padding: 10px 14px;
  border-bottom: 1px solid var(--kdr-border);
  display: flex;
  align-items: center;
}

.icon-matrix-row:last-of-type > * { border-bottom: 0; }

.icon-matrix-head > * {
  background: var(--kdr-surface-2);
  font-weight: 600;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.icon-matrix-row code {
  font-family: var(--kds-font-mono);
  background: var(--kdr-surface-2);
  padding: 2px 6px;
  border-radius: 4px;
}

.icon-matrix-cmd {
  display: inline-flex;
  gap: 8px;
  align-items: baseline;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 8px 14px;
  margin: 8px 0 24px;
  font-size: 14px;
}

.icon-matrix-cmd code {
  font-family: var(--kds-font-mono);
  background: var(--kdr-surface-2);
  padding: 2px 8px;
  border-radius: 4px;
}

/* ── Voice page ──────────────────────────────────────────── */

.voice-toggle-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
  margin: 12px 0 28px;
}

.voice-toggle-card {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
}

.voice-toggle-card-conditional { border-left: 3px solid var(--kdr-accent); }
.voice-toggle-card-off         { border-left: 3px solid var(--kdr-text-muted); }

.voice-toggle-card header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}

.voice-toggle-card code {
  font-family: var(--kds-font-mono);
  background: var(--kdr-surface-2);
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 13px;
}

.voice-toggle-default {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 4px;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.voice-toggle-default-off         { background: var(--kdr-surface-2); color: var(--kdr-text-muted); }
.voice-toggle-default-conditional { background: var(--kdr-accent); color: var(--kdr-accent-on); }

.voice-toggle-card p {
  margin: 0;
  font-size: 14px;
  color: var(--kdr-text-muted);
  line-height: 1.5;
}

.voice-callout {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-left: 4px solid var(--kdr-accent);
  border-radius: var(--kdr-radius-md);
  padding: 14px 18px;
  margin: 12px 0 24px;
}

.voice-callout-privacy { border-left-color: #155724; }
[data-theme="dark"] .voice-callout-privacy { border-left-color: #2e7d32; }

.voice-callout header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
  font-size: 14px;
}

.voice-callout p { margin: 0 0 8px; }

.voice-callout ul {
  margin: 0;
  padding-left: 22px;
  color: var(--kdr-text-muted);
  font-size: 14px;
  line-height: 1.55;
}

.voice-phrase {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 18px 22px;
  margin: 12px 0 8px;
  font-size: 16px;
}

.voice-phrase-prompt {
  font-size: 22px;
}

.voice-phrase-text {
  font-weight: 700;
  letter-spacing: 0.01em;
}

.voice-phrase-arrow {
  color: var(--kdr-text-muted);
}

.voice-phrase-result {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  padding: 4px 12px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 14px;
}

.voice-errors {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
  margin: 12px 0 24px;
  background: var(--kdr-surface);
}

.voice-errors-row { display: contents; }

.voice-errors-row > * {
  padding: 10px 14px;
  border-bottom: 1px solid var(--kdr-border);
  display: flex;
  align-items: center;
}

.voice-errors-row:last-of-type > * { border-bottom: 0; }

.voice-errors-head > * {
  background: var(--kdr-surface-2);
  font-weight: 600;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.voice-errors-row code {
  font-family: var(--kds-font-mono);
  background: var(--kdr-surface-2);
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 13px;
}

/* ── A11y page ───────────────────────────────────────────── */

.a11y-badge {
  display: inline-block;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  padding: 4px 10px;
  border-radius: 4px;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.04em;
  margin-right: 8px;
}

.a11y-focus-demo {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: 12px 0 8px;
  padding: 18px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
}

.a11y-focus-item {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
}

.a11y-element-tag {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  background: var(--kdr-surface-2);
  color: var(--kdr-text-muted);
  padding: 2px 8px;
  border-radius: 4px;
  text-transform: lowercase;
}

.a11y-demo-ctrl {
  font: inherit;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 6px 12px;
  cursor: pointer;
}

.a11y-demo-ctrl:focus-visible {
  outline: 3px solid var(--kdr-focus);
  outline-offset: 2px;
}

button.a11y-demo-ctrl {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border-color: var(--kdr-accent);
}

a.a11y-demo-ctrl {
  color: var(--kdr-accent);
  text-decoration: underline;
}

.a11y-demo-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
}

.a11y-swatch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin: 12px 0 8px;
}

.a11y-swatch {
  border-radius: var(--kdr-radius-md);
  padding: 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  border: 1px solid var(--kdr-border);
}

.a11y-swatch-sample {
  font-size: 18px;
  font-weight: 600;
}

.a11y-swatch-label {
  font-size: 13px;
  opacity: 0.85;
}

.a11y-swatch-vars {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  opacity: 0.85;
  font-family: var(--kds-font-mono);
}

.a11y-swatch-vars code {
  background: rgba(0, 0, 0, 0.15);
  padding: 1px 6px;
  border-radius: 3px;
}

.a11y-hc-demo {
  background: #ffffff;
  color: #000000;
  border: 3px solid #000000;
  border-radius: var(--kdr-radius-md);
  padding: 18px 20px;
  margin: 12px 0 8px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
}

[data-theme="dark"] .a11y-hc-demo {
  background: #000000;
  color: #ffffff;
  border-color: #ffffff;
}

.a11y-hc-demo .a11y-demo-ctrl {
  background: #000000;
  color: #ffffff;
  border: 2px solid #000000;
}

[data-theme="dark"] .a11y-hc-demo .a11y-demo-ctrl {
  background: #ffffff;
  color: #000000;
  border-color: #ffffff;
}

.a11y-hc-demo a {
  color: inherit;
  font-weight: 700;
  text-decoration: underline;
}

.a11y-reader-demo {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 16px 20px;
  margin: 12px 0 8px;
}

.a11y-reader-outline {
  margin-bottom: 10px;
}

.a11y-reader-outline ol {
  margin: 0;
  padding-left: 24px;
  display: grid;
  gap: 4px;
}

.a11y-reader-outline a {
  color: var(--kdr-accent);
  text-decoration: none;
}

.a11y-reader-caption {
  margin: 4px 0 0;
  color: var(--kdr-text-muted);
  font-size: 13px;
}

/* ── Coverage scorecard ──────────────────────────────────── */

.coverage-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
  margin: 16px 0 32px;
}

.coverage-stat {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
  text-align: center;
}

.coverage-stat-value {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.coverage-stat-label {
  font-size: 12px;
  color: var(--kdr-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-top: 4px;
}

.coverage-stat-done    { border-left: 3px solid #155724; }
.coverage-stat-partial { border-left: 3px solid #b8860b; }
.coverage-stat-todo    { border-left: 3px solid #c0392b; }
.coverage-stat-na      { border-left: 3px solid var(--kdr-text-muted); }
.coverage-stat-score   { border-left: 3px solid var(--kdr-accent); }

[data-theme="dark"] .coverage-stat-done    { border-left-color: #2e7d32; }
[data-theme="dark"] .coverage-stat-partial { border-left-color: #f9a825; }
[data-theme="dark"] .coverage-stat-todo    { border-left-color: #e74c3c; }

.coverage-matrix-wrap {
  overflow-x: auto;
  margin: 12px 0 16px;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  /* position: relative ensures the `.visually-hidden` spans inside
     each <td> (~19 cells × N rows) use this wrap as containing block
     instead of <html>. Without this, the visually-hidden's `position:
     absolute` placed it at static position (right ≥ 400 because the
     19-col matrix is wider than viewport), escaping the wrap's
     overflow-x: auto clip and pushing docScrollW to 625 @ 320 — the
     mystery /coverage/ 305px overflow tracked in #003 slice 5 audit. */
  position: relative;
}

.coverage-matrix {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.coverage-matrix th,
.coverage-matrix td {
  padding: 10px 12px;
  text-align: center;
  border-bottom: 1px solid var(--kdr-border);
}

.coverage-matrix thead th {
  background: var(--kdr-surface-2);
  font-weight: 600;
  position: sticky;
  top: 0;
  z-index: 1;
}

.coverage-row-head {
  text-align: left !important;
  background: var(--kdr-surface);
  position: sticky;
  left: 0;
  z-index: 1;
}

.coverage-row-head a {
  color: var(--kdr-text);
  text-decoration: none;
  font-weight: 600;
}

.coverage-row-head a:hover {
  text-decoration: underline;
}

.coverage-group {
  display: block;
  font-size: 11px;
  color: var(--kdr-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 500;
  margin-top: 2px;
}

.coverage-cell {
  font-weight: 700;
  font-size: 14px;
  text-align: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  min-height: 28px;
  border-radius: 4px;
}

.coverage-cell-done    { color: #155724; background: #d4edda; }
.coverage-cell-partial { color: #856404; background: #fff3cd; }
.coverage-cell-todo    { color: #721c24; background: #f8d7da; }
.coverage-cell-na      { color: var(--kdr-text-muted); }

[data-theme="dark"] .coverage-cell-done    { color: #d4edda; background: #1b3b22; }
[data-theme="dark"] .coverage-cell-partial { color: #fff3cd; background: #4d3c08; }
[data-theme="dark"] .coverage-cell-todo    { color: #f8d7da; background: #4a1820; }

.coverage-legend {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 10px 18px;
  margin: 8px 0 24px;
  align-items: baseline;
}

.coverage-legend dt { margin: 0; }
.coverage-legend dd { margin: 0; color: var(--kdr-text-muted); font-size: 14px; }

/* ── Playground ──────────────────────────────────────────── */

.playground-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin: 16px 0 32px;
}

@media (max-width: 639px) { /* #003 slice 4 (2026-05-14): aligned to canonical sm (640px); was 760px */
  .playground-grid { grid-template-columns: 1fr; }
}

.playground-editor {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  /* Grid items default to `min-width: auto`, which is the content's
     intrinsic min-content — a textarea with `width: 100%` reports
     a min-content based on the longest unbreakable line. At 320
     viewport the editor grew to 342px (34px over). #003 slice 6. */
  min-width: 0;
}

.playground-editor label {
  font-weight: 600;
  margin-bottom: 8px;
}

.playground-editor textarea {
  font-family: var(--kds-font-mono);
  font-size: 13px;
  line-height: 1.55;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 10px 12px;
  resize: vertical;
  width: 100%;
  min-height: 240px;
}

#playground-status {
  margin: 8px 0 0;
  font-family: var(--kds-font-mono);
  font-size: 12px;
  padding: 4px 8px;
  border-radius: 4px;
  width: fit-content;
}

#playground-status[data-state="ok"]  { color: #155724; background: #d4edda; }
#playground-status[data-state="err"] { color: #721c24; background: #f8d7da; }

[data-theme="dark"] #playground-status[data-state="ok"]  { color: #d4edda; background: #1b3b22; }
[data-theme="dark"] #playground-status[data-state="err"] { color: #f8d7da; background: #4a1820; }

.playground-preview {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  /* Same as .playground-editor — grid items must allow shrinking
     below intrinsic min-content at narrow viewports. #003 slice 6. */
  min-width: 0;
}

.playground-preview h3 {
  margin: 0 0 10px;
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--kdr-text-muted);
}

.playground-stage {
  flex: 1;
  background: linear-gradient(180deg, var(--kdr-surface-2), var(--kdr-surface));
  border-radius: var(--kdr-radius-md);
  padding: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.playground-card {
  background: var(--bg, #ffffff);
  color: var(--text, #161616);
  border-radius: var(--radius-md, 10px);
  padding: 22px;
  width: min(360px, 100%);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}

.playground-card h4 { margin: 0 0 8px; font-size: 17px; }
.playground-card p  { margin: 0 0 16px; color: var(--text, #161616); opacity: 0.85; }

.playground-card .actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.playground-btn-primary {
  background: var(--accent, #1f3a93);
  color: var(--accent-on, #ffffff);
  border: none;
  border-radius: var(--radius-sm, 6px);
  padding: 8px 16px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.playground-btn-secondary {
  background: var(--surface, #f5f5f7);
  color: var(--text, #161616);
  border: 1px solid var(--text, #161616);
  border-radius: var(--radius-sm, 6px);
  padding: 8px 16px;
  font: inherit;
  cursor: pointer;
}

/* ── Feedback widget (Sprint 7) ──────────────────────────── */

.koder-feedback {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 18px;
  margin: 0 0 16px;
  max-width: 540px;
}

/* By default show the prompt; hide form + thanks until state advances. */
.koder-feedback .koder-feedback-form,
.koder-feedback .koder-feedback-thanks {
  display: none;
}

.koder-feedback[data-state="open"] .koder-feedback-prompt   { display: none; }
.koder-feedback[data-state="open"] .koder-feedback-form     { display: block; }
.koder-feedback[data-state="sent"] .koder-feedback-prompt   { display: none; }
.koder-feedback[data-state="sent"] .koder-feedback-form     { display: none; }
.koder-feedback[data-state="sent"] .koder-feedback-thanks   { display: block; }

.koder-feedback p {
  margin: 0 0 8px;
  font-size: 14px;
  color: var(--kdr-text);
}

.koder-feedback-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.koder-feedback-btn,
.koder-feedback-btn-primary,
.koder-feedback-dismiss {
  font: inherit;
  font-size: 13px;
  border-radius: var(--kdr-radius-sm);
  padding: 6px 12px;
  cursor: pointer;
}

.koder-feedback-btn {
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.koder-feedback-btn:hover { background: var(--kdr-surface-2); }

.koder-feedback-btn-primary {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border: 1px solid var(--kdr-accent);
  font-weight: 600;
}

.koder-feedback-dismiss {
  background: transparent;
  color: var(--kdr-text-muted);
  border: 1px solid transparent;
  text-decoration: underline;
}

.koder-feedback-dismiss:hover { color: var(--kdr-text); }

.koder-feedback label {
  display: block;
  font-size: 13px;
  color: var(--kdr-text-muted);
  margin-bottom: 6px;
}

.koder-feedback textarea {
  width: 100%;
  font: inherit;
  font-size: 13px;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 8px 10px;
  resize: vertical;
}

.koder-feedback-thanks {
  font-size: 14px;
  color: var(--kdr-text);
  margin: 0;
  padding: 4px 0;
}

/* ── Footer ──────────────────────────────────────────────── */

.page-footer {
  border-top: 1px solid var(--kdr-border);
  margin-top: 64px;
  padding: 24px 28px;
  font-size: 13px;
  color: var(--kdr-text-muted);
  background: var(--kdr-surface);
}

.page-footer code {
  font-family: var(--kds-font-mono);
  background: var(--kdr-surface-2);
  padding: 1px 5px;
  border-radius: 3px;
}

/* ── Version badge ────────────────────────────────────────── */

.version-badge {
  display: flex;
  align-items: center;
}

.version-pill {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--kdr-accent-on);
  background: var(--kdr-accent);
  padding: 2px 8px;
  border-radius: 10px;
  white-space: nowrap;
}

/* ── Version selector (#097) ───────────────────────────────
   Topbar combobox lets the visitor switch between Latest and any
   /v<N>/ snapshot. Populated client-side from /versions.json by
   versionSelectorScript. `data-empty` is the pre-fetch state; the
   script removes it once the manifest loads. */

.version-selector {
  display: flex;
  align-items: center;
}

.version-selector[data-empty] {
  /* Hide the disabled placeholder when JS hasn't populated the
     manifest yet — the topbar stays uncluttered if /versions.json
     is missing (no JS, older deploy, etc.) instead of showing a
     dead "…" combobox. */
  display: none;
}

.version-select {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--kdr-text);
  background: var(--kdr-bg-elev-2, var(--kdr-bg-elev));
  border: 1px solid var(--kdr-border);
  padding: 2px 18px 2px 8px;
  border-radius: 10px;
  white-space: nowrap;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--kdr-text-muted) 50%),
                    linear-gradient(135deg, var(--kdr-text-muted) 50%, transparent 50%);
  background-position: calc(100% - 9px) 50%, calc(100% - 5px) 50%;
  background-size: 4px 4px;
  background-repeat: no-repeat;
}

.version-select:hover {
  border-color: var(--kdr-accent);
}

.version-select:focus-visible {
  outline: 2px solid var(--kdr-accent);
  outline-offset: 1px;
}

/* ── Migration guide ─────────────────────────────────────── */

.migrate-empty {
  color: var(--kdr-text-muted);
  font-style: italic;
}

.migrate-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  margin: 12px 0 24px;
}

.migrate-table th,
.migrate-table td {
  padding: 8px 12px;
  border: 1px solid var(--kdr-border);
  text-align: left;
}

.migrate-table th {
  background: var(--kdr-surface-2);
  font-weight: 600;
}

.migrate-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 4px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.migrate-badge-added   { background: #14532d; color: #bbf7d0; }
.migrate-badge-removed { background: #7f1d1d; color: #fecaca; }
.migrate-badge-changed { background: #713f12; color: #fef9c3; }

[data-theme="light"] .migrate-badge-added   { background: #dcfce7; color: #166534; }
[data-theme="light"] .migrate-badge-removed { background: #fee2e2; color: #991b1b; }
[data-theme="light"] .migrate-badge-changed { background: #fef9c3; color: #854d0e; }

.migrate-steps {
  padding-left: 24px;
  display: grid;
  gap: 8px;
  margin: 8px 0 24px;
}

/* ── Feedback widget ─────────────────────────────────────── */

.koder-feedback {
  margin: 24px 0 16px;
  padding: 14px 18px;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  background: var(--kdr-surface-2);
  font-size: 14px;
}

/* hide form and thanks by default; JS drives visibility via data-state */
.koder-feedback[data-state="initial"] .koder-feedback-form,
.koder-feedback[data-state="initial"] .koder-feedback-thanks { display: none; }

.koder-feedback[data-state="open"] .koder-feedback-prompt { display: none; }
.koder-feedback[data-state="open"] .koder-feedback-thanks  { display: none; }

.koder-feedback[data-state="sent"] .koder-feedback-prompt { display: none; }
.koder-feedback[data-state="sent"] .koder-feedback-form   { display: none; }

.koder-feedback-prompt p {
  margin: 0 0 10px;
  font-weight: 500;
}

.koder-feedback-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
}

.koder-feedback-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  background: var(--kdr-surface);
  color: var(--kdr-text);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}

.koder-feedback-btn:hover {
  border-color: var(--kdr-accent);
  background: var(--kdr-surface-2);
}

.koder-feedback[data-verdict="up"]   [data-act="up"],
.koder-feedback[data-verdict="down"] [data-act="down"] {
  border-color: var(--kdr-accent);
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
}

.koder-feedback-dismiss {
  background: none;
  border: none;
  color: var(--kdr-text-muted);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  padding: 4px 6px;
  margin-left: auto;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.koder-feedback-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.koder-feedback-form label {
  font-weight: 500;
}

.koder-feedback-form textarea {
  font: inherit;
  font-size: 13px;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 8px 10px;
  resize: vertical;
  min-height: 80px;
}

.koder-feedback-btn-primary {
  padding: 7px 16px;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border: none;
  border-radius: var(--kdr-radius-sm);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.koder-feedback-thanks {
  margin: 0;
  color: var(--kdr-text-muted);
  font-style: italic;
}

/* ── Reference (spec-doc catch-all, Sprint 9.1 #010) ─────── */

.specdoc-group {
  margin: 32px 0;
}

.specdoc-group h2 {
  font-size: 22px;
  margin: 0 0 8px;
  border-bottom: 1px solid var(--kdr-border);
  padding-bottom: 6px;
}

.specdoc-group-lede {
  margin: 0 0 12px;
  color: var(--kdr-text-muted);
  font-size: 14px;
}

.specdoc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: 16px;
  margin: 12px 0 0;
}

.specdoc-tile {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.specdoc-tile-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.specdoc-tile h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.specdoc-tile h3 a {
  color: var(--kdr-text);
  text-decoration: none;
}

.specdoc-tile h3 a:hover {
  text-decoration: underline;
}

.specdoc-tile-spec {
  font-size: 12px;
  color: var(--kdr-text-muted);
  margin: 0;
  font-family: var(--kds-font-mono);
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.specdoc-tile-summary {
  font-size: 14px;
  color: var(--kdr-text-muted);
  margin: 0;
  line-height: 1.5;
}

/* design-RFC-003 Phase 4 — chips de facet em spec pages.
   Renderizados abaixo do <h1> e acima do badge de grupo. Cada chip
   é um <a> clicável que navega pra /<locale>/<facet>/ listing.
   Cores neutras com hover por facet (sem overload chromático). */
.specdoc-facets {
  list-style: none;
  padding: 0;
  margin: 8px 0 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.specdoc-facet-chip {
  display: inline-block;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  background: var(--kdr-surface);
  color: var(--kdr-text-muted);
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  text-decoration: none;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.specdoc-facet-chip:hover,
.specdoc-facet-chip:focus-visible {
  background: var(--kdr-surface-2);
  color: var(--kdr-text);
  border-color: var(--kdr-accent);
}

/* spec-doc badges share the muted-then-accent fallback. Specific
   group-keyed colors stay subtle; the goal is grouping signal, not
   chromatic theming like patterns. */
[class*="badge-specdoc-"] {
  background: var(--kdr-surface);
  color: var(--kdr-text-muted);
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  font-size: 11px;
  padding: 2px 8px;
  font-weight: 500;
  letter-spacing: 0.02em;
}

.specdoc-triggers {
  list-style: none;
  padding: 0;
  margin: 8px 0 24px;
  display: grid;
  gap: 6px;
}

.specdoc-triggers li {
  background: var(--kdr-surface);
  border-left: 3px solid var(--kdr-accent);
  padding: 8px 12px;
  border-radius: 0 var(--kdr-radius-sm) var(--kdr-radius-sm) 0;
  font-size: 14px;
}

/* spec-doc body shares the pattern body typography; alias the rules
   so we don't duplicate the long markdown-block styling. */
.specdoc-body {
  margin: 8px 0 24px;
  line-height: 1.65;
  color: var(--kdr-text);
}

.specdoc-body h2 {
  font-size: 22px;
  margin: 36px 0 12px;
  border-bottom: 1px solid var(--kdr-border);
  padding-bottom: 6px;
}

.specdoc-body h3 { font-size: 17px; margin: 28px 0 8px; }

.specdoc-body h4 {
  font-size: 15px;
  margin: 20px 0 8px;
  color: var(--kdr-text-muted);
}

.specdoc-body p { margin: 0 0 14px; }

.specdoc-body ul,
.specdoc-body ol {
  margin: 0 0 14px;
  padding-left: 24px;
}

.specdoc-body li { margin: 4px 0; }

.specdoc-body code {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 3px;
  padding: 1px 6px;
  font-family: var(--kds-font-mono);
  font-size: 0.9em;
}

.specdoc-body pre {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px 16px;
  overflow-x: auto;
  font-family: var(--kds-font-mono);
  font-size: 13px;
  line-height: 1.55;
  margin: 8px 0 18px;
}

.specdoc-body pre code {
  background: transparent;
  border: 0;
  padding: 0;
}

.specdoc-body blockquote {
  border-left: 4px solid var(--kdr-accent);
  margin: 8px 0 18px;
  padding: 4px 14px;
  color: var(--kdr-text-muted);
  background: var(--kdr-surface);
  border-radius: 0 var(--kdr-radius-sm) var(--kdr-radius-sm) 0;
}

.specdoc-body table {
  border-collapse: collapse;
  margin: 12px 0 18px;
  font-size: 13px;
  width: 100%;
}
/* Mobile-friendly tables: at narrow viewports, switch to block-level
   layout with horizontal scroll inside the table itself instead of
   forcing the entire page to scroll horizontally.  This is the
   standard mobile-pattern; RFC-002 will absorb the helper into a
   `.kds-table-scrollable` utility class for site-wide reuse.
   Observed 2026-05-12 on /voice/, /style/, /themes/, /coverage/
   (all spec-doc rendered tables overflowing at 320-540px). */
@media (max-width: 540px) {
  /* Apply to tables that DON'T already have a `*-wrap` scrollable
     container in the HTML (.coverage-matrix-wrap and .icon-matrix-wrap
     already handle overflow-x: auto on the wrapping div).  Forcing
     `display: block` on a table whose parent already clips would
     break the table's internal layout (thead/tbody escape into
     block flow and widen the document). */
  .specdoc-body table,
  .pattern-body table,
  .migrate-table {
    display: block;
    overflow-x: auto;
    max-width: 100%;
    /* white-space nowrap on cells keeps rows readable while scrolling
       horizontally — otherwise cell content wraps awkwardly. */
    white-space: nowrap;
  }
}

.specdoc-body th,
.specdoc-body td {
  border: 1px solid var(--kdr-border);
  padding: 6px 10px;
  text-align: left;
  vertical-align: top;
}

.specdoc-body th {
  background: var(--kdr-surface);
  font-weight: 600;
}

.specdoc-refs {
  list-style: none;
  padding: 0;
  margin: 8px 0 24px;
  display: grid;
  gap: 4px;
}

.specdoc-refs li {
  font-family: var(--kds-font-mono);
  font-size: 13px;
}

/* ── Copy-code button + page ToC (Sprint 9.5 #014) ───────── */

.copy-code-wrapper {
  position: relative;
  margin: 8px 0 18px;
}

.copy-code-wrapper > pre {
  margin: 0; /* wrapper carries the spacing now */
}

.copy-code-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 4px 10px;
  font: inherit;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.2;
  background: var(--kdr-surface);
  color: var(--kdr-text-muted);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s, background 0.15s;
}

.copy-code-wrapper:hover .copy-code-btn,
.copy-code-wrapper:focus-within .copy-code-btn,
.copy-code-btn:focus-visible {
  opacity: 1;
}

.copy-code-btn:hover {
  background: var(--kdr-bg);
  color: var(--kdr-text);
}

.copy-code-btn:focus-visible {
  outline: 2px solid var(--kdr-accent);
  outline-offset: 2px;
}

.copy-code-btn[data-state="copied"] {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border-color: var(--kdr-accent);
  opacity: 1;
}

.copy-code-btn[data-state="failed"] {
  background: #c0392b;
  color: #ffffff;
  border-color: #c0392b;
  opacity: 1;
}

/* ── On-this-page Table of Contents ───────────────────────── */

.page-toc {
  display: none; /* mobile: hidden by default — body takes priority */
  position: sticky;
  /* Clear the fixed topbar (#149 S8) so the card's header isn't cut
     off when the user scrolls down. 16px of breathing room above. */
  top: calc(var(--kds-topbar-height) + 16px);
  align-self: start;
  font-size: 13px;
  line-height: 1.5;
  color: var(--kdr-text-muted);
  /* Match the new top offset so the card never extends below the
     viewport when fully stuck. */
  max-height: calc(100vh - var(--kds-topbar-height) - 32px);
  overflow-y: auto;
  padding: 12px 14px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
}

.page-toc-title {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--kdr-text-muted);
  margin: 0 0 8px;
  padding: 0;
  border: none;
}

.page-toc ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.page-toc-h3 {
  padding-left: 12px;
}

.page-toc a {
  display: block;
  padding: 3px 6px;
  color: var(--kdr-text-muted);
  text-decoration: none;
  border-left: 2px solid transparent;
  border-radius: 0 4px 4px 0;
}

.page-toc a:hover {
  color: var(--kdr-text);
  background: var(--kdr-bg);
}

/* Ticket #043 — Scroll-spy: page-enhance.js toggles .is-current on
   the TOC anchor whose target heading sits in the upper third of
   the viewport. */
.page-toc a.is-current {
  color: var(--kdr-accent);
  border-left-color: var(--kdr-accent);
  font-weight: 500;
}

/* Ticket #045 — Token copy-on-click. Any element with
   .kds-token-copyable becomes click-to-copy. Visual feedback via
   .is-copied class set by page-enhance.js for 1.2s. */
.kds-token-copyable {
  cursor: pointer;
  position: relative;
  user-select: all;
  border-radius: 4px;
  padding: 1px 4px;
  transition: background-color 120ms ease, color 120ms ease;
}
.kds-token-copyable:hover {
  background: color-mix(in srgb, var(--kdr-accent) 12%, transparent);
}
.kds-token-copyable:focus-visible {
  outline: 2px solid var(--kdr-focus);
  outline-offset: 1px;
}
.kds-token-copyable.is-copied::after {
  content: "✓";
  position: absolute;
  top: -2px;
  right: -16px;
  font-size: 12px;
  color: var(--kdr-accent);
  animation: kds-token-copied-pop 1200ms ease forwards;
  pointer-events: none;
}
@keyframes kds-token-copied-pop {
  0%   { opacity: 0; transform: scale(0.8) translateY(2px); }
  20%  { opacity: 1; transform: scale(1) translateY(0); }
  80%  { opacity: 1; transform: scale(1) translateY(0); }
  100% { opacity: 0; transform: scale(1) translateY(-4px); }
}

.page-toc a:focus-visible {
  outline: 2px solid var(--kdr-accent);
  outline-offset: 2px;
}

.page-toc a[aria-current="true"] {
  color: var(--kdr-text);
  border-left-color: var(--kdr-accent);
  background: var(--kdr-bg);
  font-weight: 500;
}

/* On wide enough viewports, lay the page out as
     [main body] [ToC right-rail]
   The ToC appears as a right column inside main.page when present. */
@media (min-width: 1100px) { /* TODO RFC-002 #003 slice 3: between md(900) and lg(1280); ToC gate, needs visual review */
  main.page.has-toc {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 240px;
    gap: 32px;
    align-items: start;
  }
  main.page.has-toc > section {
    grid-column: 1;
  }
  main.page.has-toc > .page-toc {
    display: block;
    grid-column: 2;
    grid-row: 1 / span 99;
  }
}

/* ── Global full-text search (Sprint 9.2 #011) ───────────── */

.search-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  font: inherit;
  font-size: 13px;
  background: var(--kdr-surface);
  color: var(--kdr-text-muted);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  cursor: pointer;
  min-width: 200px;
}

.search-trigger:hover {
  background: var(--kdr-bg);
  color: var(--kdr-text);
}

.search-trigger:focus-visible {
  outline: 2px solid var(--kdr-accent);
  outline-offset: 2px;
}

.search-trigger-label {
  flex: 1;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.search-trigger-kbd {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  padding: 1px 6px;
  border: 1px solid var(--kdr-border);
  border-radius: 3px;
  background: var(--kdr-bg);
  color: var(--kdr-text-muted);
}

@media (max-width: 639px) { /* #003 slice 4 (2026-05-14): aligned to canonical sm (640px); was 720px */
  .search-trigger-label { display: none; }
  .search-trigger { min-width: auto; }
}

.koder-search-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 64px 16px 16px;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(2px);
}

.koder-search-modal[hidden] { display: none; }

.koder-search-panel {
  width: 100%;
  max-width: 640px;
  max-height: calc(100vh - 96px);
  display: flex;
  flex-direction: column;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}

.koder-search-header {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid var(--kdr-border);
}

.koder-search-input {
  flex: 1;
  padding: 14px 16px;
  font: inherit;
  font-size: 15px;
  background: transparent;
  color: var(--kdr-text);
  border: 0;
  outline: none;
}

.koder-search-input::placeholder { color: var(--kdr-text-muted); }

.koder-search-close {
  padding: 0 16px;
  font: inherit;
  font-size: 22px;
  line-height: 1;
  background: transparent;
  color: var(--kdr-text-muted);
  border: 0;
  border-left: 1px solid var(--kdr-border);
  cursor: pointer;
}

.koder-search-close:hover { color: var(--kdr-text); }

.koder-search-close:focus-visible {
  outline: 2px solid var(--kdr-accent);
  outline-offset: -3px;
}

.koder-search-status {
  margin: 0;
  padding: 8px 16px;
  font-size: 12px;
  color: var(--kdr-text-muted);
  background: var(--kdr-surface);
  border-bottom: 1px solid var(--kdr-border);
}

.koder-search-results {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  max-height: calc(100vh - 240px);
}

.koder-search-result {
  border-bottom: 1px solid var(--kdr-border);
}

.koder-search-result:last-child { border-bottom: 0; }

.koder-search-result a {
  display: block;
  padding: 12px 16px;
  color: var(--kdr-text);
  text-decoration: none;
}

.koder-search-result a:hover,
.koder-search-result a[aria-selected="true"] {
  background: var(--kdr-surface);
}

.koder-search-result a:focus-visible {
  outline: 2px solid var(--kdr-accent);
  outline-offset: -3px;
}

.koder-search-result-title {
  font-size: 15px;
  font-weight: 600;
  margin: 0 0 2px;
}

.koder-search-result-section {
  font-size: 11px;
  color: var(--kdr-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0 0 4px;
}

.koder-search-result-body {
  font-size: 13px;
  color: var(--kdr-text-muted);
  line-height: 1.5;
}

.koder-search-result mark {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  padding: 0 2px;
  border-radius: 2px;
}

/* ── Cross-link enrichment — Sprint 9 follow-up #029 ──────── */

.spec-xref {
  border-bottom: 1px dotted currentColor;
  text-decoration: none;
  position: relative;
  padding-right: 14px;
}

.spec-xref::after {
  content: "↗";
  position: absolute;
  right: 0;
  top: -1px;
  font-size: 0.85em;
  color: var(--kdr-text-muted);
}

.spec-xref:hover,
.spec-xref:focus-visible {
  color: var(--kdr-accent);
  border-bottom-color: var(--kdr-accent);
}

.spec-xref:focus-visible {
  outline: 3px solid var(--kdr-focus);
  outline-offset: 2px;
  border-radius: 2px;
}

.koder-xref-tooltip {
  position: absolute;
  z-index: 70;
  max-width: 360px;
  padding: 10px 12px;
  background: var(--kdr-surface);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  font-size: 13px;
  line-height: 1.45;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 120ms ease-out, transform 120ms ease-out;
}

.koder-xref-tooltip[data-state="open"] {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .koder-xref-tooltip { transition: none; }
}

/* ── Settings rail (drawer) — Sprint 9 follow-up #026 ─────── */

.settings-trigger {
  width: 34px;
  height: 34px;
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  font-size: 18px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.settings-trigger:hover { background: var(--kdr-surface-2); }
.settings-trigger:focus-visible {
  outline: 3px solid var(--kdr-focus);
  outline-offset: 2px;
}

.koder-settings-rail {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  grid-template-columns: 1fr min(420px, 100vw);
  pointer-events: none;
}

.koder-settings-rail[hidden] { display: none; }

.koder-settings-scrim {
  background: rgba(0, 0, 0, 0.45);
  pointer-events: auto;
  opacity: 0;
  transition: opacity 180ms ease-out;
}

.koder-settings-rail[data-state="open"] .koder-settings-scrim { opacity: 1; }

.koder-settings-panel {
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border-left: 1px solid var(--kdr-border);
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 200ms ease-out;
  box-shadow: -8px 0 32px rgba(0, 0, 0, 0.25);
  overflow-y: auto;
}

.koder-settings-rail[data-state="open"] .koder-settings-panel {
  transform: translateX(0);
}

@media (prefers-reduced-motion: reduce) {
  .koder-settings-panel,
  .koder-settings-scrim {
    transition: none;
  }
}

.koder-settings-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 22px;
  border-bottom: 1px solid var(--kdr-border);
}

.koder-settings-header h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
}

.koder-settings-close {
  width: 34px;
  height: 34px;
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  background: transparent;
  color: var(--kdr-text);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

.koder-settings-close:hover { background: var(--kdr-surface-2); }
.koder-settings-close:focus-visible {
  outline: 3px solid var(--kdr-focus);
  outline-offset: 2px;
}

.koder-settings-body {
  padding: 18px 22px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.koder-settings-group h3 {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--kdr-text-muted);
}

.koder-settings-themes {
  display: inline-flex;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 2px;
  gap: 2px;
}

.koder-settings-themes button {
  flex: 1;
  /* `appearance: none` strips ALL UA-default button styling. Chrome
     (esp. with OS dark mode + color-scheme: light page) was leaking
     a translucent system "ButtonText" through the explicit `color:`
     declaration, making the inactive theme button label nearly
     invisible. With appearance: none, only the rules below apply. */
  -webkit-appearance: none;
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--kdr-text);
  padding: 8px 16px;
  border-radius: calc(var(--kdr-radius-sm) - 2px);
  cursor: pointer;
  font: inherit;
  /* Bump the inactive label from default 400 to 500 — improves
     legibility on smaller font sizes without competing with the
     active button (which is on accent bg + white text). */
  font-weight: 500;
}

.koder-settings-themes button[aria-pressed="true"] {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  font-weight: 600;
}

.koder-settings-themes button:focus-visible {
  outline: 3px solid var(--kdr-focus);
  outline-offset: 2px;
}

.koder-settings-langs {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.koder-settings-langs a {
  padding: 10px 12px;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  color: var(--kdr-text);
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.koder-settings-langs a[aria-current="true"] {
  border-color: var(--kdr-accent);
  color: var(--kdr-accent);
  font-weight: 600;
}

.koder-settings-langs a:hover { background: var(--kdr-surface-2); }
.koder-settings-langs a:focus-visible {
  outline: 3px solid var(--kdr-focus);
  outline-offset: 2px;
}

.koder-settings-toggle {
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  padding: 10px 0;
}

.koder-settings-toggle input {
  appearance: none;
  width: 38px;
  height: 22px;
  background: var(--kdr-surface-2);
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  position: relative;
  cursor: pointer;
  transition:
    background var(--kds-motion-duration-fast) var(--kds-motion-easing-standard),
    border-color var(--kds-motion-duration-fast) var(--kds-motion-easing-standard);
  flex-shrink: 0;
}

.koder-settings-toggle input::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 999px;
  background: var(--kdr-text);
  transition: transform var(--kds-motion-duration-fast) var(--kds-motion-spring-spatial-fast);
}

.koder-settings-toggle input:checked {
  background: var(--kdr-accent);
  border-color: var(--kdr-accent);
}

.koder-settings-toggle input:checked::after {
  transform: translateX(16px);
  background: var(--kdr-accent-on);
}

.koder-settings-toggle input:focus-visible {
  outline: 3px solid var(--kdr-focus);
  outline-offset: 2px;
}

.koder-settings-toggle-label {
  font-weight: 500;
}

.koder-settings-help {
  margin: 6px 0 0;
  color: var(--kdr-text-muted);
  font-size: 14px;
  line-height: 1.5;
}

.koder-settings-help a {
  color: inherit;
  text-decoration: underline;
}

@media (max-width: 540px) {
  .koder-settings-rail { grid-template-columns: 0 100vw; }
}

/* ── PDF print rules ─────────────────────────────────────── */

@media print {
  .topnav,
  .controls,
  .breadcrumb,
  .koder-settings-rail { display: none !important; }

  body { background: #fff; color: #000; }

  .page { max-width: none; padding: 0; }

  section { page-break-before: auto; }

  h1, h2 { page-break-after: avoid; }

  pre, table { page-break-inside: avoid; }

  a[href]::after { content: " (" attr(href) ")"; font-size: 10px; }
}

/* ──────────────────────────────────────────────────────────────────────
   Landing redesign — Facets-First Grid (Direção C, ratified 2026-05-10)
   Hero is compact; the visual weight lives in 5 facet cards each
   carrying its own living preview, built from the same tokens consumers
   will use. Catalog of specs is preserved at the bottom as supporting
   content, not hero. Class prefix `lp-` to avoid collision with shared
   styles (.hero/.lede/.cta still in use by sub-pages).
   ────────────────────────────────────────────────────────────────────── */

.lp-hero {
  display: flex;
  flex-direction: column;
  gap: 24px;
  /* Horizontal padding (32px) keeps the title/tagline from butting the
     mesh-gradient pseudo-element edges — the radial gradients on
     ::before bleed all the way to the hero bounds, so without internal
     padding the heading visually sits on the colored border. Issue
     reported 2026-05-12 (screenshot: text "A forma intencional…" glued
     to the left edge of the card). */
  padding: 64px 32px 48px;
  border-bottom: 1px solid var(--kdr-border);
  margin-bottom: 56px;
}
.lp-hero-text { max-width: 880px; }
.lp-hero-title {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: clamp(40px, 6vw, 72px);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin: 0 0 20px;
  background: linear-gradient(135deg, var(--kdr-text) 0%, var(--kdr-accent) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.lp-hero-tagline {
  font-size: clamp(18px, 1.6vw, 22px);
  line-height: 1.45;
  color: var(--kdr-text-muted);
  margin: 0;
  font-weight: 400;
}

/* ── Hero split-panel variant (#149 S2+S3+S7, 2026-05-11) ──────────
   When .lp-hero carries the .lp-hero--split modifier (root index
   only), the hero rearranges to a two-column layout: tagline+meta on
   the left, "spec → render" demonstrator on the right. The giant
   "Koder Design" gradient title is dropped here (S3) because the
   wordmark already lives in the TopBar — repeating it added vertical
   bulk without communication. The compact result lets the first row
   of facet cards peek above the fold at 1080p (S7). */
.lp-hero--split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  /* Horizontal padding (32px) keeps the title/tagline + the spec→render
     panel from butting the mesh-gradient pseudo-element edges.  The
     radial gradients on ::before bleed to the hero bounds, so without
     internal padding both columns visually sit on the colored border.
     Issue reported 2026-05-12 (e2e: TestE2EHeroHasInternalHorizontalPadding).
     This sibling rule to `.lp-hero` exists because the --split
     modifier was previously resetting padding back to vertical-only. */
  padding: 40px 32px 32px;
  margin-bottom: 40px;
}
@media (min-width: 900px) { /* #003 slice 4 (2026-05-14): aligned to canonical md (900px); was 980px */
  .lp-hero--split {
    grid-template-columns: minmax(280px, 1fr) minmax(360px, 1.1fr);
    gap: 48px;
    align-items: center;
  }
}
.lp-hero--split .lp-hero-tagline {
  font-size: clamp(22px, 2.2vw, 34px);
  line-height: 1.2;
  color: var(--kdr-text);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0 0 18px;
}
/* Wide-monitor hero-tagline ceiling (2026-05-16) — paired with the
   sidebar typography block near line 660. The clamp ceiling of 34px
   above caps at ~1546px and then freezes, which reads small on
   1800/2160/2560 monitors. Raise the ceiling progressively. */
@media (min-width: 1600px) {
  .lp-hero--split .lp-hero-tagline {
    font-size: clamp(22px, 3.2vw, 52px);
  }
}
@media (min-width: 2200px) {
  .lp-hero--split .lp-hero-tagline {
    font-size: clamp(22px, 3.2vw, 64px);
  }
}
.lp-hero--split .lp-hero-meta {
  flex-wrap: wrap;
}

/* The right-side panel — spec snippet + arrow + rendered output. */
.lp-hero-split-panel {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-lg);
  padding: 22px 24px 18px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  position: relative;
  overflow: hidden;
}
.lp-hero-split-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(60% 80% at 100% 0%,
    color-mix(in srgb, var(--kdr-accent) 14%, transparent) 0%,
    transparent 60%);
  z-index: 0;
}
.lp-hero-split-panel > * { position: relative; z-index: 1; }
.lp-hero-split-head { display: flex; flex-direction: column; gap: 2px; }
.lp-hero-split-title {
  font-family: var(--kds-font-mono);
  font-size: 13px;
  font-weight: 600;
  color: var(--kdr-accent);
  margin: 0;
  letter-spacing: 0.02em;
  text-transform: lowercase;
}
.lp-hero-split-sub {
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--kdr-text-muted);
  margin: 0;
}
.lp-hero-split-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 12px;
  align-items: stretch;
}
.lp-hero-split-spec {
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.lp-hero-split-spec-head {
  padding: 6px 10px;
  border-bottom: 1px solid var(--kdr-border);
  background: var(--kdr-surface);
}
.lp-hero-split-spec-path {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  color: var(--kdr-text-muted);
  letter-spacing: 0.01em;
}
/* Specificity bump: `main.page pre` (0,1,2) was overriding the
   single-class rule (0,1,0) — it kept overflow-x:auto + the surface
   background + the border, so the snippet rendered as a nested box
   with a horizontal scrollbar at narrow viewports. Issue reported
   2026-05-12 (screenshot showed ◄/► scrollbar inside the spec code
   block). Scoping to `main.page pre.lp-hero-split-spec-code` (0,1,2)
   ties our rule, and source order wins. */
main.page pre.lp-hero-split-spec-code,
main.page pre.lp-hero-split-spec-code > code {
  margin: 0;
  padding: 12px 14px;
  font-family: var(--kds-font-mono);
  font-size: 12px;
  line-height: 1.55;
  /* pre-wrap lets natural-language lines like "name: Product Icons"
     wrap on spaces.  overflow-wrap: anywhere catches long tokens
     without break points (e.g. "specs/icons/products.kmd") that
     pre-wrap alone can't break — observed 2026-05-12 at 320px:
     <code> rendered 242px wide overflowing a 320px viewport.
     The descendant selector applies both rules to the inner <code>
     because <code> is inline-display by default and a few browsers
     don't propagate overflow-wrap from inline ancestors. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
  overflow: hidden;
  background: transparent;
  border: 0;
  border-radius: 0;
  color: var(--kdr-text);
  min-width: 0;
  max-width: 100%;
  /* Fade the bottom in case the snippet ever gets cropped on narrow
     viewports — keeps the panel from looking truncated. */
  mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent 100%);
}
.lp-hero-split-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  color: var(--kdr-accent);
  font-weight: 300;
  padding: 0 4px;
}
.lp-hero-split-render {
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px;
  min-width: 0;
}
.lp-hero-split-render svg {
  width: 100%;
  height: auto;
  max-width: 140px;
  max-height: 140px;
  filter: drop-shadow(0 6px 14px color-mix(in srgb, var(--kdr-accent) 28%, transparent));
}
.lp-hero-split-render-caption {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  color: var(--kdr-text-muted);
  letter-spacing: 0.04em;
}
.lp-hero-split-cta {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--kdr-accent);
  text-decoration: none;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  transition: border-color 160ms ease;
}
.lp-hero-split-cta:hover,
.lp-hero-split-cta:focus-visible {
  border-bottom-color: var(--kdr-accent);
  outline: none;
}

/* Narrow viewports: stack spec / arrow / render vertically. */
@media (max-width: 640px) {
  .lp-hero-split-body {
    grid-template-columns: 1fr;
    gap: 8px;
  }
  .lp-hero-split-arrow {
    transform: rotate(90deg);
    padding: 4px 0;
  }
}
.lp-hero-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.lp-hero-meta-pill {
  display: inline-flex;
  align-items: center;
  font-size: 13px;
  padding: 6px 12px;
  border: 1px solid var(--kdr-border);
  border-radius: 999px;
  color: var(--kdr-text-muted);
  background: var(--kdr-surface);
  letter-spacing: 0.01em;
}
.lp-hero-meta-pill--version {
  font-family: var(--kds-font-mono);
  color: var(--kdr-accent);
  border-color: color-mix(in srgb, var(--kdr-accent) 40%, transparent);
}

/* ── Facets grid ─────────────────────────────────────────── */

.lp-facets { margin-bottom: 64px; }

.lp-facets-grid {
  display: grid;
  gap: 20px;
  /* #123 (2026-05-24): base = 1 column for <640px (canonical sm).
     Owner-reported at 412dp the 2-col base squeezed each card body
     to 6-9 char lines ("Como produtos / Koder se / apresentam..."),
     well below the 45-75 char comfort band. Ladder is now
     1 / 2 / 3 / 6 across xs / sm / md / lg. */
  grid-template-columns: 1fr;
}
@media (min-width: 640px) { /* #123 (2026-05-24): canonical sm — pair the cards once each fits ≥ ~280dp */
  .lp-facets-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) { /* #003 slice 4 (2026-05-14): aligned to canonical md (900px); was 980px */
  .lp-facets-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1280px) {
  .lp-facets-grid {
    grid-template-columns: repeat(6, 1fr);
  }
  /* On wide screens, give facet 1 (Visual) and 6 (System) extra room
     so the row reads as 5 cards with Visual emphasized. */
  .lp-facet--visual { grid-column: span 2; }
  .lp-facet--code { grid-column: span 2; }
  .lp-facet--data { grid-column: span 2; }
  .lp-facet--interface { grid-column: span 3; }
  .lp-facet--system { grid-column: span 3; }
}

.lp-facet {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 24px 22px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-lg);
  text-decoration: none;
  color: var(--kdr-text);
  position: relative;
  overflow: hidden;
  transition: transform 200ms ease, border-color 200ms ease, box-shadow 200ms ease;
  min-height: 280px;
}
.lp-facet::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, transparent 0%, color-mix(in srgb, var(--kdr-accent) 6%, transparent) 100%);
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}
.lp-facet:hover,
.lp-facet:focus-visible {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--kdr-accent) 60%, var(--kdr-border));
  box-shadow: 0 8px 24px -8px color-mix(in srgb, var(--kdr-accent) 30%, transparent);
  outline: none;
}
.lp-facet:hover::before,
.lp-facet:focus-visible::before { opacity: 1; }

.lp-facet-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  position: relative;
}
.lp-facet-tag {
  font-family: var(--kds-font-mono);
  font-size: 12px;
  color: var(--kdr-text-muted);
  letter-spacing: 0.05em;
}
.lp-facet-name {
  font-size: 24px;
  font-weight: 700;
  margin: 0;
  letter-spacing: -0.02em;
}
.lp-facet-lede {
  font-size: 14px;
  line-height: 1.5;
  color: var(--kdr-text-muted);
  margin: 0;
  position: relative;
}
.lp-facet-sample {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  position: relative;
  overflow: hidden;
}
.lp-facet-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
  color: var(--kdr-text-muted);
  position: relative;
}
.lp-arrow {
  font-size: 16px;
  transition: transform 200ms ease;
  color: var(--kdr-accent);
}
.lp-facet:hover .lp-arrow { transform: translateX(4px); }

/* Visual facet — color swatches */
.lp-facet-sample--visual {
  display: flex;
  flex-direction: row;
  gap: 6px;
  padding: 14px;
}
.lp-swatch {
  flex: 1;
  height: 64px;
  border-radius: var(--kdr-radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  font-size: 18px;
  border: 1px solid var(--kdr-border);
}
.lp-swatch--bg { background: var(--kdr-bg); }
.lp-swatch--surface { background: var(--kdr-surface-2); }
.lp-swatch--accent { background: var(--kdr-accent); }
.lp-swatch--accent-on { background: var(--kdr-accent); color: var(--kdr-accent-on); }
.lp-swatch--text { background: var(--kdr-text); color: var(--kdr-bg); }

/* Code facet — syntax-highlighted snippet */
.lp-facet-sample--code {
  align-items: stretch;
  padding: 0;
}
.lp-facet-sample--code pre {
  margin: 0;
  padding: 14px 16px;
  font-family: var(--kds-font-mono);
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre;
  width: 100%;
  overflow: hidden;
  background: transparent;
  /* Snippet is hand-tuned to fit; if it ever overflows on narrow viewports
     the fade mask hides the cut without showing a scrollbar. */
  mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
}
.lp-tok-keyword { color: #c084fc; font-weight: 600; }
.lp-tok-fn { color: #60a5fa; }
.lp-tok-comment { color: var(--kdr-text-muted); font-style: italic; }
[data-theme="dark"] .lp-tok-keyword { color: #b79eff; }
[data-theme="dark"] .lp-tok-fn { color: #7bc4ff; }

/* Data facet — mini schema table */
.lp-facet-sample--data {
  padding: 0;
  align-items: stretch;
}
.lp-facet-sample--data table {
  width: 100%;
  font-family: var(--kds-font-mono);
  font-size: 12px;
  border-collapse: collapse;
  border-spacing: 0;
  table-layout: fixed;
}
.lp-facet-sample--data {
  overflow: hidden;
}
.lp-facet-sample--data th,
.lp-facet-sample--data td {
  padding: 8px 14px;
  text-align: left;
  border-bottom: 1px solid var(--kdr-border);
}
.lp-facet-sample--data thead th {
  background: var(--kdr-surface);
  color: var(--kdr-text-muted);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.lp-facet-sample--data tbody tr:last-child td { border-bottom: none; }
.lp-facet-sample--data td:last-child { color: var(--kdr-text-muted); }

/* Interface facet — request/response */
.lp-facet-sample--interface {
  align-items: stretch;
  padding: 0;
}
.lp-facet-sample--interface pre {
  margin: 0;
  padding: 14px 16px;
  font-family: var(--kds-font-mono);
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre;
  width: 100%;
  overflow: hidden;
  background: transparent;
  mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
}
.lp-tok-method {
  color: #34d399;
  font-weight: 700;
  background: color-mix(in srgb, #34d399 15%, transparent);
  padding: 1px 6px;
  border-radius: 4px;
}
.lp-tok-status {
  color: #34d399;
  font-weight: 700;
}

/* System facet — mini architecture diagram */
.lp-facet-sample--system {
  padding: 18px;
}
.lp-arch {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}
.lp-arch-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}
.lp-arch-node {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 14px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  font-family: var(--kds-font-mono);
  font-size: 12px;
  min-width: 80px;
  text-align: center;
}
.lp-arch-node--app { border-color: color-mix(in srgb, #60a5fa 50%, var(--kdr-border)); }
.lp-arch-node--svc { border-color: color-mix(in srgb, #c084fc 50%, var(--kdr-border)); }
.lp-arch-node--db  { border-color: color-mix(in srgb, #34d399 50%, var(--kdr-border)); }
.lp-arch-edge {
  color: var(--kdr-text-muted);
  font-size: 14px;
}

/* ── Catalog shelf (relegated, organized) ────────────────── */

.lp-catalog {
  margin-top: 48px;
  padding-top: 40px;
  border-top: 1px solid var(--kdr-border);
}
.lp-catalog-head { margin-bottom: 24px; }
.lp-catalog-head h2 {
  font-size: 28px;
  font-weight: 700;
  margin: 0 0 8px;
  letter-spacing: -0.02em;
}
.lp-catalog-lede {
  color: var(--kdr-text-muted);
  font-size: 15px;
  margin: 0;
  max-width: 640px;
}
/* `.lp-catalog-list` — migrated to consume the vendored `.kds-grid-auto`
   utility (design-RFC-002, ticket #003 slice 1, 2026-05-12).  The
   list-reset + 4px-gap + 380px-min are still site-specific so they stay
   here; the auto-fit + overflow-safe-min comes from the SDK utility.
   This is the proof-of-concept consumer migration. */
.lp-catalog-list {
  list-style: none;
  padding: 0;
  margin: 0;
  --kds-grid-gap: 4px;
  --kds-grid-min: 380px;
}
.lp-catalog-list { /* compose: also takes everything from .kds-grid-auto when its class is on the DOM */ }
.lp-catalog-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-radius: var(--kdr-radius-sm);
  font-size: 13.5px;
  transition: background 150ms ease;
  /* min-width: 0 lets flex children shrink below their content's
     intrinsic min size — without it, long monospace paths like
     `specs/landing-pages/products.kmd` extend past the item box at
     narrow viewports (320px probe: spans rendered right=404 vs vp=320).
     overflow: hidden on the parent + ellipsis on the children below
     gives a clean truncation. */
  min-width: 0;
  overflow: hidden;
}
.lp-catalog-item:hover { background: var(--kdr-surface); }
.lp-catalog-path {
  font-family: var(--kds-font-mono);
  font-size: 12px;
  color: var(--kdr-text-muted);
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 1;
}
.lp-catalog-name {
  color: var(--kdr-text);
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 1;
}

.lp-pill {
  display: inline-block;
  font-size: 10.5px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--kdr-surface-2);
  color: var(--kdr-text);
  text-transform: lowercase;
  font-weight: 600;
  white-space: nowrap;
  letter-spacing: 0.02em;
  min-width: 60px;
  text-align: center;
}
.lp-pill--ui-style { background: #1f3a93; color: #fff; }
.lp-pill--pattern  { background: #2e7d32; color: #fff; }
.lp-pill--icon     { background: #ad1457; color: #fff; }
.lp-pill--theme    { background: #6a1b9a; color: #fff; }
.lp-pill--voice    { background: #ef6c00; color: #fff; }
.lp-pill--spec-doc { background: #455a64; color: #fff; }
.lp-pill--app-layout { background: #00695c; color: #fff; }

/* ──────────────────────────────────────────────────────────────────────
   #149 — Visual polish batch (S1 + P5 + P6, 2026-05-11)
   S1: hide redundant FacetsRibbon on the root index (the page already
       lists facets in the grid below; the ribbon was added before the
       grid existed). Selector relies on :has — well supported in
       Chrome 105+/Firefox 121+/Safari 15.4+, which matches our browser
       baseline. Other landings (facet pages, etc.) still show ribbon.
   P5: subtle radial-gradient mesh behind the hero — adds warmth without
       glow noise. Opacity capped low so it reads as ambient, not
       decoration. Disabled by prefers-reduced-motion users? — not
       relevant (it's static; no animation).
   P6: facet cards as protagonists — bigger lift on hover, accent glow,
       and micro-animations on each inner preview (swatches shimmer,
       code caret blinks, table rows stagger in, method pulses, arch
       nodes pulse). All gated on :hover + prefers-reduced-motion
       respected so the page stays calm by default.
   ────────────────────────────────────────────────────────────────────── */

/* S1 ─ Hide secondary ribbon only on the index page. */
nav.facets-ribbon:has(+ main .lp-facets) {
  display: none;
}

/* P5 ─ Warmth gradient behind the hero. The .lp-hero block is the
   first child of <main> on the index page; place the mesh in a
   pseudo-element so we don't add markup and so it stacks below text.
   Mesh is confined to hero bounds (overflow: hidden) so we never
   trigger horizontal page scroll on narrow viewports. */
main.page > .lp-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
main.page > .lp-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(60% 80% at 12% 25%,
      color-mix(in srgb, var(--kdr-accent) 22%, transparent) 0%,
      transparent 70%),
    radial-gradient(55% 75% at 88% 15%,
      color-mix(in srgb, #c084fc 18%, transparent) 0%,
      transparent 70%),
    radial-gradient(50% 70% at 65% 90%,
      color-mix(in srgb, #34d399 14%, transparent) 0%,
      transparent 70%);
  filter: blur(50px);
  opacity: 0.9;
}
[data-theme="light"] main.page > .lp-hero::before {
  opacity: 0.55;
}

/* P6 ─ Facet cards as protagonists.
   Lift them: stronger hover transform, accent border, accent glow,
   and per-facet micro-animation on the inner sample. Animations only
   run while the card is hovered/focused, so the page is calm at rest
   and respects users with reduced-motion preferences. */

.lp-facet {
  /* slightly more breathing room — sample is the protagonist */
  min-height: 320px;
  transition:
    transform var(--kds-motion-duration-medium) var(--kds-motion-easing-emphasize),
    border-color var(--kds-motion-duration-medium) var(--kds-motion-easing-standard),
    box-shadow var(--kds-motion-duration-medium) var(--kds-motion-easing-standard);
}
.lp-facet:hover,
.lp-facet:focus-visible {
  transform: translateY(-6px);
  border-color: color-mix(in srgb, var(--kdr-accent) 75%, var(--kdr-border));
  box-shadow:
    0 16px 40px -12px color-mix(in srgb, var(--kdr-accent) 45%, transparent),
    0 0 0 1px color-mix(in srgb, var(--kdr-accent) 25%, transparent);
}
.lp-facet-sample {
  transition: transform var(--kds-motion-duration-medium) var(--kds-motion-easing-emphasize);
}
.lp-facet:hover .lp-facet-sample,
.lp-facet:focus-visible .lp-facet-sample {
  transform: scale(1.015);
}

/* Visual facet — swatches shimmer on hover (subtle scale + accent halo). */
@keyframes lp-swatch-shimmer {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}
.lp-facet--visual:hover .lp-swatch,
.lp-facet--visual:focus-visible .lp-swatch {
  animation: lp-swatch-shimmer 1.6s ease-in-out infinite;
}
.lp-facet--visual:hover .lp-swatch:nth-child(1),
.lp-facet--visual:focus-visible .lp-swatch:nth-child(1) { animation-delay: 0s; }
.lp-facet--visual:hover .lp-swatch:nth-child(2),
.lp-facet--visual:focus-visible .lp-swatch:nth-child(2) { animation-delay: 0.12s; }
.lp-facet--visual:hover .lp-swatch:nth-child(3),
.lp-facet--visual:focus-visible .lp-swatch:nth-child(3) { animation-delay: 0.24s; }
.lp-facet--visual:hover .lp-swatch:nth-child(4),
.lp-facet--visual:focus-visible .lp-swatch:nth-child(4) { animation-delay: 0.36s; }
.lp-facet--visual:hover .lp-swatch:nth-child(5),
.lp-facet--visual:focus-visible .lp-swatch:nth-child(5) { animation-delay: 0.48s; }

/* Code facet — caret blink at end of last line on hover. */
.lp-facet-sample--code pre {
  position: relative;
}
.lp-facet-sample--code pre::after {
  content: "▍";
  position: absolute;
  right: 32px;
  bottom: 14px;
  color: var(--kdr-accent);
  opacity: 0;
  transition: opacity 200ms ease;
}
@keyframes lp-caret-blink {
  0%, 49%   { opacity: 0.85; }
  50%, 100% { opacity: 0; }
}
.lp-facet--code:hover .lp-facet-sample--code pre::after,
.lp-facet--code:focus-visible .lp-facet-sample--code pre::after {
  animation: lp-caret-blink 1s steps(1, end) infinite;
}

/* Data facet — rows stagger into view on hover. */
@keyframes lp-row-in {
  from { opacity: 0; transform: translateX(-8px); }
  to   { opacity: 1; transform: translateX(0); }
}
.lp-facet--data:hover .lp-facet-sample--data tbody tr,
.lp-facet--data:focus-visible .lp-facet-sample--data tbody tr {
  animation: lp-row-in 320ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.lp-facet--data:hover .lp-facet-sample--data tbody tr:nth-child(1),
.lp-facet--data:focus-visible .lp-facet-sample--data tbody tr:nth-child(1) { animation-delay: 0s; }
.lp-facet--data:hover .lp-facet-sample--data tbody tr:nth-child(2),
.lp-facet--data:focus-visible .lp-facet-sample--data tbody tr:nth-child(2) { animation-delay: 0.08s; }
.lp-facet--data:hover .lp-facet-sample--data tbody tr:nth-child(3),
.lp-facet--data:focus-visible .lp-facet-sample--data tbody tr:nth-child(3) { animation-delay: 0.16s; }

/* Interface facet — pulse the method/status tokens on hover. */
@keyframes lp-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, #34d399 35%, transparent); }
  50%      { box-shadow: 0 0 0 6px color-mix(in srgb, #34d399 0%, transparent); }
}
.lp-facet--interface:hover .lp-tok-method,
.lp-facet--interface:focus-visible .lp-tok-method {
  animation: lp-pulse 1.6s ease-in-out infinite;
}

/* System facet — arch nodes pulse the connection edge. */
@keyframes lp-edge-flow {
  0%   { opacity: 0.35; transform: translateX(-2px); }
  50%  { opacity: 1; transform: translateX(2px); }
  100% { opacity: 0.35; transform: translateX(-2px); }
}
.lp-facet--system:hover .lp-arch-edge,
.lp-facet--system:focus-visible .lp-arch-edge {
  animation: lp-edge-flow 1.8s ease-in-out infinite;
  color: var(--kdr-accent);
}

/* prefers-reduced-motion: disable micro-animations but keep the lift +
   border + glow (those communicate state without motion). */
@media (prefers-reduced-motion: reduce) {
  .lp-facet--visual:hover .lp-swatch,
  .lp-facet--visual:focus-visible .lp-swatch,
  .lp-facet--code:hover .lp-facet-sample--code pre::after,
  .lp-facet--code:focus-visible .lp-facet-sample--code pre::after,
  .lp-facet--data:hover .lp-facet-sample--data tbody tr,
  .lp-facet--data:focus-visible .lp-facet-sample--data tbody tr,
  .lp-facet--interface:hover .lp-tok-method,
  .lp-facet--interface:focus-visible .lp-tok-method,
  .lp-facet--system:hover .lp-arch-edge,
  .lp-facet--system:focus-visible .lp-arch-edge {
    animation: none;
  }
  .lp-facet,
  .lp-facet-sample {
    transition: none;
  }
}

/* ── Components parity catalogue (render gap fix, 2026-05-11) ───
   New section in /components/ that lists the 24 Material-parity
   component specs as compact tiles linked to their /reference/
   spec-doc pages. Closes the spec → render visibility loop. */

.comp-section-lede {
  color: var(--kdr-text-muted);
  font-size: 14px;
  line-height: 1.55;
  margin: 0 0 16px;
  max-width: 720px;
}
.component-parity {
  margin-top: 40px;
  padding-top: 32px;
  border-top: 1px solid var(--kdr-border);
}
.component-parity-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.component-parity-item a {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 14px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  text-decoration: none;
  color: var(--kdr-text);
  transition: border-color 120ms ease, background 120ms ease;
}
.component-parity-item a:hover,
.component-parity-item a:focus-visible {
  border-color: color-mix(in srgb, var(--kdr-accent) 60%, var(--kdr-border));
  background: var(--kdr-surface-2);
  outline: none;
}
.component-parity-name {
  font-weight: 600;
  font-size: 14px;
  color: var(--kdr-text);
}
.component-parity-spec {
  font-family: var(--kds-font-mono);
  font-size: 11.5px;
  color: var(--kdr-text-muted);
  background: transparent;
  padding: 0;
}

/* ── Theme Builder (#049.55 — fourth KDS tool, 2026-05-11) ─────────
   Interactive seed → preview → export tool at /{locale}/themer/.
   Three-pane layout on wide viewports; stacked on mobile. */

.themer { max-width: none; }
.themer-header { margin-bottom: 24px; }
.themer-shell {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr) 300px;
  gap: 20px;
  margin: 24px 0;
  align-items: start;
}
@media (max-width: 1100px) { /* TODO RFC-002 #003 slice 3: between md(900) and lg(1280); needs visual review before align */
  .themer-shell {
    grid-template-columns: 1fr 1fr;
  }
  .themer-preview { grid-column: 1 / -1; order: -1; }
}
@media (max-width: 640px) {
  .themer-shell { grid-template-columns: 1fr; }
  .themer-preview { order: 0; }
}

.themer-pane-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--kdr-text-muted);
  margin: 0 0 14px;
}

.themer-inputs,
.themer-export-pane {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 18px;
  /* Allow these grid items to shrink below their content's intrinsic
     min-content at narrow viewports. Otherwise the 280px-side panes
     in `.themer-shell grid-template-columns: 1fr` (≤640) would inherit
     a min-content from their longest token (chip code/CSS snippet) and
     overflow by 7px @ 320. #003 slice 6. */
  min-width: 0;
}
.themer-field { margin-bottom: 14px; }
.themer-field-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 6px;
  color: var(--kdr-text);
}
.themer-seed-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
}
.themer-seed-row input[type="color"] {
  width: 48px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  cursor: pointer;
  background: transparent;
  flex-shrink: 0;
}
/* Fix 2026-05-13 (owner): native color-swatch wrapper tem padding
   default que faz o swatch interno parecer pequeno/desalinhado em
   relação ao input de texto ao lado. Remover padding + arredondar
   o swatch pra coerência visual. */
.themer-seed-row input[type="color"]::-webkit-color-swatch-wrapper {
  padding: 0;
}
.themer-seed-row input[type="color"]::-webkit-color-swatch {
  border: none;
  border-radius: calc(var(--kdr-radius-sm) - 1px);
}
.themer-seed-row input[type="color"]::-moz-color-swatch {
  border: none;
  border-radius: calc(var(--kdr-radius-sm) - 1px);
}
.themer-seed-row input[type="text"] {
  flex: 1;
  min-width: 0;
  height: 40px;
  font-family: var(--kds-font-mono);
  font-size: 14px;
  padding: 0 12px;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  background: var(--kdr-bg);
  color: var(--kdr-text);
}
.themer-mode-row {
  display: inline-flex;
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  padding: 2px;
  gap: 2px;
  width: 100%;
}
.themer-mode-row button {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  border: 0;
  background: transparent;
  padding: 7px 12px;
  font-size: 13px;
  font-weight: 500;
  color: var(--kdr-text);
  cursor: pointer;
  border-radius: calc(var(--kdr-radius-sm) - 2px);
}
.themer-mode-row button[aria-pressed="true"] {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  font-weight: 600;
}
.themer-reset {
  width: 100%;
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid var(--kdr-border);
  background: transparent;
  color: var(--kdr-text);
  padding: 8px 12px;
  border-radius: var(--kdr-radius-sm);
  font-size: 13px;
  cursor: pointer;
  margin-top: 6px;
}
.themer-reset:hover { background: var(--kdr-surface-2); }
.themer-deferred-note {
  margin-top: 14px;
  font-size: 12px;
  color: var(--kdr-text-muted);
  line-height: 1.45;
  padding-top: 12px;
  border-top: 1px dashed var(--kdr-border);
}

/* ── Preview pane — uses the CSS vars set by the JS ───────── */
.themer-preview {
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
  border: 1px solid var(--kdr-border);
  /* Grid item — let it shrink below intrinsic min-content. #003 slice 6. */
  min-width: 0;
  /* These vars get overridden by the JS on input change. */
  background: var(--kdr-bg);
  color: var(--kdr-text);
  display: flex;
  flex-direction: column;
}
.themer-preview-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  background: var(--kdr-surface);
  border-bottom: 1px solid var(--kdr-border);
}
.themer-preview-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--kdr-border);
}
.themer-preview-title {
  margin-left: 8px;
  font-size: 12px;
  color: var(--kdr-text-muted);
  font-family: var(--kds-font-mono);
}
.themer-preview-body {
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.themer-preview-card {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 18px 20px;
}
.themer-preview-card--filled {
  background: var(--kdr-surface-2);
}
.themer-preview-card h3,
.themer-preview-card h4 { margin: 0 0 6px; color: var(--kdr-text); }
.themer-preview-card p { margin: 0 0 14px; color: var(--kdr-text-muted); font-size: 14px; line-height: 1.5; }
.themer-preview-card-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.themer-btn {
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid transparent;
  padding: 8px 16px;
  border-radius: var(--kdr-radius-sm);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.themer-btn--filled {
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
}
.themer-btn--outlined {
  background: transparent;
  border-color: var(--kdr-accent);
  color: var(--kdr-accent);
}

.themer-preview-typescale {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px 20px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
}
.themer-preview-display { margin: 0; font-size: 32px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; color: var(--kdr-text); }
.themer-preview-headline { margin: 0; font-size: 22px; font-weight: 600; color: var(--kdr-text); }
.themer-preview-body-text { margin: 0; font-size: 15px; line-height: 1.5; color: var(--kdr-text); }
.themer-preview-caption { margin: 0; font-size: 12px; color: var(--kdr-text-muted); }

/* ── Export pane ──────────────────────────────────────────── */
.themer-export-lede {
  font-size: 13px;
  color: var(--kdr-text-muted);
  margin: 0 0 12px;
  line-height: 1.5;
}
.themer-export-format-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--kdr-text-muted);
  margin-bottom: 4px;
}
.themer-export-format {
  width: 100%;
  margin-bottom: 10px;
  padding: 8px 12px;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  font-size: 13px;
}
.themer-export-text {
  width: 100%;
  min-height: 220px;
  font-family: var(--kds-font-mono);
  font-size: 12px;
  line-height: 1.5;
  padding: 10px 12px;
  background: var(--kdr-bg);
  color: var(--kdr-text);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  resize: vertical;
}
.themer-copy {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  margin-top: 10px;
  padding: 8px 14px;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border: 0;
  border-radius: var(--kdr-radius-sm);
  font-weight: 600;
  font-size: 13.5px;
  cursor: pointer;
  position: relative;
}
.themer-copy:hover { filter: brightness(1.06); }
.themer-copy .themer-copy-active { display: none; }
.themer-copy[data-state="copied"] .themer-copy-default { display: none; }
.themer-copy[data-state="copied"] .themer-copy-active { display: inline; }

.themer-help {
  margin-top: 32px;
  padding: 16px 20px;
  background: var(--kdr-surface);
  border-left: 3px solid var(--kdr-accent);
  border-radius: 0 var(--kdr-radius-md) var(--kdr-radius-md) 0;
}
.themer-help h2 { font-size: 15px; margin: 0 0 6px; }
.themer-help p { font-size: 13.5px; line-height: 1.5; margin: 0 0 8px; color: var(--kdr-text-muted); }
.themer-help a { color: var(--kdr-accent); text-decoration: none; }
.themer-help a:hover { text-decoration: underline; }

/* ── Migrate from Material (#049.58 — third KDS tool, 2026-05-11) ───
   Hand-curated single page at /{locale}/migrate/material/m3/. Reuses
   existing typography + tokens; adds responsive tables and stepwise-
   upgrade list styling. */

.migrate-material { max-width: 920px; }
.migrate-material h2 {
  margin-top: 40px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.migrate-material > section > p { line-height: 1.6; }
.migrate-why,
.migrate-gaps {
  list-style: disc;
  padding-left: 22px;
  line-height: 1.6;
}
.migrate-why li,
.migrate-gaps li { margin-bottom: 8px; }

.migrate-table-wrap {
  overflow-x: auto;
  margin: 12px 0;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
}
.migrate-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.migrate-table thead th {
  background: var(--kdr-surface-2);
  padding: 10px 14px;
  text-align: left;
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--kdr-text);
  border-bottom: 1px solid var(--kdr-border);
}
.migrate-table tbody td {
  padding: 9px 14px;
  border-bottom: 1px solid var(--kdr-border);
  vertical-align: top;
  line-height: 1.5;
}
.migrate-table tbody tr:last-child td { border-bottom: 0; }
.migrate-table code {
  font-family: var(--kds-font-mono);
  font-size: 12.5px;
  background: var(--kdr-surface);
  padding: 1px 6px;
  border-radius: 4px;
}
.migrate-table a {
  color: var(--kdr-accent);
  text-decoration: none;
}
.migrate-table a:hover { text-decoration: underline; }

.migrate-breaking,
.migrate-steps {
  counter-reset: step;
  list-style: none;
  padding: 0;
  margin: 16px 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.migrate-breaking li,
.migrate-steps li {
  position: relative;
  padding: 14px 18px 14px 56px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  line-height: 1.5;
}
.migrate-breaking li::before,
.migrate-steps li::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  left: 16px;
  top: 14px;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  border-radius: 50%;
  font-family: var(--kds-font-mono);
  font-size: 13px;
  font-weight: 700;
}
.migrate-breaking li strong,
.migrate-steps li strong {
  display: inline;
  margin-right: 4px;
}
.migrate-steps li p { margin: 4px 0 0; }

.migrate-gaps-note {
  margin-top: 12px;
  padding: 10px 14px;
  background: var(--kdr-surface);
  border-left: 3px solid var(--kdr-accent);
  border-radius: 0 var(--kdr-radius-sm) var(--kdr-radius-sm) 0;
  font-size: 14px;
  color: var(--kdr-text-muted);
}
.migrate-gaps-note a { color: var(--kdr-accent); text-decoration: none; }
.migrate-gaps-note a:hover { text-decoration: underline; }

/* ── Blog / changelog index (#049.59 — second KDS tool, 2026-05-11) ───
   Page lives at /{locale}/blog/. Vertical stack of release cards,
   newest-first. Source: meta/docs/stack/releases/releases.toml. */

.blog-index { max-width: 760px; }

.blog-cards {
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.blog-card {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-lg);
  padding: 22px 24px 18px;
  position: relative;
  overflow: hidden;
}
.blog-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 3px;
  background: var(--kdr-accent);
  border-radius: var(--kdr-radius-lg) 0 0 var(--kdr-radius-lg);
}

.blog-card-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 16px;
  margin-bottom: 8px;
}
.blog-card-meta {
  display: inline-flex;
  align-items: baseline;
  gap: 12px;
}
.blog-card-version {
  font-family: var(--kds-font-mono);
  font-size: 14px;
  font-weight: 700;
  color: var(--kdr-accent);
  letter-spacing: 0.01em;
}
.blog-card-date {
  font-family: var(--kds-font-mono);
  font-size: 12.5px;
  color: var(--kdr-text-muted);
}
.blog-card-tags {
  list-style: none;
  margin: 0;
  padding: 0;
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-left: auto;
}
.blog-card-tags li {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--kdr-surface-2);
  color: var(--kdr-text-muted);
  letter-spacing: 0.02em;
}

.blog-card-title {
  font-size: 20px;
  font-weight: 700;
  margin: 0 0 8px;
  letter-spacing: -0.01em;
  color: var(--kdr-text);
}
.blog-card-summary {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--kdr-text-muted);
  margin: 0 0 14px;
}

.blog-card-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 20px;
  margin: 0 0 14px;
  padding: 10px 14px;
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
}
.blog-card-stats > div {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
}
.blog-card-stats dt {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--kdr-text-muted);
  font-weight: 600;
  margin: 0;
}
.blog-card-stats dd {
  font-family: var(--kds-font-mono);
  font-size: 13.5px;
  font-weight: 700;
  color: var(--kdr-text);
  margin: 0;
}

.blog-card-foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 10px;
  font-size: 12px;
  color: var(--kdr-text-muted);
  border-top: 1px solid var(--kdr-border);
  padding-top: 10px;
}
.blog-card-foot-label {
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 11px;
}
.blog-card-commits {
  list-style: none;
  margin: 0;
  padding: 0;
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
}
.blog-card-commits li code {
  font-family: var(--kds-font-mono);
  font-size: 11.5px;
  background: var(--kdr-surface-2);
  padding: 1px 6px;
  border-radius: 4px;
  color: var(--kdr-text);
}

.blog-empty {
  margin: 24px 0;
  padding: 24px;
  background: var(--kdr-surface);
  border: 1px dashed var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  color: var(--kdr-text-muted);
  text-align: center;
}

/* ── Tools / contrast checker (#049.57 — first KDS tool, 2026-05-11) ───
   Page lives at /{locale}/tools/contrast/. Pure client-side WCAG 2.2
   ratio checker; the inline JS in toolsContrastScript wires the form.
   Styles target the markup emitted by ToolsContrastPage. */

.tools-contrast { max-width: 800px; }

.tools-contrast-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin: 24px 0;
}
.tools-contrast-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
@media (max-width: 640px) {
  .tools-contrast-row { grid-template-columns: 1fr; }
}
.tools-contrast-input {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.tools-contrast-input-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--kdr-text-muted);
}
.tools-contrast-input-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
}
.tools-contrast-input-row input[type="color"] {
  width: 48px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  background: transparent;
  cursor: pointer;
  flex-shrink: 0;
}
.tools-contrast-input-row input[type="text"] {
  flex: 1;
  font-family: var(--kds-font-mono);
  font-size: 14px;
  padding: 8px 12px;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  background: var(--kdr-bg);
  color: var(--kdr-text);
}
.tools-contrast-input-row input[type="text"]:focus-visible {
  outline: 2px solid var(--kdr-focus);
  outline-offset: 1px;
}
.tools-contrast-swap-row { display: flex; justify-content: flex-end; }
.tools-contrast-swap {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-sm);
  background: var(--kdr-surface);
  color: var(--kdr-text);
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  -webkit-appearance: none;
  appearance: none;
}
.tools-contrast-swap:hover { background: var(--kdr-surface-2); }

.tools-contrast-output {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 20px;
  margin: 24px 0;
}
@media (max-width: 639px) { /* #003 slice 4 (2026-05-14): aligned to canonical sm (640px); was 720px */
  .tools-contrast-output { grid-template-columns: 1fr; }
}
.tools-contrast-sample {
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* JS will paint background-color + color; defaults provide a calm
     starting frame before init() runs. */
  background: #fff;
  color: #1976d2;
  min-height: 160px;
  transition: background-color 120ms ease, color 120ms ease;
}
.tools-contrast-sample-large { font-size: 22px; font-weight: 700; margin: 0; line-height: 1.3; }
.tools-contrast-sample-normal { font-size: 15px; margin: 0; line-height: 1.5; }

.tools-contrast-summary {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.tools-contrast-ratio {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 2px;
  padding: 14px 18px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
}
.tools-contrast-ratio-label {
  font-size: 12px;
  color: var(--kdr-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.tools-contrast-ratio-value {
  font-family: var(--kds-font-mono);
  font-size: 28px;
  font-weight: 700;
  color: var(--kdr-text);
  letter-spacing: -0.01em;
}
.tools-contrast-ratio-value[data-state="aaa"] { color: #2e7d32; }
.tools-contrast-ratio-value[data-state="aa"]  { color: #1f6feb; }
.tools-contrast-ratio-value[data-state="aa-large"] { color: #ef6c00; }
.tools-contrast-ratio-value[data-state="fail"] { color: #c62828; }
[data-theme="dark"] .tools-contrast-ratio-value[data-state="aaa"] { color: #66bb6a; }
[data-theme="dark"] .tools-contrast-ratio-value[data-state="aa"]  { color: #82b1ff; }
[data-theme="dark"] .tools-contrast-ratio-value[data-state="aa-large"] { color: #ffb74d; }
[data-theme="dark"] .tools-contrast-ratio-value[data-state="fail"] { color: #ef5350; }

.tools-contrast-checks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tools-contrast-checks li {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 8px 12px;
  border-radius: var(--kdr-radius-sm);
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  font-size: 13.5px;
}
.tools-contrast-check-icon {
  font-family: var(--kds-font-mono);
  font-size: 16px;
  font-weight: 700;
  text-align: center;
  color: var(--kdr-text-muted);
}
.tools-contrast-checks li[data-pass="true"] .tools-contrast-check-icon { color: #2e7d32; }
.tools-contrast-checks li[data-pass="false"] .tools-contrast-check-icon { color: #c62828; }
[data-theme="dark"] .tools-contrast-checks li[data-pass="true"] .tools-contrast-check-icon { color: #66bb6a; }
[data-theme="dark"] .tools-contrast-checks li[data-pass="false"] .tools-contrast-check-icon { color: #ef5350; }
.tools-contrast-check-label { color: var(--kdr-text); }
.tools-contrast-check-threshold {
  font-family: var(--kds-font-mono);
  font-size: 12px;
  color: var(--kdr-text-muted);
}

.tools-contrast-help {
  margin-top: 32px;
  padding: 18px 22px;
  background: var(--kdr-surface);
  border-left: 3px solid var(--kdr-accent);
  border-radius: 0 var(--kdr-radius-md) var(--kdr-radius-md) 0;
}
.tools-contrast-help h2 {
  font-size: 16px;
  margin: 0 0 8px;
  font-weight: 600;
}
.tools-contrast-help p {
  font-size: 14px;
  line-height: 1.5;
  color: var(--kdr-text-muted);
  margin: 0 0 8px;
}
.tools-contrast-help a {
  color: var(--kdr-accent);
  text-decoration: none;
}
.tools-contrast-help a:hover { text-decoration: underline; }

/* ── Mobile responsive — Sprint #131 (2026-05-11) ────────────
   The grid components above already use auto-fill+minmax which
   collapses gracefully on narrow screens. What needs explicit
   mobile rules: the topnav (flex of brand + primary links +
   controls), the facets ribbon, hero typography, page padding,
   breadcrumb wrapping, and the settings rail. Two breakpoints:
   tablet (≤ 768 px) and phone (≤ 480 px). */

@media (max-width: 639px) { /* #003 slice 4 (2026-05-14): aligned to canonical sm (640px); was 768px */
  /* Topbar tightens padding on tablet. The primary nav now lives in
     the lateral sidebar (S8) so there's no wrap-onto-second-line
     pattern any more. */
  .topbar {
    padding: 0 12px;
    gap: 8px;
  }
  .topbar .controls {
    gap: 8px;
  }

  /* Page shell: smaller side padding, slightly less top space. */
  main.page {
    padding: 20px 16px 48px;
  }

  /* Breadcrumb wraps instead of overflowing. */
  .breadcrumb {
    flex-wrap: wrap;
    row-gap: 4px;
  }

  /* Hero: clamp scales naturally, but tighten meta line. */
  .hero h1 { line-height: 1.15; }
  .hero .lede { font-size: 16px; }

  /* Icon detail: master stage smaller. */
  .icon-master-stage { padding: 16px; min-height: 200px; }

  /* Settings rail: full width on tablet too (already 540 in the
     existing block; ensure padding adjusts). */
  .koder-settings-panel { padding: 16px; }
}

@media (max-width: 480px) {
  /* Phone: shrink the brand mark; the wordmark stays — the topbar
     is much sparser now (S8) so there's room. */
  .topbar { padding: 0 10px; gap: 8px; }
  .topbar .brand { font-size: 14px; gap: 8px; }
  .topbar .brand-mark { width: 24px; height: 24px; }
  .topbar select { padding: 4px 6px; font-size: 13px; }

  main.page { padding: 16px 12px 40px; }

  .hero h1 { font-size: 26px; }
  .hero .lede { font-size: 15px; }

  /* Cards/tiles drop side margins for edge-to-edge feel. */
  .preset-card,
  .icon-tile { border-radius: var(--kdr-radius-sm); }

  /* Code blocks: avoid horizontal cropping by allowing scroll. */
  main.page pre {
    margin-left: -12px;
    margin-right: -12px;
    border-radius: 0;
    padding: 12px;
  }

  /* Tables: scroll horizontally instead of clipping. */
  .icon-matrix { overflow-x: auto; }

  /* Settings rail: take full viewport. */
  .koder-settings-rail { grid-template-columns: 0 100vw; }
}

/* <koder-embed> — Flutter Web embed wrapper (backlog ticket #001 task 3).
 * The element wraps the existing HTML mock as a child; CSS controls which
 * of mock-children / iframe is visible based on data-koder-embed-state.
 *
 * States (see assets/js/embed.js):
 *   - "mock"     — initial. Mock children visible. Iframe absent.
 *   - "loading"  — bundle HEAD probe in flight. Mock children visible
 *                  (acts as skeleton).
 *   - "ready"    — iframe loaded and painted. Mock children hidden,
 *                  iframe takes over the box.
 *   - "fallback" — bundle missing or load failed. Mock children stay.
 *
 * Mock children get a transition to keep the cross-fade subtle when the
 * iframe takes over (no flash of empty space).
 */
koder-embed {
  display: block;
  position: relative;
  /* Carry the same surface tokens as the surrounding demo containers so
   * the embed feels native even before the iframe paints. */
  min-height: 200px;
}
koder-embed[data-koder-embed-state="ready"] > :not(iframe) {
  display: none;
}
koder-embed > iframe {
  display: block;
  width: 100%;
  min-height: 200px;
  border: 0;
  background: transparent;
}

/* ── Verge token map (2026-05-14) ────────────────────────────────
   /<locale>/verge/ — owner reference surface for divergence requests.
   Each token row: name (mono), light value + sample, dark value +
   sample, use caption. Categories: color / shape / space / shadow /
   font. */

.verge-token-table {
  width: 100%;
  border-collapse: collapse;
  margin: 16px 0 28px;
  font-size: 14px;
}
.verge-token-table th,
.verge-token-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--kdr-border);
  vertical-align: top;
}
.verge-token-table thead th {
  background: var(--kdr-surface-2);
  color: var(--kdr-text-muted);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  border-bottom-width: 2px;
}
.verge-token-table tbody tr:hover { background: var(--kdr-surface-2); }

.verge-token-name {
  font-family: var(--kds-font-mono, 'JetBrains Mono', monospace);
  font-size: 13px;
  background: transparent;
  padding: 0;
  color: var(--kdr-text);
}
.verge-token-value {
  font-family: var(--kds-font-mono, 'JetBrains Mono', monospace);
  font-size: 12px;
  background: transparent;
  padding: 0;
  color: var(--kdr-text-muted);
  display: inline-block;
  vertical-align: middle;
  margin-left: 8px;
}
.verge-token-inherit {
  font-style: italic;
  color: var(--kdr-text-muted);
  font-size: 12px;
}
.verge-token-use {
  color: var(--kdr-text-muted);
  font-size: 13px;
  line-height: 1.5;
  max-width: 36em;
}

.verge-swatch {
  display: inline-block;
  width: 24px;
  height: 24px;
  vertical-align: middle;
  border-radius: 4px;
  border: 1px solid var(--kdr-border);
  flex-shrink: 0;
}
.verge-swatch--color { border-radius: 4px; }
.verge-swatch--radius {
  background: var(--kdr-accent);
  border: none;
  width: 28px;
  height: 28px;
}
.verge-swatch--pad {
  background: transparent;
  border: 1px dashed var(--kdr-border);
  width: 32px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.verge-swatch--pad > span {
  display: block;
  width: 100%;
  height: 8px;
  background: var(--kdr-accent);
  opacity: 0.4;
}
.verge-swatch--border {
  background: var(--kdr-surface);
  width: 32px;
  height: 18px;
}
.verge-swatch--shadow {
  background: var(--kdr-surface);
  width: 28px;
  height: 18px;
  border: none;
  margin: 4px;
}
.verge-swatch--font {
  width: 28px;
  height: 28px;
  background: transparent;
  border: 1px solid var(--kdr-border);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  color: var(--kdr-text);
  border-radius: 4px;
}

.verge-divergence-flow {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 8px;
  padding: 16px 24px 16px 40px;
  margin: 16px 0 32px;
}
.verge-divergence-flow li {
  margin: 8px 0;
  line-height: 1.55;
  color: var(--kdr-text);
}

@media (max-width: 640px) {
  .verge-token-table thead { display: none; }
  .verge-token-table tr {
    display: block;
    padding: 12px 0;
    border-bottom: 1px solid var(--kdr-border);
  }
  .verge-token-table td {
    display: block;
    border: none;
    padding: 2px 0;
  }
  .verge-token-table td:first-child { font-weight: 600; }
}

/* ── Get Started page (#013, 2026-05-14) ───────────────────────
   /<locale>/get-started/ landing: hero + 6 surface cards grid +
   decision tree dl + behaviors cross-link. CSS deferred from the
   original ticket; this block ships the polished look. */

.get-started-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 20px;
  margin: 16px 0 32px;
}

.get-started-card {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 10px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.get-started-card:hover { border-color: var(--kdr-accent); }

.get-started-card-head {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.get-started-card-title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  color: var(--kdr-text);
}
.get-started-card-stack {
  margin: 0;
  font-size: 12px;
  color: var(--kdr-text-muted);
  font-family: var(--kds-font-mono, 'JetBrains Mono', monospace);
}

.get-started-card-snippet {
  margin: 0;
  background: var(--kdr-surface-2);
  border: 1px solid var(--kdr-border);
  border-radius: 6px;
  padding: 12px 14px;
  overflow-x: auto;
  font-family: var(--kds-font-mono, 'JetBrains Mono', monospace);
  font-size: 12px;
  line-height: 1.55;
  color: var(--kdr-text);
}
.get-started-card-snippet code {
  display: block;
  white-space: pre;
  background: transparent;
  padding: 0;
  font: inherit;
  color: inherit;
}

.get-started-card-foot {
  margin-top: auto;
  display: flex;
  justify-content: flex-end;
}
.get-started-card-cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--kdr-accent);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
}
.get-started-card-cta:hover { text-decoration: underline; }

.get-started-decision {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 10px;
  padding: 20px 24px;
  margin: 16px 0 32px;
  display: grid;
  grid-template-columns: minmax(220px, max-content) 1fr;
  gap: 12px 24px;
}
.get-started-decision dt {
  font-weight: 600;
  color: var(--kdr-text);
  padding-top: 2px;
}
.get-started-decision dd {
  margin: 0;
  color: var(--kdr-text-muted);
  line-height: 1.55;
}
.get-started-decision dd a {
  color: var(--kdr-accent);
  text-decoration: none;
  margin-right: 4px;
}
.get-started-decision dd a:hover { text-decoration: underline; }

@media (max-width: 640px) {
  .get-started-decision { grid-template-columns: 1fr; gap: 4px 0; }
  .get-started-decision dt { padding-top: 12px; }
  .get-started-decision dt:first-of-type { padding-top: 0; }
}

.get-started-behaviors-list {
  list-style: none;
  padding: 0;
  margin: 16px 0 32px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px;
}
.get-started-behaviors-list li { margin: 0; }
.get-started-behaviors-list li a {
  display: block;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 8px;
  padding: 14px 16px;
  color: var(--kdr-text);
  text-decoration: none;
  transition: border-color 150ms ease;
}
.get-started-behaviors-list li a:hover { border-color: var(--kdr-accent); }
.get-started-behaviors-list li a strong {
  color: var(--kdr-accent);
  margin-right: 8px;
  font-weight: 600;
}

/* ── Motion gallery (#009 CSS-only slice, 2026-05-14) ────────────
   Live previews for /motion/ — easing curves (SVG path + animated
   ball), duration tokens (timeline bar), transition patterns (fade /
   scale / slide / cross-fade), and the reduced-motion comparison.
   Tokens are mirrored from specs/themes/motion/easing-duration.kmd
   so the visual matches the contract (no hardcoded values that drift).

   Global @media (prefers-reduced-motion: reduce) collapse already
   lives in this file (animations forced to 0ms). The reduced-motion
   pane below uses an opt-in 600ms loop on `.motion-reduced-ball--anim`
   that the global rule explicitly silences — exactly what the spec
   asks for. ───────────────────────────────────────────────────── */

.motion-easing-grid,
.motion-duration-grid,
.motion-transitions-grid,
.motion-reduced-grid {
  display: grid;
  gap: 20px;
  margin: 16px 0 24px;
}
.motion-easing-grid { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.motion-duration-grid { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.motion-transitions-grid { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.motion-reduced-grid { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

.motion-easing-card,
.motion-duration-card,
.motion-transition-card,
.motion-reduced-pane {
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 8px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.motion-easing-head,
.motion-duration-head,
.motion-transition-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}
.motion-easing-head .motion-token,
.motion-duration-head .motion-token { font-size: 13px; }
.motion-easing-bezier,
.motion-duration-ms,
.motion-transition-tokens {
  font-family: var(--kds-font-mono, 'JetBrains Mono', monospace);
  font-size: 12px;
  color: var(--kdr-text-muted);
}

.motion-easing-svg {
  width: 100%;
  height: auto;
  max-width: 200px;
  align-self: center;
}

.motion-easing-demo {
  display: block;
  width: 100%;
  height: 48px;
  background: var(--kdr-surface-2);
  border: 1px solid var(--kdr-border);
  border-radius: 6px;
  padding: 0;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.motion-easing-ball {
  display: block;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--kdr-accent);
  position: absolute;
  top: 50%;
  left: 8px;
  transform: translate(0, -50%);
}
.motion-easing-demo.is-playing .motion-easing-ball {
  animation: motion-easing-slide var(--motion-duration, 800ms) var(--motion-easing, ease) forwards;
}
@keyframes motion-easing-slide {
  from { transform: translate(0, -50%); }
  to   { transform: translate(calc(100% - 36px), -50%); }
}

.motion-duration-range { color: var(--kdr-text-muted); font-size: 13px; margin: 0; }
.motion-duration-timeline {
  background: var(--kdr-surface-2);
  border-radius: 4px;
  height: 12px;
  overflow: hidden;
  position: relative;
}
.motion-duration-demo {
  display: block;
  width: 100%;
  height: 100%;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.motion-duration-bar {
  display: block;
  height: 100%;
  width: 0;
  background: var(--kdr-accent);
  border-radius: 4px;
}
.motion-duration-demo.is-playing .motion-duration-bar {
  animation: motion-duration-fill var(--motion-duration, 250ms) linear forwards;
}
@keyframes motion-duration-fill {
  from { width: 0; }
  to   { width: 100%; }
}

.motion-transition-stage {
  background: var(--kdr-surface-2);
  border-radius: 6px;
  height: 120px;
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
}
.motion-transition-demo {
  display: grid;
  place-items: center;
  width: 70%;
  height: 70%;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 6px;
  cursor: pointer;
  padding: 0;
  position: relative;
}
.motion-transition-card-title {
  font-size: 13px;
  color: var(--kdr-text);
  font-weight: 500;
}
.motion-transition-demo--fade.is-playing { animation: motion-trans-fade 800ms cubic-bezier(0.2, 0, 0, 1) forwards; }
@keyframes motion-trans-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.motion-transition-demo--scale.is-playing { animation: motion-trans-scale 800ms cubic-bezier(0, 0, 0, 1) forwards; }
@keyframes motion-trans-scale {
  from { transform: scale(0.5); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
.motion-transition-demo--slide.is-playing { animation: motion-trans-slide 800ms cubic-bezier(0, 0, 0, 1) forwards; }
@keyframes motion-trans-slide {
  from { transform: translateX(-120%); }
  to   { transform: translateX(0); }
}
.motion-transition-demo--cross-fade {
  background: linear-gradient(90deg, var(--kdr-surface) 50%, var(--kdr-accent) 50%);
  background-size: 200% 100%;
}
.motion-transition-demo--cross-fade.is-playing {
  animation: motion-trans-crossfade 800ms cubic-bezier(0.2, 0, 0, 1) forwards;
}
@keyframes motion-trans-crossfade {
  from { background-position: 0% 0; }
  to   { background-position: 100% 0; }
}

/* Ticket #036 — Material parity transitions (CSS-only previews).
   Stateful gestures still tracked separately for the Flutter embed
   pipeline; these forward-only demos match the existing 4 above. */

/* Container transform: a small card grows into a full panel — the
   signature M3 "card → detail page" choreography. We simulate it by
   scaling a child element from a corner toward fill while fading. */
.motion-transition-demo--container-transform { position: relative; overflow: hidden; }
.motion-transition-demo--container-transform::after {
  content: "";
  position: absolute;
  inset: 60% 60% 8px 8px;
  background: var(--kdr-accent);
  border-radius: 4px;
  opacity: 0.85;
}
.motion-transition-demo--container-transform.is-playing::after {
  animation: motion-trans-container-transform 800ms cubic-bezier(0.2, 0, 0, 1) forwards;
}
@keyframes motion-trans-container-transform {
  from { inset: 60% 60% 8px 8px; opacity: 0.85; border-radius: 4px; }
  to   { inset: 8px 8px 8px 8px;  opacity: 1;    border-radius: 8px; }
}

/* Shared axis: stepwise nav (onboarding/wizard) — content slides
   horizontally while fading in. Two overlapping panes evoke the
   "outgoing fades + slides out, incoming fades + slides in" motion
   without requiring stateful demos. */
.motion-transition-demo--shared-axis { position: relative; overflow: hidden; }
.motion-transition-demo--shared-axis::before,
.motion-transition-demo--shared-axis::after {
  content: "";
  position: absolute;
  inset: 12px;
  border-radius: 4px;
}
.motion-transition-demo--shared-axis::before { background: var(--kdr-surface-2); }
.motion-transition-demo--shared-axis::after  { background: var(--kdr-accent); opacity: 0; }
.motion-transition-demo--shared-axis.is-playing::before {
  animation: motion-trans-shared-axis-out 600ms cubic-bezier(0.2, 0, 0, 1) forwards;
}
.motion-transition-demo--shared-axis.is-playing::after {
  animation: motion-trans-shared-axis-in 600ms 100ms cubic-bezier(0.2, 0, 0, 1) forwards;
}
@keyframes motion-trans-shared-axis-out {
  from { transform: translateX(0);    opacity: 1; }
  to   { transform: translateX(-30%); opacity: 0; }
}
@keyframes motion-trans-shared-axis-in {
  from { transform: translateX(30%); opacity: 0; }
  to   { transform: translateX(0);   opacity: 1; }
}

/* Push/Pop: stack-based mobile nav. The outgoing pane slides left
   while the incoming pane slides in from the right, layered on top —
   the back gesture animation as you'd see in iOS/Android stack nav. */
.motion-transition-demo--push-pop { position: relative; overflow: hidden; }
.motion-transition-demo--push-pop::before,
.motion-transition-demo--push-pop::after {
  content: "";
  position: absolute;
  inset: 8px;
  border-radius: 4px;
}
.motion-transition-demo--push-pop::before { background: var(--kdr-surface-2); }
.motion-transition-demo--push-pop::after  {
  background: var(--kdr-accent);
  transform: translateX(105%);
  box-shadow: -4px 0 12px rgba(0, 0, 0, 0.18);
}
.motion-transition-demo--push-pop.is-playing::before {
  animation: motion-trans-push-pop-out 600ms cubic-bezier(0, 0, 0, 1) forwards;
}
.motion-transition-demo--push-pop.is-playing::after {
  animation: motion-trans-push-pop-in 600ms cubic-bezier(0, 0, 0, 1) forwards;
}
@keyframes motion-trans-push-pop-out {
  from { transform: translateX(0);    filter: brightness(1); }
  to   { transform: translateX(-25%); filter: brightness(0.85); }
}
@keyframes motion-trans-push-pop-in {
  from { transform: translateX(105%); }
  to   { transform: translateX(0); }
}

/* Ticket #038 — Interaction state demos. Same grid layout as
   transitions; each demo box auto-plays a one-shot animation that
   visualizes the state's color/elevation/scale change. Driven by
   .is-playing toggled by motionReplayScript. */
.motion-states-grid,
.motion-spring-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
  margin: 16px 0 24px;
}
.motion-state-card,
.motion-spring-card {
  display: flex;
  flex-direction: column;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px;
}
.motion-state-head,
.motion-spring-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}
.motion-state-head h3,
.motion-spring-head h3 { margin: 0; font-size: 14px; }
.motion-state-tokens,
.motion-spring-tokens {
  font-family: var(--kds-font-mono);
  font-size: 11px;
  color: var(--kdr-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 60%;
}
.motion-state-stage,
.motion-spring-stage {
  background: var(--kdr-surface-2);
  border-radius: 6px;
  height: 110px;
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
}
.motion-state-demo {
  appearance: none;
  border: 0;
  cursor: pointer;
  width: 88px;
  height: 56px;
  border-radius: 6px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  position: relative;
}
.motion-state-demo:focus-visible { outline: 2px solid var(--kdr-focus); outline-offset: 2px; }
.motion-state-use,
.motion-spring-use {
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--kdr-text-muted);
}

.motion-state-demo--hover.is-playing {
  animation: motion-state-hover 1200ms cubic-bezier(0.2, 0, 0, 1) forwards;
}
@keyframes motion-state-hover {
  0%   { background: var(--kdr-surface); box-shadow: none; }
  50%  { background: color-mix(in srgb, var(--kdr-accent) 18%, var(--kdr-surface)); box-shadow: 0 1px 3px rgba(0,0,0,0.18); }
  100% { background: color-mix(in srgb, var(--kdr-accent) 18%, var(--kdr-surface)); box-shadow: 0 1px 3px rgba(0,0,0,0.18); }
}

.motion-state-demo--focus.is-playing {
  animation: motion-state-focus 800ms ease-out forwards;
}
@keyframes motion-state-focus {
  0%   { box-shadow: 0 0 0 0 var(--kdr-focus); }
  20%  { box-shadow: 0 0 0 3px var(--kdr-focus); }
  100% { box-shadow: 0 0 0 3px var(--kdr-focus); }
}

.motion-state-demo--press.is-playing {
  animation: motion-state-press 800ms cubic-bezier(0.2, 0, 0, 1) forwards;
}
@keyframes motion-state-press {
  0%   { transform: scale(1); }
  20%  { transform: scale(0.97); }
  100% { transform: scale(1); }
}

.motion-state-demo--drag.is-playing {
  animation: motion-state-drag 1200ms cubic-bezier(0.2, 0, 0, 1) forwards;
}
@keyframes motion-state-drag {
  0%   { transform: translateY(0) rotate(0); box-shadow: none; }
  100% { transform: translateY(-4px) rotate(-1.5deg); box-shadow: 0 6px 14px rgba(0,0,0,0.22); }
}

.motion-state-demo--selection.is-playing {
  animation: motion-state-selection 1000ms ease-out forwards;
}
@keyframes motion-state-selection {
  0%   { background: var(--kdr-surface); border-color: var(--kdr-border); }
  100% { background: color-mix(in srgb, var(--kdr-accent) 28%, var(--kdr-surface)); border-color: var(--kdr-accent); }
}

.motion-state-demo--disabled.is-playing {
  animation: motion-state-disabled 1200ms ease-out forwards;
}
@keyframes motion-state-disabled {
  0%   { opacity: 1; }
  100% { opacity: 0.38; }
}

/* Ticket #039 — Spring physics demo. Each ball slides X 0→78% with
   animation-timing-function bound to the live --kds-motion-spring-*
   token so overshoot/settle is observable. Browsers without linear()
   support fall back to ease-out via base @supports rule above. */
.motion-spring-demo {
  appearance: none;
  border: 0;
  cursor: pointer;
  background: transparent;
  position: relative;
  width: 100%;
  height: 100%;
  padding: 0;
}
.motion-spring-ball {
  display: block;
  position: absolute;
  top: 50%;
  left: 6%;
  transform: translateY(-50%);
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--kdr-accent);
  box-shadow: 0 2px 6px rgba(0,0,0,0.22);
}
.motion-spring-demo--spatial-fast.is-playing .motion-spring-ball {
  animation: motion-spring-slide 700ms forwards;
  animation-timing-function: var(--kds-motion-spring-spatial-fast, ease-out);
}
.motion-spring-demo--spatial-default.is-playing .motion-spring-ball {
  animation: motion-spring-slide 1200ms forwards;
  animation-timing-function: var(--kds-motion-spring-spatial-default, ease-out);
}
.motion-spring-demo--effect-default.is-playing .motion-spring-ball {
  animation: motion-spring-slide 900ms forwards;
  animation-timing-function: var(--kds-motion-spring-effect-default, ease-out);
}
@keyframes motion-spring-slide {
  from { left: 6%; }
  to   { left: 78%; }
}

/* Ticket #041 — Scroll-driven animation demo. The blob's hue +
   shape morph as the user scrolls the rail. animation-timeline:
   view() is bound to the rail's intersection with the viewport
   so progress = scroll position. @supports fallback parks the
   blob in its initial state. */
.motion-scroll-stage {
  background: var(--kdr-surface-2);
  border-radius: 8px;
  padding: 16px;
  margin: 16px 0 24px;
}
.motion-scroll-rail {
  height: clamp(220px, 28vw, 340px);
  border-radius: 6px;
  background: linear-gradient(180deg, var(--kdr-surface) 0%, var(--kdr-surface-2) 100%);
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
}
/* Blob sized off the rail so it occupies meaningful card real-estate
   (user feedback 2026-05-21: was too small). Aspect-ratio 1:1 keeps
   it proportional; min/max prevent it from going bigger than the
   shorter rail dimension on extreme viewports. */
.motion-scroll-blob {
  /* Floor 79px = 22vw @ 360dp per koder-css-audit clamp-floor
     (specs/develop/visual-regression-tdds.kmd § R1.C.3). Previously
     150px which won at Compact viewports and blocked smooth scaling.
     Ticket #099 fix. */
  width: clamp(79px, 22vw, 280px);
  aspect-ratio: 1 / 1;
  background: var(--kdr-accent);
  border-radius: 50%;
}
/* Scroll-driven via the STAGE's view-timeline (not the blob's own) —
   the stage covers the full demo card so morphing spans the entire
   stage's traversal of the viewport. Tying to view() of the blob
   itself gave too short a scroll window. */
@supports (animation-timeline: scroll()) {
  .motion-scroll-stage {
    view-timeline-name: --kds-motion-scroll-stage;
    view-timeline-axis: block;
  }
  .motion-scroll-blob {
    animation: motion-scroll-blob-morph linear both;
    animation-timeline: --kds-motion-scroll-stage;
    animation-range: cover 0% cover 100%;
  }
}
/* Time-based fallback for browsers without animation-timeline.
   Guarantees the demo is always animated even when scroll-driven
   can't bind. */
@supports not (animation-timeline: scroll()) {
  .motion-scroll-blob {
    animation: motion-scroll-blob-morph 12s ease-in-out infinite;
  }
}
@keyframes motion-scroll-blob-morph {
  0%   { border-radius: 50%; transform: rotate(0) scale(0.6); filter: hue-rotate(0deg); }
  50%  { border-radius: 38% 62% 73% 27% / 41% 32% 68% 59%; transform: rotate(45deg) scale(1.1); filter: hue-rotate(60deg); }
  100% { border-radius: 70% 30% 30% 70% / 60% 40% 60% 40%; transform: rotate(180deg) scale(1); filter: hue-rotate(120deg); }
}
.motion-scroll-hint {
  margin: 12px 0 0;
  font-size: 13px;
  color: var(--kdr-text-muted);
  text-align: center;
  font-style: italic;
}
/* Note: scroll-driven animation is user-input-driven (no autonomous
   time loop), so it does NOT respect prefers-reduced-motion by default
   — the user controls progress via scroll speed. The morph effect is
   purely visual feedback for their explicit action. Material/WAI
   guidance: only autonomous motion needs reduced-motion suppression. */

/* Ticket #040 — Ambient hero animation + global pause toggle.
   Hero blob morphs continuously in a closed loop. Per-card pause
   button + global FAB (#koder-ambient-pause) both toggle
   data-ambient-paused which suspends every .ambient-anim. */
/* Hero ambient — redesign 2026-05-21: previously single blob centered
   in a wide card left ~80% of horizontal space empty on desktop.
   Replaced with 5 layered organic blobs in a multi-color palette,
   each morphing on its own timing offset. filter: blur on the parent
   creates soft overlap (one continuous organic mass). Sizes use vw +
   % units so the composition scales naturally from mobile to ultrawide. */
.kds-hero-ambient {
  position: relative;
  border-radius: var(--kdr-radius-md);
  background: linear-gradient(135deg, color-mix(in srgb, var(--kdr-accent) 22%, var(--kdr-bg)), color-mix(in srgb, var(--kdr-accent) 6%, var(--kdr-bg)));
  overflow: hidden;
  min-height: clamp(280px, 38vw, 460px);
  /* Breathing room before the facets grid below (user feedback 2026-05-21). */
  margin-bottom: clamp(32px, 5vw, 72px);
}
/* Redesign 2026-05-21 (user feedback): the 5-blob gradient cloud
   read as a "chroma cloud" rather than discrete shapes. Replaced
   with 3 distinct geometric objects (circle, rounded square,
   triangle) in flat saturated colors. Each shape rotates/scales/
   translates on its own loop so the composition reads as a
   coordinated piece of motion rather than an organic blur.
   No mix-blend-mode + no parent filter — straightforward solid
   fills so animation runs cleanly on every browser. */
/* Hero card redesign 2026-05-21 (user feedback round 3): switched
   from position: absolute with hand-picked top/left percentages to a
   flex container so the three shapes are automatically (a) centered
   on the same horizontal axis (identical card-edge margins top and
   bottom), (b) evenly distributed on the horizontal axis (identical
   spacing between siblings and to the side edges), and (c) sized
   for real visual-area parity — earlier the triangle was 22vw and
   the pink 17vw, which inverted the parity (a 22vw triangle has more
   area than an 18vw circle even though circles fill 78% of their box
   vs the triangle's ~85% post-path-expansion). Corrected: pink and
   triangle now sit 11% / 6% below the circle reference (16/17/18vw)
   so silhouettes match. Keyframes use only transform delta on top of
   the flex-resolved position, so the rest pose still lands the shape
   at the flex center. */
.kds-hero-ambient-blobs {
  position: absolute;
  /* Decorative margin (specs/develop/visual-regression-tdds.kmd § R1.C.4):
     shapes live inside an inset so they never graze the card edges
     even at keyframe peaks. clamp() scales 12 → 32 px with the hero. */
  inset: clamp(12px, 4%, 32px);
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: clamp(8px, 2%, 24px);
}
.kds-hero-blob {
  position: relative;
  opacity: 0.92;
  flex: 0 0 auto;
}
.kds-hero-blob--c {
  /* Indigo triangle — middle slot. Rounded-corner polygon via inline
     SVG background-image (CSS clip-path can't round polygon vertices).
     Floor 61px = 17vw @ 360dp (clamp-floor compliance, ticket #099). */
  width: clamp(61px, 17vw, 232px); aspect-ratio: 1/1;
  background: transparent;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><path d='M 50 4 Q 57 4 60 11 L 94 86 Q 99 96 88 96 L 12 96 Q 1 96 6 86 L 40 11 Q 43 4 50 4 Z' fill='%236366f1'/></svg>");
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  order: 2;
}
.kds-hero-blob--a {
  /* Pink rounded-square — left slot.
     Floor 57px = 16vw @ 360dp (clamp-floor compliance, ticket #099). */
  width: clamp(57px, 16vw, 218px); aspect-ratio: 1/1;
  background: #ec4899;
  border-radius: 28% 32% 30% 26%;
  order: 1;
}
.kds-hero-blob--b {
  /* Amber circle — right slot. Reference size in the parity calc.
     Floor 64px = 18vw @ 360dp (clamp-floor compliance, ticket #099). */
  width: clamp(64px, 18vw, 246px); aspect-ratio: 1/1;
  background: #fbbf24;
  border-radius: 50%;
  order: 3;
}
/* The 4th and 5th blob classes from the previous design are kept
   as no-ops so any cached HTML referencing --d/--e doesn't 404 —
   they just don't render anything visible. */
.kds-hero-blob--d, .kds-hero-blob--e { display: none; }

.kds-hero-blob--a.ambient-anim { animation: kds-hero-shape-a 14s ease-in-out infinite; }
.kds-hero-blob--b.ambient-anim { animation: kds-hero-shape-b 16s ease-in-out infinite; }
.kds-hero-blob--c.ambient-anim { animation: kds-hero-shape-c 18s ease-in-out infinite; }
/* With flex layout the rest pose is at transform: none. Keyframes
   ride on top of that as small wobble (±2% of own size) + rotation +
   subtle scale. Amplitudes intentionally small per
   specs/develop/visual-regression-tdds.kmd § R1.C.4 — animation peaks
   must respect the 4% decorative margin. */
@keyframes kds-hero-shape-a {
  0%, 100% { transform: translate(0,    0)   rotate(0)    scale(1); }
  33%      { transform: translate(2%,  -2%)  rotate(8deg) scale(1.04); }
  66%      { transform: translate(-2%,  2%)  rotate(-6deg) scale(0.97); }
}
@keyframes kds-hero-shape-b {
  0%, 100% { transform: translate(0,   0)   scale(1); }
  50%      { transform: translate(0,  -2%) scale(1.06); }
}
@keyframes kds-hero-shape-c {
  0%, 100% { transform: translate(0,   0)   rotate(0); }
  33%      { transform: translate(0,  -2%) rotate(8deg); }
  66%      { transform: translate(0,   2%) rotate(-6deg); }
}
/* Backward-compat: legacy single-blob class still works for any
   external pages referencing .kds-hero-ambient-blob. */
.kds-hero-ambient-blob {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  /* Floor 79px = 22vw @ 360dp (clamp-floor compliance, ticket #099). */
  width: clamp(79px, 22vw, 320px); aspect-ratio: 1/1;
  background: var(--kdr-accent);
  opacity: 0.78;
  animation: kds-hero-blob-morph 18s ease-in-out infinite;
}
@keyframes kds-hero-blob-morph {
  0%, 100% { border-radius: 41% 59% 70% 30% / 51% 32% 68% 49%; transform: translate(-50%, -50%) rotate(0) scale(1); }
  25%      { border-radius: 70% 30% 30% 70% / 60% 40% 60% 40%; transform: translate(-50%, -50%) rotate(45deg) scale(1.05); }
  50%      { border-radius: 38% 62% 73% 27% / 41% 32% 68% 59%; transform: translate(-50%, -50%) rotate(180deg) scale(0.95); }
  75%      { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; transform: translate(-50%, -50%) rotate(270deg) scale(1.08); }
}
:root[data-ambient-paused="true"] .ambient-anim { animation-play-state: paused !important; }
/* Note: prefers-reduced-motion respect is handled by the anti-flash
   script which sets data-ambient-paused="true" on first paint when
   the OS reports the preference. The user can override by clicking
   the topbar ▶ toggle — clicking removes data-ambient-paused so the
   animation resumes. A pure @media (prefers-reduced-motion: reduce)
   { animation-play-state: paused } CSS rule was REMOVED because it
   would override the user's explicit override choice (toggle wouldn't
   work for reduced-motion users). Fix 2026-05-21. */

/* Ambient pause trigger lives in TopBar as of 2026-05-21 — peer of
   search + settings buttons, no longer a body-level FAB. Visual
   matches .settings-trigger for consistency. Icon flips ▶/❚❚ via
   the data-ambient-paused attribute on <html>. */
.ambient-pause-trigger {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--kdr-text);
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  cursor: pointer;
  font-size: 13px;
  font-family: var(--kds-font-mono);
}
.ambient-pause-trigger:hover { background: color-mix(in srgb, var(--kdr-text) 12%, transparent); }
.ambient-pause-trigger:focus-visible { outline: 2px solid var(--kdr-focus); outline-offset: 2px; }
:root[data-ambient-paused="true"] .ambient-pause-trigger::before { content: "▶"; }
:root:not([data-ambient-paused="true"]) .ambient-pause-trigger::before { content: "❚❚"; }

/* Ticket #050 (2026-05-21) — topbar theme toggle. Single-button
   cycle paired with the Settings drawer Light/Dark tri-state.
   Icon flips ☾ (in light theme → click for dark) / ☀ (in dark
   theme → click for light). */
.theme-toggle-trigger {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--kdr-text);
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  cursor: pointer;
  font-size: 15px;
}
.theme-toggle-trigger:hover { background: color-mix(in srgb, var(--kdr-text) 12%, transparent); }
.theme-toggle-trigger:focus-visible { outline: 2px solid var(--kdr-focus); outline-offset: 2px; }
:root[data-theme="dark"] .theme-toggle-trigger::before { content: "☀"; }
:root[data-theme="light"] .theme-toggle-trigger::before { content: "☾"; }
:root:not([data-theme]) .theme-toggle-trigger::before { content: "☀"; }

/* Ticket #042 — Anatomy dots + legend on /components/<slug>.
   Dots overlay the live demo; legend lists each part. CSS-only
   :hover/:has sync: hovering a row shadows the matching dot. */
.stage { position: relative; }
.comp-anatomy-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.comp-anatomy-dot {
  position: absolute;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--kdr-accent);
  color: var(--kdr-bg);
  font-size: 12px;
  font-weight: 700;
  display: grid;
  place-items: center;
  box-shadow: 0 0 0 3px var(--kdr-bg), 0 3px 8px rgba(0,0,0,0.3);
  transform: translate(-50%, -50%);
  pointer-events: auto;
  cursor: pointer;
}
.comp-anatomy-dot:hover,
.comp-anatomy-dot:focus-visible {
  outline: 2px solid var(--kdr-focus);
  outline-offset: 2px;
}
.comp-anatomy-legend {
  margin: 16px 0 24px;
  padding: 16px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
}
.comp-anatomy-title {
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 600;
}
.comp-anatomy-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.comp-anatomy-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 8px;
  border-radius: 4px;
  cursor: default;
}
.comp-anatomy-row:hover { background: var(--kdr-bg); }
.comp-anatomy-num {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--kdr-accent);
  color: var(--kdr-bg);
  font-size: 11px;
  font-weight: 700;
  flex-shrink: 0;
}

/* Ticket #046 — Per-component playground rail. Sits beside the
   stage on wide viewports; stacks below on narrow.
   page-enhance.js wires checkbox/select/text inputs to write
   data-* attributes on the stage element identified by data-target. */
.comp-playground {
  margin: 16px 0 24px;
  padding: 16px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
}
.comp-playground-title { margin: 0 0 12px; font-size: 14px; font-weight: 600; }
.comp-playground-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.comp-playground-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
}
.comp-playground-label { color: var(--kdr-text-muted); }
.comp-playground-row input[type="text"],
.comp-playground-row select {
  background: var(--kdr-bg);
  border: 1px solid var(--kdr-border);
  border-radius: 4px;
  padding: 4px 8px;
  color: var(--kdr-text);
  font-size: 13px;
}
.comp-playground-reset {
  align-self: flex-start;
  margin-top: 6px;
  appearance: none;
  border: 1px solid var(--kdr-border);
  background: transparent;
  color: var(--kdr-text-muted);
  border-radius: 4px;
  padding: 4px 10px;
  font-size: 12px;
  cursor: pointer;
}
.comp-playground-reset:hover { color: var(--kdr-text); border-color: var(--kdr-text); }

/* Ticket #044 — Multi-framework code tabs. Tab strip + N <pre><code>
   panes; one visible at a time. Selection persisted in localStorage
   under kds.framework. */
.kds-codetabs {
  margin: 16px 0;
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  overflow: hidden;
}
.kds-codetabs-strip {
  display: flex;
  background: var(--kdr-surface);
  border-bottom: 1px solid var(--kdr-border);
  overflow-x: auto;
}
.kds-codetabs-tab {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 8px 16px;
  font-size: 13px;
  color: var(--kdr-text-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  font-family: var(--kds-font-sans);
}
.kds-codetabs-tab:hover { color: var(--kdr-text); }
.kds-codetabs-tab.is-active {
  color: var(--kdr-accent);
  border-bottom-color: var(--kdr-accent);
}
.kds-codetabs-pane { display: none; }
.kds-codetabs-pane.is-active { display: block; }

/* Ticket #048 — Widget motion gallery. 12 concrete UI shapes with
   canonical motion (clock/calendar/counter/form/table/card/photo/
   video/date-picker/progress/carousel/slider). All CSS-only;
   auto-replay via data-motion-replay shared hook. */
.motion-widget-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
  margin: 16px 0 24px;
}
.motion-widget-card {
  display: flex;
  flex-direction: column;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  padding: 14px;
}
.motion-widget-head h3 { margin: 0 0 10px; font-size: 14px; }
/* Vibrant per-widget stage backgrounds (user feedback 2026-05-21:
   gadget colors needed to be richer, Material 3 style with saturated
   per-card hues). Each widget gets a curated gradient so the gallery
   reads as a colorful catalog rather than a mono-accent grid. */
.motion-widget-stage {
  background: var(--kdr-surface-2);
  border-radius: 6px;
  height: 140px;
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
  cursor: pointer;
}
/* Per-widget muted hues (user feedback 2026-05-21: "mais discreto").
   Each color mixed 24% into the canonical dark surface — gallery has
   variety without competing chroma. Theme-aware via --kdr-surface-2. */
.motion-widget-stage--clock         { background: color-mix(in srgb, #f59e0b 24%, var(--kdr-surface-2)); }
.motion-widget-stage--calendar      { background: color-mix(in srgb, #7c3aed 24%, var(--kdr-surface-2)); }
.motion-widget-stage--counter       { background: color-mix(in srgb, #059669 24%, var(--kdr-surface-2)); }
.motion-widget-stage--form-focus    { background: color-mix(in srgb, #2563eb 24%, var(--kdr-surface-2)); }
.motion-widget-stage--table-row     { background: color-mix(in srgb, #be123c 24%, var(--kdr-surface-2)); }
.motion-widget-stage--card-flip     { background: color-mix(in srgb, #ea580c 24%, var(--kdr-surface-2)); }
.motion-widget-stage--photo-gallery { background: color-mix(in srgb, #db2777 24%, var(--kdr-surface-2)); }
.motion-widget-stage--video-play    { background: var(--kdr-surface-2); }
.motion-widget-stage--date-picker   { background: color-mix(in srgb, #6366f1 24%, var(--kdr-surface-2)); }
.motion-widget-stage--progress-bar  { background: color-mix(in srgb, #0891b2 24%, var(--kdr-surface-2)); }
.motion-widget-stage--carousel      { background: color-mix(in srgb, #ca8a04 24%, var(--kdr-surface-2)); }
.motion-widget-stage--slider        { background: color-mix(in srgb, #4338ca 24%, var(--kdr-surface-2)); }
.motion-widget-stage--card-reorder  { background: color-mix(in srgb, #e11d48 24%, var(--kdr-surface-2)); }
.motion-widget-stage--progress-circle { background: color-mix(in srgb, #0e7490 24%, var(--kdr-surface-2)); }

/* ── Circular progress — determinate + indeterminate (user request
   2026-05-21). SVG ring with stroke-dasharray + pathLength=100 so
   the fill is expressible as a 0-100 number. */
.wm-circprog { display: flex; gap: 16px; align-items: center; }
.wm-circprog-svg { width: 56px; height: 56px; }
.wm-circprog-track { stroke: rgba(255,255,255,0.25); stroke-width: 5; }
.wm-circprog-fill, .wm-circprog-spin { stroke: #fff; stroke-width: 5; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 50% 50%; }
.wm-circprog-fill { stroke-dasharray: 0 100; }
.wm-circprog-spin { stroke-dasharray: 25 75; }
.motion-widget-stage--progress-circle.is-playing .wm-circprog-fill {
  animation: wm-circprog-fill 2400ms cubic-bezier(0.2,0,0,1) forwards;
}
.motion-widget-stage--progress-circle.is-playing .wm-circprog-spin {
  animation: wm-circprog-spin 1400ms linear infinite;
}
@keyframes wm-circprog-fill {
  from { stroke-dasharray: 0 100; }
  to   { stroke-dasharray: 75 100; }
}
@keyframes wm-circprog-spin {
  from { transform: rotate(-90deg); }
  to   { transform: rotate(270deg); }
}

/* Per-widget contrast overrides so inner elements pop on the new
   vibrant stage backgrounds. Each override matches the stage hue. */
.motion-widget-stage--clock .wm-clock { background: #fff; border-color: rgba(0,0,0,0.15); }
.motion-widget-stage--clock .wm-clock-hand--h,
.motion-widget-stage--clock .wm-clock-hand--m { background: #1e293b; }
.motion-widget-stage--clock .wm-clock-hand--s { background: #ef4444; }
.motion-widget-stage--clock .wm-clock-center { background: #ef4444; }

.motion-widget-stage--calendar .wm-cal { background: #fff; border-color: rgba(0,0,0,0.12); }
.motion-widget-stage--calendar .wm-cal-month { color: #6d28d9; }
.motion-widget-stage--calendar .wm-cal-grid span { background: #ede9fe; }
.motion-widget-stage--calendar .wm-cal-grid span:nth-child(7n) { background: #c4b5fd; }
.motion-widget-stage--calendar .wm-cal-grid span:nth-child(3n) { background: #a78bfa; }

.motion-widget-stage--counter .wm-counter { color: #fff; text-shadow: 0 2px 6px rgba(0,0,0,0.25); }

.motion-widget-stage--form-focus .wm-form-label { color: rgba(255,255,255,0.92); font-weight: 500; }
.motion-widget-stage--form-focus .wm-form-input { background: #fff; border-color: rgba(0,0,0,0.12); }
.motion-widget-stage--form-focus.is-playing .wm-form-input { animation: wm-focus-bright 1800ms cubic-bezier(0.2,0,0,1) forwards; }
@keyframes wm-focus-bright {
  0%, 100% { box-shadow: 0 0 0 0 #fbbf24; border-color: rgba(0,0,0,0.12); }
  20%, 80% { box-shadow: 0 0 0 2px #fbbf24; border-color: #fbbf24; }
}

.motion-widget-stage--table-row .wm-table { color: #fff; }
.motion-widget-stage--table-row .wm-table-row { border-bottom-color: rgba(255,255,255,0.18); }
.motion-widget-stage--table-row .wm-table-row--head { color: rgba(255,255,255,0.7); }
.motion-widget-stage--table-row.is-playing .wm-table-row:not(.wm-table-row--head) { animation: wm-row-hl-bright 1800ms cubic-bezier(0.2,0,0,1) forwards; }
@keyframes wm-row-hl-bright {
  0%, 100% { background: transparent; }
  30%, 70% { background: rgba(255,255,255,0.22); }
}

.motion-widget-stage--card-flip .wm-card-face--front { background: #fff; color: #ea580c; border-color: rgba(0,0,0,0.1); }
.motion-widget-stage--card-flip .wm-card-face--back { background: #1e293b; color: #fbbf24; }

.motion-widget-stage--video-play .wm-video-frame { background: linear-gradient(135deg, #6366f1, #ec4899); }
.motion-widget-stage--video-play .wm-video-play { background: #ef4444; }
.motion-widget-stage--video-play.is-playing .wm-video-play {
  animation: wm-video-pulse-bright 1400ms ease-in-out infinite;
}
@keyframes wm-video-pulse-bright {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 #ef4444; }
  50%      { transform: scale(1.12); box-shadow: 0 0 0 14px rgba(239,68,68,0.08); }
}

.motion-widget-stage--date-picker .wm-dp-field { background: #fff; border-color: rgba(0,0,0,0.12); color: #4338ca; }
.motion-widget-stage--date-picker .wm-dp-popup { background: #fff; border-color: rgba(0,0,0,0.12); }
.motion-widget-stage--date-picker .wm-dp-popup-head { color: #4338ca; }
.motion-widget-stage--date-picker .wm-dp-popup-grid span { background: #e0e7ff; }
.motion-widget-stage--date-picker .wm-dp-popup-grid span:nth-child(7n) { background: #a5b4fc; }

.motion-widget-stage--progress-bar .wm-prog-bar { background: rgba(255,255,255,0.25); }
.motion-widget-stage--progress-bar .wm-prog-bar--det span { background: linear-gradient(90deg, #fbbf24, #ef4444, #ec4899); }
.motion-widget-stage--progress-bar .wm-prog-bar--ind span { background: #fff; }

.motion-widget-stage--carousel .wm-carousel-slide[style*="--c:1"] { background: #ef4444; }
.motion-widget-stage--carousel .wm-carousel-slide[style*="--c:2"] { background: #ec4899; }
.motion-widget-stage--carousel .wm-carousel-slide[style*="--c:3"] { background: #8b5cf6; }
.motion-widget-stage--carousel .wm-carousel-dots span { background: rgba(255,255,255,0.4); }
.motion-widget-stage--carousel.is-playing .wm-carousel-dots span:nth-child(1),
.motion-widget-stage--carousel.is-playing .wm-carousel-dots span:nth-child(2),
.motion-widget-stage--carousel.is-playing .wm-carousel-dots span:nth-child(3) {
  animation: wm-dot-on-bright 4000ms ease-in-out infinite;
}
.motion-widget-stage--carousel.is-playing .wm-carousel-dots span:nth-child(2) { animation-delay: 1333ms; }
.motion-widget-stage--carousel.is-playing .wm-carousel-dots span:nth-child(3) { animation-delay: 2666ms; }
@keyframes wm-dot-on-bright {
  0%, 33%, 100% { background: rgba(255,255,255,0.4); }
  10%, 23%      { background: #fff; }
}

.motion-widget-stage--slider .wm-slider-track { background: rgba(255,255,255,0.25); }
.motion-widget-stage--slider .wm-slider-fill { background: #fff; }
.motion-widget-stage--slider .wm-slider-thumb { background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.35); }

.motion-widget-stage--photo-gallery .wm-gallery-slide[style*="--g:1"] { background: linear-gradient(135deg, #ef4444, #fbbf24); }
.motion-widget-stage--photo-gallery .wm-gallery-slide[style*="--g:2"] { background: linear-gradient(135deg, #22c55e, #06b6d4); }
.motion-widget-stage--photo-gallery .wm-gallery-slide[style*="--g:3"] { background: linear-gradient(135deg, #8b5cf6, #ec4899); }
.motion-widget-stage:focus-visible { outline: 2px solid var(--kdr-focus); outline-offset: 2px; }
.motion-widget-use { margin: 10px 0 0; font-size: 13px; color: var(--kdr-text-muted); }

/* ── Clock — second/minute/hour hand sweep. ───────────────────── */
.wm-clock {
  width: 96px; height: 96px; border-radius: 50%;
  background: var(--kdr-surface); border: 2px solid var(--kdr-border);
  position: relative;
}
.wm-clock-hand {
  position: absolute; bottom: 50%; left: 50%; transform-origin: 0% 100%;
  background: var(--kdr-text);
}
.wm-clock-hand--h { width: 2px; height: 22px; }
.wm-clock-hand--m { width: 2px; height: 34px; }
.wm-clock-hand--s { width: 1px; height: 40px; background: var(--kdr-accent); }
.wm-clock-center {
  position: absolute; top: 50%; left: 50%;
  width: 6px; height: 6px; margin: -3px 0 0 -3px;
  background: var(--kdr-accent); border-radius: 50%;
}
.motion-widget-stage--clock.is-playing .wm-clock-hand--s { animation: wm-spin 4s linear infinite; }
.motion-widget-stage--clock.is-playing .wm-clock-hand--m { animation: wm-spin 240s linear infinite; }
.motion-widget-stage--clock.is-playing .wm-clock-hand--h { animation: wm-spin 2880s linear infinite; }
@keyframes wm-spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }

/* ── Calendar — flip in. ──────────────────────────────────────── */
.wm-cal { width: 140px; padding: 8px; background: var(--kdr-surface); border: 1px solid var(--kdr-border); border-radius: 6px; perspective: 600px; }
.wm-cal-month { font-size: 11px; font-weight: 600; margin-bottom: 6px; text-align: center; color: var(--kdr-text-muted); }
.wm-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; transform-style: preserve-3d; }
.wm-cal-grid span { aspect-ratio: 1/1; background: color-mix(in srgb, var(--kdr-accent) 18%, transparent); border-radius: 2px; }
.motion-widget-stage--calendar.is-playing .wm-cal-grid { animation: wm-cal-flip 1500ms cubic-bezier(0.2,0,0,1) forwards; }
@keyframes wm-cal-flip {
  0%   { transform: rotateY(-90deg); opacity: 0; }
  60%  { transform: rotateY(10deg); opacity: 1; }
  100% { transform: rotateY(0); opacity: 1; }
}

/* ── Counter — number roll-up. ────────────────────────────────── */
.wm-counter { display: flex; gap: 6px; font-family: var(--kds-font-mono); font-size: 36px; font-weight: 700; color: var(--kdr-accent); }
.wm-counter-digit { display: inline-block; width: 22px; height: 44px; line-height: 44px; text-align: center; }
.motion-widget-stage--counter.is-playing .wm-counter-digit:nth-child(1) { animation: wm-roll 1200ms cubic-bezier(0.2,0,0,1) forwards; }
.motion-widget-stage--counter.is-playing .wm-counter-digit:nth-child(2) { animation: wm-roll 1500ms 100ms cubic-bezier(0.2,0,0,1) forwards; }
.motion-widget-stage--counter.is-playing .wm-counter-digit:nth-child(3) { animation: wm-roll 1800ms 200ms cubic-bezier(0.2,0,0,1) forwards; }
@keyframes wm-roll {
  0%   { transform: translateY(-100%); opacity: 0; }
  60%  { transform: translateY(10%); opacity: 1; }
  100% { transform: translateY(0); opacity: 1; }
}

/* ── Form focus — propagates through rows. ──────────────────── */
.wm-form { display: flex; flex-direction: column; gap: 6px; width: 80%; }
.wm-form-row { display: grid; grid-template-columns: 44px 1fr; gap: 8px; align-items: center; }
.wm-form-label { font-size: 10px; color: var(--kdr-text-muted); }
.wm-form-input { height: 18px; background: var(--kdr-surface); border: 1px solid var(--kdr-border); border-radius: 3px; }
.motion-widget-stage--form-focus.is-playing .wm-form-input { animation: wm-focus 1800ms cubic-bezier(0.2,0,0,1) forwards; }
.motion-widget-stage--form-focus.is-playing .wm-form-row:nth-child(1) .wm-form-input { animation-delay: 0ms; }
.motion-widget-stage--form-focus.is-playing .wm-form-row:nth-child(2) .wm-form-input { animation-delay: 250ms; }
.motion-widget-stage--form-focus.is-playing .wm-form-row:nth-child(3) .wm-form-input { animation-delay: 500ms; }
@keyframes wm-focus {
  0%, 100% { box-shadow: 0 0 0 0 var(--kdr-focus); border-color: var(--kdr-border); }
  20%, 80% { box-shadow: 0 0 0 2px var(--kdr-focus); border-color: var(--kdr-accent); }
}

/* ── Table row — highlight sweep. ────────────────────────────── */
.wm-table { width: 90%; font-size: 10px; }
.wm-table-row { display: grid; grid-template-columns: 1fr 60px; padding: 4px 6px; border-bottom: 1px solid var(--kdr-border); color: var(--kdr-text); }
.wm-table-row--head { font-weight: 600; color: var(--kdr-text-muted); }
.motion-widget-stage--table-row.is-playing .wm-table-row:not(.wm-table-row--head) { animation: wm-row-hl 1800ms cubic-bezier(0.2,0,0,1) forwards; }
.motion-widget-stage--table-row.is-playing .wm-table-row:nth-child(2) { animation-delay: 0ms; }
.motion-widget-stage--table-row.is-playing .wm-table-row:nth-child(3) { animation-delay: 200ms; }
.motion-widget-stage--table-row.is-playing .wm-table-row:nth-child(4) { animation-delay: 400ms; }
@keyframes wm-row-hl {
  0%, 100% { background: transparent; }
  30%, 70% { background: color-mix(in srgb, var(--kdr-accent) 22%, transparent); }
}

/* ── Card flip. ─────────────────────────────────────────────── */
.wm-card { width: 80px; height: 110px; position: relative; transform-style: preserve-3d; perspective: 600px; }
.wm-card-face {
  position: absolute; inset: 0; display: grid; place-items: center;
  border-radius: 6px; font-size: 28px; font-weight: 700;
  backface-visibility: hidden;
}
.wm-card-face--front { background: var(--kdr-surface); border: 1px solid var(--kdr-border); color: var(--kdr-text); }
.wm-card-face--back { background: var(--kdr-accent); color: var(--kdr-bg); transform: rotateY(180deg); }
.motion-widget-stage--card-flip.is-playing .wm-card { animation: wm-card-flip 2000ms cubic-bezier(0.2,0,0,1) forwards; }
@keyframes wm-card-flip {
  0%, 100% { transform: rotateY(0); }
  50%      { transform: rotateY(180deg); }
}

/* ── Photo gallery — slide track. ────────────────────────────── */
.wm-gallery { width: 96px; height: 60px; overflow: hidden; border-radius: 6px; }
.wm-gallery-track { display: flex; width: 300%; height: 100%; }
.wm-gallery-slide { flex: 1; height: 100%; }
.wm-gallery-slide[style*="--g:1"] { background: color-mix(in srgb, var(--kdr-accent) 60%, var(--kdr-bg)); }
.wm-gallery-slide[style*="--g:2"] { background: color-mix(in srgb, var(--kdr-accent) 30%, var(--kdr-bg)); }
.wm-gallery-slide[style*="--g:3"] { background: color-mix(in srgb, var(--kdr-accent) 80%, var(--kdr-bg)); }
.motion-widget-stage--photo-gallery.is-playing .wm-gallery-track { animation: wm-gallery 2400ms ease-in-out forwards; }
@keyframes wm-gallery {
  0%   { transform: translateX(0); }
  35%  { transform: translateX(-33.33%); }
  70%  { transform: translateX(-66.66%); }
  100% { transform: translateX(0); }
}

/* ── Video play — pulsing play icon. ─────────────────────────── */
.wm-video { position: relative; width: 110px; height: 70px; }
.wm-video-frame { width: 100%; height: 100%; background: color-mix(in srgb, var(--kdr-text) 70%, transparent); border-radius: 6px; }
.wm-video-play {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 16px; color: var(--kdr-bg);
  background: color-mix(in srgb, var(--kdr-accent) 75%, transparent);
  border-radius: 50%;
  width: 36px; height: 36px;
  margin: auto;
}
.motion-widget-stage--video-play.is-playing .wm-video-play { animation: wm-video-pulse 1400ms ease-in-out infinite; }
@keyframes wm-video-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 var(--kdr-accent); }
  50%      { transform: scale(1.1); box-shadow: 0 0 0 10px color-mix(in srgb, var(--kdr-accent) 5%, transparent); }
}

/* ── Date picker — popup drop. ───────────────────────────────── */
/* Fix 2026-05-21: previously the wm-dp was centered in the 140px
   stage, leaving < ~60px below the field for the popup → 4 day rows
   got clipped. Anchor the date-picker stage content to the top and
   shrink popup cell sizes so the whole flyout fits inside the card. */
.motion-widget-stage--date-picker { align-items: start; padding-top: 14px; }
.wm-dp { position: relative; width: 110px; }
.wm-dp-field { padding: 3px 8px; background: var(--kdr-surface); border: 1px solid var(--kdr-border); border-radius: 4px; font-size: 11px; }
.wm-dp-popup {
  position: absolute; top: 100%; left: 0; right: 0; margin-top: 4px;
  background: var(--kdr-surface); border: 1px solid var(--kdr-border); border-radius: 4px;
  padding: 4px; transform-origin: top center;
  transform: scaleY(0); opacity: 0;
  box-shadow: 0 4px 12px rgba(0,0,0,0.18);
}
.wm-dp-popup-head { font-size: 9px; text-align: center; color: var(--kdr-text-muted); margin-bottom: 3px; }
.wm-dp-popup-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
.wm-dp-popup-grid span { aspect-ratio: 1/1; background: color-mix(in srgb, var(--kdr-accent) 18%, transparent); border-radius: 1px; min-height: 8px; }
.motion-widget-stage--date-picker.is-playing .wm-dp-popup { animation: wm-dp-drop 1800ms cubic-bezier(0.2,0,0,1) forwards; }
@keyframes wm-dp-drop {
  0%   { transform: scaleY(0); opacity: 0; }
  30%  { transform: scaleY(1.05); opacity: 1; }
  40%, 80% { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(0); opacity: 0; }
}

/* ── Progress bar — determinate + indeterminate. ─────────────── */
.wm-prog { display: flex; flex-direction: column; gap: 10px; width: 88%; }
.wm-prog-bar { height: 8px; background: var(--kdr-surface); border-radius: 4px; overflow: hidden; position: relative; }
.wm-prog-bar span { display: block; height: 100%; background: var(--kdr-accent); border-radius: 4px; }
.wm-prog-bar--det span { width: 0; }
.wm-prog-bar--ind span { width: 30%; position: absolute; }
.motion-widget-stage--progress-bar.is-playing .wm-prog-bar--det span { animation: wm-prog-det 2000ms cubic-bezier(0.2,0,0,1) forwards; }
.motion-widget-stage--progress-bar.is-playing .wm-prog-bar--ind span { animation: wm-prog-ind 1400ms ease-in-out infinite; }
@keyframes wm-prog-det { from { width: 0; } to { width: 100%; } }
@keyframes wm-prog-ind { from { left: -30%; } to { left: 100%; } }

/* ── Carousel — slide track with dots. ───────────────────────── */
.wm-carousel { width: 96px; }
.wm-carousel-track { display: flex; width: 400%; height: 50px; overflow: hidden; }
.wm-carousel-slide { flex: 1; height: 100%; }
.wm-carousel-slide[style*="--c:1"] { background: color-mix(in srgb, var(--kdr-accent) 60%, var(--kdr-bg)); }
.wm-carousel-slide[style*="--c:2"] { background: color-mix(in srgb, var(--kdr-accent) 30%, var(--kdr-bg)); }
.wm-carousel-slide[style*="--c:3"] { background: color-mix(in srgb, var(--kdr-accent) 80%, var(--kdr-bg)); }
.wm-carousel-dots { display: flex; gap: 4px; justify-content: center; margin-top: 6px; }
.wm-carousel-dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--kdr-border); }
.motion-widget-stage--carousel.is-playing .wm-carousel-track { animation: wm-carousel-slide 4000ms ease-in-out infinite; }
.motion-widget-stage--carousel.is-playing .wm-carousel-dots span:nth-child(1) { animation: wm-dot-on 4000ms ease-in-out infinite; animation-delay: 0ms; }
.motion-widget-stage--carousel.is-playing .wm-carousel-dots span:nth-child(2) { animation: wm-dot-on 4000ms ease-in-out infinite; animation-delay: 1333ms; }
.motion-widget-stage--carousel.is-playing .wm-carousel-dots span:nth-child(3) { animation: wm-dot-on 4000ms ease-in-out infinite; animation-delay: 2666ms; }
@keyframes wm-carousel-slide {
  0%, 33%   { transform: translateX(0); }
  43%, 66%  { transform: translateX(-25%); }
  76%, 100% { transform: translateX(-50%); }
}
@keyframes wm-dot-on {
  0%, 33%, 100% { background: var(--kdr-border); }
  10%, 23%      { background: var(--kdr-accent); }
}

/* ── Slider — thumb drag along track. ────────────────────────── */
.wm-slider { position: relative; width: 88%; height: 18px; display: grid; place-items: center; }
.wm-slider-track { position: relative; width: 100%; height: 4px; background: var(--kdr-surface); border-radius: 2px; }
.wm-slider-fill { position: absolute; left: 0; top: 0; height: 100%; width: 30%; background: var(--kdr-accent); border-radius: 2px; }
.wm-slider-thumb {
  position: absolute; left: 30%; top: 50%;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--kdr-accent); transform: translate(-50%, -50%);
  box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.motion-widget-stage--slider.is-playing .wm-slider-fill { animation: wm-slider-fill 2400ms cubic-bezier(0.2,0,0,1) forwards; }
.motion-widget-stage--slider.is-playing .wm-slider-thumb { animation: wm-slider-thumb 2400ms cubic-bezier(0.2,0,0,1) forwards; }
@keyframes wm-slider-fill {
  0%   { width: 30%; }
  50%  { width: 78%; }
  100% { width: 55%; }
}
@keyframes wm-slider-thumb {
  0%   { left: 30%; transform: translate(-50%, -50%) scale(1); }
  20%  { transform: translate(-50%, -50%) scale(1.2); }
  50%  { left: 78%; }
  80%  { transform: translate(-50%, -50%) scale(1); }
  100% { left: 55%; }
}

/* ── Card reorder — Material 3 drag-and-drop card stack
   (user request 2026-05-21). 3 colored cards stacked; the middle
   card lifts (scale+shadow), slides down into the bottom slot, the
   bottom card slides up to fill the gap. */
.wm-cardstack { display: flex; flex-direction: column; gap: 4px; width: 88%; }
.wm-cardstack-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: 8px;
  font-size: 10px;
  position: relative;
}
.wm-cardstack-icon { width: 22px; height: 14px; border-radius: 2px; flex-shrink: 0; }
.wm-cardstack-icon--a { background: linear-gradient(135deg, #fbbf24, #f59e0b); }
.wm-cardstack-icon--b { background: linear-gradient(135deg, #ef4444, #b91c1c); }
.wm-cardstack-icon--c { background: linear-gradient(135deg, #22c55e, #16a34a); }
.wm-cardstack-grip { margin-left: auto; color: var(--kdr-text-muted); font-size: 14px; line-height: 1; }
.motion-widget-stage--card-reorder.is-playing .wm-cardstack-item--b {
  animation: wm-cardstack-lift 2400ms cubic-bezier(0.2,0,0,1) forwards;
  z-index: 2;
}
.motion-widget-stage--card-reorder.is-playing .wm-cardstack-item--c {
  animation: wm-cardstack-slide-up 2400ms cubic-bezier(0.2,0,0,1) forwards;
}
@keyframes wm-cardstack-lift {
  0%   { transform: translate(0,0) scale(1); box-shadow: none; }
  15%  { transform: translate(8px,-2px) scale(1.04); box-shadow: 0 6px 14px rgba(0,0,0,0.32); }
  45%  { transform: translate(8px, calc(100% + 4px)) scale(1.04); box-shadow: 0 6px 14px rgba(0,0,0,0.32); }
  85%  { transform: translate(0, calc(100% + 4px)) scale(1); box-shadow: 0 1px 3px rgba(0,0,0,0.18); }
  100% { transform: translate(0, calc(100% + 4px)) scale(1); box-shadow: none; }
}
@keyframes wm-cardstack-slide-up {
  0%, 30%   { transform: translateY(0); }
  60%, 100% { transform: translateY(calc(-100% - 4px)); }
}

@media (prefers-reduced-motion: reduce) {
  .motion-widget-stage * { animation: none !important; }
}

/* Ticket #049 — Creative motion showcase. 8 elaborate multi-color
   compositions. All CSS-only; reduced-motion disables. */
.motion-creative-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; margin: 16px 0 24px; }
.motion-creative-card { display: flex; flex-direction: column; background: var(--kdr-surface); border: 1px solid var(--kdr-border); border-radius: var(--kdr-radius-md); padding: 14px; }
.motion-creative-head h3 { margin: 0 0 10px; font-size: 14px; }
.motion-creative-stage { background: #0a0a14; border-radius: 6px; height: 160px; display: grid; place-items: center; position: relative; overflow: hidden; cursor: pointer; }
.motion-creative-stage:focus-visible { outline: 2px solid var(--kdr-focus); outline-offset: 2px; }
.motion-creative-use { margin: 10px 0 0; font-size: 13px; color: var(--kdr-text-muted); }

/* Aurora — 3 colored bands flowing. */
.cm-aurora { position: absolute; inset: 0; filter: blur(18px); }
.cm-aurora-band { position: absolute; left: -20%; right: -20%; height: 60%; border-radius: 50%; opacity: 0.7; }
.cm-aurora-band--1 { top: -20%; background: radial-gradient(ellipse, #4ade80, transparent 70%); }
.cm-aurora-band--2 { top: 20%; background: radial-gradient(ellipse, #38bdf8, transparent 70%); }
.cm-aurora-band--3 { top: 50%; background: radial-gradient(ellipse, #c084fc, transparent 70%); }
.motion-creative-stage--aurora.is-playing .cm-aurora-band--1 { animation: cm-aurora-1 6s ease-in-out infinite; }
.motion-creative-stage--aurora.is-playing .cm-aurora-band--2 { animation: cm-aurora-2 7s ease-in-out infinite; }
.motion-creative-stage--aurora.is-playing .cm-aurora-band--3 { animation: cm-aurora-3 8s ease-in-out infinite; }
@keyframes cm-aurora-1 { 0%,100% { transform: translateX(-10%) scaleY(1); } 50% { transform: translateX(10%) scaleY(1.3); } }
@keyframes cm-aurora-2 { 0%,100% { transform: translateX(10%) scaleY(0.8); } 50% { transform: translateX(-15%) scaleY(1.4); } }
@keyframes cm-aurora-3 { 0%,100% { transform: translateX(-5%) scaleY(1.2); } 50% { transform: translateX(15%) scaleY(0.9); } }

/* Color wheel — conic gradient spinner. */
.cm-wheel { width: 110px; height: 110px; border-radius: 50%; background: conic-gradient(from 0deg, #ef4444, #f59e0b, #eab308, #84cc16, #22c55e, #06b6d4, #3b82f6, #8b5cf6, #d946ef, #ef4444); box-shadow: 0 0 30px rgba(255,255,255,0.15) inset; }
.motion-creative-stage--color-wheel.is-playing .cm-wheel { animation: cm-wheel-spin 6s linear infinite; }
@keyframes cm-wheel-spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }

/* Lava lamp — 4 colored blobs that mix via blur+contrast. */
.cm-lava { position: absolute; inset: 0; filter: blur(8px) contrast(1.4); }
.cm-lava-blob { position: absolute; width: 60px; height: 60px; border-radius: 50%; opacity: 0.85; }
.cm-lava-blob--a { background: #ec4899; left: 20%; top: 20%; }
.cm-lava-blob--b { background: #8b5cf6; left: 55%; top: 30%; }
.cm-lava-blob--c { background: #f59e0b; left: 30%; top: 55%; }
.cm-lava-blob--d { background: #06b6d4; left: 60%; top: 60%; }
.motion-creative-stage--lava-lamp.is-playing .cm-lava-blob--a { animation: cm-lava-a 5s ease-in-out infinite; }
.motion-creative-stage--lava-lamp.is-playing .cm-lava-blob--b { animation: cm-lava-b 6s ease-in-out infinite; }
.motion-creative-stage--lava-lamp.is-playing .cm-lava-blob--c { animation: cm-lava-c 4.5s ease-in-out infinite; }
.motion-creative-stage--lava-lamp.is-playing .cm-lava-blob--d { animation: cm-lava-d 7s ease-in-out infinite; }
@keyframes cm-lava-a { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(30px,15px) scale(1.3); } }
@keyframes cm-lava-b { 0%,100% { transform: translate(0,0) scale(0.9); } 50% { transform: translate(-25px,20px) scale(1.2); } }
@keyframes cm-lava-c { 0%,100% { transform: translate(0,0) scale(1.1); } 50% { transform: translate(20px,-25px) scale(0.8); } }
@keyframes cm-lava-d { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(-30px,-15px) scale(1.4); } }

/* Confetti — 18 colored particles falling with rotation. */
.cm-confetti { position: absolute; inset: 0; }
.cm-confetti-piece { position: absolute; width: 8px; height: 14px; top: -10%; }
.cm-confetti-piece--0  { left: 5%;  background: #ef4444; }
.cm-confetti-piece--1  { left: 12%; background: #f59e0b; }
.cm-confetti-piece--2  { left: 20%; background: #eab308; }
.cm-confetti-piece--3  { left: 27%; background: #84cc16; }
.cm-confetti-piece--4  { left: 34%; background: #22c55e; }
.cm-confetti-piece--5  { left: 41%; background: #06b6d4; }
.cm-confetti-piece--6  { left: 48%; background: #3b82f6; }
.cm-confetti-piece--7  { left: 55%; background: #8b5cf6; }
.cm-confetti-piece--8  { left: 62%; background: #d946ef; }
.cm-confetti-piece--9  { left: 69%; background: #ec4899; }
.cm-confetti-piece--10 { left: 76%; background: #ef4444; }
.cm-confetti-piece--11 { left: 83%; background: #f59e0b; }
.cm-confetti-piece--12 { left: 90%; background: #22c55e; }
.cm-confetti-piece--13 { left: 8%;  background: #06b6d4; }
.cm-confetti-piece--14 { left: 30%; background: #d946ef; }
.cm-confetti-piece--15 { left: 50%; background: #84cc16; }
.cm-confetti-piece--16 { left: 70%; background: #8b5cf6; }
.cm-confetti-piece--17 { left: 95%; background: #ec4899; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece { animation: cm-confetti-fall 2400ms linear infinite; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--1  { animation-delay: 200ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--2  { animation-delay: 400ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--3  { animation-delay: 600ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--4  { animation-delay: 800ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--5  { animation-delay: 1000ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--6  { animation-delay: 100ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--7  { animation-delay: 300ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--8  { animation-delay: 500ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--9  { animation-delay: 700ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--10 { animation-delay: 900ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--11 { animation-delay: 150ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--12 { animation-delay: 350ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--13 { animation-delay: 550ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--14 { animation-delay: 750ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--15 { animation-delay: 250ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--16 { animation-delay: 450ms; }
.motion-creative-stage--confetti.is-playing .cm-confetti-piece--17 { animation-delay: 650ms; }
@keyframes cm-confetti-fall { 0% { transform: translateY(0) rotate(0); opacity: 1; } 100% { transform: translateY(180px) rotate(720deg); opacity: 0; } }

/* Equalizer — 12 colored bars dancing. */
.cm-eq { display: flex; align-items: flex-end; gap: 3px; height: 80%; padding: 8px 0; }
.cm-eq-bar { width: 8px; background: #06b6d4; border-radius: 2px 2px 0 0; height: 20%; }
.cm-eq-bar--0  { background: #ef4444; }
.cm-eq-bar--1  { background: #f59e0b; }
.cm-eq-bar--2  { background: #eab308; }
.cm-eq-bar--3  { background: #84cc16; }
.cm-eq-bar--4  { background: #22c55e; }
.cm-eq-bar--5  { background: #06b6d4; }
.cm-eq-bar--6  { background: #3b82f6; }
.cm-eq-bar--7  { background: #8b5cf6; }
.cm-eq-bar--8  { background: #d946ef; }
.cm-eq-bar--9  { background: #ec4899; }
.cm-eq-bar--10 { background: #ef4444; }
.cm-eq-bar--11 { background: #f59e0b; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar { animation: cm-eq-bounce 600ms ease-in-out infinite alternate; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--0  { animation-delay: 0ms; animation-duration: 480ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--1  { animation-delay: 80ms; animation-duration: 720ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--2  { animation-delay: 160ms; animation-duration: 540ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--3  { animation-delay: 60ms; animation-duration: 660ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--4  { animation-delay: 140ms; animation-duration: 600ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--5  { animation-delay: 100ms; animation-duration: 800ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--6  { animation-delay: 40ms; animation-duration: 520ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--7  { animation-delay: 180ms; animation-duration: 700ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--8  { animation-delay: 120ms; animation-duration: 580ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--9  { animation-delay: 20ms; animation-duration: 640ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--10 { animation-delay: 160ms; animation-duration: 760ms; }
.motion-creative-stage--equalizer.is-playing .cm-eq-bar--11 { animation-delay: 80ms; animation-duration: 540ms; }
@keyframes cm-eq-bounce { from { height: 15%; } to { height: 95%; } }

/* Glitch — RGB-split text oscillation. */
.cm-glitch { position: relative; font-family: var(--kds-font-mono); font-size: 44px; font-weight: 900; letter-spacing: 2px; color: #fff; }
.cm-glitch-base { position: relative; z-index: 1; color: #fff; }
.cm-glitch-layer { position: absolute; top: 0; left: 0; mix-blend-mode: screen; opacity: 0.85; }
.cm-glitch-layer--r { color: #ef4444; }
.cm-glitch-layer--g { color: #22c55e; }
.cm-glitch-layer--b { color: #3b82f6; }
.motion-creative-stage--glitch.is-playing .cm-glitch-layer--r { animation: cm-glitch-r 600ms steps(8) infinite; }
.motion-creative-stage--glitch.is-playing .cm-glitch-layer--g { animation: cm-glitch-g 700ms steps(9) infinite; }
.motion-creative-stage--glitch.is-playing .cm-glitch-layer--b { animation: cm-glitch-b 800ms steps(7) infinite; }
@keyframes cm-glitch-r { 0%,100% { transform: translate(0,0); } 25% { transform: translate(-3px,1px); } 50% { transform: translate(2px,-2px); } 75% { transform: translate(-2px,2px); } }
@keyframes cm-glitch-g { 0%,100% { transform: translate(0,0); } 33% { transform: translate(2px,-1px); } 66% { transform: translate(-1px,2px); } }
@keyframes cm-glitch-b { 0%,100% { transform: translate(0,0); } 40% { transform: translate(3px,2px); } 80% { transform: translate(-3px,-1px); } }

/* Neon ring — rotating conic border + dark core. */
.cm-neon { position: relative; width: 96px; height: 96px; }
.cm-neon-ring { position: absolute; inset: 0; border-radius: 50%; background: conic-gradient(from 0deg, #ef4444, #f59e0b, #84cc16, #06b6d4, #8b5cf6, #ec4899, #ef4444); filter: blur(6px); }
.cm-neon-core { position: absolute; inset: 8px; border-radius: 50%; background: #0a0a14; box-shadow: 0 0 20px rgba(255,255,255,0.1) inset; }
.motion-creative-stage--neon-ring.is-playing .cm-neon-ring { animation: cm-neon-spin 3s linear infinite; }
@keyframes cm-neon-spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }

/* Mosaic — 25 color cells flipping in stagger. */
.cm-mosaic { display: grid; grid-template-columns: repeat(5, 1fr); gap: 3px; width: 120px; height: 120px; }
.cm-mosaic-cell { background: #1e293b; border-radius: 2px; transform-style: preserve-3d; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell { animation: cm-mosaic-flip 3s cubic-bezier(0.2,0,0,1) infinite; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--0  { animation-delay: 0ms;  background: #ef4444; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--1  { animation-delay: 80ms; background: #f59e0b; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--2  { animation-delay: 160ms; background: #eab308; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--3  { animation-delay: 240ms; background: #84cc16; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--4  { animation-delay: 320ms; background: #22c55e; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--5  { animation-delay: 80ms;  background: #f59e0b; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--6  { animation-delay: 160ms; background: #eab308; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--7  { animation-delay: 240ms; background: #84cc16; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--8  { animation-delay: 320ms; background: #22c55e; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--9  { animation-delay: 400ms; background: #06b6d4; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--10 { animation-delay: 160ms; background: #eab308; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--11 { animation-delay: 240ms; background: #84cc16; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--12 { animation-delay: 320ms; background: #22c55e; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--13 { animation-delay: 400ms; background: #06b6d4; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--14 { animation-delay: 480ms; background: #3b82f6; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--15 { animation-delay: 240ms; background: #84cc16; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--16 { animation-delay: 320ms; background: #22c55e; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--17 { animation-delay: 400ms; background: #06b6d4; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--18 { animation-delay: 480ms; background: #3b82f6; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--19 { animation-delay: 560ms; background: #8b5cf6; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--20 { animation-delay: 320ms; background: #22c55e; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--21 { animation-delay: 400ms; background: #06b6d4; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--22 { animation-delay: 480ms; background: #3b82f6; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--23 { animation-delay: 560ms; background: #8b5cf6; }
.motion-creative-stage--mosaic.is-playing .cm-mosaic-cell--24 { animation-delay: 640ms; background: #ec4899; }
@keyframes cm-mosaic-flip {
  0%, 100% { transform: rotateY(0); opacity: 1; }
  40%      { transform: rotateY(180deg); opacity: 0.6; }
  60%      { transform: rotateY(180deg); opacity: 0.6; }
}

@media (prefers-reduced-motion: reduce) {
  .motion-creative-stage * { animation: none !important; }
}

.motion-reduced-pane header h3 { margin: 0 0 8px; font-size: 14px; }
.motion-reduced-stage {
  background: var(--kdr-surface-2);
  border-radius: 6px;
  height: 100px;
  display: grid;
  place-items: center;
  position: relative;
}
.motion-reduced-ball {
  display: block;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--kdr-accent);
}
.motion-reduced-ball--anim { animation: motion-reduced-pulse 600ms ease-in-out infinite alternate; }
@keyframes motion-reduced-pulse {
  from { transform: scale(0.7); opacity: 0.6; }
  to   { transform: scale(1.15); opacity: 1; }
}
/* The "still" pane is deliberately not animated — illustrates the
   reduced-motion fallback contract regardless of OS preference. */

.motion-easing-use,
.motion-duration-use,
.motion-transition-use {
  margin: 0;
  font-size: 13px;
  color: var(--kdr-text-muted);
}

/* ── Tools index grid (2026-05-16) ───────────────────────────────
   Card grid for /tools/ — was rendering as inline links because the
   templ classes had no CSS counterpart. */

.tools-index-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
  margin: 24px 0 32px;
}

.tools-index-card {
  display: grid;
  grid-template-columns: 40px 1fr 20px;
  align-items: center;
  gap: 14px;
  padding: 16px 18px;
  background: var(--kdr-surface);
  border: 1px solid var(--kdr-border);
  border-radius: var(--kdr-radius-md);
  color: var(--kdr-text);
  text-decoration: none;
  transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
}

.tools-index-card:hover {
  border-color: var(--kdr-accent);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
}

.tools-index-card:focus-visible {
  outline: 2px solid var(--kdr-accent);
  outline-offset: 2px;
}

.tools-index-card-glyph {
  font-size: 24px;
  line-height: 1;
  color: var(--kdr-accent);
  text-align: center;
}

.tools-index-card-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.tools-index-card-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--kdr-text);
}

.tools-index-card-lede {
  font-size: 13px;
  line-height: 1.4;
  color: var(--kdr-text-muted);
}

.tools-index-card-arrow {
  font-size: 18px;
  color: var(--kdr-text-muted);
  transition: transform 120ms ease, color 120ms ease;
}

.tools-index-card:hover .tools-index-card-arrow {
  color: var(--kdr-accent);
  transform: translateX(2px);
}

.tools-index-note {
  margin-top: 32px;
  padding: 16px 18px;
  background: var(--kdr-surface-2);
  border-left: 3px solid var(--kdr-accent);
  border-radius: var(--kdr-radius-sm);
}

.tools-index-note h2 {
  margin: 0 0 6px;
  font-size: 14px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--kdr-text-muted);
}

.tools-index-note p {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
}


/* Command palette demo (#001 — visual mock for /components/command-palette).
   Mimics the dialog look without binding Ctrl+K — the live <koder-embed>
   wraps this and the real KoderCommandPalette is exercised by visitors. */
.demo-palette {
  padding: 0;
  overflow: hidden;
}
.demo-palette-search {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--kdr-border);
  font-size: 15px;
  color: var(--kdr-text-muted);
}
.demo-palette-shortcut {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  padding: 2px 6px;
  border: 1px solid var(--kdr-border);
  border-radius: 4px;
  color: var(--kdr-text);
}
.demo-palette-input {
  flex: 1;
}
.demo-palette-list {
  list-style: none;
  margin: 0;
  padding: 8px 0;
}
.demo-palette-list li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 8px 16px;
  font-size: 14px;
}
.demo-palette-list li:hover {
  background: var(--kdr-surface-2);
}
.demo-palette-cat {
  color: var(--kdr-accent);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.demo-palette-acc {
  margin-left: auto;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--kdr-text-muted);
}

/* #027 — skip-to-content a11y link (WCAG 2.4.1). Visually hidden until
   focused; becomes visible at the top-left corner when keyboard users
   Tab into the page, lets them bypass the sidebar nav. */
.skip-to-content {
  position: absolute;
  top: 0;
  left: 0;
  padding: 12px 16px;
  background: var(--kdr-accent);
  color: var(--kdr-accent-on);
  font-weight: 600;
  text-decoration: none;
  border-radius: 0 0 8px 0;
  transform: translateY(-100%);
  transition: transform var(--kds-motion-duration-fast, 150ms) var(--kds-motion-easing-standard, ease);
  z-index: 1000;
}
.skip-to-content:focus {
  transform: translateY(0);
  outline: 2px solid var(--kdr-focus);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .skip-to-content { transition: none; }
}

/* ============================================================
 * Ticket #052 — Materials: acrylic + mica translucent surface
 * tokens. Provides backdrop-blur surfaces for floating UI
 * (acrylic) and window-chrome backgrounds (mica). @supports
 * gates the live blur; fallback emits opaque tinted color.
 * Spec: meta/docs/stack/specs/themes/materials.kmd
 * ============================================================ */

:root {
  /* Mica — window-chrome background. Subtle desaturated tint. */
  --kds-material-mica-bg: color-mix(in srgb, var(--kdr-surface) 70%, var(--kdr-accent) 6%);
  /* Acrylic — floating-surface translucent. */
  --kds-material-acrylic-bg: color-mix(in srgb, var(--kdr-surface) 50%, transparent);
  --kds-material-acrylic-blur: 24px;
  --kds-material-acrylic-saturation: 1.4;
}
:root[data-theme="light"] {
  --kds-material-mica-bg: color-mix(in srgb, var(--kdr-surface) 80%, var(--kdr-accent) 4%);
  --kds-material-acrylic-bg: color-mix(in srgb, var(--kdr-surface) 65%, transparent);
}

.kds-material-mica {
  background: var(--kds-material-mica-bg);
}
.kds-material-acrylic {
  background: var(--kds-material-acrylic-bg);
  border: 1px solid color-mix(in srgb, var(--kdr-text) 12%, transparent);
}
@supports (backdrop-filter: blur(1px)) {
  .kds-material-acrylic {
    backdrop-filter: blur(var(--kds-material-acrylic-blur)) saturate(var(--kds-material-acrylic-saturation));
    -webkit-backdrop-filter: blur(var(--kds-material-acrylic-blur)) saturate(var(--kds-material-acrylic-saturation));
  }
}

/* ============================================================
 * Ticket #053 — Reveal effect. Cursor-tracking radial highlight.
 * --kds-reveal-x / --kds-reveal-y are updated by initReveal()
 * in page-enhance.js. Pointer-tracking on hover; no-op for
 * keyboard users + reduced-motion respects the media query.
 * ============================================================ */
.kds-reveal {
  position: relative;
  isolation: isolate;
}
.kds-reveal::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(
    circle at var(--kds-reveal-x, -100px) var(--kds-reveal-y, -100px),
    color-mix(in srgb, var(--kdr-accent) 28%, transparent) 0%,
    transparent 60%
  );
  opacity: 0;
  transition: opacity 200ms ease;
  z-index: -1;
}
.kds-reveal:hover::before { opacity: 1; }
.kds-reveal:focus-visible::before {
  opacity: 1;
  background: radial-gradient(
    circle at 50% 50%,
    color-mix(in srgb, var(--kdr-accent) 22%, transparent) 0%,
    transparent 70%
  );
}
@media (prefers-reduced-motion: reduce) {
  .kds-reveal::before { transition: none; }
}

/* Demo section "Interaction surface effects" on /motion/ */
.motion-reveal-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 12px;
  margin: 16px 0 24px;
}
.motion-reveal-tile {
  appearance: none;
  border: 1px solid var(--kdr-border);
  background: var(--kdr-surface);
  color: var(--kdr-text);
  padding: 32px 16px;
  border-radius: 12px;
  font-size: 14px;
  cursor: pointer;
  text-align: center;
}

/* ─── Typography reference page (#057) ─────────────────────────── */
.typography-role-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
  margin: 16px 0 24px;
}
.typography-role-card {
  border: 1px solid var(--kdr-border);
  border-radius: 14px;
  padding: 18px 20px;
  background: var(--kdr-surface);
}
.typography-role-card h3 {
  margin: 0 0 4px;
  font-size: 20px;
  font-family: var(--kds-font-mono, monospace);
}
.typography-role-purpose {
  margin: 0 0 10px;
  color: var(--kdr-text-muted);
  font-size: 13px;
  line-height: 1.5;
}
.typography-role-card .meta {
  margin: 0 0 12px;
  font-size: 12px;
  color: var(--kdr-text-muted);
}
.typography-role-sample {
  font-size: 22px;
  line-height: 1.4;
  margin: 0;
  padding: 12px 14px;
  background: color-mix(in srgb, var(--kdr-accent) 6%, var(--kdr-surface));
  border-radius: 10px;
}

.typography-weight-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
  margin: 16px 0 24px;
}
.typography-weight-card {
  border: 1px solid var(--kdr-border);
  border-radius: 14px;
  padding: 16px 18px;
  background: var(--kdr-surface);
}
.typography-weight-card h3 {
  margin: 0 0 10px;
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--kdr-text-muted);
  font-family: var(--kds-font-mono, monospace);
}
.typography-weight-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 10px;
}
.typography-weight-list li {
  display: grid;
  grid-template-columns: 48px 1fr;
  align-items: baseline;
  gap: 12px;
}
.typography-weight-label {
  font-family: var(--kds-font-mono, monospace);
  font-size: 12px;
  color: var(--kdr-text-muted);
}
.typography-weight-sample {
  font-size: 18px;
}

.typography-scale-list {
  display: grid;
  gap: 6px;
  margin: 16px 0 24px;
}
.typography-scale-row {
  display: grid;
  grid-template-columns: 64px 96px 1fr auto;
  gap: 16px;
  align-items: baseline;
  padding: 10px 14px;
  border-bottom: 1px solid var(--kdr-border);
}
.typography-scale-size {
  font-family: var(--kds-font-mono, monospace);
  font-size: 13px;
  color: var(--kdr-accent);
}
.typography-scale-label {
  font-size: 12px;
  color: var(--kdr-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.typography-scale-sample {
  font-family: var(--kds-font-sans);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.typography-scale-lh {
  font-size: 11px;
  color: var(--kdr-text-muted);
}
@media (max-width: 720px) {
  .typography-scale-row {
    grid-template-columns: 64px 1fr;
    grid-template-rows: auto auto;
  }
  .typography-scale-label { grid-column: 2; }
  .typography-scale-sample { grid-column: 1 / -1; }
  .typography-scale-lh { grid-column: 1 / -1; }
}

.typography-tests-table {
  width: 100%;
  border-collapse: collapse;
  margin: 12px 0 24px;
  font-size: 14px;
}
.typography-tests-table th,
.typography-tests-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--kdr-border);
  vertical-align: top;
}
.typography-tests-table th {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--kdr-text-muted);
}
.typography-tests-table td:first-child {
  width: 56px;
}

/* ─── Density modes (#054) ─────────────────────────────────────── */
/* Spec: meta/docs/stack/specs/themes/density.kmd.
   data-density on <html> picks the rhythm. Compact = -20%, default = 0,
   comfortable = +20%. Tokens read through --kds-density-scale so any
   space/min-height computed with calc() automatically respects the mode.
   Typography sizes stay constant (per spec § R2). */
:root {
  --kds-density-scale: 1;
  --kds-density-scale-line: 1;
  --kds-space-xs: calc(4px  * var(--kds-density-scale));
  --kds-space-sm: calc(8px  * var(--kds-density-scale));
  --kds-space-md: calc(12px * var(--kds-density-scale));
  --kds-space-lg: calc(16px * var(--kds-density-scale));
  --kds-space-xl: calc(24px * var(--kds-density-scale));
  --kds-density-control-min-h: calc(40px * var(--kds-density-scale));
  --kds-density-button-pad-y:  calc(8px  * var(--kds-density-scale));
  --kds-density-row-pad-y:     calc(8px  * var(--kds-density-scale));
  --kds-density-line-tight:    calc(1.4  * var(--kds-density-scale-line));
}
[data-density="compact"] {
  --kds-density-scale: 0.8;
  --kds-density-scale-line: 0.95;
}
[data-density="comfortable"] {
  --kds-density-scale: 1.2;
  --kds-density-scale-line: 1.05;
}
/* R3 — touch floor: coarse pointers always get comfortable rhythm so a
   compact desktop surface viewed on a tablet stays WCAG 2.2 touch-target
   compliant (≥ 44 px). */
@media (pointer: coarse) {
  [data-density="compact"] {
    --kds-density-scale: 1.2;
    --kds-density-scale-line: 1.05;
  }
}

/* Settings drawer — 3-segment density control. Visual parity with
   the existing 2-button theme group above it. */
.koder-settings-densities {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.koder-settings-densities button {
  appearance: none;
  border: 1px solid var(--kdr-border);
  background: var(--kdr-surface);
  color: var(--kdr-text);
  padding: 8px 10px;
  border-radius: 8px;
  font-size: 13px;
  cursor: pointer;
}
.koder-settings-densities button[aria-pressed="true"] {
  background: var(--kdr-accent);
  border-color: var(--kdr-accent);
  color: var(--kdr-bg);
}

/* Density preview row used on /verge/ — 3 columns showing the same
   button trio rendered at each density. Each column scopes its own
   density via data-density so the live cascade is visible side by side. */
.kds-density-preview-row {
  display: grid;
  /* #124 (2026-05-24): base = 1 column for <640px. The three-way
     comparison is the whole point of this widget — at narrow
     viewports stack vertically so each density gets a comfortable
     full-width preview rather than squeezing all three into
     ~90-120dp columns where the buttons start wrapping. */
  grid-template-columns: 1fr;
  gap: 16px;
  margin: 16px 0 24px;
  /* #125 (2026-05-24) — Option B ratified by owner. Cap the row at
     a body reading-column width so the cards visually align with
     the surrounding prose flow instead of bleeding to main.page's
     full content area (which on wide monitors lands cards spanning
     1700+px while paragraphs read narrow, producing visible
     asymmetry). Floor matches .lede's 720px; cap raised slightly
     to 1040px to give the 3 cards comfortable breathing at wide
     viewports without crossing into "design specimen" territory.
     `margin-inline: 0` left-anchors to align with prose left edge,
     so the row reads as an inline comparison widget rather than
     a centered hero. At narrow viewports the cap is academic —
     the grid is already 1-col and constrained by the parent. */
  max-width: clamp(720px, 80%, 1040px);
  margin-inline: 0;
}
@media (min-width: 640px) { /* #124 (2026-05-24): canonical sm — restore side-by-side at tablet+ */
  .kds-density-preview-row {
    grid-template-columns: repeat(3, 1fr);
  }
}
.kds-density-preview-col {
  border: 1px solid var(--kdr-border);
  border-radius: 12px;
  padding: 14px;
  background: var(--kdr-surface);
}
.kds-density-preview-col h4 {
  margin: 0 0 var(--kds-space-sm);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--kdr-text-muted);
}
.kds-density-preview-col .kds-density-preview-buttons {
  display: flex;
  gap: var(--kds-space-sm);
}
.kds-density-preview-col .kds-density-preview-buttons button {
  appearance: none;
  border: 1px solid var(--kdr-border);
  background: var(--kdr-surface);
  color: var(--kdr-text);
  border-radius: 8px;
  padding-block: var(--kds-density-button-pad-y);
  padding-inline: var(--kds-space-md);
  min-height: var(--kds-density-control-min-h);
  font-size: 14px;
  cursor: pointer;
}
.kds-density-preview-col .kds-density-preview-buttons button.primary {
  background: var(--kdr-accent);
  border-color: var(--kdr-accent);
  color: var(--kdr-bg);
}

/* ---------------------------------------------------------------- *
 * #062 — Accessibility theme modes (specs/themes/a11y-modes.kmd)
 *
 * Two opt-in modes that compose with light/dark via the
 * [data-a11y-mode] attribute:
 *   - color-blind  → deuteranopia-safe palette swap (semantic
 *                    status tokens; gated on Verge ratification of
 *                    --kdr-success / --kdr-danger / --kdr-warning).
 *   - low-vision   → +20% text, +AAA contrast intent.
 *
 * v0 ships the SELECTORS only — palette swaps for semantic status
 * tokens are intentionally absent until those tokens land in
 * internal/kinds/verge.go. Text-scaling (--kdr-fs-base) ships now.
 * ---------------------------------------------------------------- */

/* Color-blind mode — palette swap (deuteranopia-safe). v0: gated on
   semantic token ratification; selector ships so products can begin
   wiring the toggle even if visual deltas land in a follow-up. */
[data-a11y-mode="color-blind"] {
  /* Forward-declare future tokens; consumers SHOULD NOT rely on these
     until Verge ratifies them in v0.1+. */
  --kdr-success: #2563eb;  /* blue (was green) */
  --kdr-danger:  #ea7c34;  /* orange (was red) */
  --kdr-warning: #a855f7;  /* violet (was amber) */
}
:root[data-theme="dark"] [data-a11y-mode="color-blind"],
[data-a11y-mode="color-blind"][data-theme="dark"] {
  --kdr-success: #60a5fa;
  --kdr-danger:  #f59e0b;
  --kdr-warning: #c084fc;
}

/* Low-vision mode — +20% base text size + line-height bump. Ships
   immediately; --kdr-fs-base already exists in Verge v0. */
[data-a11y-mode="low-vision"] {
  --kdr-fs-base: 19px;
  --kdr-line-height: 1.6;
  --kdr-font-weight-min: 500;
}


/* -----------------------------------------------------------------
 * Inline motion clips (.kds-motion-clip) — ticket #051 (2026-05-22).
 *
 * Pairs with @inlineMotionVideo() in internal/kinds/inline_motion_video.templ.
 * The <video> shows by default; the <img> poster is hidden. When
 * `prefers-reduced-motion: reduce` matches, the cascade flips:
 * <video> hides, <img> shows. Toggle button is sticky in the bottom-
 * right of the clip frame.
 * --------------------------------------------------------------- */
.kds-motion-clip {
  position: relative;
  display: inline-block;
  margin: 0;
  border-radius: var(--kdr-radius-md, 8px);
  overflow: hidden;
  background: var(--kdr-surface-2, #f3f4f6);
}
.kds-motion-clip__video,
.kds-motion-clip__poster {
  display: block;
  width: 100%;
  height: auto;
  border: 0;
}
.kds-motion-clip__poster { display: none; }
.kds-motion-clip[data-paused="true"] .kds-motion-clip__video  { display: none; }
.kds-motion-clip[data-paused="true"] .kds-motion-clip__poster { display: block; }

.kds-motion-clip__toggle {
  position: absolute;
  right: 6px;
  bottom: 6px;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 150ms cubic-bezier(0.2, 0, 0, 1);
}
.kds-motion-clip:hover .kds-motion-clip__toggle,
.kds-motion-clip:focus-within .kds-motion-clip__toggle { opacity: 1; }
.kds-motion-clip__icon-pause { display: inline; }
.kds-motion-clip__icon-play  { display: none; }
.kds-motion-clip[data-paused="true"] .kds-motion-clip__icon-pause { display: none; }
.kds-motion-clip[data-paused="true"] .kds-motion-clip__icon-play  { display: inline; }

@media (prefers-reduced-motion: reduce) {
  .kds-motion-clip .kds-motion-clip__video  { display: none; }
  .kds-motion-clip .kds-motion-clip__poster { display: block; }
  .kds-motion-clip .kds-motion-clip__toggle { display: none; }
}

/* -----------------------------------------------------------------
 * Personas grid (.kds-persona-*) — ticket #100 (2026-05-22).
 * Renders the 8 inclusive-design personas defined in
 * meta/docs/stack/specs/accessibility/personas.kmd § R2.
 * Card layout is content-grid; per-axis tint comes from accent
 * tokens to keep dark/light mode coherent.
 * --------------------------------------------------------------- */
.kds-persona-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
  margin: 16px 0 32px;
}
.kds-persona-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  border: 1px solid var(--kdr-border, #d1d5db);
  border-radius: var(--kdr-radius-md, 8px);
  background: var(--kdr-surface, #fff);
}
.kds-persona-card__header {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  font-size: 13px;
}
.kds-persona-card__code {
  font-weight: 700;
  font-family: var(--kds-font-mono, ui-monospace, monospace);
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--kdr-accent, #2563eb);
  color: #fff;
}
.kds-persona-card__axis,
.kds-persona-card__permanence {
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--kdr-surface-2, #f3f4f6);
  color: var(--kdr-text, #111);
}
.kds-persona-card__title { margin: 4px 0 0; font-size: 16px; }
.kds-persona-card__placeholder {
  margin: 0;
  padding: 8px;
  background: var(--kdr-warning-soft, #fef3c7);
  color: var(--kdr-warning-strong, #92400e);
  border-radius: 4px;
  font-size: 13px;
  font-style: italic;
}
.kds-persona-card__details { margin: 0; font-size: 14px; }
.kds-persona-card__details dt { font-weight: 600; margin-top: 8px; }
.kds-persona-card__details dd { margin: 4px 0 0; }

/* -----------------------------------------------------------------
 * Sound swatches (.kds-sound-*) — ticket #101 (2026-05-22).
 * Renders the canonical 8-cue Koder Sound vocabulary defined in
 * meta/docs/stack/specs/sound/vocabulary.kmd § R1. Click-to-play
 * wires through KoderSound.play() loaded from sound-cues.js.
 * --------------------------------------------------------------- */
.kds-sound-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin: 16px 0 32px;
}
.kds-sound-swatch {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px;
  border: 1px solid var(--kdr-border, #d1d5db);
  border-radius: var(--kdr-radius-md, 8px);
  background: var(--kdr-surface, #fff);
}
.kds-sound-swatch__header {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  align-items: center;
  font-size: 12px;
  color: var(--kdr-text-secondary, #4b5563);
}
.kds-sound-swatch__id {
  font-family: var(--kds-font-mono, ui-monospace, monospace);
  font-weight: 700;
  background: var(--kdr-surface-2, #f3f4f6);
  padding: 1px 6px;
  border-radius: 4px;
  color: var(--kdr-text, #111);
}
.kds-sound-swatch__default { font-weight: 600; }
.kds-sound-swatch__duration { font-variant-numeric: tabular-nums; }
.kds-sound-swatch__name { margin: 4px 0 0; font-size: 15px; }
.kds-sound-swatch__pair { margin: 0; font-size: 13px; color: var(--kdr-text-secondary, #4b5563); }
.kds-sound-swatch__play {
  align-self: flex-start;
  margin-top: 8px;
  padding: 6px 12px;
  border: 1px solid var(--kdr-border, #d1d5db);
  border-radius: 999px;
  background: var(--kdr-accent, #2563eb);
  color: #fff;
  font-size: 13px;
  cursor: pointer;
}
.kds-sound-swatch__play:hover  { filter: brightness(1.05); }
.kds-sound-swatch__play:active { transform: translateY(1px); }

.kds-sound-settings {
  display: grid;
  gap: 12px;
  margin: 16px 0;
  padding: 16px;
  border: 1px solid var(--kdr-border, #d1d5db);
  border-radius: var(--kdr-radius-md, 8px);
  background: var(--kdr-surface-2, #f3f4f6);
  max-width: 480px;
}
.kds-sound-settings__row {
  display: flex;
  gap: 12px;
  align-items: center;
}
.kds-sound-settings__row input[type="range"] { flex: 1; }
