/* ────────────────────────────────────────────────────────────
   Inter Variable — self-hosted, v2 design system primary face.
   Variable font: single file covers weights 100-900. Loaded
   from /fonts/InterVariable.woff2 (~344 KB, ships with deploy).
   Added 2026-05-26, Phase B.
   ──────────────────────────────────────────────────────────── */
@font-face {
  font-family: "Inter";
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  src: url("./fonts/InterVariable.woff2") format("woff2-variations"),
       url("./fonts/InterVariable.woff2") format("woff2");
  font-feature-settings: "cv11", "ss01", "ss03";
}

/* ────────────────────────────────────────────────────────────
   Lucide icon helper (Phase B.2). Used with the SVG sprite at the
   top of <body> via <svg class="icon"><use href="#i-X"/></svg>.
   - Inherits text color via stroke="currentColor" on each <symbol>
   - Sizes to 1em by default so it scales with parent font-size
   - Variants: .icon.sm (0.875em), .icon.md (1.25em), .icon.lg (1.5em)
   ──────────────────────────────────────────────────────────── */
.icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.125em; /* aligns icon to text baseline */
  flex-shrink: 0;
}
.icon.sm { width: 0.875em; height: 0.875em; }
.icon.md { width: 1.25em;  height: 1.25em; }
.icon.lg { width: 1.5em;   height: 1.5em; }

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

/* ────────────────────────────────────────────────────────────
   SVG Lab — design tokens (OKLCH, warm-tinted neutrals)
   ──────────────────────────────────────────────────────────── */
