/* === src/css/scratch-tokens.css === */
/* ============================================================
 * SCRATCH TOKENS — Scratch Proto design tokens
 *
 * The themable contract of the design language, and the ONLY
 * file an app needs to import to adopt it. Custom properties
 * inherit through shadow DOM, so this one :root block themes
 * every scratch-* component; each component also bakes in
 * var(..., fallback) defaults, so a missing token degrades
 * gracefully instead of breaking.
 *
 * Split out of scratch-proto.css (which keeps the demo pages'
 * reset + style-guide scaffolding). Token values are canon —
 * change them here, nowhere else.
 * ============================================================ */

:root {
  /* --- Surfaces ---
     bg-deep/bg are opaque (the substrate everything composites onto).
     The raised surfaces are --text-bright at low alpha, so they read as
     translucent tints and let the dot-grid / layering show through. */
  --bg-deep:       #08090c;
  --bg:            #0d0f14;
  --bg-surface:    color-mix(in srgb, var(--text-bright) 3%, transparent);
  --bg-elevated:   color-mix(in srgb, var(--text-bright) 6%, transparent);
  --bg-hover:      color-mix(in srgb, var(--text-bright) 10%, transparent);

  /* --- Text --- */
  --text:          #c8cdd8;
  --text-bright:   #e8ecf4;
  --text-muted:    #6b7280;
  --text-disabled: #565b69;

  /* --- Accent: Amber / Caution (primary; LOCKED) ---
     --accent is 100% saturation + 100% value (HSV). Each *-dim is the SAME
     color at 50% alpha — full saturation preserved, only opacity reduced, so
     dims are vivid translucent tints. --accent-hover drops saturation for a
     white-tinted lift. */
  --accent:        #ffae00;
  --accent-dim:    color-mix(in srgb, var(--accent) 50%, transparent);
  --accent-glow:   rgba(255, 174, 0, 0.12);
  --accent-hover:  #ffc64d;

  /* --- Secondary: Signal green (success / live) --- */
  --signal:        #00e47a;
  --signal-dim:    color-mix(in srgb, var(--signal) 50%, transparent);
  --signal-glow:   rgba(0, 228, 122, 0.08);

  /* --- Borders --- */
  --border:        #2a2e3a;
  --border-light:  #1e222c;
  --border-dashed: rgba(51, 56, 68, 0.67);   /* #333844 @ 0.67 — softened dividers + disabled border */

  /* --- Danger (error / destructive) --- */
  --danger:        #ff4444;
  --danger-dim:    color-mix(in srgb, var(--danger) 50%, transparent);
  --danger-glow:   rgba(255, 68, 68, 0.10);
  --warning:       var(--accent);

  /* --- Grid substrate --- */
  --grid-dot:      rgba(200, 205, 216, 0.08);
  --grid-size:     24px;

  /* --- Scanline overlay (alpha tweakable; 0 = off) --- */
  --scanline-alpha: 0.03;
  --scanline: repeating-linear-gradient(
    to bottom,
    transparent 0px,
    transparent 2px,
    rgba(0, 0, 0, var(--scanline-alpha)) 2px,
    rgba(0, 0, 0, var(--scanline-alpha)) 4px
  );

  /* --- Typography --- */
  --font-mono:     'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', ui-monospace, monospace;
  --font-display:  'Space Grotesk', 'JetBrains Mono', monospace;
  --font-body:     'Quantico', 'Segoe UI', system-ui, sans-serif;  /* reading text */

  /* --- Type scale --- */
  --fs-micro:  10px;   /* labels, badges, build-stamp */
  --fs-tiny:   11px;   /* meta, captions */
  --fs-small:  12px;   /* secondary body, descriptions */
  --fs-body:   14px;   /* base */
  --fs-lg:     16px;   /* sidebar title */
  --fs-h3:     1.1rem;
  --fs-h2:     1.5rem;
  --fs-h1:     1.75rem;

  /* --- Spacing scale (NEW — neither repo had one) --- */
  --sp-1:  4px;
  --sp-2:  8px;
  --sp-3:  12px;
  --sp-4:  16px;
  --sp-5:  24px;
  --sp-6:  32px;
  --sp-7:  48px;
  --sp-8:  64px;

  /* --- Applied spacing: component padding & gaps (tweakable · Density) ---
     Components reference THESE, not raw px, so padding/margins are iterable
     from one place. Defaults sit on the 4-based scale. */
  --pad-control-y: 8px;    /* buttons, inputs, tabs — vertical */
  --pad-control-x: 12px;   /* buttons, inputs, tabs — horizontal */
  --pad-card:      18px;   /* cards, list items, modal rows */
  --gap-stack:     8px;    /* vertical gap inside stacks */

  /* --- Radius: SQUARE by default. The system is hard-edged; the only
     rounded elements are true pills / dots (--r-pill). --- */
  --r-base:  0;
  --r-sm:    0;
  --r-md:    0;
  --r-lg:    0;
  --r-pill:  999px;

  /* --- Motion --- */
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);   /* the ONLY easing curve in the system */
  --dur-fast:    0.09s;   /* 25% faster than the original 0.12 / 0.15 / 0.25 */
  --dur:         0.11s;
  --dur-slow:    0.19s;

  /* --- Elevation --- */
  --shadow-pop: 0 2px 12px rgba(0, 0, 0, 0.4);
  --shadow-modal: 0 18px 50px rgba(0, 0, 0, 0.55);
}