:root {
  /* ────────────────────────────────────────────────────────────
     v2 TOKEN REMAP (2026-05-26 — same-day pivot)
     The original warm-graphite oklch values are commented in each
     line. The active values are the v2 vibrant-dark palette — pink
     primary accent, near-black surfaces, mint as secondary accent
     (already applied to brand mark + BETA pill in Phase C earlier).
     This single edit propagates the new look through the WHOLE app
     because every component references these tokens by name.
     ──────────────────────────────────────────────────────────── */

  /* Surfaces — near-black scale, slightly warm */
  --bg:           #0B0B10;  /* was oklch(0.200 0.008 70) — warm graphite */
  --bg-deep:      #050507;  /* was oklch(0.155 0.008 70) */
  --panel:        #14141B;  /* was oklch(0.235 0.010 70) */
  --panel-2:      #1C1C25;  /* was #2C2C35 */
  --panel-3:      #26262F;  /* was oklch(0.315 0.012 70) */
  --panel-sunken: #050507;  /* was #1A1A22 */

  /* Structure — semi-transparent white lines for that "modern dark" feel */
  --line:        rgba(255, 255, 255, 0.06);
  --line-soft:   rgba(255, 255, 255, 0.10);
  --line-faint:  rgba(255, 255, 255, 0.04);

  /* Canvas backdrop dot grid (camera-synced via applyView()). A subtle light
     dot on the dark canvas — the "infinite drawing surface" look that Figma /
     tldraw / Miro use. The dots pan and scale with the camera. */
  --grid-dot:    rgba(255, 255, 255, 0.10);

  /* Text — neutral whites instead of warm-cream */
  --ink:         #F5F5F7;  /* was oklch(0.945 0.008 80) */
  --ink-2:       #A1A1AF;  /* was oklch(0.760 0.012 80) */
  --ink-3:       #8A8A99;  /* lightened 2026-05-29 → WCAG AA (#6B6B78 was ~3.4:1 on panels) */
  --ink-4:       #4B4B58;  /* was oklch(0.400 0.010 80) */

  /* Accents — primary palette pivoted to ELECTRIC LIME (#B5FF3A) per
     user reference 2026-05-26. Tool-active highlight, selection chrome,
     snap rings, slider thumbs, primary button state — all lime.
     Selection chrome uses AMBER (#F2D43D) for visual contrast against
     lime CTAs so a selected shape doesn't blend with an active tool. */
  --accent:      #B5FF3A;  /* electric lime — primary CTA */
  --accent-hi:   #C9FF66;  /* lighter lime — hover */
  --accent-lo:   #8FCC1F;  /* darker lime — pressed */
  --accent-soft: rgba(181, 255, 58, 0.18);
  --accent-glow: rgba(181, 255, 58, 0.40);
  --accent-ink:  #0B0B10;  /* dark text on bright lime button */

  /* Selection chrome — amber, distinct from primary lime */
  --select:      #F2D43D;
  --select-soft: rgba(242, 212, 61, 0.18);

  /* Danger */
  --danger:      #FF4D4D;
  --danger-soft: rgba(255, 77, 77, 0.18);

  /* Canvas — neutral dark surface (user direction: canvas stays clean) */
  --canvas-bg:   #0B0B10;
  --doc-bg:      #f7f3ec;  /* keep — this is the SVG document's background */

  /* Spacing scale */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;

  /* Radius */
  --r-1: 4px;
  --r-2: 6px;
  --r-3: 8px;
  --r-pill: 999px;

  /* Motion — single canonical timing scale (2026-05-29 consolidation).
     The legacy --t-* names and the DESIGN.md --dur-* names had drifted to
     different values (fast 110 vs 160, base 200 vs 240 …), so hover timing
     was inconsistent across the app. Both naming systems now resolve to ONE
     scale: snappy values tuned for a product tool. --dur-* alias --t-* below. */
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out-q:  cubic-bezier(0.22, 1, 0.36, 1);
  --ease-press:  cubic-bezier(0.4, 0, 0.6, 1);
  --t-instant: 80ms;
  --t-fast:    130ms;
  --t-base:    200ms;
  --t-slow:    300ms;

  /* Elevation */
  --shadow-1: 0 1px 0 oklch(0 0 0 / 0.28), 0 1px 2px oklch(0 0 0 / 0.18);
  --shadow-2: 0 6px 16px oklch(0 0 0 / 0.36), 0 1px 0 oklch(0 0 0 / 0.40);
  --shadow-3: 0 14px 38px oklch(0 0 0 / 0.46), 0 2px 0 oklch(0 0 0 / 0.50);
  --inner-hi:    inset 0 1px 0 oklch(1 0 0 / 0.06);
  --inner-hi-2:  inset 0 1px 0 oklch(1 0 0 / 0.10);

  /* Focus ring */
  /* Keyboard focus ring: a 2px dark gap then a crisp solid-lime band. The
     outer band was --accent-soft (0.18 alpha) — too faint to read as a focus
     indicator. Solid lime gives a clearly visible ring for keyboard users. */
  --ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);

  /* ────────────────────────────────────────────────────────────
     v2 DESIGN.md tokens (added 2026-05-26, Phase A)
     ----------------------------------------------------------------
     These are the new vibrant-dark token system per DESIGN.md.
     INTENTIONALLY UNUSED in Phase A — defined here so phases B-H can
     swap component usage from legacy tokens (--bg/--panel/--accent)
     to these new ones surgically, one section at a time.
     Do NOT delete the legacy tokens above; they stay until the full
     migration is done.
     ──────────────────────────────────────────────────────────── */

  /* Surfaces — 6-step near-black scale, slightly warm */
  --surface-0: #050507;
  --surface-1: #0B0B10;
  --surface-2: #14141B;
  --surface-3: #1C1C25;
  --surface-4: #26262F;
  --surface-5: #33333D;

  /* Text scale */
  --text-primary:   #F5F5F7;
  --text-secondary: #A1A1AF;
  --text-tertiary:  #8A8A99;  /* bumped from #6B6B78 (~3.5:1) → WCAG AA on panels (2026-05-29) */
  --text-inverse:   #0B0B10;

  /* Vibrant accent palette (extracted from reference image) */
  /* Legacy v2 tokens — DEFINED BUT UNUSED after 2026-05-26 lime pivot.
     Components that referenced these were swapped to lime/olive/amber.
     Kept here so any stray reference resolves to a known color. */
  --accent-mint:     #5DD5C9;
  --accent-violet:   #D459FA;
  --accent-pink:     #F25287;
  --accent-electric: #F02D71;
  /* --accent-lime: now defined below at #B5FF3A (electric lime, new primary) */
  --accent-amber:    #F2D43D;

  /* Soft accent tints (8% alpha — for backgrounds, hover surfaces) */
  --accent-mint-soft:     rgba( 93, 213, 201, 0.08);
  --accent-violet-soft:   rgba(212,  89, 250, 0.08);
  --accent-pink-soft:     rgba(242,  82, 135, 0.08);
  --accent-electric-soft: rgba(240,  45, 113, 0.08);
  /* --accent-lime-soft: redefined below at lime #B5FF3A */
  --accent-amber-soft:    rgba(242, 212,  61, 0.08);

  /* Semantic mappings — repointed to lime palette (2026-05-26).
     --color-info uses amber (distinct from primary lime), --color-pro
     uses olive (the secondary green from the new reference). */
  --color-primary: #B5FF3A; /* lime */
  --color-success: #B5FF3A; /* lime */
  --color-warning: #F2D43D; /* amber */
  --color-info:    #F2D43D; /* amber */
  --color-pro:     #6B8E3D; /* olive */
  --color-danger:  #FF4D4D;

  /* Brand gradients — pivoted to LIME → OLIVE → AMBER (2026-05-26).
     Replaces the previous mint→violet→pink combo per user direction
     "no pink/blue/purple, use the colors from the new reference image." */
  --gradient-brand: linear-gradient(135deg, #B5FF3A 0%, #6B8E3D 50%, #F2D43D 100%);
  --gradient-brand-soft: linear-gradient(135deg,
    rgba(181, 255,  58, 0.15) 0%,
    rgba(107, 142,  61, 0.15) 50%,
    rgba(242, 212,  61, 0.15) 100%);

  /* PRO badge gradients — also pivoted to lime variants. */
  --gradient-pro:      linear-gradient(135deg, #B5FF3A 0%, #F2D43D 100%);
  --gradient-pro-plus: linear-gradient(110deg,
    #B5FF3A 0%, #C9FF66 33%, #F2D43D 66%, #B5FF3A 100%);

  /* Typography stack — Inter loaded in Phase B via @font-face */
  --font-sans: "Inter", "SF Pro Display", -apple-system, BlinkMacSystemFont,
               "Segoe UI", Roboto, sans-serif;
  /* One canonical UI mono stack (2026-05-29). The app had three different
     hardcoded mono stacks (Cascadia / Source Code Pro / JetBrains); all UI
     mono now resolves here. System-first so it renders instantly with no
     web-font dependency or FOUT. (Source Code Pro stays a Text-tool content
     option, not a UI face.) */
  --font-mono: ui-monospace, "Cascadia Code", "Cascadia Mono", "SF Mono",
               "JetBrains Mono", Menlo, Consolas, monospace;

  /* Type sizes (size / line-height pairs — apply via shorthand) */
  --type-display-size: 32px;  --type-display-line: 40px;
  --type-h1-size:      24px;  --type-h1-line:      32px;
  --type-h2-size:      18px;  --type-h2-line:      24px;
  --type-h3-size:      14px;  --type-h3-line:      20px;
  --type-body-size:    13px;  --type-body-line:    18px;
  --type-small-size:   12px;  --type-small-line:   16px;
  --type-tiny-size:    11px;  --type-tiny-line:    14px;
  --type-mono-size:    12px;  --type-mono-line:    16px;

  /* Letter-spacing presets */
  --tracking-brand:   0.02em;
  --tracking-tight:  -0.01em;
  --tracking-caps:    0.06em;
  --tracking-default: 0;

  /* Spacing (4px base — new names alongside legacy --s-N) */
  --space-0: 0;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* Radius (new names alongside legacy --r-N) */
  --radius-xs:   4px;
  --radius-sm:   8px;
  --radius-md:  12px;
  --radius-lg:  16px;
  --radius-xl:  20px;
  --radius-2xl: 24px;
  --radius-pill: 999px;

  /* Elevation (new names alongside legacy --shadow-N) */
  --shadow-e1: 0 1px 2px 0 rgba(0,0,0,0.4);
  --shadow-e2: 0 4px 8px -2px rgba(0,0,0,0.4), 0 2px 4px -2px rgba(0,0,0,0.3);
  --shadow-e3: 0 8px 16px -4px rgba(0,0,0,0.5), 0 4px 8px -4px rgba(0,0,0,0.3);
  --shadow-e4: 0 16px 32px -8px rgba(0,0,0,0.6), 0 8px 16px -8px rgba(0,0,0,0.4);

  /* Accent glows for hover/pulse states */
  --shadow-glow-pink:   0 0 32px rgba(242,  82, 135, 0.35);
  --shadow-glow-violet: 0 0 32px rgba(212,  89, 250, 0.35);
  --shadow-glow-mint:   0 0 32px rgba( 93, 213, 201, 0.35);

  /* Lime-palette glows (post-pivot, 2026-05-26). */
  --shadow-glow-lime:   0 0 32px rgba(181, 255,  58, 0.40);
  --shadow-glow-amber:  0 0 32px rgba(242, 212,  61, 0.35);
  --shadow-glow-olive:  0 0 32px rgba(107, 142,  61, 0.40);

  /* Explicit lime + olive accent tokens for components that want to
     reference them by name. */
  --accent-lime:   #B5FF3A;
  --accent-olive:  #6B8E3D;
  --accent-lime-soft:  rgba(181, 255,  58, 0.18);
  --accent-olive-soft: rgba(107, 142,  61, 0.18);

  /* Glass system — for floating chrome (modals, popovers, tooltips).
     Used on translucent surfaces ONLY; structural surfaces stay solid. */
  --glass-base:       rgba(20, 20, 27, 0.65);
  --glass-strong:     rgba(20, 20, 27, 0.85);
  --glass-light:      rgba(255, 255, 255, 0.04);
  --glass-blur:       blur(24px) saturate(180%);
  --glass-blur-heavy: blur(40px) saturate(200%);
  --glass-border-top: inset 0 1px 0 rgba(255, 255, 255, 0.08);
  --glass-border-all: 0 0 0 1px rgba(255, 255, 255, 0.06);

  /* Motion — new easing/duration tokens.
     --ease-out already exists above with the matching value; reusing it. */
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-linear: linear;

  /* DESIGN.md duration names now alias the canonical --t-* scale above so the
     two systems can't drift apart again. --dur-page has no --t-* equivalent. */
  --dur-instant: var(--t-instant);
  --dur-fast:    var(--t-fast);
  --dur-base:    var(--t-base);
  --dur-slow:    var(--t-slow);
  --dur-page:    480ms;
}

/* ────────────────────────────────────────────────────────────
   Light theme — overrides all color tokens.
   Applied via class="theme-light" on <html> for the current page visit.
   Non-color tokens (spacing, radius, motion) stay in :root and
   do not need overriding.
   ──────────────────────────────────────────────────────────── */
.theme-light {
  color-scheme: light;

  /* Surfaces */
  --bg:           #F6F5F0;
  --bg-deep:      #ECEAE3;
  --panel:        #FFFFFF;
  --panel-2:      #F1EEE6;
  --panel-3:      #E8E4D9;
  --panel-sunken: #E8E4D9;

  /* Structure */
  --line:        rgba(20, 20, 27, 0.08);
  --line-soft:   rgba(20, 20, 27, 0.14);
  --line-faint:  rgba(20, 20, 27, 0.04);

  /* Canvas */
  --grid-dot:    rgba(20, 20, 27, 0.12);
  --canvas-bg:   #E8E4D9;

  /* Text */
  --ink:   #1A1A22;
  --ink-2: #4F4F58;
  --ink-3: #6E6E78;
  --ink-4: #A5A5B0;

  /* Accent — olive-lime for light mode */
  --accent:      #6FAE0E;
  --accent-hi:   #82C816;
  --accent-lo:   #5A8E0A;
  --accent-soft: rgba(111, 174, 14, 0.16);
  --accent-glow: rgba(111, 174, 14, 0.30);
  --accent-ink:  #FFFFFF;
  --accent-lime:       #6FAE0E;
  --accent-olive:      #5A8E0A;
  --accent-lime-soft:  rgba(111, 174, 14, 0.16);
  --accent-olive-soft: rgba( 90, 142, 10, 0.18);

  /* Selection chrome */
  --select:      #B8930D;
  --select-soft: rgba(184, 147, 13, 0.16);

  /* Danger */
  --danger:      #C73A3A;
  --danger-soft: rgba(199,  58,  58, 0.16);

  /* Elevation */
  --shadow-1:   0 1px 0 rgba(20,20,27,0.08), 0 1px 2px rgba(20,20,27,0.05);
  --shadow-2:   0 6px 16px rgba(20,20,27,0.08), 0 1px 0 rgba(20,20,27,0.06);
  --shadow-3:   0 14px 38px rgba(20,20,27,0.10), 0 2px 0 rgba(20,20,27,0.06);
  --inner-hi:   inset 0 1px 0 rgba(255,255,255,0.70);
  --inner-hi-2: inset 0 1px 0 rgba(255,255,255,0.85);
  --shadow-e1:  0 1px 2px 0 rgba(20,20,27,0.08);
  --shadow-e2:  0 4px 8px -2px rgba(20,20,27,0.10), 0 2px 4px -2px rgba(20,20,27,0.06);
  --shadow-e3:  0 8px 16px -4px rgba(20,20,27,0.12), 0 4px 8px -4px rgba(20,20,27,0.06);
  --shadow-e4:  0 16px 32px -8px rgba(20,20,27,0.14), 0 8px 16px -8px rgba(20,20,27,0.08);

  /* Glass (floating panels / modals) */
  --glass-base:       rgba(240, 237, 230, 0.80);
  --glass-strong:     rgba(240, 237, 230, 0.95);
  --glass-light:      rgba(20, 20, 27, 0.04);
  --glass-border-top: inset 0 1px 0 rgba(20, 20, 27, 0.06);
  --glass-border-all: 0 0 0 1px rgba(20, 20, 27, 0.08);

  /* v2 surface scale */
  --surface-0: #ECEAE3;
  --surface-1: #F6F5F0;
  --surface-2: #FFFFFF;
  --surface-3: #F1EEE6;
  --surface-4: #E8E4D9;
  --surface-5: #DDD9CE;

  /* v2 text scale */
  --text-primary:   #1A1A22;
  --text-secondary: #4F4F58;
  --text-tertiary:  #6E6E78;
  --text-inverse:   #F5F5F7;

  /* Semantic */
  --color-primary: #6FAE0E;
  --color-success: #6FAE0E;
  --color-warning: #B8930D;
  --color-info:    #B8930D;
  --color-pro:     #5A8E0A;
  --color-danger:  #C73A3A;
}

/* Light-mode component overrides — things that can't be fixed with token
   swaps alone because they use hardcoded dark values in the base rule. */
.theme-light .seg button.active {
  background: linear-gradient(180deg, var(--panel-2) 0%, var(--panel-3) 100%);
  border-color: var(--line-soft);
  color: var(--ink);
}

/* ────────────────────────────────────────────────────────────
   Base
   ──────────────────────────────────────────────────────────── */
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }

body {
  /* v2 design system: Inter as primary (Phase B). System-font fallbacks
     kick in only if the self-hosted Inter file fails to load — should
     never happen in production since the font ships with the deploy. */
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.4;
  font-feature-settings: "ss01", "cv11";
  letter-spacing: 0.01em;
  overflow: hidden;
  user-select: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button, input, select { font-family: inherit; font-size: 12px; color: inherit; }
button { -webkit-appearance: none; }

/* Focus rings are applied per-component below — no global override that would
   force a uniform border-radius onto every focusable element. */
button:focus-visible,
input:focus-visible,
select:focus-visible,
.tool:focus-visible,
.swatch-none:focus-visible,
.actions button:focus-visible,
.file-btn:focus-visible,
.row.gap button:focus-visible,
.zoom-pill button:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
.tool:focus-visible {
  /* tool buttons keep their own border-radius via inheritance */
  box-shadow: var(--ring);
}

/* Broad keyboard focus-ring fallback (2026-05-29): any interactive control not
   covered by a specific rule above still gets a visible ring. :where() keeps
   specificity at 0 so component-specific focus rules still win. */
:where(button, [role="button"], a[href], input, select, textarea, summary, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

/* Disabled controls (2026-05-29): the selection-gated panel buttons used to look
   identical whether enabled or not. */
button:disabled, button[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

/* ────────────────────────────────────────────────────────────
   App grid
   Floating-panel layout (Phase C+, 2026-05-26): toolbar and
   properties panel get extra column width so they can float with
   margin and rounded corners inside their grid cells. Topbar +
   statusbar stay full-bleed (structural surfaces per DESIGN.md §5.3).
   ──────────────────────────────────────────────────────────── */
.app {
  display: grid;
  grid-template-columns: 68px 1fr 322px;
  grid-template-rows: auto 1fr 26px;
  grid-template-areas:
    "topbar topbar topbar"
    "toolbar canvas properties"
    "statusbar statusbar statusbar";
  height: 100vh;
  width: 100vw;
  /* Uniform field behind everything (matches the canvas tone). The floating
     panels are elevated cards a step lighter than this, so they read as clean
     rounded rectangles with no dark rectangle framing them. (2026-05-29) */
  background: var(--canvas-bg);
}

/* ────────────────────────────────────────────────────────────
   Topbar
   ──────────────────────────────────────────────────────────── */
.topbar {
  grid-area: topbar;
  background:
    linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
  border-bottom: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  /* Hoist above sibling grid areas. The Pro extensions added animations that
     create stacking contexts on .properties / .canvas-area; without an
     explicit z-index here, dropdowns inside the topbar (Export menu) render
     beneath those siblings. Modal/banner z-indexes (100+) still win. */
  position: relative;
  z-index: 50;
}
.topbar-row {
  display: flex;
  align-items: center;
  padding: 8px var(--s-4);
  gap: var(--s-3);
  flex-wrap: wrap;
  min-height: 44px;
}
.topbar-row + .topbar-row {
  border-top: 1px solid var(--line);
  background: oklch(0 0 0 / 0.18);
  min-height: 38px;
  padding: 6px var(--s-4);
}

.row-label {
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 1.4px;
  color: var(--ink-3);
  font-weight: 600;
  margin-right: var(--s-1);
}
.x-sep { color: var(--ink-3); font-size: 11px; }
.ctrl-sep { width: 1px; height: 18px; background: var(--line); margin: 0 var(--s-1); }

/* Brand */
.brand {
  display: flex; align-items: center; gap: 9px;
  padding-right: var(--s-3);
  margin-right: var(--s-1);
  border-right: 1px solid var(--line);
}
/* Brand mark icon — v2 (2026-05-26 lime pivot). Electric lime glow. */
.brand-mark {
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--accent-lime);
  filter: drop-shadow(0 0 8px rgba(181, 255, 58, 0.30))
          drop-shadow(0 1px 1px rgba(0, 0, 0, 0.4));
  transition: filter var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-spring);
}
.brand:hover .brand-mark {
  transform: rotate(-6deg) scale(1.05);
  filter: drop-shadow(0 0 14px rgba(181, 255, 58, 0.60))
          drop-shadow(0 1px 1px rgba(0, 0, 0, 0.4));
}
.brand-mark svg { width: 100%; height: 100%; display: block; }

/* Brand wordmark — refined tracking + gradient sweep on hover. */
.brand-name {
  font-weight: 600;
  font-size: 13.5px;
  letter-spacing: var(--tracking-brand);
  color: var(--text-primary);
  /* Solid wordmark (2026-05-29): dropped the background-clip:text gradient
     sweep on hover (decorative gradient-text). The mark stays a clean white
     wordmark and shifts to lime on hover — same accent, no gradient. */
  transition: color var(--dur-base) var(--ease-out);
}
.brand:hover .brand-name {
  color: var(--accent-lime);
}
.brand-name em {
  font-style: normal;
  color: var(--text-tertiary);
  font-weight: 400;
  margin-left: 6px;
}
/* .beta-badge rule removed 2026-05-31 — BETA badge swept from editor /
   profile / billing / email templates per "BETA is internal, not user-
   facing." Stays in changelog.html and internal docs. */

.canvas-controls { gap: 6px; }
.canvas-controls #doc-x,
.canvas-controls #doc-y {
  width: 64px;
}

/* Form-like control: select */
.ctrl-select {
  background: var(--panel-sunken);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: 5px 22px 5px 10px;
  border-radius: var(--r-2);
  font-size: 11px;
  cursor: pointer;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23A1A1AF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 6px center;
  transition:
    border-color var(--t-fast) var(--ease-out),
    background-color var(--t-fast) var(--ease-out);
}
.ctrl-select:hover { background-color: var(--panel-2); border-color: var(--line-faint); }
.ctrl-select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.ctrl-select option { background: var(--panel); color: var(--ink); }

/* Field wrapper for input + label */
.field {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--panel-sunken);
  padding: 4px 8px;
  border-radius: var(--r-2);
  border: 1px solid var(--line);
  transition:
    border-color var(--t-fast) var(--ease-out),
    background-color var(--t-fast) var(--ease-out);
}
.field:hover { border-color: var(--line-faint); }
.field:focus-within {
  border-color: var(--accent);
  background: #1F1F28;
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.field span {
  font-size: 9.5px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-weight: 600;
}
.field input[type="number"], .field input[type="text"] {
  background: transparent;
  border: none; outline: none;
  width: 56px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  letter-spacing: 0.02em;
}
.field input[type="color"] {
  width: 22px; height: 22px; padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-1);
  background: transparent;
  cursor: pointer;
  overflow: hidden;
}
.field input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.field input[type="color"]::-webkit-color-swatch { border: none; border-radius: 3px; }

/* The "show BG" — turn the checkbox into a soft pill toggle */
.field.checkbox {
  padding: 4px 10px 4px 8px;
  cursor: pointer;
  gap: 6px;
}
.field.checkbox input { margin: 0; accent-color: var(--accent); cursor: pointer; }

/* Action button group */
.actions {
  margin-left: auto;
  display: flex;
  gap: 4px;
  align-items: center;
}
/* Premium rounded-rect language (2026-05-30 refresh — pill rolled back).
   Flat panel surfaces + soft border + lime halo on hover. Rounded
   rectangles (10px), NOT pills — pills are reserved for the profile
   page's chip language; the editor's buttons stay button-shaped. */
.actions button, .file-btn {
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: 0 14px;
  border-radius: 10px;
  cursor: pointer;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.1px;
  height: 30px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  transition:
    background var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out),
    transform var(--t-instant) var(--ease-press);
  position: relative;
}
.actions button:hover, .file-btn:hover {
  background: var(--panel-3);
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.actions button:active, .file-btn:active {
  transform: translateY(1px);
  background: var(--panel);
  box-shadow: none;
}
.actions .divider { width: 1px; height: 16px; background: var(--line); margin: 0 var(--s-1); }

/* Export — primary CTA. Solid lime pill, lime halo on hover. */
.actions button#btn-export {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: transparent;
  font-weight: 600;
}
.actions button#btn-export:hover {
  background: var(--accent-hi);
  color: var(--accent-ink);
  border-color: transparent;
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.actions button#btn-export:active {
  background: var(--accent-lo);
  box-shadow: none;
}

/* ────────────────────────────────────────────────────────────
   Toolbar (left) — floating "hanging rectangle" card (Phase C+, 2026-05-26)
   Lifted off the edges with margin, heavily rounded corners give the
   pill-at-top-and-bottom feel from the reference image.
   ──────────────────────────────────────────────────────────── */
.toolbar {
  grid-area: toolbar;
  /* Defined floating panel (2026-05-29): the toolbar used to be fully
     transparent with a transparent border, so the tools floated edgelessly
     in the dark gutter. It now has the working-surface tone + a hairline
     border so it reads as a contained card — same treatment as .properties
     and the canvas, separated by the dark gutter. */
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  margin: 12px 4px 12px 12px;
  display: flex; flex-direction: column;
  padding: 14px 6px;
  gap: 2px;
  align-items: center;
  position: relative;
  /* min-height: 0 lets the toolbar shrink inside its grid row so overflow can
     scroll on short viewports. Without it the grid item refuses to be smaller
     than its content and the last tools spill below the screen. */
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.toolbar::-webkit-scrollbar { width: 6px; }
.toolbar::-webkit-scrollbar-thumb {
  background: #36363F;
  border-radius: 8px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.toolbar::-webkit-scrollbar-thumb:hover { background: #424252; }
.toolbar::-webkit-scrollbar-track { background: transparent; }
.tool {
  width: 40px; height: 40px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-2);
  cursor: pointer;
  border-radius: var(--r-2);
  display: flex; align-items: center; justify-content: center;
  position: relative;
  transition:
    background-color var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out),
    transform var(--t-instant) var(--ease-press),
    border-color var(--t-fast) var(--ease-out);
}
.tool svg {
  width: 19px; height: 19px;
  display: block;
  pointer-events: none;
  transition: transform var(--t-base) var(--ease-out);
}
.tool:hover {
  background: #303038;
  color: var(--ink);
  border-color: var(--line-faint);
}
.tool:hover svg { transform: scale(1.04); }
.tool:active { transform: scale(0.94); }

.tool.active {
  /* Lime active-tool gradient (was warm gold). 2026-05-26 lime pivot. */
  background: linear-gradient(135deg, #B5FF3A 0%, #8FCC1F 100%);
  color: var(--accent-ink); /* dark text on bright lime */
  border-color: #6B8E3D;
  box-shadow:
    0 1px 0 rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 0 16px rgba(181, 255, 58, 0.40);
}
/* Active-tool right-edge indicator bar removed 2026-05-29 (user: "green on
   the right side ... gone"). The lime gradient fill alone marks the active
   tool now. */

.tool-sep {
  width: 22px; height: 1px;
  background: var(--line-soft);
  margin: 6px 0;
}

/* ────────────────────────────────────────────────────────────
   Canvas area
   ──────────────────────────────────────────────────────────── */
.canvas-area {
  grid-area: canvas;
  /* Dark frame tone (matches the page-tab strip + gutter). The lighter
     "workspace" --panel tone is now carried by #canvas's own background, so
     when #canvas's top-right cuts off cleanly under the strip, the small
     triangle behind it shows the dark strip color — not a light pocket.
     (2026-05-30) */
  background: var(--bg);
  /* Bottom corners + bottom-left rounding (2026-05-30 user request): parent
     clips its contents to this radius, so the dotted #canvas SVG below shows
     curved BR + BL corners. Top-left stays square (active page tab attaches
     flush). Top-right is rounded on #canvas directly — see #canvas rule — so
     the curve appears on the dotted area, not on the dark page-tab strip. */
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  /* Lift bottom edge to match the 12px gap the toolbar and properties panels
     have above the statusbar — all three panels now share the same bottom line. */
  margin-bottom: 12px;
  position: relative;
  overflow: hidden;
  isolation: isolate;       /* contain the ::before z-index: -1 trick */
}
/* (Page-tab "comet" outline animation removed — 2026-05-30, user request.) */
#canvas {
  width: 100%; height: 100%; display: block; cursor: default;
  /* Camera-synced dot grid (driven by --grid-step / --grid-x / --grid-y, set in
     applyView()). The dots translate with the pan and scale with the zoom, so
     the dark canvas reads as a real movable drawing surface — the way Figma /
     tldraw / Miro render their backdrops. The SVG itself is transparent, so the
     dots sit on the canvas-area tone; the artboard paints over them. */
  /* Workspace tone now lives on #canvas (was on .canvas-area — moved 2026-05-30
     so the rounded-TR cut-off shows the dark strip behind it, not a light
     pocket). The dot grid layers on top via background-image. */
  background-color: var(--panel);
  background-image: radial-gradient(circle, var(--grid-dot) 1.1px, transparent 1.7px);
  background-size: var(--grid-step, 24px) var(--grid-step, 24px);
  background-position: var(--grid-x, 0px) var(--grid-y, 0px);
  /* Round the dotted canvas's top-right corner directly. The dark page-tab
     strip sits ABOVE #canvas, so the parent (.canvas-area) can't round this
     corner — rounding the parent would round the dark strip instead. By
     rounding #canvas itself, the curve appears where the dotted area meets
     the strip — visually matching the parent-clipped BR + BL corners on the
     same dotted area. 2026-05-30 user request. */
  border-top-right-radius: var(--radius-md);
}
#canvas.cursor-crosshair { cursor: crosshair; }
#canvas.cursor-pen { cursor: crosshair; }
#canvas.cursor-grab { cursor: grab; }
#canvas.cursor-grabbing { cursor: grabbing; }
#canvas.cursor-zoom { cursor: zoom-in; }
#canvas.cursor-zoom-out { cursor: zoom-out; }
#canvas.cursor-text { cursor: text; }

/* Zoom pill — v2 liquid glass (Phase C+, 2026-05-26). */
.zoom-pill {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--glass-base);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-pill);
  padding: 4px;
  display: flex; align-items: center; gap: 1px;
  box-shadow:
    var(--glass-border-top),
    var(--shadow-e3);
  font-size: 11px;
}
.zoom-pill button {
  background: transparent;
  border: none;
  color: var(--ink);
  padding: 5px 11px;
  border-radius: var(--r-pill);
  cursor: pointer;
  font-size: 12px;
  font-weight: 500;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
  letter-spacing: 0.02em;
}
.zoom-pill button:hover {
  background: #32323A;
  color: var(--ink);
}
.zoom-pill button:active { background: #1A1A22; }
.zoom-pill #zoom-level {
  min-width: 52px;
  text-align: center;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  padding: 0 4px;
  font-weight: 500;
}
.zoom-pill #zoom-out, .zoom-pill #zoom-in {
  font-size: 14px;
  font-weight: 400;
  padding: 4px 11px;
}

/* ────────────────────────────────────────────────────────────
   Properties (right) — floating card (Phase C+, 2026-05-26).
   Mirror of the toolbar: lifted off the edges with margin, rounded
   corners, subtle gradient + border + inner highlight + drop shadow.
   ──────────────────────────────────────────────────────────── */
.properties {
  grid-area: properties;
  /* Defined floating panel (2026-05-29) — see .toolbar. Working-surface tone
     + hairline border so the properties column has a clean contained edge
     instead of rows floating in the gutter. */
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  margin: 12px 12px 12px 4px;
  padding: 16px 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.properties::-webkit-scrollbar { width: 8px; }
.properties::-webkit-scrollbar-thumb {
  background: #36363F;
  border-radius: 8px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.properties::-webkit-scrollbar-thumb:hover { background: #424252; background-clip: padding-box; border: 2px solid transparent; }
.properties::-webkit-scrollbar-track { background: transparent; }

.prop-group {
  padding: 0 var(--s-3) var(--s-4);
  margin-bottom: var(--s-3);
  border-bottom: 1px solid var(--line);
  position: relative;
}
.prop-group:last-of-type { border-bottom: none; margin-bottom: 0; }
.prop-group h3 {
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 1.4px;
  color: var(--ink-3);
  font-weight: 600;
  margin-bottom: var(--s-3);
  padding: var(--s-2) 0 6px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.prop-group h3::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--line-soft) 0%, transparent 100%);
}

/* Row */
.row { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.row.gap { gap: 4px; margin-top: var(--s-2); }
.row.gap button {
  flex: 1 1 calc(50% - 2px);
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: 6px 8px;
  border-radius: var(--r-2);
  cursor: pointer;
  font-size: 11px;
  font-weight: 500;
  transition:
    background var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out),
    transform var(--t-instant) var(--ease-press),
    color var(--t-fast) var(--ease-out);
}
.row.gap button:hover {
  background: var(--panel-3);
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.row.gap button:active {
  background: var(--panel);
  transform: translateY(1px);
  box-shadow: none;
}

/* Color swatch row in stroke/fill */
.row > input[type="color"] {
  width: 40px; height: 32px; padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: transparent;
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
.row > input[type="color"]:hover { border-color: var(--line-faint); transform: translateY(-1px); }
.row > input[type="color"]::-webkit-color-swatch-wrapper { padding: 2px; }
.row > input[type="color"]::-webkit-color-swatch { border: none; border-radius: 3px; }

/* No-stroke / no-fill swatch */
.swatch-none {
  width: 32px; height: 32px;
  border-radius: var(--r-2);
  background: var(--panel-sunken);
  border: 1px solid var(--line);
  color: var(--ink-3);
  cursor: pointer;
  position: relative;
  font-size: 14px;
  display: flex; align-items: center; justify-content: center;
  transition:
    background-color var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out);
}
.swatch-none:hover { border-color: var(--accent); color: var(--accent); }
.swatch-none::after {
  content: "";
  position: absolute;
  left: 4px; right: 4px;
  top: 50%;
  height: 1.5px;
  background: var(--danger);
  transform: rotate(-30deg);
  pointer-events: none;
  border-radius: 1px;
}
.swatch-none.active {
  background: var(--danger-soft);
  color: var(--danger);
  border-color: var(--danger);
}
.swatch-none.active::after { background: var(--danger); }

/* Slider row */
.slider-row {
  display: grid;
  grid-template-columns: 48px 1fr 52px;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-3);
}
.slider-row span {
  font-size: 11px;
  color: var(--ink-2);
  font-weight: 500;
}
.slider-row input[type="number"] {
  background: var(--panel-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-1);
  padding: 4px 6px;
  color: var(--ink);
  width: 100%;
  font-variant-numeric: tabular-nums;
  transition: border-color var(--t-fast) var(--ease-out);
}
.slider-row input[type="number"]:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}

/* Custom range slider */
.slider-row input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  background: transparent;
  cursor: pointer;
  height: 18px;
}
.slider-row input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  /* Fluid fill: left of thumb is accent, right is sunken. --fill-pct is set by
     setRangeFill() in app.js whenever the value changes or selection syncs. */
  background: linear-gradient(
    to right,
    var(--accent)       0%,
    var(--accent)       var(--fill-pct, 0%),
    var(--panel-sunken) var(--fill-pct, 0%),
    var(--panel-sunken) 100%
  );
  border-radius: 999px;
  border: 1px solid var(--line);
}
.slider-row input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: linear-gradient(180deg, var(--accent-hi), var(--accent));
  border: 1px solid var(--accent-lo);
  margin-top: -6px;
  box-shadow: 0 1px 2px oklch(0 0 0 / 0.5), var(--inner-hi-2);
  transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
  cursor: grab;
}
.slider-row input[type="range"]:hover::-webkit-slider-thumb {
  transform: scale(1.12);
  box-shadow: 0 2px 6px var(--accent-glow), var(--inner-hi-2);
}
.slider-row input[type="range"]:active::-webkit-slider-thumb {
  cursor: grabbing;
  transform: scale(1.06);
}
.slider-row input[type="range"]::-moz-range-track {
  height: 4px;
  background: linear-gradient(
    to right,
    var(--accent)       0%,
    var(--accent)       var(--fill-pct, 0%),
    var(--panel-sunken) var(--fill-pct, 0%),
    var(--panel-sunken) 100%
  );
  border-radius: 999px;
  border: 1px solid var(--line);
}
.slider-row input[type="range"]::-moz-range-thumb {
  width: 14px; height: 14px;
  border-radius: 50%;
  background: linear-gradient(180deg, var(--accent-hi), var(--accent));
  border: 1px solid var(--accent-lo);
  cursor: grab;
}