/* === src/components/scratch-badge/scratch-badge.css (scoped to scratch-badge) === */
:host(scratch-badge) { display: inline-flex; vertical-align: middle; }
/* Every variant is the same chip; a variant carries COLOUR, nothing else.
   Keeping the geometry here is what stops the tiers drifting apart as the
   family grows. "key" is the one shape exception and says so. */:host(scratch-badge) .box {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono, "JetBrains Mono", monospace);
  user-select: none;
  box-sizing: border-box;
  font-size: var(--fs-micro, 10px);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border: 1px solid transparent;
  border-radius: var(--r-sm, 0);
  padding: 5px 9px;
  line-height: 1;
}
/* proto (default) — the prototype tag: amber chip + status LED.
   accent is the same chip WITHOUT the dot, for labelling a thing rather than
   reporting a state (a static amber LED already means "stale"). */:host(scratch-badge:not([variant])) .box, :host(scratch-badge[variant="proto"]) .box, :host(scratch-badge[variant="accent"]) .box {
  color: var(--accent, #ffae00);
  background: var(--accent-glow, rgba(255,174,0,0.12));
  border-color: var(--accent-dim, #7d6939);
}
/* signal — the success/kept chip */:host(scratch-badge[variant="signal"]) .box {
  color: var(--signal, #00e47a);
  background: var(--signal-glow, rgba(0,228,122,0.08));
  border-color: var(--signal-dim, #00b25f);
}
/* off — neutral DIM chip: the disabled/inactive tag. Dashed border (the
   system's disabled signal), muted text, no fill, no LED. */:host(scratch-badge[variant="off"]) .box {
  color: var(--text-muted, #6b7280);
  background: none;
  border: 1px dashed var(--border-dashed, #333844);
}
/* key — plain neutral tag; the one variant with its own metrics */:host(scratch-badge[variant="key"]) .box {
  font-size: 9px;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--text-muted, #6b7280);
  background: var(--bg-elevated, #181c26);
  border-color: var(--border, #2a2e3a);
  padding: 4px 6px;
}
/* the LED only renders for proto */:host(scratch-badge) scratch-led { display: none; }:host(scratch-badge:not([variant])) scratch-led, :host(scratch-badge[variant="proto"]) scratch-led { display: inline-block; }

/* === src/components/scratch-button/scratch-button.css (scoped to scratch-button) === */
:host(scratch-button) {
  display: inline-flex;
  position: relative;
  vertical-align: middle;
  /* typographic props live here so the slotted label inherits them */
  font-family: var(--font-mono, "JetBrains Mono", "SF Mono", monospace);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--btn-fg);
  /* default (neutral) variant colors */
  --btn-fg: var(--text, #c8cdd8);
  --btn-edge: var(--border, #2a2e3a);
  --btn-tint: var(--bg-elevated, #181c26);
}:host(scratch-button[variant="accent"]) {
  --btn-fg: var(--accent, #ffae00);
  --btn-edge: var(--accent-dim, #7d6939);
  --btn-tint: var(--accent-glow, rgba(255, 174, 0, 0.12));
}:host(scratch-button[variant="danger"]) {
  --btn-fg: var(--danger, #ff4444);
  --btn-edge: var(--danger, #ff4444);
  --btn-tint: var(--danger-glow, rgba(255, 68, 68, 0.10));
}:host(scratch-button) button {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  position: relative;
  cursor: pointer;
  padding: var(--pad-control-y, 8px) var(--pad-control-x, 12px);
  background: var(--btn-tint);
  border: 1px solid var(--btn-edge);
  border-radius: var(--r-md, 0);
  /* corner-mark color = the button's own edge, brightened */
  --corner: color-mix(in srgb, var(--btn-edge), white 18%);
  transition: background-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), border-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)),
              color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), transform var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)),
              box-shadow 250ms var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}

/* Registration corner-marks — the interactive-surface cue, sealed in. */:host(scratch-button) button::before, :host(scratch-button) button::after {
  content: '';
  position: absolute;
  width: 5px; height: 5px;
  border-color: var(--corner);
  border-style: solid;
  pointer-events: none;
  transition: border-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-button) button::before { top: 3px; left: 3px; border-width: 1px 0 0 1px; }:host(scratch-button) button::after { bottom: 3px; right: 3px; border-width: 0 1px 1px 0; }

/* Hover — neutral lightens; colored variants fill. */:host(scratch-button) button:hover { background: var(--bg-hover, #1e2330); border-color: var(--text-muted, #6b7280); }:host(scratch-button:hover) { color: var(--text-bright, #e8ecf4); }:host(scratch-button) button:hover::before, :host(scratch-button) button:hover::after { border-color: var(--accent-dim, #7d6939); }:host(scratch-button[variant="accent"]:hover) button, :host(scratch-button[variant="danger"]:hover) button {
  background: var(--btn-fg);
  border-color: var(--btn-fg);
}:host(scratch-button[variant="accent"]:hover), :host(scratch-button[variant="danger"]:hover) { color: var(--bg-deep, #08090c); }:host(scratch-button[variant="accent"]:hover) button::before, :host(scratch-button[variant="accent"]:hover) button::after, :host(scratch-button[variant="danger"]:hover) button::before, :host(scratch-button[variant="danger"]:hover) button::after {
  border-color: var(--bg-deep, #08090c);
}:host(scratch-button) button:focus-visible { outline: 2px solid var(--accent, #ffae00); outline-offset: 2px; box-shadow: 0 0 18px color-mix(in srgb, var(--accent, #ffae00) 38%, transparent); }

/* Link variant — inline text link, no box, no brackets. */:host(scratch-button[variant="link"]) { text-transform: none; letter-spacing: normal; font-weight: 400;
  font-size: var(--fs-small, 12px); color: var(--accent, #ffae00); }:host(scratch-button[variant="link"]) button {
  background: none; border: none; padding: 0; text-decoration: underline;
}:host(scratch-button[variant="link"]) button::before, :host(scratch-button[variant="link"]) button::after { display: none; }:host(scratch-button[variant="link"]) button:hover { background: none; color: var(--accent-hover, #ffc64d); }:host(scratch-button[variant="link"]:hover) { color: var(--accent-hover, #ffc64d); }

/* Ghost variant — the quiet borderless tier (icon/text micro-actions).
   No box, no corner-marks, no ring burst: muted at rest, bright on hover
   over a faint wash. */:host(scratch-button[variant="ghost"]) { --btn-fg: var(--text-muted, #6b7280); }:host(scratch-button[variant="ghost"]) button { background: none; border: none; }:host(scratch-button[variant="ghost"]) button::before, :host(scratch-button[variant="ghost"]) button::after { display: none; }:host(scratch-button[variant="ghost"]) button:hover { background: var(--bg-hover, #1e2330); }
/* disabled ghost: dimmed only — no dashed box, no dither (there's no box) */:host(scratch-button[variant="ghost"][disabled]) {
  opacity: 0.45;
  -webkit-mask-image: none;
          mask-image: none;
}:host(scratch-button[variant="ghost"][disabled]) button { border: none; }

/* Disabled — dashed border (the system's disabled signal) + dithered out
   with a 2×2px checkerboard. Squares alternate between 75% and 25%
   visibility (a soft screen, not hard holes). No corner-marks: those signal
   an interactive surface, and a disabled button isn't clickable. */:host(scratch-button[disabled]) button { border-style: dashed; }:host(scratch-button[disabled]) button::before, :host(scratch-button[disabled]) button::after { display: none; }:host(scratch-button[disabled]) {
  pointer-events: none;
  -webkit-mask-image: conic-gradient(rgba(0,0,0,0.75) 90deg, rgba(0,0,0,0.25) 0 180deg, rgba(0,0,0,0.75) 0 270deg, rgba(0,0,0,0.25) 0);
          mask-image: conic-gradient(rgba(0,0,0,0.75) 90deg, rgba(0,0,0,0.25) 0 180deg, rgba(0,0,0,0.75) 0 270deg, rgba(0,0,0,0.25) 0);
  -webkit-mask-size: 4px 4px;
          mask-size: 4px 4px;
}

/* === src/components/scratch-card/scratch-card.css (scoped to scratch-card) === */
:host(scratch-card) { display: block; }:host(scratch-card) .card {
  display: block; position: relative;
  background-color: var(--bg-surface, #12151c);
  background-image: var(--scanline, none);
  background-attachment: fixed;
  border: 1px solid var(--border-dashed, #333844);
  border-radius: var(--r-md, 0);
  padding: var(--pad-card, 18px);
  text-decoration: none; color: inherit;
  transition: background-color var(--dur-slow, 0.19s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)),
              border-color var(--dur-slow, 0.19s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)),
              box-shadow var(--dur-slow, 0.19s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
  overflow: hidden;
  cursor: pointer;
  --corner-color: color-mix(in srgb, var(--border-dashed, #333844), white 18%);
}
/* registration corner-marks */:host(scratch-card) .card::before, :host(scratch-card) .card::after {
  content: ''; position: absolute; width: 10px; height: 10px;
  border-color: var(--corner-color); border-style: solid;
  pointer-events: none;
  transition: border-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-card) .card::before { top: 4px; left: 4px; border-width: 1px 0 0 1px; }:host(scratch-card) .card::after { bottom: 4px; right: 4px; border-width: 0 1px 1px 0; }:host(scratch-card) .card:hover {
  background-color: var(--bg-elevated, #181c26);
  border-color: var(--accent-dim, #7d6939);
  box-shadow: 0 0 20px var(--accent-glow, rgba(255,174,0,0.12));
}:host(scratch-card) .card:hover::before, :host(scratch-card) .card:hover::after { border-color: var(--accent-dim, #7d6939); }:host(scratch-card) .index {
  position: absolute; top: 6px; right: 10px;
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-micro, 10px);
  color: var(--text-disabled, #565b69);
  font-variant-numeric: tabular-nums;
  transition: color var(--dur-slow, 0.19s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-card) .index:empty { display: none; }:host(scratch-card) .card:hover .index { color: var(--text-muted, #6b7280); }:host(scratch-card) .name {
  font-family: var(--font-display, "Space Grotesk", sans-serif);
  font-size: 0.95rem; font-weight: 600;
  color: var(--text-bright, #e8ecf4);
  margin-bottom: 4px; letter-spacing: 0.01em;
}:host(scratch-card) .desc {
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-small, 12px);
  color: var(--text-muted, #6b7280);
  line-height: 1.5;
}:host(scratch-card) .desc:empty { display: none; }:host(scratch-card) .card:focus-visible { outline: 2px solid var(--accent, #ffae00); outline-offset: 2px; }

/* === src/components/scratch-caution/scratch-caution.css (scoped to scratch-caution) === */
:host(scratch-caution) { display: block; position: relative; border-top: 3px solid transparent; }
/* The stripe overlays the host's (transparent, layout-keeping) top border:
   height 0 + an own 3px border-top, so the border-image raster box is
   exactly W×3 — identical geometry to the .caution-stripe::before it
   replaced. Opacity comes from the view-timeline animation below, or from
   the JS fallback's inline style where timelines are unsupported. */:host(scratch-caution) .stripe {
  position: absolute;
  top: -3px; left: 0; right: 0;
  height: 0;
  border-top: 3px solid transparent;
  border-image: repeating-linear-gradient(45deg, var(--accent, #ffae00) 0 6px, transparent 6px 12px) 3;
  pointer-events: none;
}
/* Same query the JS gates on — exactly one mechanism ever drives opacity. */
@supports (animation-timeline: view()) {:host(scratch-caution) .stripe {
    animation-name: scratch-caution-dim;
    animation-duration: auto;              /* progress-based, not time-based */
    animation-timing-function: linear;     /* linear segments = the formula */
    animation-fill-mode: both;
    animation-timeline: view(block);       /* longhand AFTER the others — the
                                              animation shorthand resets it */
  }
}
/* max(0.7, 1 − 0.45·d/vh) expressed over the stripe's cover progress
   p = (vh − y)/vh: enter bottom 0.70 → read line (y = vh/3) 1 → top 0.85. */
@keyframes scratch-caution-dim {
  0%      { opacity: 0.7; }
  66.667% { opacity: 1; }
  100%    { opacity: 0.85; }
}

/* === src/components/scratch-composer/scratch-composer.css (scoped to scratch-composer) === */
:host(scratch-composer) { display: grid; grid-template-columns: 1fr auto; gap: var(--gap-stack, 8px); align-items: stretch; }:host(scratch-composer) scratch-field { display: block; }:host(scratch-composer) scratch-button { display: inline-flex; align-items: stretch; }

/* === src/components/scratch-field/scratch-field.css (scoped to scratch-field) === */
:host(scratch-field) { display: block; }:host(scratch-field[inline]) { display: inline-block; }:host(scratch-field) .control {
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  color: var(--text, #c8cdd8);
  font-family: var(--font-mono, "JetBrains Mono", monospace);
  font-size: var(--fs-small, 12px);
  background: var(--bg-deep, #08090c);
  border: 1px solid var(--border, #2a2e3a);
  border-radius: var(--r-md, 0);
  padding: var(--pad-control-y, 8px) var(--pad-control-x, 12px);
  outline: none;
  transition: border-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), box-shadow 250ms var(--ease-out, cubic-bezier(0.16,1,0.3,1)), background-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-field) .control::placeholder { color: var(--text-disabled, #565b69); }:host(scratch-field) .control:hover:not(:focus) { border-color: color-mix(in srgb, var(--border, #2a2e3a), white 30%); }:host(scratch-field) .control:focus { border-color: var(--accent-dim, #7d6939); box-shadow: 0 0 18px color-mix(in srgb, var(--accent, #ffae00) 38%, transparent); }

/* DISABLED — dashed border is the system's single "disabled" signal;
   dashed/dotted borders appear nowhere else. */:host(scratch-field[disabled]) .control {
  border-style: dashed;
  border-color: var(--border-dashed, #333844);
  opacity: 0.55;
  cursor: not-allowed;
}:host(scratch-field) textarea.control { resize: vertical; min-height: 64px; display: block; }

/* === src/components/scratch-led/scratch-led.css (scoped to scratch-led) === */
:host(scratch-led) {
  display: inline-block;
  width: var(--dot-size, 6px);
  height: var(--dot-size, 6px);
  border-radius: 50%;
  vertical-align: middle;
  background: var(--signal, #00e47a);
  --dot-glow: var(--signal-glow, rgba(0,228,122,0.08));
}:host(scratch-led[state="accent"]) {
  background: var(--accent, #ffae00);
  --dot-glow: var(--accent-glow, rgba(255,174,0,0.12));
}:host(scratch-led[state="bad"]) {
  background: var(--danger, #ff4444);
  --dot-glow: var(--danger-glow, rgba(255,68,68,0.10));
}:host(scratch-led[live]) { animation: scratch-led-pulse 2.5s var(--ease-out, cubic-bezier(0.16,1,0.3,1)) infinite; }
@keyframes scratch-led-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 4px var(--dot-glow); }
  50%      { opacity: 0.4; box-shadow: none; }
}
@media (prefers-reduced-motion: reduce) {:host(scratch-led[live]) { animation: none; }
}

/* === src/components/scratch-message/scratch-message.css (scoped to scratch-message) === */
:host(scratch-message) { display: flex; flex-direction: column; gap: 4px; max-width: 520px; }:host(scratch-message) .head { display: flex; align-items: center; gap: 10px; }:host(scratch-message) .author {
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-micro, 10px); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-muted, #6b7280);
}:host(scratch-message[author="user"]) .author { color: var(--accent, #ffae00); }:host(scratch-message[author="assistant"]) .author { color: var(--signal, #00e47a); }:host(scratch-message) .stats {
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-micro, 10px);
  color: var(--text-disabled, #565b69);
  margin-left: auto;
}:host(scratch-message) .stats:empty { display: none; }:host(scratch-message) .body {
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-body, 14px); line-height: 1.6;
  color: var(--text, #c8cdd8);
}:host(scratch-message[streaming]) .body::after {
  content: '▍'; color: var(--accent, #ffae00);
  animation: msg-caret 0.9s var(--ease-out, cubic-bezier(0.16,1,0.3,1)) infinite;
}
/* Hold → fast fade → hold → fast fade. Each fade spans 10% of the cycle
   (90ms ≈ --dur-fast) so it still reads as a caret blink, not a slow pulse
   — but the on/off flips render as smooth opacity ramps. (The old
   steps(2, end) timing quantized each half-cycle into two hard jumps —
   opacity 1 → .5 → 0 → .5 → 1 — which read as a low-frame-rate stutter.) */
@keyframes msg-caret {
  0%, 40%  { opacity: 1; }
  50%, 90% { opacity: 0; }
  100%     { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {:host(scratch-message[streaming]) .body::after { animation: none; }
}

/* === src/components/scratch-modal/scratch-modal.css (scoped to scratch-modal) === */
:host(scratch-modal) { display: block; width: 100%; max-width: 460px; }:host(scratch-modal) .surface {
  /* Floating surface must be opaque — layer the translucent wash over --bg so page content can't bleed through. */
  background-color: var(--bg, #0d0f14);
  background-image: linear-gradient(var(--bg-surface, #12151c), var(--bg-surface, #12151c));
  border: 1px solid var(--border-dashed, #333844);
  border-radius: var(--r-lg, 0);
  box-shadow: var(--shadow-modal, 0 18px 50px rgba(0,0,0,0.55));
  overflow: hidden;
}:host(scratch-modal) .eyebrow {
  font-family: var(--font-mono, monospace);
  font-size: 8px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-disabled, #565b69);
  padding: var(--sp-2, 8px) var(--sp-3, 12px) 0;
}:host(scratch-modal) .eyebrow::before { content: '// '; }:host(scratch-modal) .eyebrow:empty { display: none; padding: 0; }

/* === src/components/scratch-nav/scratch-nav-item.css (scoped to scratch-nav-item) === */
:host(scratch-nav-item) { display: block; }:host(scratch-nav-item) .item {
  position: relative;
  display: block;
  padding: 11px 16px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), box-shadow 250ms var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}
/* shorter when there's no description (rail style) */:host(scratch-nav-item:not([desc])) .item { padding: var(--sp-2, 8px) var(--sp-3, 12px); }:host(scratch-nav-item) .row { display: flex; align-items: baseline; gap: 6px; }:host(scratch-nav-item) .num {
  color: var(--text-disabled, #565b69);
  font-size: var(--fs-tiny, 11px);
  font-variant-numeric: tabular-nums;
}:host(scratch-nav-item) .name {
  font-size: 13px; font-weight: 500;
  color: var(--text, #c8cdd8);
  transition: color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-nav-item:not([desc])) .name { font-size: var(--fs-small, 12px); font-weight: 400; color: var(--text-muted, #6b7280); }:host(scratch-nav-item) .desc {
  display: block;
  font-size: 11px; color: var(--text-muted, #6b7280);
  margin-top: 3px;
}:host(scratch-nav-item) .desc:empty { display: none; }

/* connected left-edge indicator */:host(scratch-nav-item) .item::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 1px;
  background: color-mix(in srgb, var(--text-bright, #e8ecf4) 50%, transparent);
  transition: width var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), background-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-nav-item) .item:hover { background: var(--bg-surface, #12151c); }:host(scratch-nav-item) .item:hover .name { color: var(--text-bright, #e8ecf4); }:host(scratch-nav-item) .item:hover::before { width: 2px; background: var(--text-bright, #e8ecf4); }

/* The active background is painted by the nav container's sliding
   .indicator so it can glide between selections. Transparent — not unset —
   so the hover surface never covers the indicator on the active item. */:host(scratch-nav-item[active]) .item { background: transparent; }:host(scratch-nav-item[active]) .name { color: var(--accent, #ffae00); }:host(scratch-nav-item[active]) .num { color: var(--accent, #ffae00); }:host(scratch-nav-item[active]) .item::before { width: 2px; background: var(--accent, #ffae00); }:host(scratch-nav-item) .item:focus-visible { outline: 2px solid var(--accent, #ffae00); outline-offset: -2px; box-shadow: 0 0 18px color-mix(in srgb, var(--accent, #ffae00) 38%, transparent); }

/* === src/components/scratch-nav/scratch-nav.css (scoped to scratch-nav) === */
:host(scratch-nav) { display: block; position: relative; }:host(scratch-nav[boxed]) {
  background: var(--bg-deep, #08090c);
  border: 1px solid var(--border, #2a2e3a);
  border-radius: var(--r-md, 0);
  overflow: hidden;
  background-image:
    var(--scanline, none),
    radial-gradient(circle, var(--grid-dot, rgba(200,205,216,0.08)) 1px, transparent 1px);
  background-size: auto, var(--grid-size, 24px) var(--grid-size, 24px);
  background-attachment: fixed, fixed;
}:host(scratch-nav) .head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 16px 14px;
  border-bottom: 1px solid var(--border-dashed, #333844);
}:host(scratch-nav) .head:not(.show) { display: none; }:host(scratch-nav) .title {
  font-family: var(--font-display, "Space Grotesk", sans-serif);
  font-size: 15px; font-weight: 600; color: var(--text-bright, #e8ecf4);
}:host(scratch-nav) .title::before { content: '// '; color: var(--text-muted, #6b7280); font-weight: 400; }
/* the × is a ghost <scratch-button>; only the glyph size is ours */:host(scratch-nav) .close { font-size: 18px; }:host(scratch-nav) .list { padding: 8px 0; }:host(scratch-nav[flush]) .list { padding: 0; }

/* Sliding active-item highlight: one absolutely-positioned strip behind the
   slotted items (their .item is position:relative, so it paints above),
   moved with translateY + height so a selection change glides instead of
   jumping. Positioned against the host (offsetTop space of the items). */:host(scratch-nav) .indicator {
  position: absolute; left: 0; right: 0; top: 0;
  height: 0;
  background: var(--accent-glow, rgba(255,174,0,0.12));
  opacity: 0;
  pointer-events: none;
}:host(scratch-nav) .indicator.slide {
  transition: transform var(--dur-slow, 0.19s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)),
              height var(--dur-slow, 0.19s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}
@media (prefers-reduced-motion: reduce) {:host(scratch-nav) .indicator.slide { transition: none; }
}

/* === src/components/scratch-preview/scratch-preview.css (scoped to scratch-preview) === */
:host(scratch-preview) {
  display: block;
  font-family: var(--font-mono, "JetBrains Mono", monospace);
  color: var(--text-muted, #6b7280);
  font-size: var(--fs-micro, 10px);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}:host(scratch-preview) .wrap {
  border: 1px solid var(--border, #2a2e3a);
  border-radius: var(--r-md, 0);
  overflow: hidden;
  background: var(--bg-surface, #12151c);
  position: relative;   /* the index is positioned against this */
}:host(scratch-preview) .index {
  position: absolute; top: 6px; right: 9px;
  font-size: var(--fs-micro, 10px);
  color: var(--text-disabled, #565b69);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}:host(scratch-preview) .body {
  min-height: 72px;
  border-bottom: 1px solid var(--border, #2a2e3a);
  position: relative;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}:host(scratch-preview) .body::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  display: none;
  background-image: radial-gradient(circle, var(--grid-dot, rgba(200,205,216,0.08)) 1px, transparent 1px);
  background-size: var(--grid-size, 24px) var(--grid-size, 24px);
}:host(scratch-preview[grid]) .body::after { display: block; }:host(scratch-preview) .caption { padding: var(--sp-2, 8px) var(--sp-3, 12px); }:host(scratch-preview) .title {
  font-size: var(--fs-tiny, 11px);
  color: var(--text-bright, #e8ecf4);
  text-transform: none;
  letter-spacing: normal;
}:host(scratch-preview) .sub {
  font-size: var(--fs-micro, 10px);
  color: var(--text-muted, #6b7280);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}:host(scratch-preview) .note {
  font-size: var(--fs-tiny, 11px);
  color: var(--text-muted, #6b7280);
  text-transform: none;
  letter-spacing: normal;
  line-height: 1.5;
  margin-top: 4px;
}

/* an unset caption line (or index) takes no space */:host(scratch-preview) .index:empty, :host(scratch-preview) .title:empty, :host(scratch-preview) .sub:empty, :host(scratch-preview) .note:empty { display: none; }

/* === src/components/scratch-progress/scratch-progress.css (scoped to scratch-progress) === */
:host(scratch-progress) {
  display: block;
  /* default (accent) fill colors */
  --fill: var(--accent, #ffae00);
  --fill-glow: var(--accent-glow, rgba(255, 174, 0, 0.12));
}:host(scratch-progress[state="signal"]) {
  --fill: var(--signal, #00e47a);
  --fill-glow: var(--signal-glow, rgba(0, 228, 122, 0.08));
}:host(scratch-progress[state="danger"]) {
  --fill: var(--danger, #ff4444);
  --fill-glow: var(--danger-glow, rgba(255, 68, 68, 0.10));
}:host(scratch-progress) .track {
  height: var(--progress-height, 6px);
  box-sizing: border-box;
  background: var(--bg-elevated, #181c26);
  border: 1px solid var(--border, #2a2e3a);
  border-radius: var(--r-sm, 0);
  overflow: hidden;
  position: relative;
}:host(scratch-progress) .fill {
  height: 100%;
  width: 0%;
  background: var(--fill);
  /* subtle glow edge in the state color */
  box-shadow: 0 0 8px var(--fill-glow);
}

/* Indeterminate — a 30%-wide segment sweeps the track on the system
   ease/duration tokens (loop period = 8 × --dur-slow). */:host(scratch-progress[indeterminate]) .fill {
  width: 30%;
  animation: scratch-progress-sweep calc(var(--dur-slow, 0.19s) * 8) var(--ease-out, cubic-bezier(0.16,1,0.3,1)) infinite;
}
@keyframes scratch-progress-sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(334%); }
}
@media (prefers-reduced-motion: reduce) {:host(scratch-progress[indeterminate]) .fill {
    animation: none;
    width: 40%;
    opacity: 0.5;
  }
}

/* === src/components/scratch-reveal/scratch-reveal.css === */
@media (hover: hover) and (pointer: fine) {
  :host(:not(scratch-toggle)) { position: relative; }

  /* The lit edge: a full-box layer with a 1px-inset layer masked out of it,
     leaving a ring that traces the control's existing border instead of adding
     a second one. No transition — --rv-o is recomputed every frame from the
     cursor distance, so the tracking IS the fade.

     The inset layer is sized by mask-position/mask-size, NOT by padding or
     border. A host's ::before lives in the LIGHT tree, so a consuming page's
     reset (*, *::before { padding: 0 } — this repo's own demo has one) beats
     the :host rule here: outer-tree declarations win over shadow-tree ones.
     A padding-defined ring silently collapses to nothing under any such reset;
     nothing in a reset touches mask. The ring is square-cornered, which is
     exact at the system's --r-md of 0. */
  :host(:not(scratch-toggle))::before,
  :host(scratch-toggle) .box::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    border-radius: var(--r-md, 0);
    opacity: var(--rv-o, 0);
    pointer-events: none;
    --rv-tint: color-mix(in srgb, var(--text-bright, #e8ecf4) 85%, transparent);
    -webkit-mask: linear-gradient(#000 0 0) 1px 1px / calc(100% - 2px) calc(100% - 2px) no-repeat,
                  linear-gradient(#000 0 0) 0 0 / 100% 100% no-repeat;
            mask: linear-gradient(#000 0 0) 1px 1px / calc(100% - 2px) calc(100% - 2px) no-repeat,
                  linear-gradient(#000 0 0) 0 0 / 100% 100% no-repeat;
    -webkit-mask-composite: xor;
            mask-composite: exclude;
  }

  /* Positional light: the gradient centre follows the cursor — and sits
     OUTSIDE the box while the cursor is merely near it, which is what makes
     only the nearest stretch of edge brighten.

     --rv-r is written by the tracker from its own RADIUS, so the falloff and
     the gradient cannot disagree. The fallback here only covers the frame
     before the first pointer event; it is not a second knob to tune. */
  :host(:not(scratch-toggle))::before {
    background: radial-gradient(circle var(--rv-r, 512px) at var(--rv-x, 50%) var(--rv-y, 50%),
                var(--rv-tint), transparent 100%);
  }

  /* The toggle's box is 14px across — far under the falloff, so a gradient
     inside it would read as flat. Light its ring uniformly and let --rv-o
     alone carry the proximity. */
  :host(scratch-toggle) .box::before { background: var(--rv-tint); }
}

/* A light that chases the cursor is motion, so reduced-motion gets no ring at
   all — content:none means the pseudo-element is never generated, the same way
   it is absent on a touch device. AFTER the block above so it wins. The
   tracker stops too, rather than writing properties nothing reads. */
@media (prefers-reduced-motion: reduce) {
  :host(:not(scratch-toggle))::before,
  :host(scratch-toggle) .box::before { content: none; }
}

/* === src/components/scratch-ring/scratch-ring.css (scoped to scratch-ring) === */
:host(scratch-ring) {
  position: fixed;
  box-sizing: border-box;
  border: 1px solid var(--accent, #ffae00);
  border-radius: var(--r-md, 0);
  pointer-events: none;
  z-index: 90;
  opacity: 0;
}

/* === src/components/scratch-select/scratch-select.css (scoped to scratch-select) === */
:host(scratch-select) { display: block; }:host(scratch-select[inline]) { display: inline-block; }:host(scratch-select) .wrap { position: relative; display: block; }:host(scratch-select) select {
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  color: var(--text, #c8cdd8);
  font-family: var(--font-mono, "JetBrains Mono", monospace);
  font-size: var(--fs-small, 12px);
  background: var(--bg-elevated, #181c26);
  border: 1px solid var(--border, #2a2e3a);
  border-radius: var(--r-md, 0);
  padding: var(--pad-control-y, 8px) var(--pad-control-x, 12px);
  padding-right: calc(var(--pad-control-x, 12px) + 16px);  /* room for the ▾ */
  outline: none;
  cursor: pointer;
  -webkit-appearance: none;
          appearance: none;
  transition: border-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), box-shadow 250ms var(--ease-out, cubic-bezier(0.16,1,0.3,1)), background-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-select) select:hover:not(:focus) { border-color: color-mix(in srgb, var(--border, #2a2e3a), white 30%); }:host(scratch-select) select:focus { border-color: var(--accent-dim, #7d6939); box-shadow: 0 0 18px color-mix(in srgb, var(--accent, #ffae00) 38%, transparent); }

/* the dropdown panel is OS-drawn; keep its rows on-theme where honored */:host(scratch-select) option { background: var(--bg, #0d0f14); color: var(--text, #c8cdd8); }

/* drawn ▾ affordance — replaces the native arrow killed by appearance:none */:host(scratch-select) .chev {
  position: absolute;
  right: var(--pad-control-x, 12px);
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  color: var(--accent, #ffae00);
  font-size: 9px;
  line-height: 1;
}

/* DISABLED — dashed border is the system's single "disabled" signal. */:host(scratch-select[disabled]) select {
  border-style: dashed;
  border-color: var(--border-dashed, #333844);
  opacity: 0.55;
  cursor: not-allowed;
}:host(scratch-select[disabled]) .chev { color: var(--text-disabled, #565b69); }

/* === src/components/scratch-tabs/scratch-tabs.css (scoped to scratch-tabs) === */
:host(scratch-tabs) { display: block; }:host(scratch-tabs) .strip { display: flex; gap: 0; align-items: stretch; border-bottom: 1px solid var(--border, #2a2e3a); }:host(scratch-tabs) .tabbtns { display: flex; }:host(scratch-tabs) .lead { display: flex; align-items: center; }:host(scratch-tabs) .trail { display: flex; align-items: center; margin-left: auto; }:host(scratch-tabs) .tab {
  position: relative;
  background: none; border: none;
  color: var(--text-muted, #6b7280);
  padding: var(--pad-control-y, 8px) var(--pad-control-x, 12px);
  padding-bottom: calc(var(--pad-control-y, 8px) / 2);
  font: inherit;
  font-family: var(--font-mono, "JetBrains Mono", monospace);
  font-size: var(--fs-small, 12px);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition: color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), box-shadow 250ms var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-tabs) .tab::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px;
  background: color-mix(in srgb, var(--text-bright, #e8ecf4) 50%, transparent);
  transition: height var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), background-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-tabs) .tab:hover { color: var(--text-bright, #e8ecf4); }:host(scratch-tabs) .tab:hover::after { height: 2px; background: var(--text-bright, #e8ecf4); }:host(scratch-tabs) .tab[aria-selected="true"] { color: var(--accent, #ffae00); }:host(scratch-tabs) .tab[aria-selected="true"]::after { height: 2px; background: var(--accent, #ffae00); }:host(scratch-tabs) .tab:focus-visible { outline: 2px solid var(--accent, #ffae00); outline-offset: -2px; box-shadow: 0 0 18px color-mix(in srgb, var(--accent, #ffae00) 38%, transparent); }:host(scratch-tabs) .panels { padding-top: var(--sp-4, 16px); }:host(scratch-tabs[strip-only]) .panels { display: none; }

/* === src/components/scratch-toggle/scratch-toggle.css (scoped to scratch-toggle) === */
:host(scratch-toggle) { display: inline-flex; vertical-align: middle; }:host(scratch-toggle) label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  position: relative;
  cursor: pointer;
  user-select: none;
  font-family: var(--font-mono, "JetBrains Mono", monospace);
  font-size: var(--fs-small, 12px);
  color: var(--text, #c8cdd8);
}

/* the native checkbox: invisible but real — keyboard, focus, a11y */:host(scratch-toggle) input {
  position: absolute;
  opacity: 0;
  width: 1px; height: 1px;
  margin: 0;
  pointer-events: none;
}:host(scratch-toggle) .box {
  width: 14px; height: 14px;
  box-sizing: border-box;
  flex: none;
  position: relative;
  background: var(--bg-deep, #08090c);
  border: 1px solid var(--border, #2a2e3a);
  border-radius: 0;   /* hard-edged, always — never a pill */
  transition: border-color var(--dur, 0.11s) var(--ease-out, cubic-bezier(0.16,1,0.3,1)), box-shadow 250ms var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}
/* the inset amber square — the "LED" fill */:host(scratch-toggle) .box::after {
  content: '';
  position: absolute;
  inset: 3px;
  background: var(--accent, #ffae00);
  opacity: 0;
  transition: opacity var(--dur-fast, 0.09s) var(--ease-out, cubic-bezier(0.16,1,0.3,1));
}:host(scratch-toggle) label:hover .box { border-color: color-mix(in srgb, var(--border, #2a2e3a), white 30%); }:host(scratch-toggle) input:checked ~ .box { border-color: var(--accent-dim, #7d6939); box-shadow: 0 0 6px var(--accent-glow, rgba(255, 174, 0, 0.12)); }:host(scratch-toggle) input:checked ~ .box::after { opacity: 1; }:host(scratch-toggle) input:focus-visible ~ .box { outline: 2px solid var(--accent, #ffae00); outline-offset: 2px; box-shadow: 0 0 18px color-mix(in srgb, var(--accent, #ffae00) 38%, transparent); }

/* DISABLED — dashed box + dimmed label, inert. */:host(scratch-toggle[disabled]) { pointer-events: none; }:host(scratch-toggle[disabled]) label { cursor: not-allowed; color: var(--text-disabled, #565b69); }:host(scratch-toggle[disabled]) .box {
  border-style: dashed;
  border-color: var(--border-dashed, #333844);
  background: none;
  box-shadow: none;
}:host(scratch-toggle[disabled]) .box::after { background: var(--text-disabled, #565b69); }