/* Segmented control */
.seg {
  display: flex;
  gap: 1px;
  margin-top: var(--s-2);
  background: var(--panel-sunken);
  border-radius: var(--r-2);
  padding: 2px;
  border: 1px solid var(--line);
  align-items: center;
  position: relative;
}
.seg .seg-label {
  font-size: 9.5px;
  color: var(--ink-3);
  padding: 0 8px 0 6px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  font-weight: 600;
  flex-shrink: 0;
}
.seg button {
  flex: 1;
  background: transparent;
  /* Transparent placeholder border so the active state can add a visible
     1px border without shifting adjacent buttons. 2026-05-30. */
  border: 1px solid transparent;
  color: var(--ink-2);
  padding: 5px 4px;
  cursor: pointer;
  border-radius: var(--r-1);
  font-size: 10.5px;
  font-weight: 500;
  transition:
    background var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out);
}
.seg button:hover { color: var(--accent); background: var(--accent-soft); }
.seg button.active {
  /* Matches the topbar action buttons (Copy/Paste/Import/…): dark vertical
     gradient + hairline edge + inner highlight + soft outer shadow. So the
     currently-selected option in any segmented control reads as a real
     "pressed pill" of the same family as the topbar buttons. 2026-05-30.
     Radius matches Copy's (--r-2 = 6px) so the corner curvature is identical;
     --inner-hi-2 (10%) is used instead of --inner-hi (6%) so the raised
     highlight stays readable at the smaller seg height (24px vs 28px). */
  background: linear-gradient(180deg, #303038 0%, #26262F 100%);
  border-color: var(--line);
  border-radius: var(--r-2);
  color: var(--ink);
  box-shadow: var(--shadow-1), var(--inner-hi-2);
}

/* X/Y/W/H grid */
.grid2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-1) 6px;
  margin-top: var(--s-3);
}
.grid2 .field { padding: 4px 8px; }
.grid2 .field input { width: 100%; font-size: 11px; }

/* Layers */
.layers-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 4px;
}
.layers-head h3 { margin-bottom: 0; padding: var(--s-2) 0 6px; }
.layers-head h3::after { display: none; }
.layer-count {
  font-size: 10px;
  color: var(--ink-3);
  background: var(--panel-sunken);
  padding: 2px 8px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

#layers {
  list-style: none;
  max-height: 240px;
  overflow-y: auto;
  margin-top: 4px;
  border-top: 1px solid var(--line-faint);
  border-bottom: 1px solid var(--line-faint);
  background: oklch(0 0 0 / 0.10);
  border-radius: var(--r-1);
}
#layers::-webkit-scrollbar { width: 6px; }
#layers::-webkit-scrollbar-thumb { background: #32323A; border-radius: 6px; }
#layers::-webkit-scrollbar-track { background: transparent; }

#layers li {
  padding: 6px 8px 6px 14px;
  border-radius: 0;
  cursor: grab;
  font-size: 11px;
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--ink-2);
  position: relative;
  user-select: none;
  border-top: 1px solid transparent;
  border-bottom: 1px solid transparent;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
#layers li + li { border-top-color: oklch(0 0 0 / 0.18); }

/* Group stripe */
#layers li.in-group::after {
  content: "";
  position: absolute;
  left: 4px; top: 5px; bottom: 5px;
  width: 3px;
  border-radius: 2px;
  background: var(--group-color, var(--accent));
  box-shadow: 0 0 6px color-mix(in oklch, var(--group-color, var(--accent)) 50%, transparent);
}
#layers li.in-group.group-first::after { border-top-left-radius: 2px; border-top-right-radius: 2px; }
#layers li.in-group.group-last::after  { border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; }

#layers li:active { cursor: grabbing; }
#layers li.dragging {
  opacity: 0.45;
  background: var(--panel-sunken);
}
#layers li.drop-above::before,
#layers li.drop-below::after {
  content: "";
  position: absolute;
  left: 6px; right: 6px;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
  pointer-events: none;
  box-shadow: 0 0 8px var(--accent-glow);
}
#layers li.drop-above::before { top: -1px; }
#layers li.drop-below::after { bottom: -1px; }

#layers li:hover {
  background: #32323A;
  color: var(--ink);
}
#layers li.selected {
  background: linear-gradient(90deg, var(--accent-soft) 0%, rgba(181, 255, 58, 0.06) 100%);
  color: var(--ink);
  font-weight: 500;
  box-shadow: inset 2px 0 0 var(--accent);
}
#layers li.selected .swatch { border-color: oklch(1 0 0 / 0.25); }

#layers li .swatch {
  width: 12px; height: 12px;
  border-radius: 3px;
  border: 1px solid oklch(0 0 0 / 0.25);
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px oklch(1 0 0 / 0.04);
}
#layers li .name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  letter-spacing: 0.01em;
}
#layers li .lock-btn {
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 3px;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-3);
  border-radius: var(--r-1);
  flex-shrink: 0;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
#layers li .lock-btn:hover {
  background: oklch(1 0 0 / 0.06);
  color: var(--ink);
}
#layers li .lock-btn.locked { color: var(--accent); }
#layers li.locked { opacity: 0.6; }
#layers li.locked .name { font-style: italic; }

/* ────────────────────────────────────────────────────────────
   Statusbar
   ──────────────────────────────────────────────────────────── */
.statusbar {
  grid-area: statusbar;
  background: var(--panel);
  border-top: 1px solid var(--line);
  font-size: 11px;
  padding: 0 var(--s-4);
  display: flex; align-items: center; justify-content: space-between;
  color: var(--ink-3);
  letter-spacing: 0.01em;
}
.statusbar #status::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  margin-right: 8px;
  box-shadow: 0 0 6px var(--accent-glow);
  vertical-align: 1px;
  /* Static "ready" dot. The old infinite opacity pulse was idle decoration
     (and repainted forever); a status indicator doesn't need to breathe. */
}
.cursor-pos {
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
}
.statusbar-right {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.statusbar .version {
  font-size: 10.5px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  cursor: help;
  font-variant-numeric: tabular-nums;
}
.statusbar .version::before {
  content: "";
  display: inline-block;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
  margin-right: 7px;
  vertical-align: 1px;
  opacity: 0.7;
}
.legal-links {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 10.5px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
}
.legal-links a {
  color: var(--ink-3);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-out);
}
.legal-links a:hover { color: var(--accent); }
.legal-links .sep { opacity: 0.5; }

/* ────────────────────────────────────────────────────────────
   Hint toast
   ──────────────────────────────────────────────────────────── */
/* Hint toast — v2 liquid glass (Phase C+, 2026-05-26). */
.hint {
  position: fixed;
  bottom: 60px;
  left: 80px; /* clear the 68px toolbar rail (2026-05-29) */
  background: var(--glass-base);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(255, 255, 255, 0.08);
  padding: 12px 16px;
  border-radius: var(--radius-lg);
  font-size: 11.5px;
  color: var(--ink-2);
  pointer-events: none;
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity var(--t-base) var(--ease-out),
    transform var(--t-base) var(--ease-out);
  max-width: 380px;
  line-height: 1.5;
  box-shadow:
    var(--glass-border-top),
    var(--shadow-e3);
  z-index: 50;
}
.hint.show { opacity: 1; transform: translateY(0); }
.hint strong {
  color: var(--accent);
  margin-right: 6px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
/* .hint itself is pointer-events:none so it never blocks canvas hovers,
   but inline links inside hints (e.g. "Start over" in the restored-
   autosave hint) need to be clickable. */
.hint a {
  pointer-events: auto;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.hint a:hover { color: var(--ink); }

/* ────────────────────────────────────────────────────────────
   Context menu
   ──────────────────────────────────────────────────────────── */
/* Context menu — v2 liquid glass (Phase C+, 2026-05-26). */
.ctx-menu {
  position: fixed;
  /* Below the modal layer (100) so a right-click menu never paints over an
     open dialog; above the rest of the chrome. Was 1000. */
  z-index: 99;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: var(--radius-lg);
  padding: 6px;
  min-width: 220px;
  box-shadow:
    var(--glass-border-top),
    var(--shadow-e3);
  display: flex;
  flex-direction: column;
  gap: 1px;
  font-size: 12px;
  /* Elastic "bubble pop" entrance — overshoots past full size then settles. */
  animation: ctx-pop 240ms var(--ease-spring);
  transform-origin: top left;
}
@keyframes ctx-pop {
  from { opacity: 0; transform: scale(0.82); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: scale(1); }
}
.ctx-menu[hidden] { display: none; }
.ctx-menu button {
  background: transparent;
  border: none;
  color: var(--ink);
  padding: 7px 12px;
  cursor: pointer;
  text-align: left;
  border-radius: var(--r-1);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.ctx-menu button:hover {
  /* Text glows lime on hover (matches the universal hover language); a faint
     frosted lift marks the active row instead of a solid lime fill. */
  background: var(--glass-light);
  color: var(--accent-lime);
}
.ctx-menu button:hover .kbd { color: var(--accent-lime); opacity: 0.7; }
.ctx-menu button:disabled { color: var(--ink-4); cursor: default; }
.ctx-menu button:disabled:hover { background: transparent; color: var(--ink-4); }
.ctx-menu hr {
  border: none;
  border-top: 1px solid var(--line-soft);
  margin: 4px 6px;
}
.ctx-menu .kbd {
  font-size: 10px;
  color: var(--ink-3);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
}

/* ────────────────────────────────────────────────────────────
   SVG overlay guides
   ──────────────────────────────────────────────────────────── */
#overlay .selbox {
  fill: none;
  stroke: var(--select);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 4 3;
}

/* Artboard resize chrome — drag the artboard's edges/corners to resize it.
   Lime, to set it apart from the amber shape-selection chrome. The frame is a
   thin lime outline; handles are dark squares with a lime ring (fill lime on
   hover). Shown only when the Select tool is active and nothing is selected. */
#overlay .ab-frame {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
  opacity: 0.55;
  pointer-events: none;
}
#overlay .ab-handle {
  fill: var(--bg);
  stroke: var(--accent);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}
#overlay .ab-handle:hover { fill: var(--accent); }
#overlay .ab-guide {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 7 5;
  opacity: 0.9;
  pointer-events: none;
}
#overlay .ab-guide.center {
  stroke-dasharray: 2 4;
}

/* Artboard name labels (Figma/Paper style) — sit above each artboard. Click to
   select, drag to move, double-click to rename. The active artboard's label is
   lime; others are muted until hovered. */
#artboards .ab-label {
  fill: var(--ink-2);
  font-family: var(--font-sans);
  font-weight: 500;
  letter-spacing: 0.02em;
  cursor: move;
  -webkit-user-select: none;
  user-select: none;
  transition: fill var(--t-fast) var(--ease-out);
}
#artboards .ab-label.active { fill: var(--accent); }
#artboards .ab-label:hover { fill: var(--accent-hi); }
.artboard-rename-input {
  position: fixed;
  z-index: 130;
  box-sizing: border-box;
  padding: 2px 8px;
  border: 1px solid var(--accent);
  border-radius: 4px;
  background: var(--panel);
  color: var(--ink);
  font: 500 12px/1.4 var(--font-sans);
  letter-spacing: 0;
  outline: none;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28);
}
.artboard-rename-input::selection {
  background: color-mix(in oklab, var(--accent) 45%, transparent);
}
#overlay .anchor {
  fill: white;
  stroke: var(--select);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
#overlay .anchor.smooth { fill: var(--select); }
#overlay .handle-line {
  stroke: var(--select);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  fill: none;
}
#overlay .handle-dot {
  fill: var(--select);
  stroke: white;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
#overlay .resize {
  fill: white;
  stroke: var(--select);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
#overlay .preview {
  fill: rgba(242, 212, 61, 0.06);
  stroke: var(--select);
  stroke-width: 1;
  stroke-dasharray: 4 3;
  vector-effect: non-scaling-stroke;
}
#overlay .pen-preview {
  fill: none;
  stroke: var(--select);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  vector-effect: non-scaling-stroke;
}
#overlay .snap-ring {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  animation: snap-pulse 1.2s ease-in-out infinite;
}
#overlay .snap-dot {
  fill: var(--accent);
  vector-effect: non-scaling-stroke;
}

/* Rotation handle — small stem with a dot above the selection bbox. The dot
   is the grab target; the corner rings (rot-corner-zone) are invisible but
   pick up "just past the corner" drags. */
#overlay .rot-stem {
  stroke: var(--accent);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  opacity: 0.65;
}
#overlay .rot-handle {
  fill: var(--accent);
  stroke: white;
  stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
  cursor: grab;
  transition: transform 120ms cubic-bezier(0.16, 1, 0.3, 1);
}
#overlay .rot-handle:hover {
  fill: var(--accent-hi);
}
#overlay .rot-corner-zone {
  /* invisible but pickable */
  cursor: grab;
}

/* While a rotation drag is active, every cursor in the document shows the
   "grabbing" state — keeps feedback consistent even when the pointer
   crosses out of the original handle bounds during the drag. */
body.cursor-rotating,
body.cursor-rotating * {
  cursor: grabbing !important;
}
@keyframes snap-pulse {
  0%, 100% { opacity: 0.7; }
  50%      { opacity: 1; }
}

/* ────────────────────────────────────────────────────────────
   Text properties section
   ──────────────────────────────────────────────────────────── */
.prop-text .field.full {
  width: 100%;
}
.prop-text .field.full > span {
  min-width: 32px;
}
.prop-text .field.full .ctrl-select {
  flex: 1;
  width: 100%;
}
textarea.text-content {
  width: 100%;
  min-height: 56px;
  max-height: 160px;
  resize: vertical;
  padding: var(--s-2) var(--s-3);
  background: var(--panel-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--ink);
  font-family: inherit;
  font-size: 12px;
  line-height: 1.4;
  outline: none;
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
  margin-bottom: var(--s-2);
}
textarea.text-content:hover { border-color: var(--line-faint); }
textarea.text-content:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Style toggle buttons (B / I / U) render their label glyph straight */
#text-style-seg button b,
#text-style-seg button i,
#text-style-seg button u {
  font-size: 13px;
  font-style: normal;
  text-decoration: none;
}
#text-style-seg button b      { font-weight: 700; }
#text-style-seg button i      { font-style: italic; font-family: 'Georgia', 'Times New Roman', serif; }
#text-style-seg button u      { text-decoration: underline; text-underline-offset: 2px; }

/* ────────────────────────────────────────────────────────────
   Inline text editor — textarea overlaid on the canvas while typing
   ──────────────────────────────────────────────────────────── */
.text-editor {
  position: absolute;
  z-index: 100;
  margin: 0;
  padding: 0;
  border: 1px dashed var(--accent);
  border-radius: 2px;
  outline: none;
  resize: none;
  overflow: hidden;
  background: oklch(1 0 0 / 0.04);
  color: inherit;
  white-space: pre;
  word-wrap: normal;
  font-family: inherit;
  font-size: 16px;
  line-height: 1.2;
  caret-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
  user-select: text;
}
.text-editor::selection { background: var(--accent-soft); }

/* ────────────────────────────────────────────────────────────
   Entrance reveal (2026-05-29: de-choreographed).
   The old version slid the topbar/toolbar/properties/statusbar in from
   four different directions with staggered delays — an orchestrated
   page-load sequence, which a product tool should not do (the register
   rule: "Product loads into a task; users don't want to watch it load").
   Replaced with a single quick whole-app opacity fade so first paint isn't
   a hard flash, but nothing moves and nothing staggers.
   ──────────────────────────────────────────────────────────── */
.app { animation: fade-in 180ms var(--ease-out) both; }

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0ms !important;
    transition-duration: 0ms !important;
  }
}

/* ────────────────────────────────────────────────────────────
   Pro extensions — gradients, swatches, effects, alignment,
   booleans, components, autotrace, pages, rulers, modals
   ──────────────────────────────────────────────────────────── */

/* Split button + dropdown — pill-shaped split (2026-05-30 refresh).
   The two halves keep their rounded outer corners and share a hairline
   divider in the middle, so the pair reads as one continuous pill.
   Used for both #export-split and #user-menu. */
.split-btn { position: relative; display: inline-flex; }
.split-btn > button:not(.caret) {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: none;
}
.split-btn .caret {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  padding: 0 10px;
  border-left: 1px solid var(--line);
}
.split-btn .menu {
  position: absolute; top: calc(100% + 6px); right: 0;
  background: var(--panel); border: 1px solid var(--line-soft); border-radius: var(--r-3);
  box-shadow: var(--shadow-2); padding: 6px; min-width: 180px; z-index: 80;
  display: flex; flex-direction: column; gap: 2px;
}
.split-btn .menu button {
  text-align: left; padding: 7px 10px; font-size: 12px;
  background: transparent; border: none; color: var(--ink);
  border-radius: var(--r-2); cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}
.split-btn .menu button:hover { background: var(--panel-2); color: var(--accent); }

/* Fill type segmented tabs */
.seg-tabs button { padding: 4px 8px; font-size: 11px; }

/* Gradient + pattern editors */
.gradient-editor, .pattern-picker {
  margin-top: 6px;
  padding: 8px; border: 1px dashed var(--line-soft); border-radius: var(--r-2);
  background: var(--panel-sunken);
  display: flex; flex-direction: column; gap: 6px;
}
.gradient-preview {
  height: 22px; border-radius: var(--r-1); border: 1px solid var(--line);
  cursor: pointer;
}
.gradient-editor .row.gap button.mini,
.gradient-editor .row.gap .field { font-size: 11px; }
.pattern-picker .grid-pats {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px;
}
.pattern-picker .pat-cell {
  width: 100%; aspect-ratio: 1/1; border: 1px solid var(--line);
  border-radius: var(--r-1); cursor: pointer; background-size: 14px 14px;
}
.pattern-picker .pat-cell.active {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

/* Eyedropper icon button */
.mini-icon {
  padding: 3px 7px; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: var(--r-2); color: var(--ink-2); cursor: pointer;
  transition:
    background var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out);
}
.mini-icon:hover {
  background: var(--panel-3);
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Swatches */
.swatches {
  margin-top: 4px; padding-top: 6px; border-top: 1px solid var(--line-faint);
}
.swatches-head {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--ink-3); margin-bottom: 4px;
}
.swatches-head .mini {
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink-2);
  border-radius: var(--r-1); width: 18px; height: 18px; cursor: pointer; line-height: 1;
}
.swatches-grid {
  display: grid; grid-template-columns: repeat(10, 1fr); gap: 3px;
}
.swatch-chip {
  aspect-ratio: 1/1; border-radius: 3px; border: 1px solid var(--line);
  cursor: pointer; padding: 0;
}
.swatch-chip:hover { outline: 1px solid var(--accent); }
.swatch-chip.active { outline: 2px solid var(--accent); outline-offset: 1px; }
.swatch-chip[data-removable]:active { transform: scale(0.95); }

/* Align row icons */
.align-row button {
  width: 30px; height: 26px; padding: 0;
  font-family: 'Segoe UI Symbol', sans-serif; font-size: 16px;
}

/* Pages strip — v2 redesign (Phase C). White-pill active tab + smooth
   hover transitions, matching the reference image's segmented control. */
.pages-strip {
  /* Tab strip for "round-out" tabs (Chris Coyier / Frontend Masters technique:
     https://frontendmasters.com/blog/modern-css-round-out-tabs/). Each tab is
     clip-path:shape()'d into a silhouette with rounded TOP corners and bottom
     corners that flare OUTWARD into the workspace below — a paper-tab look.
     The strip is just the dark chrome backdrop; no baseline border needed —
     the tabs' own flared feet visually land on the workspace. */
  display: flex; align-items: flex-end; gap: 2px;
  /* No left padding — the first tab sits flush against the strip's left edge,
     so its bottom-left flare merges directly into the workspace below (both
     are --panel) and the "notch" between toolbar and Page 1 disappears. */
  padding: 10px 14px 0 0; background: var(--bg);
  overflow-x: auto;
  position: relative; z-index: 2;
}
.page-tab {
  /* Round-out tabs — verbatim CSS clip-path:shape() from the Frontend Masters
     article (Block 8, the variablized recommended version). The shape begins
     at bottom-left and walks: flare-out curve up, vertical, top-left curve in,
     horizontal across the top, top-right curve in, vertical down, flare-out
     curve to bottom-right. Result: a tab silhouette with rounded TOP corners
     and bottom corners that flare OUTWARD — exactly like a Chrome paper tab. */
  --tabGirth: 10px;

  position: relative;
  display: inline-flex;           /* preserve internal text + dot + close-× alignment */
  align-items: center;
  padding: 7px 22px;              /* extra inline padding so text clears the bottom flares */
  /* Inactive: subtle midpoint between strip (--bg) and active tab (--panel) —
     visible silhouette, clearly behind the active tab. */
  background: color-mix(in srgb, var(--bg) 75%, var(--panel) 25%);
  border: none;                   /* clip-path replaces all border-based shaping */
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 11.5px;
  font-weight: 500;
  white-space: nowrap;
  letter-spacing: 0.01em;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);

  /* Asymmetric round-out tab — Frontend Masters Block 8 with the LEFT-bottom
     flare removed. The tab's left edge is a straight vertical at x=0 from the
     bottom up to the rounded top-left corner — aligned with the workspace's
     left edge below (strip has padding-left:0), so the tab body sits flush
     against the dotted "pan" on the left. The RIGHT side keeps Block 8's
     outward flare — the tab still has its "pan-foot" curvature on the trailing
     side. Walk: straight up the left, curve into top-left, across the top,
     curve into top-right, straight down the right, flare out at bottom-right. */
  clip-path: shape(
    from bottom left,
    vline to var(--tabGirth),
    curve to var(--tabGirth) 0 with 0 0,
    hline to calc(100% - calc(var(--tabGirth) * 2)),
    curve to calc(100% - var(--tabGirth)) var(--tabGirth) with calc(100% - var(--tabGirth)) 0,
    vline to calc(100% - var(--tabGirth)),
    curve to 100% 100% with calc(100% - var(--tabGirth)) 100%
  );

  /* Fallback for engines without clip-path: shape() support — verbatim Block 9. */
  @supports not (clip-path: shape(from top left, hline to 0)) {
    padding-inline: 1rem;
    border-start-start-radius: var(--tabGirth);
    border-start-end-radius: var(--tabGirth);
  }
}
.page-tab:hover {
  background: color-mix(in srgb, var(--bg) 60%, var(--panel) 40%);
  /* Lime glow on hover — text turns accent + drop-shadow gives the
     "green light" feel the user asked for. drop-shadow respects clip-path,
     so the glow follows the round-out tab silhouette. */
  color: var(--accent);
  filter: drop-shadow(0 0 6px var(--accent-glow));
}
.page-tab.active {
  /* Active tab — visually MERGED with the dotted canvas below. The same
     camera-synced radial-gradient dot pattern (driven by --grid-step/x/y on
     :root) paints across the tab so the tab reads as a piece of the canvas
     lifted up into the strip — not a separate panel. The clip-path shape gives
     the rounded silhouette. A rotating lime conic-gradient "shine" traces the
     tab's perimeter (same mechanism as the feedback pill, clipped to the
     round-out silhouette), and an additional drop-shadow filter extends the
     glow OUTSIDE the silhouette into the canvas area below. */
  background:
    radial-gradient(circle, var(--grid-dot) 1.1px, transparent 1.7px) var(--grid-x, 0px) var(--grid-y, 0px) / var(--grid-step, 24px) var(--grid-step, 24px),
    var(--panel);
  color: var(--ink);
  font-weight: 600;
  isolation: isolate;       /* contain the ::before z-index:-1 trick */
  /* Drop-shadow extends past the clip-path silhouette into the strip and the
     canvas area below — so the lime glow flows over the canvas edges, not
     just the tab. Animated to "breathe" in sync with the shine. */
  animation: tab-glow-bleed 4s ease-in-out infinite;
}
@keyframes tab-glow-bleed {
  0%, 100% { filter: drop-shadow(0 0 6px var(--accent-glow)); }
  50%      { filter: drop-shadow(0 4px 14px var(--accent-glow)) drop-shadow(0 0 8px var(--accent)); }
}
/* The two separate perimeter rings (tab + canvas) have been replaced by a
   SINGLE comet element (#page-comet) that travels a continuous compound
   path: tab left → top → right → (turn) → canvas top → right → bottom → left
   → (close) back to tab bottom-left → up the tab left again. The path is
   generated in JS (updatePageCometPath) based on the active tab's measured
   bounds + canvas-area's bounds, so one moving light reads as ONE continuous
   green shine flowing around the page's outline. (2026-05-29) */
.page-tab.active:hover {
  /* On hover, brighten the text — the conic shine already provides motion. */
  color: var(--accent);
}
/* Status slot — the green dot and the close × occupy ONE spot (browser-tab
   pattern). The dot shows by default; hovering the tab cross-fades the dot out
   and the × in, so the × lands exactly where the dot was. */
.tab-slot {
  /* Enlarged to a reliable hit target (was 13px — too small, clicks often
     fell through to the parent tab and switched pages instead of deleting).
     Now an 18px square so the × is comfortably clickable. */
  position: relative;
  width: 18px; height: 18px;
  margin-left: 8px;
  flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
}
.tab-slot .page-dot {
  /* The dot stays small + centered; pointer-events:none so clicks pass through
     to the × beneath. */
  position: absolute;
  top: 50%; left: 50%;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent-glow);
  transition: opacity var(--dur-fast) var(--ease-out);
  pointer-events: none;
  /* Soft pulse — the green dot "breathes" so the active tab feels alive. */
  animation: page-dot-pulse 2.4s ease-in-out infinite;
}
@keyframes page-dot-pulse {
  0%, 100% { box-shadow: 0 0 4px var(--accent-glow); transform: translate(-50%, -50%) scale(1); }
  50%      { box-shadow: 0 0 12px var(--accent-glow); transform: translate(-50%, -50%) scale(1.15); }
}
.tab-slot .x {
  /* The × fills the entire 18px slot — large click target. Text remains
     small and visually centered, but the click area covers the whole slot. */
  position: absolute;
  inset: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px;
  line-height: 1;
  border-radius: 50%;
  opacity: 0;            /* hidden until the tab is hovered */
  color: var(--ink-2);
  cursor: pointer;
  transition: opacity var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.page-tab:hover .tab-slot .page-dot { opacity: 0; animation: none; }
.page-tab:hover .tab-slot .x { opacity: 0.9; }
.tab-slot .x:hover { opacity: 1 !important; color: var(--ink); background: rgba(255, 255, 255, 0.08); }
.page-tab.active .tab-slot .x { color: var(--ink); }

.page-add {
  background: transparent;
  border: 1px dashed rgba(255, 255, 255, 0.12);
  color: var(--text-tertiary);
  /* Rounded RECTANGLE, not a pill (user request, repeated) — matches the
     page tab's 9px corner radius for a consistent shape language. */
  border-radius: 9px;
  padding: 6px 14px;
  /* Lift off the canvas so its bottom edge isn't kissing the dotted workspace
     below — user said it felt cramped. 6px gap keeps it visually contained
     in the strip while still aligned with the tabs' baseline area. */
  margin-bottom: 6px;
  cursor: pointer;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.01em;
  transition:
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    border-style var(--dur-fast) var(--ease-out);
}
.page-add:hover {
  color: var(--text-primary);
  border-color: rgba(255, 255, 255, 0.25);
  border-style: solid;
}

/* Rulers */
.rulers {
  position: absolute; inset: 0; pointer-events: none;
  font-family: var(--font-mono); font-size: 9px;
  color: var(--ink-3);
}
.ruler { position: absolute; background: var(--panel-sunken); border-color: var(--line-faint); }
.ruler-x { top: 0; left: 18px; right: 0; height: 18px; border-bottom: 1px solid; }
.ruler-y { top: 18px; left: 0; bottom: 0; width: 18px; border-right: 1px solid; }
.ruler-corner {
  position: absolute; top: 0; left: 0; width: 18px; height: 18px;
  background: var(--panel-sunken); border-right: 1px solid var(--line-faint);
  border-bottom: 1px solid var(--line-faint);
}
.canvas-area.has-rulers .ruler-x .tick,
.canvas-area.has-rulers .ruler-y .tick {
  position: absolute; color: var(--ink-3);
}

/* Code panel */
.code-panel {
  position: fixed; right: 0; top: 0; bottom: 0;
  width: min(380px, 100vw); background: var(--panel); border-left: 1px solid var(--line);
  display: flex; flex-direction: column; z-index: 90;
  box-shadow: var(--shadow-3);
}
.code-panel-head {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px;
  border-bottom: 1px solid var(--line);
}
.code-panel-head h3 { flex: 1; font-size: 12px; }
.code-panel-head button {
  padding: 4px 10px; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: var(--r-1); color: var(--ink); cursor: pointer;
}
.code-panel-head button.ghost { background: transparent; }
.code-panel textarea {
  flex: 1; resize: none; background: var(--bg-deep); color: var(--ink);
  font-family: var(--font-mono); font-size: 11px;
  padding: 10px; border: none; outline: none; white-space: pre;
}

/* Modals — v2 redesign (Phase C+, 2026-05-26).
   True liquid glass: heavy backdrop blur on the scrim AND on the card,
   visible top-edge highlight, deep shadow for depth. */
.modal {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(8px) saturate(140%);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  display: flex; align-items: center; justify-content: center;
  animation: modal-scrim-in 240ms var(--ease-out);
}
.modal[hidden] { display: none; }
.modal-card {
  background: var(--glass-base);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-xl);
  box-shadow:
    var(--glass-border-top),
    var(--shadow-e4),
    0 0 80px rgba(0, 0, 0, 0.5);
  padding: 20px;
  min-width: 360px; max-width: 90vw;
  display: flex; flex-direction: column; gap: 12px;
  animation: modal-card-in 320ms var(--ease-spring);
}
@keyframes modal-scrim-in {
  from { opacity: 0; backdrop-filter: blur(0); -webkit-backdrop-filter: blur(0); }
  to   { opacity: 1; }
}
@keyframes modal-card-in {
  from { opacity: 0; transform: translateY(12px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.modal-head {
  display: flex; align-items: center; justify-content: space-between;
}
.modal-head h3 { font-size: 13px; }
.modal-head .ghost {
  background: transparent; border: none; color: var(--ink-3); cursor: pointer;
  font-size: 18px; line-height: 1;
}

/* Gradient stop bar */
.gradient-bar {
  position: relative; height: 30px; border-radius: var(--r-1);
  border: 1px solid var(--line); cursor: copy;
}
.gradient-bar .stop {
  position: absolute; top: -2px; bottom: -2px; width: 10px;
  margin-left: -5px; border: 2px solid var(--ink); background: transparent;
  border-radius: 3px; cursor: ew-resize;
  box-shadow: 0 0 0 1px var(--bg-deep);
}
.gradient-bar .stop.active { border-color: var(--accent); }
.gradient-bar .stop .inner { position: absolute; inset: 2px; border-radius: 2px; }

/* Symbols list */
.symbols-list, .symbols-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; margin-top: 4px;
}
.symbol-tile {
  aspect-ratio: 1/1; border: 1px solid var(--line); border-radius: var(--r-2);
  background: var(--panel-sunken); padding: 4px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.symbol-tile svg { width: 100%; height: 100%; }
.symbol-tile.active { outline: 2px solid var(--accent); }

/* Knife / eyedropper / add-anchor cursors */
.cursor-knife { cursor: crosshair; }
.cursor-eyedropper { cursor: copy; }

/* Knife stroke overlay */
.knife-stroke {
  stroke: var(--accent); stroke-width: 1; stroke-dasharray: 4 3;
  fill: none; pointer-events: none;
}

/* Snap a few buttons to a compact size */
#bool-union, #bool-sub, #bool-int, #bool-xor,
#al-l, #al-cx, #al-r, #al-t, #al-cy, #al-b,
#dist-h, #dist-v { flex: 1; }

/* ────────────────────────────────────────────────────────────
   Examples modal
   ──────────────────────────────────────────────────────────── */
.examples-card { min-width: 560px; max-width: 720px; }
.examples-help {
  margin: 0 0 14px;
  color: var(--ink-3);
  font-size: 12.5px;
  letter-spacing: 0.01em;
}
.examples-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
}
.example-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--panel-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  padding: 12px;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  color: var(--ink-2);
  transition: border-color var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out),
              background-color var(--t-fast) var(--ease-out);
}
.example-card:hover {
  border-color: var(--accent);
  background: oklch(from var(--panel-sunken) calc(l + 0.015) c h);
  transform: translateY(-1px);
}
.example-card .example-thumb {
  width: 100%;
  aspect-ratio: 3/2;
  background: oklch(from var(--bg) calc(l + 0.02) c h);
  border-radius: var(--r-2);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.example-card .example-thumb svg { width: 100%; height: 100%; display: block; }
.example-card .example-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.01em;
}
.example-card .example-desc {
  font-size: 11.5px;
  color: var(--ink-3);
  line-height: 1.4;
}

/* ────────────────────────────────────────────────────────────
   Onboarding modal — first-run, 4 panels, skippable
   ──────────────────────────────────────────────────────────── */
.onboarding-card {
  max-width: 480px;
  min-width: 360px;
  width: calc(100vw - 60px);
  padding: 0;
  display: flex;
  flex-direction: column;
}
.onboarding-step {
  padding: 32px 32px 14px;
  min-height: 280px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.onboarding-step .onb-eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}
.onboarding-step h2 {
  margin: 0;
  /* Was 'Lora' serif — a display serif in product UI chrome is off-system.
     The onboarding modal is UI, not content, so it uses the UI sans. */
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 22px;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.onboarding-step p {
  margin: 0;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.55;
}
.onboarding-step ul {
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.onboarding-step li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.5;
}
.onboarding-step li .kbd {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  padding: 1px 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--accent);
  background: oklch(from var(--accent) l c h / 0.10);
  border: 1px solid oklch(from var(--accent) l c h / 0.3);
  border-radius: 4px;
  line-height: 1.3;
}
.onboarding-step li b {
  color: var(--ink);
  font-weight: 600;
}
.onboarding-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px 16px;
  border-top: 1px solid var(--line);
  gap: 12px;
}
.onboarding-skip {
  background: transparent;
  border: none;
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: 0.02em;
  cursor: pointer;
  padding: 6px 10px;
  border-radius: var(--r-2);
  transition: color var(--t-fast) var(--ease-out);
}
.onboarding-skip:hover { color: var(--ink-2); }
.onboarding-dots {
  display: flex;
  gap: 6px;
}
.onboarding-dots .dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: oklch(from var(--ink-3) l c h / 0.4);
  transition: background var(--t-fast) var(--ease-out);
}
.onboarding-dots .dot.active { background: var(--accent); }
.onboarding-nav {
  display: flex;
  gap: 8px;
}
.onboarding-back, .onboarding-next {
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  padding: 7px 14px;
  border-radius: var(--r-2);
  cursor: pointer;
  border: 1px solid var(--line);
  transition: border-color var(--t-fast) var(--ease-out),
              background-color var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}
.onboarding-back {
  background: transparent;
  color: var(--ink-2);
}
.onboarding-back:hover {
  border-color: var(--ink-3);
  color: var(--ink);
}
.onboarding-next {
  background: var(--accent);
  border-color: var(--accent);
  color: #0B0B10;
  font-weight: 600;
}
.onboarding-next:hover {
  background: oklch(from var(--accent) calc(l + 0.04) c h);
  border-color: oklch(from var(--accent) calc(l + 0.04) c h);
}

/* ────────────────────────────────────────────────────────────
   Feedback widget — floating pill bottom-right, expands to a panel
   ──────────────────────────────────────────────────────────── */
.feedback-widget {
  position: fixed;
  /* Bottom-right corner of the viewport (user request 2026-05-29) — was
     offset to right:334px to clear the properties panel; user prefers it
     in the true bottom-right corner, even if that sits over the panel. */
  right: 16px;
  bottom: 16px;
  z-index: 95;  /* below modals (100) so opening a modal still covers it */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}
.feedback-toggle {
  /* isolation creates a new stacking context so the ::before shine layer can
     sit BEHIND the pill content (z-index:-1) without escaping to behind
     other page content. */
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px 7px 11px;
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--ink-2);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  box-shadow: 0 4px 12px oklch(0 0 0 / 0.28), 0 1px 0 oklch(0 0 0 / 0.18);
  cursor: pointer;
  overflow: hidden;     /* clip the shine to the pill silhouette */
  transition: color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
/* Rotating lime "shine" — a conic-gradient that sweeps around the pill's
   border, restored by user request (2026-05-29). The mask cuts a 1px-wide
   ring around the perimeter so only the border lights up, not the whole pill.
   `inset:-1px` extends past the pill so the conic continues smoothly across
   the rounded corners. */
.feedback-toggle::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: inherit;
  background: conic-gradient(
    from 0deg,
    transparent 0deg,
    var(--accent) 60deg,
    var(--accent-glow) 90deg,
    transparent 180deg,
    transparent 360deg
  );
  animation: feedback-shine 4s linear infinite;
}
/* Repaint the pill body OVER the conic so only the border-band remains lit. */
.feedback-toggle::after {
  content: "";
  position: absolute;
  inset: 1px;
  z-index: -1;
  border-radius: inherit;
  background: var(--panel);
}
@keyframes feedback-shine {
  to { transform: rotate(360deg); }
}
.feedback-toggle:hover {
  transform: translateY(-1px);
  border-color: var(--accent-soft);
}
.feedback-toggle svg { color: var(--accent); flex-shrink: 0; }

.feedback-panel {
  width: 320px;
  max-width: calc(100vw - 40px);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  box-shadow: 0 12px 28px oklch(0 0 0 / 0.40), 0 2px 0 oklch(0 0 0 / 0.18);
  padding: 14px 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  animation: feedback-pop 200ms var(--ease-out);
}
@keyframes feedback-pop {
  from { transform: translateY(8px) scale(0.97); opacity: 0; }
  to   { transform: translateY(0)    scale(1);    opacity: 1; }
}
.feedback-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.feedback-head h3 {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.feedback-x {
  background: transparent;
  border: none;
  color: var(--ink-3);
  font-size: 18px;
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
  transition: color var(--t-fast) var(--ease-out);
}
.feedback-x:hover { color: var(--ink); }
.feedback-help {
  margin: 0;
  font-size: 11.5px;
  color: var(--ink-3);
  line-height: 1.45;
  letter-spacing: 0.01em;
}
.feedback-panel textarea {
  resize: vertical;
  min-height: 90px;
  max-height: 240px;
  width: 100%;
  box-sizing: border-box;
  background: var(--panel-sunken);
  border: 1px solid var(--line);
  color: var(--ink);
  font-family: inherit;
  font-size: 13px;
  line-height: 1.5;
  padding: 10px 12px;
  border-radius: var(--r-2);
  outline: none;
  transition: border-color var(--t-fast) var(--ease-out);
}
.feedback-panel textarea:focus { border-color: var(--accent); }
.feedback-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
}
.feedback-status {
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  min-height: 1em;
}
.feedback-status.ok  { color: var(--accent); }
.feedback-status.err { color: #E04444; }
.feedback-submit {
  background: var(--accent);
  color: #0B0B10;
  border: none;
  border-radius: var(--r-2);
  padding: 6px 14px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out);
}
.feedback-submit:hover {
  background: oklch(from var(--accent) calc(l + 0.04) c h);
}
.feedback-submit:disabled {
  opacity: 0.55;
  cursor: default;
}

/* ────────────────────────────────────────────────────────────
   Mobile soft-gate banner
   ──────────────────────────────────────────────────────────── */
.mobile-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 110; /* above modals so it can't be missed */
  background: var(--panel-sunken);
  border-bottom: 1px solid var(--accent);
  box-shadow: 0 2px 8px oklch(0 0 0 / 0.3);
  color: var(--ink-2);
  font-size: 12.5px;
  line-height: 1.4;
  letter-spacing: 0.01em;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.mobile-banner strong { color: var(--accent); font-weight: 600; }
.mobile-banner-msg { flex: 1; }
.mobile-banner-x {
  background: transparent;
  border: none;
  color: var(--ink-3);
  font-size: 20px;
  cursor: pointer;
  padding: 0 6px;
  line-height: 1;
  margin-left: auto;
  flex-shrink: 0;
  transition: color var(--t-fast) var(--ease-out);
}
.mobile-banner-x:hover { color: var(--ink); }
/* When the banner is visible, push .app down by its height. */
body:has(.mobile-banner:not([hidden])) .app { padding-top: 44px; }
body:has(.mobile-banner:not([hidden])) .app .topbar { animation: none; }

/* Text-on-path sub-panel (revealed inside prop-text when textPathRef is set). */
.prop-sub {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--line-faint);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.prop-sub-label {
  font-size: 10px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.8px;
  font-weight: 600;
  margin-bottom: 2px;
}

/* True mesh-gradient editor */
.mesh-hint {
  font-size: 11px;
  color: var(--ink-3);
  line-height: 1.5;
  margin-bottom: 10px;
}
#mesh-grid-seg .seg-label { margin-right: 6px; }
.mesh-grid-wrap {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin: 12px 0;
  align-items: stretch;
}
.mesh-grid {
  display: grid;
  gap: 4px;
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--r-1);
  padding: 6px;
  aspect-ratio: 1 / 1;
}
.mesh-grid .mesh-node {
  position: relative;
  width: 100%; height: 100%;
  border-radius: 4px;
  border: 2px solid rgba(0,0,0,0.35);
  cursor: pointer;
  padding: 0;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.18);
  transition: transform 0.1s ease, border-color 0.1s ease;
}
.mesh-grid .mesh-node:hover { transform: scale(1.08); border-color: var(--accent); }
.mesh-grid .mesh-node:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mesh-grid .mesh-node input[type="color"] {
  position: absolute; inset: 0; opacity: 0; cursor: pointer; border: none;
}
.mesh-preview {
  border: 1px solid var(--line);
  border-radius: var(--r-1);
  background-color: var(--bg-deep);
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
  aspect-ratio: 1 / 1;
  min-height: 120px;
}

/* ============================================================
   Auth (subsection 31) — sign-in button, modal, sign-up bar
   ============================================================ */

/* Topbar user-menu pill (2026-05-30 v2).
   Single-button pill matching profile.html's .account-trigger:
   one continuous border holding avatar + name + chevron. Replaces the
   prior split-btn pattern (which had a hairline divider between the
   name and the chevron). The chevron is intentionally larger here
   than profile.html's 10px because users reported it reading as too
   small in the editor topbar. */
.user-menu { position: relative; display: inline-flex; }
.user-menu .user-pill {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 4px 12px 4px 4px;
  height: auto;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out);
}
.user-menu .user-pill:hover { border-color: var(--line-soft); background: var(--panel-2); }
.user-menu .user-pill[aria-expanded="true"] { border-color: var(--accent); }
.user-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-lo) 100%);
  color: var(--accent-ink);
  font-weight: 700; font-size: 11.5px;
  letter-spacing: 0.02em;
  flex-shrink: 0;
}
.user-menu .user-pill .user-name { font-size: 13px; font-weight: 500; color: var(--ink); line-height: 1; }
.user-menu .user-pill .user-chev { font-size: 14px; line-height: 1; color: var(--ink-3); }
#user-menu-dropdown {
  position: absolute; top: calc(100% + 6px); right: 0;
  background: var(--panel); border: 1px solid var(--line-soft);
  border-radius: var(--r-3); box-shadow: var(--shadow-2);
  padding: 6px; min-width: 200px; z-index: 80;
  display: flex; flex-direction: column; gap: 2px;
}
#user-menu-dropdown button {
  text-align: left; padding: 7px 10px; font-size: 12px;
  background: transparent; border: none; color: var(--ink);
  border-radius: var(--r-2); cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}
#user-menu-dropdown button:hover { background: var(--panel-2); color: var(--accent); }
.menu-note {
  max-width: 230px;
  padding: 8px 10px;
  color: var(--ink-3);
  font-size: 11.5px;
  line-height: 1.35;
  border-bottom: 1px solid var(--line);
}

/* Auth modal — reuses .modal / .modal-card base */
.auth-card { max-width: 420px; }
.auth-lede {
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.55;
  margin: 4px 0 18px;
}
.auth-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 10px 16px;
  background: #fff;
  color: #1a1a1a;
  border: 1px solid #dadce0;
  border-radius: 6px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: box-shadow 0.15s ease, background-color 0.15s ease;
}
.auth-google:hover { background: #f8f9fa; box-shadow: 0 1px 3px rgba(0,0,0,0.18); }
.auth-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--ink-3);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  margin: 18px 0;
}
.auth-divider::before, .auth-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--line);
}
.auth-form { display: flex; flex-direction: column; gap: 12px; }
.auth-label { display: flex; flex-direction: column; gap: 6px; font-size: 11.5px; color: var(--ink-2); }
.auth-label > span:first-child {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  color: var(--ink-3);
}
.auth-label input[type="email"] {
  padding: 9px 12px;
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  font-family: inherit;
  font-size: 14px;
}
.auth-label input[type="email"]:focus {
  outline: none;
  border-color: var(--accent);
}
.auth-optin {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  line-height: 1.45;
}
.auth-optin input { margin-top: 2px; flex-shrink: 0; }
.auth-turnstile:not(:empty) { margin: 4px 0; }
.auth-submit {
  padding: 10px 16px;
  background: var(--accent);
  color: #0B0B10;
  border: none;
  border-radius: 6px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.auth-submit:hover { filter: brightness(1.07); }
.auth-submit:disabled { opacity: 0.55; cursor: not-allowed; }
.auth-status {
  font-size: 12.5px;
  color: var(--ink-2);
  margin: 12px 0 0;
  min-height: 1.2em;
  line-height: 1.4;
}
.auth-status.is-error { color: #E04444; }
.auth-status.is-success { color: #4CDD8B; }
.auth-fine-print {
  font-size: 11px;
  color: var(--ink-3);
  margin: 14px 0 0;
  line-height: 1.5;
}
.auth-fine-print a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 2px; }
.auth-fine-print a:hover { color: var(--accent); }

/* Sign-up suggestion bar — floating bottom-left card */
.signup-bar {
  position: fixed;
  bottom: 16px;
  /* Clear the 68px toolbar rail so the card floats over the canvas, not over
     the bottom tools (was left:16px, which covered Hand/Zoom). (2026-05-29) */
  left: 80px;
  width: 280px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px 14px 12px;
  box-shadow: 0 6px 24px rgba(0,0,0,0.32);
  z-index: 60;
  font-family: inherit;
  animation: signupBarIn 320ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
@keyframes signupBarIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0);  }
}
.signup-bar-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 4px;
}
.signup-bar-head strong {
  font-size: 13px;
  color: var(--ink);
  line-height: 1.3;
}
.signup-bar-x {
  background: none;
  border: none;
  color: var(--ink-3);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  width: 20px; height: 20px;
  flex-shrink: 0;
}
.signup-bar-x:hover { color: var(--ink); }
.signup-bar-msg {
  font-size: 12px;
  color: var(--ink-2);
  line-height: 1.5;
  margin: 0 0 12px;
}
.signup-bar-actions {
  display: flex;
  gap: 6px;
  align-items: center;
}
.signup-bar-cta {
  flex: 1;
  padding: 7px 12px;
  background: var(--accent);
  color: #0B0B10;
  border: none;
  border-radius: 5px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.signup-bar-cta:hover { filter: brightness(1.07); }
.signup-bar-skip {
  padding: 7px 12px;
  background: transparent;
  color: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: 5px;
  font-size: 12px;
  cursor: pointer;
}
.signup-bar-skip:hover { color: var(--ink); border-color: var(--ink-3); }

/* ============================================================
   My Projects modal (subsection 32)
   ============================================================ */
.projects-card { max-width: 460px; }
.projects-lede {
  color: var(--ink-2);
  font-size: 12.5px;
  line-height: 1.5;
  margin: 4px 0 16px;
}
.projects-current {
  margin: 0 0 12px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: rgba(255,255,255,0.025);
}
.projects-current label {
  display: block;
  margin: 0 0 7px;
  color: var(--ink-3);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.project-name-edit {
  display: flex;
  gap: 8px;
}
.project-name-edit input {
  min-width: 0;
  flex: 1;
  padding: 9px 10px;
  color: var(--ink);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  font: inherit;
  font-size: 13px;
}
.project-name-edit input:focus {
  outline: none;
  border-color: var(--accent);
}
.project-name-edit button {
  padding: 8px 10px;
  color: #0B0B10;
  background: var(--accent);
  border: none;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}
#project-name-help,
.projects-limit,
.limit-note {
  margin: 7px 0 0;
  color: var(--ink-3);
  font-size: 11.5px;
  line-height: 1.4;
}
.projects-limit {
  margin: 0 0 10px;
}
.projects-limit.is-full {
  color: #ffbd66;
}
.projects-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 360px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 6px;
}
.projects-empty {
  padding: 20px;
  text-align: center;
  font-size: 12.5px;
  color: var(--ink-3);
}
.project-row {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid var(--line);
}
.project-row:last-child { border-bottom: none; }
.project-row.is-active { background: var(--bg-deep); }
.project-load {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--ink);
  text-align: left;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  cursor: pointer;
  font-family: inherit;
}
.project-load:hover { background: rgba(255,255,255,0.04); }
.project-name {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink);
}
.project-meta {
  font-size: 11.5px;
  color: var(--ink-3);
}
.project-delete {
  background: transparent;
  border: none;
  color: var(--ink-3);
  font-size: 18px;
  padding: 0 14px;
  cursor: pointer;
  flex-shrink: 0;
  border-left: 1px solid var(--line);
}
.project-delete:hover { color: #E04444; background: rgba(255,80,80,0.06); }
.projects-footer {
  margin-top: 14px;
  display: flex;
  justify-content: flex-end;
}
.projects-new {
  padding: 8px 14px;
  background: var(--accent);
  color: #0B0B10;
  border: none;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.projects-new:hover { filter: brightness(1.07); }
.projects-new:disabled {
  opacity: 0.48;
  cursor: not-allowed;
  filter: none;
}

.workspace-is-busy .app {
  pointer-events: none;
  user-select: none;
}
.workspace-busy {
  position: fixed;
  inset: 0;
  z-index: 118;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(10, 10, 14, 0.9);
  backdrop-filter: blur(2px);
}
.workspace-busy[hidden] {
  display: none;
}
.workspace-busy-card {
  width: min(430px, 100%);
  padding: 24px 26px;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  background: var(--panel);
  box-shadow: 0 22px 70px rgba(0,0,0,0.42);
  color: var(--ink);
  text-align: center;
}
.workspace-busy-spinner {
  width: 28px;
  height: 28px;
  margin: 0 auto 14px;
  border: 3px solid rgba(181, 255, 58, 0.18);
  border-top-color: var(--accent);
  border-radius: 999px;
  animation: traceSpin 780ms linear infinite;
}
.workspace-busy-title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.01em;
}
.workspace-busy-copy {
  margin-top: 8px;
  color: var(--ink-3);
  font-size: 12.5px;
  line-height: 1.45;
}
.workspace-busy-steps {
  display: grid;
  gap: 8px;
  margin: 16px auto 0;
  max-width: 340px;
  text-align: left;
}
.workspace-busy-steps[hidden] {
  display: none;
}
.workspace-busy-step {
  position: relative;
  display: grid;
  grid-template-columns: 12px 1fr;
  gap: 9px;
  color: var(--ink-3);
  font-size: 11.5px;
  line-height: 1.35;
}
.workspace-busy-step::before {
  content: "";
  width: 7px;
  height: 7px;
  margin-top: 4px;
  border-radius: 999px;
  border: 1px solid rgba(181, 255, 58, 0.35);
  background: rgba(181, 255, 58, 0.08);
  box-shadow: 0 0 0 0 rgba(181, 255, 58, 0);
}
.workspace-busy-step.is-active {
  color: var(--ink);
}
.workspace-busy-step.is-active::before {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 5px rgba(181, 255, 58, 0.12);
}
.workspace-busy-step.is-done {
  color: var(--ink-2);
}
.workspace-busy-step.is-done::before {
  background: rgba(181, 255, 58, 0.55);
  border-color: rgba(181, 255, 58, 0.55);
}
.workspace-busy-step-name {
  display: block;
  font-weight: 700;
}
.workspace-busy-step-copy {
  display: block;
  margin-top: 1px;
  color: var(--ink-3);
}

/* ────────────────────────────────────────────────────────────
   "Work not saved" warning strip (Phase 1 funnel hardening).
   Anonymous users only; persists across reloads, dismissible per
   tab-session. Mirrors the mobile-banner layout pattern.
   ──────────────────────────────────────────────────────────── */
.save-warning {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 109; /* just under mobile-banner so they stack cleanly */
  /* Neutral dark surface with a faint lime hint at the bottom edge —
     no more heavy green tint (2026-05-26 user feedback "lighter, less green"). */
  background: var(--panel);
  border-bottom: 1px solid rgba(181, 255, 58, 0.18);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  color: var(--ink);
  font-size: 12.5px;
  line-height: 1.4;
  letter-spacing: 0.01em;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.save-warning strong { color: var(--ink); font-weight: 600; }
.save-warning-msg { flex: 1; }
.save-warning-cta {
  background: transparent;
  border: none;
  padding: 0;
  margin-left: 6px;
  color: var(--accent);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.save-warning-cta:hover { filter: brightness(1.15); }
.save-warning-xbtn {
  background: transparent;
  border: none;
  color: var(--ink-3);
  font-size: 20px;
  cursor: pointer;
  padding: 0 6px;
  line-height: 1;
  margin-left: auto;
  flex-shrink: 0;
  transition: color var(--t-fast) var(--ease-out);
}
.save-warning-xbtn:hover { color: var(--ink); }
/* Push .app down by the warning's height when visible. Stack with the
   mobile banner if both are shown (rare but possible). */
body:has(.save-warning:not([hidden])) .app { padding-top: 44px; }
body:has(.mobile-banner:not([hidden])):has(.save-warning:not([hidden])) .app { padding-top: 88px; }
body:has(.mobile-banner:not([hidden])) .save-warning { top: 44px; }
body:has(.save-warning:not([hidden])) .app .topbar { animation: none; }

/* ===== Auto-trace busy overlay (added 2026-05-26) =====
   Sits on top of the canvas, blocks pointer events so the user can't draw
   mid-trace, but leaves topbar + properties panel reachable (they're outside
   .canvas-area). Cancel aborts the remote request. */
.trace-overlay {
  position: absolute;
  inset: 0;
  background: rgba(15, 14, 12, 0.72);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
  animation: fadeInOverlay 160ms var(--ease-out) both;
}
.trace-overlay.is-targeted {
  background: transparent;
  backdrop-filter: none;
  align-items: flex-start;
  padding-top: 16px;
}
@keyframes fadeInOverlay { from { opacity: 0; } to { opacity: 1; } }
.trace-overlay-card {
  background: var(--panel);
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  padding: 28px 32px;
  max-width: 380px;
  text-align: center;
  box-shadow: 0 16px 48px rgba(0,0,0,0.4);
  color: var(--ink, #eee);
}
.trace-overlay.is-targeted .trace-overlay-card {
  max-width: 360px;
  padding: 16px 18px;
  box-shadow: 0 10px 34px rgba(0,0,0,0.28);
}
.trace-spinner {
  width: 36px;
  height: 36px;
  border: 3px solid rgba(181, 255, 58, 0.18);
  border-top-color: var(--accent, #B5FF3A);
  border-radius: 50%;
  margin: 0 auto 18px;
  animation: traceSpin 720ms linear infinite;
}
.trace-overlay.is-targeted .trace-spinner {
  width: 24px;
  height: 24px;
  margin-bottom: 10px;
}
@keyframes traceSpin { to { transform: rotate(360deg); } }
.trace-overlay-title {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.01em;
  margin-bottom: 6px;
}
.trace-overlay-meta {
  font-size: 12px;
  color: var(--ink-3, #8a8478);
  font-variant-numeric: tabular-nums;
  margin-bottom: 14px;
}
.trace-overlay-hint {
  font-size: 11.5px;
  color: var(--ink-3, #8a8478);
  line-height: 1.5;
  margin-bottom: 14px;
  opacity: 0.85;
}
.trace-overlay-steps {
  display: grid;
  gap: 7px;
  margin: 0 0 16px;
  text-align: left;
}
.trace-overlay-steps[hidden] {
  display: none;
}
.trace-overlay-step {
  position: relative;
  display: grid;
  grid-template-columns: 12px 1fr;
  gap: 9px;
  color: var(--ink-3, #8a8478);
  font-size: 11.5px;
  line-height: 1.35;
}
.trace-overlay-step::before {
  content: "";
  width: 7px;
  height: 7px;
  margin-top: 4px;
  border-radius: 999px;
  border: 1px solid rgba(181, 255, 58, 0.35);
  background: rgba(181, 255, 58, 0.08);
  box-shadow: 0 0 0 0 rgba(181, 255, 58, 0);
}
.trace-overlay-step.is-active {
  color: var(--ink, #eee);
}
.trace-overlay-step.is-active::before {
  background: var(--accent, #B5FF3A);
  border-color: var(--accent, #B5FF3A);
  box-shadow: 0 0 0 5px rgba(181, 255, 58, 0.12);
}
.trace-overlay-step.is-done {
  color: var(--ink-2, #c7c2b8);
}
.trace-overlay-step.is-done::before {
  background: rgba(181, 255, 58, 0.55);
  border-color: rgba(181, 255, 58, 0.55);
}
.trace-step-name {
  display: block;
  font-weight: 700;
}
.trace-step-copy {
  display: block;
  margin-top: 1px;
  color: var(--ink-3, #8a8478);
}
.trace-overlay-cancel {
  background: transparent;
  color: var(--ink, #eee);
  border: 1px solid var(--line-soft);
  border-radius: 6px;
  padding: 7px 18px;
  font-size: 12.5px;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.trace-overlay-cancel:hover {
  background: rgba(181, 255, 58, 0.08);
  border-color: var(--accent, #B5FF3A);
}
#overlay .trace-target-fx {
  pointer-events: none;
}
#overlay .trace-target-veil {
  fill: var(--accent-soft);
  opacity: 0.38;
}
#overlay .trace-target-frame {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 8 6;
  animation: traceTargetPulse 900ms ease-in-out infinite alternate;
}
#overlay .trace-target-scan {
  stroke: var(--accent);
  stroke-width: 2.5;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  opacity: 0.78;
  filter: drop-shadow(0 0 8px var(--accent-glow));
}
@keyframes traceTargetPulse {
  from { opacity: 0.55; }
  to { opacity: 1; }
}

/* Auto-trace large-group summary row in the Layers panel (added 2026-05-26).
   When an auto-trace produces 20K+ shapes, renderLayers collapses them into
   ONE summary row instead of 20K <li>s (which would freeze the UI). The
   summary row shows count, swatch (gradient to distinguish from a normal
   shape swatch), and a trash button to delete the whole group. */
.layers li.layer-summary {
  font-style: italic;
  background: rgba(181, 255, 58, 0.04);
}
.layers li.layer-summary .name {
  color: var(--ink-2, #b9b1a3);
}
.layers li.layer-summary .swatch {
  border: 1px dashed rgba(181, 255, 58, 0.4);
}

/* ────────────────────────────────────────────────────────────
   Cursor follower glow (2026-05-26 — user request).
   A soft lime light that follows the pointer, mimicking the ambient
   green glow in the reference dashboard image. Uses mix-blend-mode
   so it brightens whatever is behind it instead of overlaying.
   Hidden under prefers-reduced-motion. Positioned by JS via inline
   transform — see app.js init block.
   ──────────────────────────────────────────────────────────── */
#cursor-glow {
  position: fixed;
  top: 0; left: 0;
  /* Tightened to ~20% of original size per user request 2026-05-26 —
     glow now sits close to the cursor instead of bathing the whole area. */
  width: 120px;
  height: 120px;
  margin-left: -60px;
  margin-top: -60px;
  border-radius: 50%;
  pointer-events: none; /* never blocks interaction */
  /* z-index ladder (2026-05-29): topbar 50 · dropdowns 80 · code-panel 90 ·
     feedback 95 · cursor-glow 96 · ctx-menu 99 · modal 100 · save-warning 109 ·
     mobile-banner 110. The glow sits *below* modals/menus so it never washes
     over dialog content (was 9999, painting over everything). */
  z-index: 96;
  background: radial-gradient(
    circle,
    rgba(181, 255, 58, 0.42) 0%,
    rgba(181, 255, 58, 0.21) 28%,
    rgba(181, 255, 58, 0)    62%
  );
  filter: blur(14px);
  mix-blend-mode: screen;
  will-change: transform;
  opacity: 0;
  transition: opacity 400ms var(--ease-out);
}
#cursor-glow.is-active { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  #cursor-glow { display: none; }
}

/* ────────────────────────────────────────────────────────────
   Universal hover lime — text + icons turn lime on hover for any
   interactive element (2026-05-26 user request). Specific component
   rules with stronger selectors still win where they exist (e.g. the
   Export button which has its own bg-shift hover).
   ──────────────────────────────────────────────────────────── */
button:hover,
button:hover svg.icon,
button:hover .icon,
a:hover,
.tool:hover,
.field:hover > span,
[role="button"]:hover {
  color: var(--accent-lime);
}
/* Icons inherit via currentColor on stroke — make explicit for sprite uses */
button:hover svg.icon use,
a:hover svg.icon use {
  color: var(--accent-lime);
}
/* Don't lime the text on a button that's ALREADY accent-bg
   (e.g. the Export primary button). Its text needs to stay dark for contrast.
   NOTE: .page-tab.active:hover is intentionally NOT in this list — the active
   page tab fills with --panel (NOT accent), so its hover text should turn
   lime like the rest of the UI, matching the toolbar icon hover behaviour. */
.actions button#btn-export:hover,
.feedback-submit:hover,
.signup-bar-cta:hover,
.projects-new:hover,
.auth-submit:hover,
.onboarding-next:hover {
  color: var(--accent-ink);
}

/* ────────────────────────────────────────────────────────────
   Invisible scrollbars (2026-05-26 user request).
   Hides the scrollbar UI everywhere while keeping scroll functional.
   Covers Chromium (::-webkit-scrollbar), Firefox (scrollbar-width),
   legacy Edge/IE (-ms-overflow-style). Wins over the per-panel
   scrollbar styling above thanks to specificity + display:none.
   ──────────────────────────────────────────────────────────── */
* {
  scrollbar-width: none;       /* Firefox */
  -ms-overflow-style: none;    /* legacy Edge / IE */
}
*::-webkit-scrollbar {          /* Chrome / Safari / modern Edge */
  width: 0 !important;
  height: 0 !important;
  display: none !important;
  background: transparent !important;
}

/* ────────────────────────────────────────────────────────────
   Responsive layout (2026-05-29 — user request: "make it responsive").
   The base layout is a fixed 3-column grid (68 / 1fr / 322) that
   overflows under ~960px and breaks badly below ~720px (the canvas
   gets squeezed to nothing and the side panels overflow off-screen).
   These queries progressively reclaim space, then stack to a single
   column on phones. CSS-only — no JS, no build. The desktop-first
   soft-gate banner still shows on touch + narrow via mobileGate() in
   app.js; this just stops the layout breaking when a window is resized
   or on tablets/phones.
   ──────────────────────────────────────────────────────────── */

/* Small laptops — trim the side panels so the canvas keeps room. */
@media (max-width: 1100px) {
  .app { grid-template-columns: 64px 1fr 292px; }
  /* feedback widget stays at right:16px — user prefers bottom-right corner */
}

/* Tablets — narrower still; tighten the topbar rows. */
@media (max-width: 860px) {
  .app { grid-template-columns: 58px 1fr 248px; }
  .topbar-row { padding: 6px 10px; gap: var(--s-2); }
}

/* Phones — stack to one column. Toolbar becomes a horizontal scroll
   strip, canvas takes the middle, properties is a capped scrollable
   card below. Everything stays inside 100vh because body can't scroll
   (box-sizing:border-box keeps the banner padding-top from overflowing). */
@media (max-width: 720px) {
  .app {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto minmax(150px, 1fr) minmax(0, 36vh) 26px;
    grid-template-areas:
      "topbar"
      "toolbar"
      "canvas"
      "properties"
      "statusbar";
  }

  /* Toolbar: vertical card → horizontal scroll strip of tools. */
  .toolbar {
    flex-direction: row;
    align-items: center;
    gap: 4px;
    margin: 8px 8px 0;
    padding: 6px 8px;
    overflow-x: auto;
    overflow-y: hidden;
    border-radius: 16px;
  }
  .toolbar .tool { flex: 0 0 auto; }
  /* Separators flip from horizontal lines to vertical dividers in a row. */
  .tool-sep { width: 1px; height: 22px; margin: 0 4px; }

  /* Properties: floating card below the canvas, scrolls internally. */
  .properties {
    margin: 8px 8px 0;
    border-radius: 16px;
  }

  /* Side panels are stacked (not on the left/right edges) at this width, so
     the floating widgets return to the normal viewport corners. */
  .feedback-widget { right: 16px; }
  .signup-bar { left: 16px; }
  .hint { left: 16px; }
}

/* Export artboard picker modal (2026-05-31).
   Multi-select: shown when >1 artboards. Pick any subset; export them. */
.scope-help {
  color: var(--ink-2);
  font-size: 13px;
  margin: 0 0 12px 0;
}
.scope-actions-row {
  display: flex;
  gap: 14px;
  margin-bottom: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
.link-btn {
  background: transparent;
  border: 0;
  padding: 4px 0;
  font-size: 12px;
  color: var(--ink-3);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out);
  letter-spacing: -0.005em;
}
.link-btn:hover { color: var(--accent); }
.scope-list {
  max-height: 280px;
  overflow-y: auto;
  margin: 0 -4px 14px -4px;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.scope-item {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--r-2);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
.scope-item:hover { background: var(--panel-2); }
.scope-item input[type="checkbox"] {
  accent-color: var(--accent);
  width: 16px;
  height: 16px;
  cursor: pointer;
  margin: 0;
}
.scope-item-name {
  font-size: 13.5px;
  color: var(--ink);
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.scope-item-dims {
  font-size: 11.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}
.scope-item.is-active .scope-item-name::after {
  content: "active";
  margin-left: 8px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  opacity: 0.85;
}
.scope-footer { justify-content: flex-end; }
.scope-footer #scope-go:not(:disabled) {
  background: var(--accent);
  color: var(--accent-ink);
}
.scope-footer #scope-go:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Universal hidden override — comes last to beat class rules that set display. */
[hidden] { display: none !important; }
