/* ============================================================================
   Presenta theme v17 — redesign token layer (forked from style_v16.css).
   Core palette / ghost ladder / control skins in this file are derived from
   Toolcraft (MIT License). MIT terms: permission is hereby granted, free of
   charge, to use, copy, modify, and distribute; provided the above copyright
   notice and this permission notice appear. THE SOFTWARE IS PROVIDED "AS IS".
   Legacy v16 tokens below are aliased onto the v17 core palette so existing
   var() uses keep resolving during the per-zone migration.
   ============================================================================ */
:root {
    /* ---- v17 core palette ---- */
    --background: #0A0A0A;          /* page + canvas backdrop (was --bg-base #0C0C0E) */
    --foreground: #FAFAFA;          /* primary text, slider fill/thumb (was gray-50) */
    --panel: #171717;               /* panel base (was --bg-surface #1A1A1E) */
    --popover: #171717;             /* popup base */
    --muted: #262626;               /* tooltip bg, pin tiles, thumb tiles (was --bg-elevated) */
    --muted-foreground: #A1A1A1;    /* values, placeholders, unit suffixes (was gray-400) */
    --border: #FFFFFF;              /* NEVER at 100% — always color-mix(... N%, transparent) */
    --input: #FFFFFF;               /* NEVER at 100% — always color-mix(... N%, transparent) */
    --accent: #CAFC00;              /* LIME = act: Export, Pro, switch-on, progress, randomize */
    --accent-hover: #D4FF33;
    --accent-pressed: #A8D600;
    --accent-contrast: #1A2100;
    --brand-rgb: 202, 252, 0;       /* tokenizes the hardcoded rgba(202,252,0,α) glows */
    --selection: #70B0FA;           /* BLUE = selected/focused */
    --selection-bg: color-mix(in oklab, var(--selection) 12%, transparent);
    --ring: #737373;                /* keyboard focus rings */
    --destructive: #EF4444;         /* the one red system */
    --attention: #EA733A;           /* replaces --color-warning */
    --color-brand: var(--accent);   /* devices.css selection outlines finally resolve */

    /* ---- ghost ladder (the only grays — no invented steps) ---- */
    --ghost-3:  color-mix(in oklab, var(--foreground) 3%, transparent);   /* section hover wash, dropzone fill */
    --ghost-5:  color-mix(in oklab, var(--input) 5%, transparent);        /* DEFAULT control fill; menu-item hover */
    --ghost-8:  color-mix(in oklab, var(--border) 8%, transparent);       /* section/toolbar dividers, border-t */
    --ghost-10: color-mix(in oklab, var(--input) 10%, transparent);       /* ghost-btn hover, swatch borders, scrollbar thumb */
    --ghost-12: color-mix(in oklab, var(--border) 12%, transparent);      /* DEFAULT control + panel border */
    --ghost-18: color-mix(in oklab, var(--border) 18%, transparent);      /* dashed dropzone */
    --ghost-20: color-mix(in oklab, var(--border) 20%, transparent);      /* border hover */
    --ghost-30: color-mix(in oklab, var(--border) 30%, transparent);      /* border focus/open */
    --label:    color-mix(in oklab, var(--foreground) 60%, transparent);  /* field labels */
    --title:    color-mix(in oklab, var(--foreground) 75%, transparent);  /* UPPERCASE section titles */
    --panel-surface: color-mix(in oklab, var(--panel) 75%, transparent);  /* + backdrop blur */
    --popup-surface: color-mix(in oklab, var(--popover) 98%, transparent);/* menus, dialogs */
    --tooltip-surface: color-mix(in oklab, var(--muted) 95%, transparent);

    /* ---- radius ---- */
    --r-xs: 2px;
    --r-sm: 4px;
    --r-md: 6px;
    --r-lg: 8px;    /* the workhorse: panels, inputs, buttons, dropzones, popups */
    --r-xl: 12px;
    --r-2xl: 16px;  /* dialogs */
    --r-full: 999px;

    /* ---- motion ---- */
    --dur-fast: 150ms;      /* color transitions */
    --dur-collapse: 180ms;  /* section collapse grid-rows */
    --dur-pop: 100ms;       /* popup fade + zoom-95 */
    --dur-spin: 420ms;      /* reset-icon spin */
    --dur-settle: 260ms;    /* pad overshoot settle */
    --ease-snap: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

    /* ==== legacy v16 tokens (alias shim — delete per-zone as surfaces rebuild) ==== */

    /* Brand (lime IS the brand — stays defined) */
    --color-lime-500:    var(--accent);
    --color-lime-400:    var(--accent-hover);
    --color-lime-600:    var(--accent-pressed);
    --color-lime-950:    var(--accent-contrast);

    /* Neutrals — steps with a v17 equivalent re-point at it */
    --color-gray-950:    var(--background);
    --color-gray-900:    #141416;
    --color-gray-850:    var(--panel);
    --color-gray-800:    var(--muted);
    --color-gray-700:    #2E2E34;
    --color-gray-600:    #3E3E46;
    --color-gray-500:    #5C5C66;
    --color-gray-400:    var(--muted-foreground);
    --color-gray-300:    #ABABB3;
    --color-gray-200:    #D1D1D6;
    --color-gray-100:    #EDEDF0;
    --color-gray-50:     var(--foreground);

    /* Semantic */
    --color-success:     #34D399;
    --color-warning:     var(--attention);
    --color-error:       var(--destructive);
    --color-info:        #60A5FA;

    /* Surfaces */
    --bg-base:       var(--background);
    --bg-surface:    var(--panel);
    --bg-elevated:   var(--muted);
    --bg-canvas:     var(--color-gray-900);
    --bg-input:      var(--muted);
    --bg-hover:      var(--color-gray-700);

    /* Borders */
    --border-subtle:     var(--ghost-8);
    --border-default:    var(--ghost-12);
    --border-strong:     var(--ghost-20);
    --border-accent:     var(--ghost-30);
    --focus-ring:        color-mix(in oklab, var(--foreground) 45%, transparent);

    /* Typography */
    --text-2xs:   0.625rem;
    --text-xs:    0.6875rem;
    --text-sm:    0.8125rem;
    --text-base:  0.875rem;
    --text-md:    1rem;
    --text-lg:    1.125rem;
    --text-xl:    1.5rem;

    --leading-tight:    1.1;
    --leading-snug:     1.3;
    --leading-normal:   1.5;

    --tracking-tight:   -0.01em;
    --tracking-normal:   0;
    --tracking-wide:     0.06em;

    /* Legacy compat — RGB triplets kept verbatim (export-visible).
       NOTE: the old `--background: 12,12,14` and `--panel: 26,26,30` triplets
       had ZERO rgba(var()) consumers (verified), so those two names are safely
       reused by the v17 core palette above. */
    --primary: 237, 237, 240;
    --secondary: 0, 0, 0;
    --panel-active: 46, 46, 48;
    --panel-dim: 20, 20, 22;
    --modal: 34, 34, 38;
    --success: var(--color-success);
    --dropzone-1-ratio: 1 / 1;
    --dropzone-2-ratio: 1 / 1;
    --mockup-shadow: 0, 0, 0, 0.99;
}

/* ---- FlyonUI/DaisyUI theme pin — always dark (OS light-mode must not leak).
   Values copied from output_.css dark theme block; this file loads after
   output_.css, so this wins over :root light defaults, the
   prefers-color-scheme media block, and [data-theme=light]. ---- */
:root,
[data-theme] {
    color-scheme: dark;
    background-color: var(--background);
    --fallback-p: #7582ff;
    --fallback-pc: #050617;
    --fallback-s: #ff71cf;
    --fallback-sc: #190211;
    --fallback-a: #00c7b5;
    --fallback-ac: #000e0c;
    --fallback-n: #2a323c;
    --fallback-nc: #a6adbb;
    --fallback-b1: #1d232a;
    --fallback-b2: #191e24;
    --fallback-b3: #15191e;
    --fallback-bc: #a6adbb;
    --fallback-bs: #989eab;
    --fallback-in: #00b3f0;
    --fallback-inc: #000000;
    --fallback-su: #00ca92;
    --fallback-suc: #000000;
    --fallback-wa: #ffc22d;
    --fallback-wac: #000000;
    --fallback-er: #ff6f70;
    --fallback-erc: #000000;
    --p: 57.5934% 0.247012 287.240256;
    --pc: 93.7482% 0.032368 291.504141;
    --s: 55.7871% 0.022138 301.905381;
    --sc: 100% 0 0;
    --a: 62.3083% 0.188015 259.814529;
    --ac: 93.1918% 0.031591 255.585494;
    --n: 65.7482% 0.022235 294.952761;
    --nc: 18.5128% 0.016696 301.919154;
    --b1: 26.8442% 0.028285 299.769964;
    --b2: 22.6865% 0.023344 295.952767;
    --b3: 39.9632% 0.030791 300.243839;
    --bc: 78.094% 0.014175 295.243891;
    --bs: 18.5128% 0.016696 301.919154;
    --in: 71.4837% 0.125737 215.220912;
    --inc: 95.6262% 0.044329 203.387819;
    --su: 73.1062% 0.216656 147.04398;
    --suc: 96.444% 0.02867 172.082984;
    --wa: 79.8713% 0.164239 73.093986;
    --wac: 98.4165% 0.02418 94.061783;
    --er: 65.3932% 0.222085 25.863852;
    --erc: 97.5752% 0.015143 61.349176;
}
/* Inter Variable — loaded from Google Fonts in HTML <head> */
/* JetBrains Mono — loaded from Google Fonts in HTML <head> */

/* Keep EuclidCircularA as fallback for elements that haven't been updated.
   woff2-only: every target browser supports it, and dom-to-image-more's
   font inliner fetches every url() in src: regardless of format() hint —
   keeping a woff fallback doubled the per-export font transfer. */
@font-face {
    font-family: "EuclidCircularA";
    src: url("fonts/EuclidCircularA-Regular-WebXL.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "EuclidCircularA";
    src: url("fonts/EuclidCircularA-Medium-WebXL.woff2") format("woff2");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "EuclidCircularA";
    src: url("fonts/EuclidCircularA-Semibold-WebXL.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "EuclidCircularA";
    src: url("fonts/EuclidCircularA-Light-WebXL.woff2") format("woff2");
    font-weight: 300;
    font-style: normal;
    font-display: swap;
}
html {
    font-family: "Inter", "EuclidCircularA", ui-sans-serif, system-ui, sans-serif;
    font-weight: 400;
    font-size: var(--text-base);
    letter-spacing: var(--tracking-tight);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
body {
    background: var(--bg-base);
    color: var(--color-gray-100);
    line-height: var(--leading-normal);
    position: fixed !important;
    /* WS3 full-bleed shell: body is the positioning root for the
       absolute-inset canvas — give it the full viewport explicitly. */
    inset: 0;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
}

/* Monospace for numeric values */
.font-mono,
.numeric-value,
#output-resolution,
#file-size {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
}
input[type="file"] {
    display: none;
}
[class*="icon-"] {
    display: block;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    background-color: currentColor;
    background-repeat: no-repeat;
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-image: var(--svg);
    mask-image: var(--svg);
}
.btn:active:hover, .btn:active:focus {
    transform: scale(1.0) !important;
}
/* v17: the global `transition: all 250ms` is dead (perf-hostile).
   Colors only, per the motion rules. */
a, button {
    transition: color var(--dur-fast) ease-out,
                background-color var(--dur-fast) ease-out,
                border-color var(--dur-fast) ease-out,
                opacity var(--dur-fast) ease-out;
}
.icon-dnd {
    background-image: url("img/tabler-icon-click.svg");
    background-color: #ffffff;
    background-size: contain;
}
.icon-brand-one {
    background-image: url("img/tabler-icon-photo-filled.svg");
    background-color: transparent;
    background-size: contain;
}
.icon-x {
    background-image: url("img/tabler-icon-x.svg");
    background-color: transparent;
    background-size: contain;
}
.icon-cw {
    background-image: url("img/Craftwork-Logo.svg");
    background-color: transparent;
    background-size: contain;
}
.icon-download {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 25 24' fill='none'%3E%3Cpath d='M4.5 20H20.5M12.5 14V4M12.5 14L16.5 10M12.5 14L8.5 10' stroke='%231A2100' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-color: transparent;
    background-size: contain;
}
.icon-dropdown {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 16' fill='none'%3E%3Cpath d='M8.50008 10L11.1667 7.33337H5.83341L8.50008 10Z' fill='%231A2100' stroke='%231A2100' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-color: transparent;
    background-size: contain;
}
/* Legacy header dropdown styles removed — header redesigned */
/* Loader */

#preloader {
    background-color: var(--bg-base);
    height: 100%;
    width: 100%;
    position: fixed;
    margin-top: 0;
    top: 0;
    z-index: 999;
    transition: opacity 0.5s ease;
}
#preloader-segment-item-1,
#preloader-bg-item-1,
#preloader-segment-item-2 {
    background-color: var(--bg-elevated, var(--bg-base));
    height: 100%;
    width: 100%;
    position: absolute;
    margin-top: 0;
    top: 0;
    z-index: 999;
    transition: opacity 0.3s ease, visibility 0.3s ease;
}
#loading-center,
#loading-center-segment-item-1,
#loading-center-bg-item-1,
#loading-center-segment-item-2 {
    width: 100%;
    height: 100%;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Presenta text loader */
.presenta-loader {
    display: flex;
    align-items: center;
    gap: 0;
    user-select: none;
}

.presenta-letter {
    font-family: 'Instrument Serif', Georgia, serif;
    font-style: italic;
    font-weight: 400;
    font-size: 48px;
    letter-spacing: 0.02em;
    color: var(--color-gray-50);
    display: inline-block;
    opacity: 0;
    filter: blur(12px);
    transform: translateY(20px);
    animation: presenta-letter-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards,
               presenta-letter-glow 2.4s ease-in-out infinite;
    animation-delay: calc(var(--i) * 0.07s),
                     calc(0.8s + var(--i) * 0.07s);
}

@keyframes presenta-letter-in {
    0% {
        opacity: 0;
        filter: blur(12px);
        transform: translateY(20px);
    }
    100% {
        opacity: 1;
        filter: blur(0px);
        transform: translateY(0);
    }
}

@keyframes presenta-letter-glow {
    0%, 100% {
        opacity: 0.4;
    }
    50% {
        opacity: 1;
    }
}

/* Legacy loader kept for segment/bg preloaders */
.loader {
    position: relative;
    width: 42px;
    height: 42px;
    margin: 75px;
    display: inline-block;
    vertical-align: middle;
    background-image: url("img/loader-presenta.png");
    background-size: contain;
    animation: loader-outter .75s cubic-bezier(.42, .61, .58, .41) infinite;
}

@keyframes loader-outter {
    0% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.15);
    }
    100% {
        transform: scale(1);
    }
}

/* ── Multi-artboard stack (Phase 3) ──
   Horizontal flex stack of artboards. Active artboard is the live editor
   (`.artboard[data-active="true"]`), inactive artboards are static DOM clones marked
   `.is-snapshot`. The editor remains first in DOM order so JS queries
   that pick the first match (`document.querySelector('.mockup-module')`,
   captured `const mockupModule = …`, etc.) keep targeting it; CSS `order`
   places it visually at its slot index. */
.artboard-stack {
    box-sizing: border-box;
    gap: 120px;
    justify-content: center;
    transition: opacity 220ms ease;
}
/* Phase 6 — during the on-load snapshot rebuild the editor cycles
   through every slot's state. Hiding the stack prevents the user from
   seeing that flicker; the rebuild completes in ~150-400ms × N slots
   and fades back in. */
.artboard-stack.is-rebuilding {
    opacity: 0;
    visibility: hidden;
    /* Instant, not faded: with a transition the first rebuild frames (the
       editor wearing ANOTHER board's background) slipped through as a
       visible flash on every artboard switch. */
    transition: none !important;
    pointer-events: none;
}
/* WS3: the strip lives in a world-space transform layer — no scrolling,
   no virtual gutters. The stack stays centered; tcViewport.panToArtboard
   moves the world so any board can land in the visual center. */
.artboard-stack.has-multiple {
    /* Tighter gap than the single-board default (120px) so a neighbour
       peeks past the centered active board even on narrow screens. */
    gap: 72px;
}
/* When 2+ boards exist, cap the active board narrower (70cqi vs 84cqi)
   so there is always side room for the scaled-down neighbour snapshots to
   peek at any screen width. Tall/portrait presets are already height-bound
   and stay narrow, so this only reins in wide/default boards. */
.artboard-stack.has-multiple .artboard {
    width:  min(70cqi, calc(92cqb * var(--canvas-w, 4) / var(--canvas-h, 3)));
    height: min(92cqb, calc(70cqi * var(--canvas-h, 3) / var(--canvas-w, 4)));
}
/* WS3 full-bleed canvas: absolute inset-0 under the floating chrome.
   No scrolling, no snap, no side paddings, no edge mask — the world layer
   (.viewport-world) pans/zooms instead. container-type: size stays so
   .artboard keeps sizing itself in cqi/cqb against the full viewport. */
.canvas-area {
    position: absolute;
    inset: 0;
    overflow: hidden;
    overscroll-behavior: contain;
    z-index: 10;
    /* container-type: size enables both cqi (inline) and cqb (block)
       units, so .artboard can size itself against canvas-area's width
       AND height. Plain inline-size only exposes cqi. */
    container-type: size;
    container-name: canvas-area;
}

/* The world layer — translate+scale ONLY (pure view state, set by
   tcViewport in demo.js). CSS transforms don't touch clientWidth, so
   export math is unaffected at any zoom. */
.viewport-world {
    position: absolute;
    inset: 0;
    transform-origin: 50% 50%;
    will-change: transform;
}
.viewport-world.is-gliding {
    transition: transform 340ms var(--ease-snap);
}
/* Pan-gesture cursors (space / middle-drag). */
body.is-pan-mode .canvas-area { cursor: grab; }
body.is-panning .canvas-area { cursor: grabbing; }
body.is-panning .viewport-world { transition: none; }
/* Whole-canvas drag-over wash — selection tint at 8% (SPEC #2). */
body.is-file-dragover .canvas-area::after {
    content: '';
    position: absolute;
    inset: 0;
    background: color-mix(in oklab, var(--selection) 8%, transparent);
    pointer-events: none;
    z-index: 60;
}

/* Active artboard sizes itself from `--canvas-w` / `--canvas-h` (set by
   the Canvas Size dropdown, defaults 4/3 to match the initial `aspect-4/3`
   class). We can't rely on `aspect-ratio` + max-width + max-height alone:
   when the derived dimension exceeds its max, CSS clips that dimension
   without shrinking the other one back, so tall presets like 9:16 collapsed
   to a wide-ish box. Instead we pick width = min(maxW, maxH × ratio) and
   height = min(maxH, maxW / ratio); whichever constraint is tighter wins
   on both axes simultaneously. */
.artboard {
    flex: 0 0 auto;
    /* WS3 letterbox retune: 84cqi → 96cqi (full-bleed scene, chrome floats). */
    width:  min(96cqi, calc(92cqb * var(--canvas-w, 4) / var(--canvas-h, 3)));
    height: min(92cqb, calc(96cqi * var(--canvas-h, 3) / var(--canvas-w, 4)));
    cursor: grab;
    transition: opacity 220ms ease;
}

/* Phase 4 — appear keyframes for the editor when the user presses "+".
   Snapshots intentionally don't run this animation: they're re-created
   on every switchActive and animating each clone (with its full nested
   DOM) introduced visible scroll/switch lag. The class is added in
   addArtboard() and removed after ~380ms. */
@keyframes artboard-appear {
    from { opacity: 0; transform: scale(0.86); }
}
.artboard.is-appearing {
    animation: artboard-appear 320ms cubic-bezier(0.22, 1, 0.36, 1);
}
.artboard:active {
    cursor: grabbing;
}
/* WS3: per-artboard .canvas-dragover outline retired — the consolidated
   drop path tints the whole canvas via body.is-file-dragover above. */

/* Inactive (snapshot) artboards are visually de-emphasised AND scaled
   down via `transform: scale()` (NOT via height) so the LAYOUT BOX is
   identical to the active artboard. This is critical: any layout-affecting
   size difference between active and inactive causes the stack to reflow
   on switch, which shows up as the viewport "bouncing" away from the
   newly-active artboard. Transforms paint visually without touching flow.
   transform-origin is set by data-side (JS) so snapshots anchor their
   scaled visual to the edge facing the editor — without this the peek
   would shrink inward and vanish at the canvas viewport edge. */
.artboard.is-snapshot {
    cursor: default;
    /* Full size — neighbours differ from the active board by OPACITY only
       (user call): no scale, so every artboard reads at its true dimensions. */
    transform: none;
    transform-origin: center;
    opacity: 0.4;
    transition: opacity 220ms ease;
    pointer-events: auto;
}
.artboard.is-snapshot[data-side="left"] {
    transform-origin: right center;
}
.artboard.is-snapshot[data-side="right"] {
    transform-origin: left center;
}
.artboard.is-snapshot:hover {
    opacity: 0.7;
    transform: none;
}
.artboard.is-snapshot > * {
    pointer-events: none;
}
/* Snapshots are frozen previews — interactive overlays (gizmo, drop
   labels, text resize handles) must not visibly appear on them. */
.artboard.is-snapshot .gizmo-overlay,
.artboard.is-snapshot .text-resize-handle,
.artboard.is-snapshot .image-resize-handle,
.artboard.is-snapshot .empty-drop {
    display: none !important;
}

/* ── Phase 4 — Add/Delete artboard buttons ─────────────────────────────── */

/* Delete (×) button — top-right corner of the ACTIVE artboard only.
   Hidden on snapshots (snapshots must first be clicked to activate, then
   deleted) and on single-artboard sessions. Stripped from PNG export via
   filter in demo.js renderExport. */
.artboard-close {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 28px;
    height: 28px;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(20, 20, 20, 0.4);
    color: rgba(255, 255, 255, 0.55);
    cursor: pointer;
    z-index: 60;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    transition: background 150ms ease, color 150ms ease, transform 150ms ease, opacity 150ms ease;
    opacity: 0.85;
}
/* Visible only on the active artboard AND only when there are 2+ slots
   (you can't delete the last one). Snapshots are click-to-switch only. */
.artboard-stack.has-multiple .artboard[data-active="true"] > .artboard-close {
    display: flex;
}
.artboard[data-active="true"]:hover > .artboard-close {
    opacity: 1;
}
.artboard-close:hover {
    background: rgba(20, 20, 20, 0.65);
    color: rgba(255, 255, 255, 0.9);
    opacity: 1;
}
.artboard-close:active {
    transform: scale(0.96);
}
.artboard-close svg {
    display: block;
}

/* Add (+) button — small circular pill at the end of the stack, sitting
   to the right of the last artboard. Same visual rhythm as the close
   button. `align-self: center` keeps it vertically centered relative to
   the active artboard; negative margin tightens the 120px stack gap so
   the button reads as belonging to the rightmost slot. */
.artboard-add {
    flex: 0 0 auto;
    order: 9999;
    align-self: center;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.03);
    color: rgba(255, 255, 255, 0.35);
    cursor: pointer;
    scroll-snap-align: none;
    /* Pull in towards the last artboard — 120px stack gap minus 80px = 40px effective. */
    margin-left: -80px;
    transition: color 180ms ease, background 180ms ease, transform 180ms ease;
}
/* has-multiple tightens the stack gap to 72px; keep the "+" button's
   effective distance to the last board at ~40px. */
.artboard-stack.has-multiple .artboard-add {
    margin-left: -32px;
}
.artboard-add:hover:not(.is-disabled) {
    background: rgba(255, 255, 255, 0.07);
    color: rgba(255, 255, 255, 0.7);
}
.artboard-add:active:not(.is-disabled) {
    transform: scale(0.94);
}
.artboard-add.is-disabled {
    opacity: 0.3;
    cursor: not-allowed;
}
.artboard-add svg {
    display: block;
}

/* ── Overview (grid) mode ──────────────────────────────────────────────
   A zoom-out that reflows the horizontal strip into a wrapping grid of
   thumbnails so every artboard is reachable at any screen width. Toggled
   from the bottom toolbar (#overviewToggle → body.artboards-overview +
   .is-overview on .canvas-area and .artboard-stack). Purely visual — the
   editor stays the same live node; JS click-to-pick zooms back in. */
.canvas-area.is-overview {
    overflow-x: hidden;
    overflow-y: auto;
}
/* WS3: neutralize the world transform in overview — the grid lays out in
   flow and scrolls vertically inside canvas-area instead of panning. */
.canvas-area.is-overview .viewport-world {
    position: relative;
    inset: auto;
    transform: none !important;
    height: auto;
    min-height: 100%;
    will-change: auto;
}
.artboard-stack.is-overview {
    flex-wrap: wrap;
    align-items: flex-start;
    /* `safe center`: a fitting grid sits vertically centered in the viewport;
       an overflowing one falls back to top-aligned scrolling (no clipping).
       12px top used to pin the tiles against the Scenes panel. */
    align-content: safe center;
    justify-content: safe center;
    gap: 28px;
    height: auto;
    min-height: 100%;
    padding: 96px 48px 120px;
    box-sizing: border-box;
    transition: none;
}
/* No virtual scroll gutters in the grid. */
.artboard-stack.is-overview::before,
.artboard-stack.is-overview::after {
    content: none;
    display: none;
}
/* Uniform thumbnails, aspect preserved via --canvas-w/--canvas-h (the same
   min() trick as the strip, with fixed px caps instead of container units).
   Snapshot transforms/opacity are overridden so every board reads equally. */
.artboard-stack.is-overview .artboard {
    flex: 0 0 auto;
    width:  min(300px, calc(188px * var(--canvas-w, 4) / var(--canvas-h, 3)));
    height: min(188px, calc(300px * var(--canvas-h, 3) / var(--canvas-w, 4)));
    transform: none !important;
    opacity: 1 !important;
    cursor: pointer;
    scroll-snap-align: none;
    outline: 2px solid transparent;
    outline-offset: 4px;
    border-radius: 10px;
    transition: outline-color 150ms ease;
}
.artboard-stack.is-overview .artboard:hover {
    outline-color: rgba(255, 255, 255, 0.25);
}
.artboard-stack.is-overview .artboard[data-active="true"] {
    /* SPEC #0 call 1: blue = selected (lime is reserved for act). */
    outline-color: var(--selection);
}
/* Snapshots are click-through for their inner content but the card itself
   must catch the pick click. */
.artboard-stack.is-overview .artboard.is-snapshot {
    pointer-events: auto;
}
.artboard-stack.is-overview .artboard.is-snapshot > * {
    pointer-events: none;
}
/* The active board is the live editor — suppress its interactive overlays
   (3D gizmo ball, resize handles, drop labels) so every thumbnail reads as
   a clean frozen preview in the grid. */
.artboard-stack.is-overview .gizmo-overlay,
.artboard-stack.is-overview .text-resize-handle,
.artboard-stack.is-overview .image-resize-handle,
.artboard-stack.is-overview .empty-drop {
    display: none !important;
}
/* The "×" delete button is meaningless in overview (pick, then delete in
   the strip); hide it to keep thumbnails clean. */
.artboard-stack.is-overview .artboard-close {
    display: none !important;
}
/* "+" becomes a full grid tile matching the thumbnail footprint. */
.artboard-stack.is-overview .artboard-add {
    width: min(300px, calc(188px * 4 / 3));
    height: 188px;
    margin-left: 0;
    border-radius: 10px;
    border: 1.5px dashed rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.02);
    align-self: flex-start;
}
.artboard-stack.is-overview .artboard-add svg {
    width: 30px;
    height: 30px;
}
/* Toolbar toggle pressed state (WS3 bottom toolbar). */
.tc-toolbar .tc-icon-btn.is-active,
.tc-toolbar .tc-icon-btn[aria-pressed="true"] {
    background: var(--ghost-10);
    color: var(--foreground);
}
.tc-toolbar .tc-icon-btn[aria-pressed="true"] svg {
    opacity: 1;
}
/* Hide the starter card while the grid is open — it anchors to the strip
   layout and reads as clutter over the grid. */
body.artboards-overview .tc-starter,
body.artboards-overview .tc-tour-bar {
    display: none !important;
}

/* 3D Transform transitions — opt-in via .transform-animate, added briefly
   by the 3D preset buttons. Off by default so the Size/Position sliders,
   wheel zoom and direct drag get instant visual response (slider value
   was visibly racing ahead of the picture by the full 0.4s easing). */
.mockup-module.transform-animate.screenshot .layouts,
.mockup-module.transform-animate:not(.screenshot) {
    transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Transform preset active button */
.transform-preset-btn.transform-preset-active {
    font-weight: 500;
    background: rgba(255, 255, 255, 0.08) !important;
    border-color: rgba(255, 255, 255, 0.30) !important;
    color: var(--color-gray-100) !important;
}

/* Sidebar */
.tooltip.show,
.dropdown.open {
    z-index: 999;
}
.panel .panel-scroll-view {
    width: 100%;
    flex: 1;
    min-height: 0;
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: thin;
    scrollbar-color: var(--color-gray-700) transparent;
    padding-bottom: 20px;
}
.panel .panel-scroll-view > * {
    max-width: 100%;
    min-width: 0;
}
.panel .panel-scroll-view::-webkit-scrollbar {
    /* WS3: 4px thumb on the ghost ladder (SPEC #1.4). */
    width: 4px;
    display: block;
}
.panel .panel-scroll-view::-webkit-scrollbar-thumb {
    background: var(--ghost-10);
    border-radius: var(--r-full);
}
.panel .panel-scroll-view::-webkit-scrollbar-track {
    background: transparent;
}
.range::-webkit-slider-runnable-track {
    height: 12px;
}
.range::-webkit-slider-thumb {
    width: 22px;
    height: 22px;
    background-color: #fff !important;
    border-color: rgba(255, 255, 255, 0.5) !important;
}
.range::-webkit-slider-thumb:active,
.range::-webkit-slider-thumb:hover {
    --tw-scale-x: 1;
    --tw-scale-y: 1;
    box-shadow: none;
}
.range::-moz-range-thumb {
    background-color: #fff !important;
    border-color: rgba(255, 255, 255, 0.5) !important;
}
[aria-disabled] .range.disabled,
[aria-disabled] .range:disabled, 
[aria-disabled] .range[disabled] {
    opacity: 1;
}
/*.button-bg-color-wrap:before {*/
/*    content: '';*/
/*    position: absolute;*/
/*    inset: 0;*/
/*    border-radius: 8px;*/
/*    background: linear-gradient(rgb(241, 241, 243), rgba(241, 241, 243, 0)), linear-gradient(45deg, lightgrey 25%, transparent 25%, transparent 75%, lightgrey 75%) 0 0 / 1em 1em, linear-gradient(45deg, lightgrey 25%, white 25%, white 75%, lightgrey 75%) 0.5em 0.5em / 1em 1em !important;*/
/*}*/
/* Ensure color-shadow-wrap doesn't clip dropdown */
.color-shadow-wrap,
.color-stroke-wrap {
    overflow: visible !important;
}

.color-background-wrap .picker_wrapper,
.color-shadow-wrap .picker_wrapper,
.color-stroke-wrap .picker_wrapper {
    width: 100% !important;
    box-shadow: none;
    background: transparent;
    padding: 0 !important;
}
.color-background-wrap .picker_hue,
.color-shadow-wrap .picker_hue,
.color-stroke-wrap .picker_hue {
    height: 12px;
    padding: 0 !important;
    margin: 15px 0 5px !important;
    box-shadow: none;
    border-radius: 999px;
    order: 2;
}
.color-background-wrap .picker_alpha,
.color-shadow-wrap .picker_alpha,
.color-stroke-wrap .picker_alpha {
    width: 12px;
    padding: 0 !important;
    margin: 0 0 0 10px !important;
    border-radius: 999px;
    box-shadow: none;
}
.color-background-wrap .picker_hue .picker_selector,
.color-shadow-wrap .picker_hue .picker_selector,
.color-stroke-wrap .picker_hue .picker_selector {
    border-radius: 999px;
    padding: 0;
    height: 22px;
    width: 22px;
    top: 50%;
    border-color: #fff;
    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.10), 0 1px 1px rgba(0, 0, 0, 0.06);
}
.color-background-wrap .picker_alpha .picker_selector,
.color-shadow-wrap .picker_alpha .picker_selector,
.color-stroke-wrap .picker_alpha .picker_selector {
    left: 50%;
    border-color: #fff;
}
.color-background-wrap .picker_alpha .picker_selector,
.color-shadow-wrap .picker_alpha .picker_selector,
.color-stroke-wrap .picker_alpha .picker_selector,
.color-background-wrap .picker_sl .picker_selector,
.color-shadow-wrap .picker_sl .picker_selector,
.color-stroke-wrap .picker_sl .picker_selector {
    border-radius: 999px;
    padding: 0;
    height: 22px;
    width: 22px;
    border-color: #fff;
    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.10), 0 1px 1px rgba(0, 0, 0, 0.06);
}
.color-background-wrap .picker_sl,
.color-shadow-wrap .picker_sl,
.color-stroke-wrap .picker_sl {
    margin: 0 !important;
    border-radius: 11px;
    box-shadow: none;
}
.color-background-wrap .picker_sl:before,
.color-shadow-wrap .picker_sl:before,
.color-stroke-wrap .picker_sl:before {
    border: 1px solid rgba(0,0,0,.05);
    border-radius: 11px;
}
.color-background-wrap .picker_sample,
.color-shadow-wrap .picker_sample,
.color-stroke-wrap .picker_sample,
.color-background-wrap .picker_done,
.color-shadow-wrap .picker_done,
.color-stroke-wrap .picker_done {
    display: none;
}
.color-background-wrap .picker_editor,
.color-shadow-wrap .picker_editor,
.color-stroke-wrap .picker_editor {
    order: 3 !important;
    margin: 10px 0 0 !important;
    width: 100% !important;
    height: 38px;
    display: flex;
    align-items: center;
    gap: 4px;
}
.color-background-wrap  .picker_editor input,
.color-shadow-wrap  .picker_editor input,
.color-stroke-wrap  .picker_editor input {
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .1) !important;
    border-radius: 11px;
    font-size: 14px !important;
    line-height: 24px !important;
    height: 100%;
    padding-left: 12px;
    padding-right: 12px;
    font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
    flex: 1 0 0;
}
.color-background-wrap .picker_editor button,
.color-shadow-wrap .picker_editor button,
.color-stroke-wrap .picker_editor button {
    background-color: transparent;
    background-image: none;
    border: 0;
    box-shadow: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    padding: 0;
}
.color-background-wrap .picker_editor button:before,
.color-shadow-wrap .picker_editor button:before,
.color-stroke-wrap .picker_editor button:before {
    content: '';
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23a1a1aa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='icon icon-tabler icons-tabler-outline icon-tabler-color-picker'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M11 7l6 6' /%3E%3Cpath d='M4 16l11.7 -11.7a1 1 0 0 1 1.4 0l2.6 2.6a1 1 0 0 1 0 1.4l-11.7 11.7h-4v-4z' /%3E%3C/svg%3E");
    background-size: cover;
    display: block;
    width: 24px;
    height: 24px;
}

/* WS7b(3) — Screen treatment: Duotone inline colour pickers. Same
   vanilla-picker visual language as the shadow/stroke controls, but scoped
   to its own wrap so it never touches the existing colour controls. */
.tc-fx-color-wrap .picker_wrapper {
    width: 100% !important;
    box-shadow: none;
    background: transparent;
    padding: 0 !important;
    font-family: inherit;
}
.tc-fx-color-wrap .picker_wrapper * { box-sizing: border-box; }
.tc-fx-color-wrap .picker_sl {
    margin: 0 !important;
    border-radius: 11px;
    box-shadow: none;
}
.tc-fx-color-wrap .picker_hue {
    height: 12px;
    padding: 0 !important;
    margin: 12px 0 4px !important;
    box-shadow: none;
    border-radius: 999px;
    order: 2;
}
.tc-fx-color-wrap .picker_hue .picker_selector,
.tc-fx-color-wrap .picker_sl .picker_selector {
    border-radius: 999px;
    padding: 0;
    height: 20px;
    width: 20px;
    border-color: #fff;
    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.10), 0 1px 1px rgba(0, 0, 0, 0.06);
}
.tc-fx-color-wrap .picker_hue .picker_selector { top: 50%; }
.tc-fx-color-wrap .picker_sample,
.tc-fx-color-wrap .picker_done { display: none; }
.tc-fx-color-wrap .picker_editor {
    order: 3 !important;
    margin: 8px 0 0 !important;
    width: 100% !important;
    height: 34px;
    display: flex;
    align-items: center;
}
.tc-fx-color-wrap .picker_editor input {
    box-shadow: 0 0 0 1px var(--ghost-12) !important;
    border-radius: 10px;
    font-size: 13px !important;
    line-height: 22px !important;
    height: 100%;
    width: 100%;
    padding: 0 12px;
    background: var(--muted);
    color: var(--foreground);
    font-family: inherit;
}

.shadow-position-wrap .custom-option:has(:checked) span {
    background: var(--color-gray-100);
    border-color: var(--color-gray-100);
}
.shadow-position-wrap .custom-option:hover span {
    border-color: var(--border-strong);
}
.icon-filter {
    --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M21.25 12H8.895M4.534 12H2.75M4.534 12C4.534 11.4218 4.76368 10.8673 5.17251 10.4585C5.58134 10.0497 6.13583 9.82001 6.714 9.82001C7.29217 9.82001 7.84666 10.0497 8.25549 10.4585C8.66432 10.8673 8.894 11.4218 8.894 12C8.894 12.5782 8.66432 13.1327 8.25549 13.5415C7.84666 13.9503 7.29217 14.18 6.714 14.18C6.13583 14.18 5.58134 13.9503 5.17251 13.5415C4.76368 13.1327 4.534 12.5782 4.534 12ZM21.25 18.607H15.502M15.502 18.607C15.502 19.1853 15.2718 19.7404 14.8628 20.1494C14.4539 20.5583 13.8993 20.788 13.321 20.788C12.7428 20.788 12.1883 20.5573 11.7795 20.1485C11.3707 19.7397 11.141 19.1852 11.141 18.607M15.502 18.607C15.502 18.0287 15.2718 17.4746 14.8628 17.0657C14.4539 16.6567 13.8993 16.427 13.321 16.427C12.7428 16.427 12.1883 16.6567 11.7795 17.0655C11.3707 17.4743 11.141 18.0288 11.141 18.607M11.141 18.607H2.75M21.25 5.39301H18.145M13.784 5.39301H2.75M13.784 5.39301C13.784 4.81484 14.0137 4.26035 14.4225 3.85152C14.8313 3.44269 15.3858 3.21301 15.964 3.21301C16.2503 3.21301 16.5338 3.2694 16.7983 3.37896C17.0627 3.48851 17.3031 3.64909 17.5055 3.85152C17.7079 4.05395 17.8685 4.29427 17.9781 4.55876C18.0876 4.82325 18.144 5.10673 18.144 5.39301C18.144 5.67929 18.0876 5.96277 17.9781 6.22726C17.8685 6.49175 17.7079 6.73207 17.5055 6.93451C17.3031 7.13694 17.0627 7.29751 16.7983 7.40707C16.5338 7.51663 16.2503 7.57301 15.964 7.57301C15.3858 7.57301 14.8313 7.34333 14.4225 6.93451C14.0137 6.52568 13.784 5.97118 13.784 5.39301Z' stroke='white' stroke-width='1.5' stroke-miterlimit='10' stroke-linecap='round'/%3E%3C/svg%3E");
}
label.\!bg-cover {
    position: relative;
}
label.\!bg-cover:before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 12px;
    background: rgba(255,255,255,.3);
    opacity: 0;
    transition: opacity .2s;
}
label.\!bg-cover:hover:before {
    opacity: 1;
}
.mCSB_inside>.mCSB_container {
    margin-right: 15px;
}
/* The plugin zeroes that margin while no scrollbar is needed and restores it
   the moment content overflows — the whole grid jumps 15px on tab switch.
   Reserve the gutter permanently so nothing reflows when the rail appears. */
.mCSB_inside > .mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden {
    margin-right: 15px;
}
.custom-label-option:hover, .custom-option:hover {
    box-shadow: none;
    border-color: var(--border-strong);
}
.custom-option:has(:checked):hover {
    --tw-border-opacity: 1;
    border-color: var(--fallback-p, oklch(var(--p) / var(--tw-border-opacity, 1)));
    --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
    --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
    box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
    --tw-ring-opacity: 1;
    --tw-ring-color: var(--fallback-p, oklch(var(--p) / var(--tw-ring-opacity, 1)));
}
/* /Sidebar */

.frame {
    will-change: aspect-ratio, font-size, width, height, flex-direction;
    overflow: hidden;
    position: relative;
    display: flex;
    container-type: size;
    container-name: frame-container;
}
.frame .frame-content {
    font-size: calc((100cqw + 100cqh) / 150);
}
/* Base layout for all modes — position + dimensions must always be set
   so that when a transform is applied (drag/zoom), the element still acts
   as a properly-sized containing block for absolutely-positioned children. */
.mockup-module {
    position: relative;
    height: 100%;
    width: 100%;
    pointer-events: none;
    margin: auto;
    z-index: 4;
}
.mockup-module.screenshot {
    --aspect-ratio: 1570 / 2932;
    --shadow-inset: 2% 4%;
    --shadow-radius: 6em;
    --drop-padding: 12.4% 12.5%;
    --drop-radius: 0;
    --x: 0em;
    --y: 0em;
    --b: 0em;
    --s: 1;
    will-change: contents;
    transform: translateZ(0);
}
.mockup-module.screenshot {
    --aspect-ratio: unset;
    --shadow-inset: 2%;
    --shadow-radius: 0.6em;
    --drop-padding: 0;
    --dropzone-1-ratio: unset;
    --dropzone-2-ratio: unset;
    --dropzone-3-ratio: unset;
    --border-radius: 2.5em;
}
.mockup-module.screenshot .layouts {
    aspect-ratio: var(--aspect-ratio);
    position: absolute;
    inset: 0;
    max-height: 100%;
    margin: auto;
    display: flex;
    justify-content: center;
    align-items: center;
    pointer-events: all;
    transform: translateZ(0);
    will-change: contents, transform, opacity;
    user-select: none;
    border: none !important;
    outline: none !important;
}
.mockup-module.screenshot .layouts .layouts-item {
    display: flex;
    justify-content: center;
    align-items: center;
    pointer-events: all;
    transform: translateZ(0);
    will-change: contents, transform, opacity;
    user-select: none;
    border: none !important;
    outline: none !important;
}
.mockup-module .item {
    transition: all .2s ease;
    border: none !important;
    outline: none !important;
}
.mockup-module.screenshot .item {
    position: relative;
    width: 100%;
    height: 100%;
    aspect-ratio: var(--aspect-ratio);
    container-type: size;
    container-name: item-container;
}
.mockup-module .item .item-container {
    width: 100%;
    height: 100%;
    min-width: 0;
}
.mockup-module.screenshot .layouts {
    /* aspect-ratio: 1.6 / 1; */
    aspect-ratio: 1.8 / 1;
}
.mockup-module.screenshot .layouts.lay-2-items {
    aspect-ratio: 1 / 0.9;
}
.mockup-module.screenshot .layouts.lay-3-items {
    aspect-ratio: 1 / 0.85;
}
.devices .item .device-asset {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    transform: scale(var(--device-asset-scale));
    z-index: 90;
}
.screenshot .lay-2-items .layouts-item {
    gap: 3%;
}
.screenshot .lay-3-items .layouts-item {
    gap: 1.5%;
}
.screenshot .item,
.screenshot .devices {
    aspect-ratio: unset !important;
    width: 100%;
    height: 100%;
    max-height: 100%;
    max-width: 100%;
}
.screenshot .devices:first-child {
    position: relative;
    z-index: 1;
}
.screenshot.layout-preview.layout-1-1,
.screenshot.layout-preview.layout-1-8,
.screenshot.layout-preview.layout-1-2 {
    width: 33.333%;
}
.screenshot.layout-preview .item {
    border-radius: 5px;
    position: relative;
    z-index: 2;
}
/* Unified frosted-tile look for Images layout previews — matches .device-preview-cards */
.screenshot.layout-preview .item.bg-empty {
    background: linear-gradient(155deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.05) 100%) !important;
    border: 1px solid rgba(255, 255, 255, 0.10);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        0 2px 4px rgba(0, 0, 0, 0.28);
}
/* Border-radius preview shapes (Sharp / Curved / Round) — same frosted-tile treatment */
.studio-sidebar .bg-empty.border-2.border-black {
    background: linear-gradient(155deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.05) 100%) !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        0 2px 4px rgba(0, 0, 0, 0.28);
}
/* Shadow preview shapes (None / Hug / Adaptive / Layered / Colored / Neon / Neu / Drop) —
   frosted-tile fill; existing shadow-* classes keep their own box-shadow demonstrations. */
.studio-sidebar label:has(> input[name="shadow"]) .bg-empty {
    background: linear-gradient(155deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.05) 100%) !important;
    border: 1px solid rgba(255, 255, 255, 0.10);
}
.screenshot.layout-preview .devices {
    position: relative;
    z-index: 1;
    display: block;
}
.screenshot.layout-preview .devices:before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.05);
    filter: blur(32.8125px);
    top: 15%;
    left: 30%;
}
.screenshot.layout-preview.layout-1-8 .devices:before,
.screenshot.layout-preview.layout-1-2 .devices:before {
    transform: scale(1.3);
    top: 30%;
}
.screenshot.layout-preview.layout-1-2 .devices:before {
    top: 0;
}
button .screenshot.layout-preview .item {
    border-radius: 3px;
}
.screenshot.layout-1-1 .devices:first-child .item {
    display: block;
}
.screenshot.layout-1-8 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, 15%) scale(1.3) rotateX(0deg) rotateY(0deg) rotateZ(0) skewX(0deg) skewY(0deg);
}
.screenshot.layout-1-2 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, -15%) scale(1.3) rotateX(0deg) rotateY(0deg) rotateZ(0) skewX(0deg) skewY(0deg);
}
.screenshot.layout-1-3 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, -2%) scale(0.95) rotateX(10deg) rotateY(20deg) rotateZ(-8deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-1-5 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, -5%) scale(0.95) rotateX(40deg) rotateY(0deg) rotateZ(0deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-1-6 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, -5%) scale(0.95) rotateX(45deg) rotateY(0deg) rotateZ(-45deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-1 .devices:first-child .item,
.screenshot.layout-2-1 .devices:nth-child(2) .item {
    display: block;
}
.screenshot.layout-2-5 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, -3%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-5 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) translate(0%, 3%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-6 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(10%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(-10deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-6 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) translate(-10%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(10deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-7 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(10%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(-10deg) skewX(0deg) skewY(0deg);
    z-index: 1;
}
.screenshot.layout-2-7 .devices:nth-child(2) {
    position: relative;
    z-index: 2;
}
.screenshot.layout-2-7 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) translate(-10%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(10deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-11 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(10deg) skewX(0deg) skewY(0deg);
    z-index: 1;
}
.screenshot.layout-2-11 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) translate(0%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(10deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-2 .devices:first-child .item {
    display: block;
    transform: perspective(400em) rotate(-45deg) skew(15deg, 15deg) translate3d(-25%, 25%, 0) scale(0.9);
}
.screenshot.layout-2-2 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) rotate(-45deg) skew(15deg, 15deg) translate3d(25%, -25%, 0) scale(0.9);
}
.screenshot.layout-2-8 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(-10deg) skewX(0deg) skewY(0deg);
    z-index: 1;
}
.screenshot.layout-2-8 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) translate(0%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(-10deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-9 .devices:first-child .item {
    display: block;
    transform: perspective(400em) rotate(45deg) skew(-15deg, -15deg) translate3d(-25%, -25%, 0) scale(0.9);
}
.screenshot.layout-2-9 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) rotate(45deg) skew(-15deg, -15deg) translate3d(25%, 25%, 0) scale(0.9);
}
.screenshot.layout-2-10 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-10 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) translate(0%, 0%) scale(0.85) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-12 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, 0%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-12 .devices:nth-child(2) .item {
    display: block;
}
.screenshot.layout-2-12 .devices:nth-child(3) .item {
    display: block;
}
.screenshot.layout-2-13 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(0%, 8%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(10deg) skewX(0deg) skewY(0deg);
    z-index: 1;
}
.screenshot.layout-2-13 .devices:nth-child(2) .item {
    display: block;
    transform: perspective(400em) translate(8%, -8%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(10deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-13 .devices:nth-child(3) .item {
    display: block;
    transform: perspective(400em) translate(-5%, 20%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(10deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-14 .devices:first-child .item {
    display: block;
    transform: perspective(400em) translate(25%, 3%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(-10deg) skewX(0deg) skewY(0deg);
}
.screenshot.layout-2-14 .devices:nth-child(2) {
    position: relative;
    z-index: 3;
}
.screenshot.layout-2-14 .devices:nth-child(2) .item {
    display: block;
}
.screenshot.layout-2-14 .devices:nth-child(3) .item {
    display: block;
    transform: perspective(400em) translate(-25%, 3%) scale(1) rotateX(0deg) rotateY(0deg) rotateZ(10deg) skewX(0deg) skewY(0deg);
}
.screenshot .item .item-container {
    width: unset;
    height: -moz-max-content;
    height: max-content;
    position: absolute;
    inset: 0;
    max-height: 100%;
    margin: auto;
}
.screenshot .devices:first-child .item .item-container,
.screenshot .devices:nth-child(2) .item .item-container,
.screenshot .devices:nth-child(3) .item .item-container {
    /* aspect-ratio: 393 / 852; */
    aspect-ratio: 4 / 5;
}
.mockup-module .item .item-container {
    font-size: calc((100cqw + 100cqh) / 150);
}
.mockup-module .lay-2-items .item .item-container {
    font-size: calc((100cqw + 100cqh) / 70);
}
.mockup-module .item .drop-wrapper {
    height: 100%;
    width: 100%;
    padding: var(--drop-padding);
    transition: all .2s ease;
    overflow: hidden;
    border: none !important;
    outline: none !important;
    pointer-events: all;
}
.dropzone {
    position: relative;
    height: -moz-max-content;
    height: max-content;
    width: -moz-max-content;
    width: max-content;
}
.mockup-module .item .drop-wrapper .dropzone {
    height: 100%;
    width: 100%;
    border-radius: var(--border-radius);
    border: none !important;
    outline: none !important;
    pointer-events: all;
}
.mockup-module:not(.screenshot) .item .drop-wrapper .dropzone {
    overflow: hidden;
}
.dropzone .active-drop, .dropzone .empty-drop {
    position: absolute;
    inset: 0;
}
.dropzone .file-drop {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 2;
}
.mockup-module .item .drop-wrapper .dropzone .empty-drop {
    height: 100%;
    max-width: 100% !important;
    max-height: 100% !important;
    color: rgba(var(--panel-dim), 1);
    z-index: 1000;
}
.filepond--root {
    font-family: "EuclidCircularA", sans-serif;
}
.filepond--root .filepond--list-scroller {
    height: calc(100% - 1.5em);
}
.filepond--list.filepond--list {
    inset: 0;
}
.filepond--item {
    margin: .25em 1em;
}
.trans-200 {
    transition: all .2s ease;
}
.dropzone .empty-drop .content {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    transition: inherit;
}
.dropzone .empty-drop .content .title {
    margin: .5em 0;
    font: 500 6em / 100% Inter, sans-serif;
    letter-spacing: -.02em;
}
.dropzone .empty-drop .content .formats {
    color: rgba(var(--panel-dim), .6);
    font: 500 3.5em / 100% Inter, sans-serif;
    letter-spacing: -.02em;
}
.dropzone .empty-drop .content .screen-info {
    margin-top: 1em;
    font: 600 3.5em / 100% Inter, sans-serif;
    letter-spacing: -.02em;
    padding: .32em .4em;
    border-radius: .5em;
    border: .1em solid rgba(var(--secondary), .36);
}
.dropzone .empty-drop .content.hovered {
    opacity: 0;
    visibility: hidden;
}
.dropzone .empty-drop .content svg {
    width: 8em;
    height: 8em;
}
.filepond--root {
    background-color: transparent;
    font-size: 0.85rem;
}
.lay-2-items .filepond--root {
    font-size: 100%;
}
.filepond--root .filepond--drop-label {
    min-height: auto;
}
#result,
#result-2 {
    height: 100%;
}
#result canvas,
#result img,
#result-2 canvas,
#result-2 img {
    max-width: 100%;
    max-height: 100%;
}
.dropzone canvas,
.dropzone img {
    min-width: 100%;
    min-height: 100%;
    display: block;
    transition: all .1s ease;
}
.dropzone img.show-img {
    position: relative;
    z-index: 999;
    background-color: transparent;
}
.mockup-module .item .device {
    position: absolute;
    z-index: 1;
    width: 100%;
    pointer-events: none;
}
.filepond--root {
    height: 100%;
    margin-bottom: 0;
}
.filepond--panel-root,
.filepond--drip {
    background-color: transparent;
    border: none;
}
.filepond--drop-label {
    top: 50%;
    transform: translateY(-50%) !important;
    bottom: auto;
}
.mockup-module .item .shadow-container {
    position: absolute;
    inset: 2%;
    z-index: -5;
}
.mockup-module .item .shadow-container .shadow-layer {
    will-change: transform, opacity, filter;
    position: absolute;
    inset: 3.5%;
    border-radius: inherit;
    pointer-events: none;
}
.devices .item .adaptive-shadow-layer {
    position: absolute;
    inset: 1%;
    z-index: -5;
    border-radius: 6em;
}
.devices .item .adaptive-shadow-layer>div {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    overflow: hidden;
}
.devices .item .adaptive-shadow-layer>div:first-child {
    z-index: 1;
}

/* Phase 4: Shadow preview classes */
.shadow-layered {
    box-shadow: 0 1px 1px rgba(0,0,0,0.05), 0 2px 2px rgba(0,0,0,0.05), 0 4px 4px rgba(0,0,0,0.05), 0 8px 8px rgba(0,0,0,0.05), 0 16px 16px rgba(0,0,0,0.05);
}
.shadow-colored {
    box-shadow: -5px 5px 20px rgba(99, 102, 241, 0.3), -2px 2px 8px rgba(99, 102, 241, 0.2);
}
.shadow-neon {
    box-shadow: 0 0 5px rgba(202, 252, 0, 0.5), 0 0 15px rgba(202, 252, 0, 0.3), 0 0 30px rgba(202, 252, 0, 0.15);
}
.shadow-neumorphism {
    box-shadow: 4px 4px 8px #bebebe, -4px -4px 8px #ffffff;
}
.shadow-drop-preview {
    filter: drop-shadow(-5px 5px 5px rgba(0, 0, 0, 0.15));
}

/* Stroke style toggle buttons (Solid / Dashed) — WS4a: now .tc-seg-item faces
   inside a .tc-segmented; the .stroke-style-active class demo.js toggles maps
   onto the segmented active fill. */
.studio-sidebar .stroke-style-btn {
    color: var(--label);
}
.studio-sidebar .stroke-style-btn:hover {
    color: var(--foreground);
}
.studio-sidebar .stroke-style-btn.stroke-style-active {
    background: var(--selection-bg);
    color: var(--foreground);
}
/* The 20×2 rule glyphs must not be squared off by the generic 14px icon rule. */
.stroke-style-btn svg { width: 20px; height: 2px; }

/* Position pad — shared 2D coordinate picker (DOF Focus Position +
   Shadow Position). v17 XY-pad skin (SPEC §3): dot grid, gradient
   crosshair guides, 12px ball. API in createPosPad untouched. */
.pos-pad {
    position: relative;
    width: 100%;
    height: 142px;
    border-radius: var(--r-lg);
    background-color: var(--ghost-3);
    background-image: radial-gradient(color-mix(in oklab, var(--foreground) 8%, transparent) 1px, transparent 1px);
    background-size: 14px 14px;
    background-position: center center;
    border: 1px solid var(--ghost-12);
    cursor: crosshair;
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    transition: border-color var(--dur-fast) ease;
}
.pos-pad:hover {
    border-color: var(--ghost-20);
}
/* Crosshair guides — hairlines fading toward the edges */
.pos-pad::before,
.pos-pad::after {
    content: '';
    position: absolute;
    pointer-events: none;
}
.pos-pad::before {
    left: 50%;
    top: 0;
    bottom: 0;
    width: 1px;
    background: linear-gradient(to bottom, transparent, var(--ghost-12) 30%, var(--ghost-12) 70%, transparent);
}
.pos-pad::after {
    top: 50%;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(to right, transparent, var(--ghost-12) 30%, var(--ghost-12) 70%, transparent);
}
.pos-pad-dot {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%, var(--foreground) 0%, #C9C9C9 100%);
    border: none;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.25);
    transform: translate(-50%, -50%);
    cursor: grab;
    z-index: 1;
}
.pos-pad-dot:active {
    cursor: grabbing;
}
/* Snap variant (shadow): dot glides to the nearest preset cell with a
   spring overshoot settle. */
.pos-pad--snap .pos-pad-dot {
    transition: left var(--dur-settle) var(--ease-spring), top var(--dur-settle) var(--ease-spring);
}

/* Phase 4: Slider wraps */
.blur-shadow-wrap,
.spread-shadow-wrap {
    flex: 0 0 auto;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    margin-bottom: 4px;
    box-sizing: border-box;
}

/* Allow vertical scrolling through noUiSlider areas in sidebar */
.panel-scroll-view .noUi-target,
.panel-scroll-view .noUi-target * {
    touch-action: pan-y;
}
.panel-scroll-view .noUi-handle {
    touch-action: none;
}

/* ── Slider connect fill: foreground (v17 thin-track skin) ── */
.slider-connect,
.noUi-connect.bg-brand,
.studio-sidebar .bg-brand.slider-connect {
    background: var(--foreground) !important;
}

/* ── Slider — v17 thin-track (SPEC §3): 1px line, filled part foreground,
   9px square r-2 thumb with 18px hit zone, label/value row above.
   The data-range-slider cssClasses blobs stay byte-identical — only the
   CSS behind the class names changes. ── */
.panel-scroll-view .noUi-target {
    height: 18px !important;            /* hit area; the visual track is 1px */
    border-radius: 0 !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    cursor: pointer;
    position: relative;
}
.panel-scroll-view .noUi-base {
    width: 100%;
    height: 100% !important;
    position: relative;
    z-index: 1;
}
.panel-scroll-view .noUi-origin {
    height: 100% !important;
}
/* The unfilled track: 1px hairline centered in the 18px hit box. */
.panel-scroll-view .noUi-connects {
    position: absolute !important;
    top: 50% !important;
    left: 0;
    right: 0;
    width: auto !important;
    height: 1px !important;
    margin-top: -0.5px;
    border-radius: var(--r-full) !important;
    overflow: hidden;
    background: color-mix(in oklab, var(--muted-foreground) 38%, transparent);
    z-index: 0;
}
.panel-scroll-view .noUi-connect {
    background: var(--foreground) !important;
    box-shadow: none !important;
    height: 100% !important;
}
/* 9px square thumb (r-2), scales 1.4 on hover/drag. Overrides the inline
   Tailwind classes from the cssClasses blob (bg-white rounded-full etc). */
.panel-scroll-view .noUi-handle {
    width: 9px !important;
    height: 9px !important;
    background: var(--foreground) !important;
    border: 0 !important;
    border-radius: var(--r-xs) !important;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4) !important;
    transform: translate(50%, -50%) !important;
    cursor: grab;
    outline: none;
    top: 50% !important;
    transition: transform 120ms var(--ease-snap);
}
.panel-scroll-view .noUi-handle:hover,
.panel-scroll-view .noUi-handle:active {
    transform: translate(50%, -50%) scale(1.4) !important;
}
.panel-scroll-view .noUi-handle:active {
    cursor: grabbing;
}
/* 18px touch zone around the 9px thumb. */
.panel-scroll-view .noUi-touch-area {
    width: 200% !important;
    height: 200% !important;
    transform: translate(-25%, -25%);
}
.panel-scroll-view .noUi-tooltip {
    display: none !important;
}
/* Label/value row rendered ABOVE the slider (injected by
   initPillSliderValue). Label left, click-to-edit mono value right. */
.tc-slider-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-height: 16px;
    margin-bottom: -4px;   /* tuck the row toward the 18px slider hit box */
}
.pill-slider-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--label);
    pointer-events: none;
    white-space: nowrap;
    line-height: 1;
    letter-spacing: -0.005em;
}
/* The original label-above div is hidden once its text has been moved into
   the row (JS adds .pill-slider-label-source). */
.pill-slider-label-source {
    display: none !important;
}
/* Click-to-edit value (right side of the row). */
.pill-slider-value-inline {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    font-weight: 400;
    color: var(--muted-foreground);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    line-height: 1;
    text-align: right;
    cursor: text;
    padding: 2px 4px;
    margin: -2px -4px -2px 0;
    border-radius: var(--r-sm);
    outline: none;
    transition: color var(--dur-fast) ease-out, background-color var(--dur-fast) ease-out;
}
.pill-slider-value-inline:hover {
    color: var(--foreground);
}
.pill-slider-value-inline:focus {
    color: var(--foreground);
    background: var(--ghost-5);
    box-shadow: inset 0 0 0 1px var(--ghost-12);
}
/* The external right-side value div is hidden once its text has been moved
   into the row (JS adds .pill-slider-value-source). It stays in the DOM as a
   state carrier — handlers parse #range-number-* innerText. */
.pill-slider-value-source {
    display: none !important;
}
/* Legacy class kept for any unconverted callers — old "value inside pill". */
.pill-slider-value {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    display: flex;
    align-items: center;
    padding-left: 10px;
    font-size: 11px;
    font-weight: 500;
    color: var(--color-gray-100);
    pointer-events: none;
    z-index: 2;
    white-space: nowrap;
    line-height: 1;
}
.range-number-hidden { display: none !important; }
/* Wrapper heights match the 18px slider hit box */
.panel-scroll-view .range-size-wrap,
.panel-scroll-view .range-opacity-shadow-wrap {
    height: 18px !important;
}
/* Shadow slider row wrappers too */
.blur-shadow-wrap > div:has(.noUi-target),
.spread-shadow-wrap > div:has(.noUi-target),
.opacity-shadow-wrap > div:has(.noUi-target) {
    height: 18px !important;
}

span.glass-light {
    background: rgba(255, 255, 255, 0.6);
}
span.glass-dark {
    background: rgba(0, 0, 0, 0.3);
}
span.item-card {
    transform: translate3d(-6px, 8px, 0px) rotate(-2deg) scale(0.98);
}
.filepond--credits {
    display: none;
}

/* ── Depth of Field Overlay ── */
.dof-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
    display: none;
    /* backdrop-filter, mask-image set via JS inline styles */
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
}
.dof-viewport-overlay {
    z-index: 25;
    /* Overshoot the parent by 1px on every side. backdrop-filter +
       sub-pixel rounding of the absolute parent (`w-full h-full top-0 left-0`
       vs the overlay's `inset: 0`) can leave a 1px unblurred strip at the
       artboard's bottom edge in the live preview. The artboard's
       overflow:hidden + border-radius clips the overshoot so it never
       leaks visually. Export is unaffected: canvas-pass DOF paints the
       gradient over the full PNG and never relies on this overlay. */
    inset: -1px;
}
.dof-overlay.dof-active {
    display: block;
}
/* DOF mode tab buttons */
.dof-mode-btn.dof-mode-active {
    background: rgba(0, 0, 0, 0.05);
    color: #000;
    font-weight: 500;
}
/* DOF native range slider styling — dark sidebar */
.dof-range {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 4px;
    border-radius: 2px;
    background: var(--color-gray-700);
    outline: none;
    cursor: pointer;
    margin: 0;
}
.dof-range::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #fff;
    cursor: pointer;
    border: 2px solid rgba(255, 255, 255, 0.50);
}
.dof-range::-webkit-slider-thumb:hover {
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.12);
}
.dof-range::-moz-range-thumb {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #fff;
    cursor: pointer;
    border: 2px solid rgba(255, 255, 255, 0.50);
}
.dof-range::-moz-range-track {
    height: 4px;
    border-radius: 2px;
    background: var(--color-gray-700);
}
.screenshot .item .interface .screenshot-glass {
    position: absolute;
    inset: 0;
    margin: -5px;
    transform: translateZ(0);
    overflow: hidden;
}
.screenshot .lay-2-items .item .interface .screenshot-glass {
    margin: -.5em;
}
.screenshot .lay-3-items .item .interface .screenshot-glass {
    margin: -.9em;
}
.screenshot .item .interface .screenshot-glass.glass-light {
    background: hsla(0, 0%, 100%, .6);
    backdrop-filter: blur(4em) saturate(150%) contrast(150%) brightness(105%);
    -webkit-backdrop-filter: blur(4em) saturate(150%) contrast(150%) brightness(105%);
}
.screenshot .item .interface .screenshot-glass.glass-dark {
    background: rgba(0, 0, 0, .6);
    backdrop-filter: blur(6em) saturate(250%) contrast(150%) brightness(95%);
    -webkit-backdrop-filter: blur(6em) saturate(250%) contrast(150%) brightness(95%);
}
.screenshot .item .interface .screenshot-outline {
    position: absolute;
    inset: 0;
    margin: -8px;
    border: 2px solid hsla(0, 0%, 39%, .4);
}
.screenshot .lay-2-items .item .interface .screenshot-outline {
    margin: -.5em;
    border: .1em solid hsla(0, 0%, 39%, .4)
}
.screenshot .item .interface .screenshot-border {
    position: absolute;
    inset: 0;
    margin: -5px;
    background: #000;
}
.screenshot .lay-2-items .item .interface .screenshot-border {
    margin: -.5em;
}
.screenshot .lay-3-items .item .interface .screenshot-border {
    margin: -1em;
}
.screenshot .item .interface .screenshot-retro {
    position: absolute;
    inset: 0;
    margin: -5px;
    background: #000;
}
.screenshot .lay-2-items .item .interface .screenshot-retro {
    margin: -5px;
}
.screenshot .item .interface .screenshot-retro div {
    position: absolute;
    background: #000;
    z-index: -1;
    top: 8px;
    left: 8px;
    width: 100%;
    height: 100%;
}
.screenshot .lay-2-items .item .interface .screenshot-retro div {
    top: 8px;
    left: 8px;
}
.screenshot .item .interface .screenshot-card {
    position: absolute;
    inset: 0;
    overflow: hidden;
    background: #fff;
    transform: translate3d(-2.5em, 2em, 0) rotate(-1.5deg) scale(.98);
    z-index: -1;
    box-shadow: -1em 1em 4em rgba(0, 0, 0, .2);
}
.screenshot .item .interface .screenshot-card + div {
    box-shadow: -1em 1em 4em rgba(0, 0, 0, .2);
}
.screenshot .lay-2-items .item .interface .screenshot-card {
    transform: translate3d(-1.75em, 1.5em, 0) rotate(-1.5deg) scale(.98);
}
.screenshot .item .interface .screenshot-card .filepond--root:before {
    content: "";
    position: absolute;
    inset: 0;
    background: hsla(0, 0%, 100%, .5);
    z-index: 1;
}
.screenshot .item .interface .screenshot-stack {
    position: absolute;
    inset: 0;
    box-shadow: 0 .5em .5em rgba(0, 0, 0, .2);
}
.screenshot .item .interface .screenshot-stack>div {
    position: absolute;
    overflow: hidden;
    height: 100%;
    background: #fff;
    border-radius: inherit;
}
.screenshot .item .interface .screenshot-stack>div:first-child {
    z-index: -1;
    inset: 15px;
    box-shadow: inherit;
}
.screenshot .item .interface .screenshot-stack>div:nth-child(2) {
    z-index: -2;
    inset: 30px;
    box-shadow: inherit;
}
.screenshot .item .interface .screenshot-stack-two {
    position: absolute;
    inset: 0;
    box-shadow: -1em 1em 4em rgba(0, 0, 0, .2);
}
.screenshot .item .interface .screenshot-stack-two>div {
    position: absolute;
    overflow: hidden;
    background: #fff;
    border-radius: inherit;
    inset: 0em;
}
.screenshot .item .interface .screenshot-stack-two>div:first-child {
    z-index: -1;
    box-shadow: inherit;
    transform: translate3d(-1.5em, -1.5em, 0) rotate(-1.5deg);
}
.screenshot .lay-2-items .item .interface .screenshot-stack-two>div:first-child {
    transform: translate3d(-1em, -1em, 0) rotate(-1.5deg);
}
.screenshot .lay-3-items .item .interface .screenshot-stack-two>div:first-child {
    transform: translate3d(-2em, -2em, 0) rotate(-1.5deg);
}
.screenshot .item .interface .screenshot-stack-two>div:nth-child(2) {
    z-index: -2;
    box-shadow: inherit;
    transform: translate3d(-3.5em, -4em, 0) rotate(-2.5deg) scale(.96);
}
.screenshot .lay-2-items .item .interface .screenshot-stack-two>div:nth-child(2) {
    transform: translate3d(-2.5em, -3em, 0) rotate(-2.5deg) scale(.96);
}
.screenshot .lay-3-items .item .interface .screenshot-stack-two>div:nth-child(2) {
    transform: translate3d(-4.5em, -5.5em, 0) rotate(-2.5deg) scale(.96);
}
.screenshot .item .interface .screenshot-card:before {
    content: "";
    position: absolute;
    inset: 0;
    background: hsla(0, 0%, 100%, .5);
    z-index: 1;
}
.screenshot .item .interface .screenshot-card.screenshot-card:after, .screenshot .item .interface .screenshot-card~.drop-wrapper:after {
    content: "";
    position: absolute;
    inset: 0;
    border: .1em solid rgba(0, 0, 0, .15);
    z-index: 1;
    border-radius: inherit;
}
.screenshot .item .interface .img-use {
    width: 100%;
    height: 100%;
}
.screenshot .item .interface .screenshot-card .img-use {
    transform: scale(1.5);
    filter: blur(5em);
    -webkit-filter: blur(5em);
}
.screenshot .item .interface .screenshot-stack>div .img-use {
    filter: blur(5em);
    -webkit-filter: blur(5em);
}
.screenshot .item .interface .screenshot-stack-two>div .img-use {
    transform: scale(1.5);
    filter: blur(5em);
    -webkit-filter: blur(5em);
}
.screenshot .item .interface .screenshot-stack-two>div:after, .screenshot .item .interface .screenshot-stack-two~.drop-wrapper:after {
    content: "";
    position: absolute;
    inset: 0;
    border: .1em solid rgba(0, 0, 0, .15);
    z-index: 1;
    border-radius: inherit;
}
.screenshot .item .interface .screenshot-stack-two>div:before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}
.screenshot .item .interface .screenshot-stack-two>div:first-child:before {
    background: hsla(0, 0%, 100%, .5);
}
.screenshot .item .interface .screenshot-stack-two>div:nth-child(2):before {
    background: hsla(0, 0%, 100%, .5);
}
.mockup-module .layouts .mockup-item-resize-handle {
    width: 100%;
    height: 120%;
    position: absolute;
    z-index: -1;
}
.mockup-module .layouts.lay-2-items .mockup-item-resize-handle {
    width: 140%;
    height: 100%;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area {
    width: 12em;
    aspect-ratio: 1 / 1;
    position: absolute;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.nw {
    top: 0;
    left: 0;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.ne {
    top: 0;
    right: 0;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.se {
    right: 0;
    bottom: 0;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.sw {
    left: 0;
    bottom: 0;
}
.mockup-module .layouts .mockup-item-resize-handle .handle {
    width: 20px;
    aspect-ratio: 1 / 1;
    position: absolute;
    border-bottom-right-radius: 20px;
    border-right: 4px solid #000;
    border-bottom: 4px solid #000;
    opacity: 0;
    visibility: hidden;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.nw .handle {
    top: 2.5em;
    left: 2.5em;
    transform: rotate(180deg);
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.ne .handle {
    top: 2.5em;
    right: 2.5em;
    transform: rotate(-90deg);
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.se .handle {
    right: 2.5em;
    bottom: 2.5em;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.sw .handle {
    left: 2.5em;
    bottom: 2.5em;
    transform: rotate(90deg);
}
.mockup-module .layouts .mockup-item-resize-handle .handle:after, .mockup-module .layouts .mockup-item-resize-handle .handle:before {
    content: "";
    position: absolute;
    background: #000;
    height: 4px;
    width: 4px;
    border-radius: 10px;
}
.mockup-module .layouts .mockup-item-resize-handle .handle:before {
    top: -2px;
    right: -4px;
}
.mockup-module .layouts .mockup-item-resize-handle .handle:after {
    bottom: -4px;
    left: -2px;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area:hover .handle {
    visibility: visible;
    opacity: .5;
}
.mockup-module .layouts .mockup-item-resize-handle .handle:hover {
    opacity: 1 !important;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.nw, .mockup-module .layouts .mockup-item-resize-handle .handle-area.se {
    cursor: nwse-resize;
}
.mockup-module .layouts .mockup-item-resize-handle .handle-area.ne, .mockup-module .layouts .mockup-item-resize-handle .handle-area.sw {
    cursor: nesw-resize;
}

/* ═══════════════════════════════════════════════════════ */
/* Background Effects (Phase 3.4)                        */
/* ═══════════════════════════════════════════════════════ */

/* Noise / Grain overlay via canvas-generated texture */
.bg-effect-noise {
    background-repeat: repeat;
    background-size: 150px 150px;
}

/* Bokeh: per-image overlay, clipped to dropzone, blended with image.
   mix-blend-mode lives on the layer so the whole pack of circles blends
   with the image underneath instead of with empty space inside the
   layer's own stacking context. */
.bokeh-layer {
    position: absolute;
    inset: 0;
    z-index: 1000;
    pointer-events: none;
    overflow: hidden;
    border-radius: inherit;
    mix-blend-mode: overlay;
}
.bokeh-circle {
    position: absolute;
    border-radius: 50%;
    opacity: 0.8;
    filter: blur(15px);
}

/* Light Leak: per-image overlay, clipped to dropzone, blended with image. */
.lightleak-layer {
    position: absolute;
    inset: 0;
    z-index: 1000;
    pointer-events: none;
    overflow: hidden;
    border-radius: inherit;
    mix-blend-mode: overlay;
}
.lightleak-pattern-btn.active {
    background-color: var(--bg-hover);
    border-color: rgba(255, 255, 255, 0.30);
    color: var(--color-gray-50);
}

/* Gradient orbs */
.bg-effect-blob .blob-shape {
    position: absolute;
    border-radius: 50%;
    transform-origin: center;
    will-change: transform, filter, opacity;
}

/* Effect button active state */
.bg-effect-btn.active {
    background-color: var(--bg-hover);
    border-color: rgba(255, 255, 255, 0.30);
    color: var(--color-gray-50);
}

/* Noise mode toggle buttons */
.noise-mode-btn.active {
    background-color: var(--bg-hover);
    border-color: rgba(255, 255, 255, 0.30);
    color: var(--color-gray-50);
}

/* Blob layer (z-index) toggle */
.blob-layer-btn.active {
    background-color: var(--bg-hover);
    border-color: rgba(255, 255, 255, 0.30);
    color: var(--color-gray-50);
}

/* Effect settings panels */
.effect-settings-panel {
    animation: effectPanelIn 0.15s ease-out;
    position: relative;
}
/* Inset divider between stacked effect panels.
   Sits in the parent flex gap, kept clear of the container's rounded
   corners so it doesn't appear to "spill" past the boundary. */
.effect-settings-panel::before {
    content: '';
    position: absolute;
    top: -16px;
    left: -10px;
    right: -10px;
    height: 1px;
    background-color: rgba(255, 255, 255, 0.08);
    pointer-events: none;
}

@keyframes effectPanelIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* Effect range sliders */
.effect-range {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 4px;
    border-radius: 2px;
    background: var(--color-gray-700);
    outline: none;
    cursor: pointer;
}

.effect-range::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 14px;
    height: 14px;
    background: #fff;
    border: 2px solid rgba(255, 255, 255, 0.50);
    border-radius: 50%;
    cursor: pointer;
}

.effect-range::-webkit-slider-thumb:hover {
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.12);
}

.effect-range::-moz-range-track {
    height: 4px;
    border-radius: 2px;
    background: var(--color-gray-700);
}

.effect-range::-moz-range-thumb {
    width: 14px;
    height: 14px;
    background: #fff;
    border: 2px solid rgba(255, 255, 255, 0.50);
    border-radius: 50%;
    cursor: pointer;
}

/* Color preset button active state */
.color-preset-btn.active {
    outline: 2px solid rgba(255, 255, 255, 0.40);
    outline-offset: 1px;
}

@media only screen and (max-width: 1000px){
    .adaptive-alert.hidden {
        display: flex;
        z-index: 9999;
        align-items: center;
        justify-content: center;
        padding: 15px;
    }
    .adaptive-alert:before {
        backdrop-filter: blur(10px);
    }
}

/* =========================================================================
   PHASE 5: Drag & Drop Canvas Interaction
   ========================================================================= */

/* 5.1 Canvas drag cursor — only on the mockup, not whole canvas */
.artboard {
    touch-action: none;
}
.artboard .mockup-module {
    cursor: grab;
}
.artboard.dragging,
.artboard.dragging .mockup-module {
    cursor: grabbing;
}
/* Kill native HTML5 image drag inside the artboard. WebKit ignores
   preventDefault() on `mousedown` over <img>/SVG <image>/<canvas> and
   would otherwise hijack the canvas-drag gesture mid-flight, suppressing
   mousemove and snapping the mockup to random coords on release. A JS
   `dragstart` preventDefault was tried but in Safari it also broke the
   following mousemove stream — declaring it here keeps WebKit out of
   drag-mode entirely. */
.artboard img,
.artboard svg image,
.artboard canvas {
    -webkit-user-drag: none;
    user-drag: none;
}

/* 5.2 Resize handles */
.resize-handles-container {
    position: absolute;
    inset: 0;
    z-index: 9999;
    pointer-events: none;
}
.resize-handle {
    position: absolute;
    width: 7px;
    height: 7px;
    background: rgba(255, 255, 255, 0.8);
    border: 1.5px solid rgba(0, 0, 0, 0.2);
    border-radius: 2px;
    pointer-events: all;
    z-index: 9999;
    opacity: 0;
    transition: opacity 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.resize-handle:hover {
    border-color: rgba(0, 0, 0, 0.4);
    transform: scale(1.15);
}
.resize-handle:active {
    border-color: rgba(0, 0, 0, 0.5);
    background: rgba(255, 255, 255, 0.6);
}

/* 5.3 Alignment guides
   `mix-blend-mode: difference` + white inverts whatever is underneath, so
   the line is always readable on top of any gradient / image / dark or
   light background — no need to sniff bg luminance. */
.alignment-guides-container {
    position: absolute;
    inset: 0;
    z-index: 9998;
    pointer-events: none;
}
.alignment-guide {
    position: absolute;
    pointer-events: none;
    background: #ffffff;
    mix-blend-mode: difference;
    opacity: 0;
    transition: opacity 120ms ease-out;
}
.alignment-guide.is-active {
    /* difference-blend already amplifies contrast against any bg, so we
       keep alpha low — the line should *suggest* the axis, not shout. */
    opacity: 0.32;
}
.alignment-guide-h {
    left: 0;
    right: 0;
    top: 50%;
    height: 1px;
    transform: translateY(-0.5px) scaleX(0.6);
    transform-origin: 50% 50%;
    transition: opacity 120ms ease-out, transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.alignment-guide-v {
    top: 0;
    bottom: 0;
    left: 50%;
    width: 1px;
    transform: translateX(-0.5px) scaleY(0.6);
    transform-origin: 50% 50%;
    transition: opacity 120ms ease-out, transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.alignment-guide-h.is-active {
    transform: translateY(-0.5px) scaleX(1);
}
.alignment-guide-v.is-active {
    transform: translateX(-0.5px) scaleY(1);
}

/* Micro-animation: when a text element snaps into the center axis, give
   left/top a brief easing so the jump from "near" to "exactly 50%" reads
   as a magnetic pull rather than a teleport. Class is toggled on/off
   from the drag handler for ~90ms on snap entry only. */
.text-element.is-snapping,
.image-element.is-snapping {
    transition: left 90ms cubic-bezier(0.2, 0.8, 0.2, 1),
                top  90ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* ========================================
   PHASE 7: Dark Studio UI Redesign
   ======================================== */

/* 7.3 Header — deleted (WS3): the 48px header row is gone; its actions
   moved into the scenes-panel app menu (see WS3 chrome CSS at end of file). */

/* 7.4 Controls panel (WS3) — floating top-right 320px .tc-panel.
   Class name .studio-sidebar is preserved (popover clamps, autosave
   whitelist and the shadow closure all key off it). */
.studio-sidebar {
    position: fixed;
    top: 10px;
    right: 10px;
    bottom: 10px;
    width: 320px;
    min-width: 320px;
    max-width: 320px;
    border-radius: var(--r-xl);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    height: auto;
    z-index: 30;
    transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1),
                opacity 200ms ease;
}
.studio-sidebar.collapsed {
    transform: translateX(calc(100% + 20px));
    opacity: 0;
    pointer-events: none;
}

/* Sidebar logo — deleted (WS3): the Presenta mark moved to the scenes-panel
   app-menu button. */

/* Sidebar expand button (visible when sidebar collapsed) — WS3: panel
   floats top-right now, so the expand affordance lives there too. */
.sidebar-expand-btn {
    position: fixed;
    right: 12px;
    top: 12px;
    z-index: 50;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-default);
    color: var(--color-gray-300);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transform: scale(0.85);
    transition: opacity 200ms ease, transform 200ms ease, background 150ms ease, color 150ms ease;
}
.sidebar-expand-btn.visible {
    opacity: 1;
    pointer-events: auto;
    transform: scale(1);
}
.sidebar-expand-btn:hover {
    background: var(--bg-hover);
    color: var(--color-gray-100);
    border-color: var(--border-strong);
}
.studio-sidebar .panel {
    /* WS3: transparent — the .tc-panel surface (panel-surface + blur)
       provides the background now. */
    background: transparent !important;
    border-right: none;
    box-shadow: none;
    position: relative;
    min-height: 0;
}
.studio-sidebar .sidebar-form {
    padding: 12px 12px 20px !important;
    gap: 20px !important;
    position: relative;
    z-index: 0;
    border-top: 1px solid var(--ghost-8);
    /* 44px bottom scroll-fade mask (SPEC #1.4). */
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent 100%);
            mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent 100%);
}
/* Ensure all direct children inside sidebar-form have proper spacing */
.studio-sidebar .sidebar-form > div {
    padding-left: 0;
    padding-right: 0;
}
/* Section separator lines should respect padding */
.studio-sidebar .border-t {
    margin-left: -20px;
    margin-right: -20px;
    padding-left: 20px;
    padding-right: 20px;
}

/* Sidebar footer actions (above export bar) */
.sidebar-footer-actions {
    padding: 6px 10px;
    border-top: 1px solid var(--border-subtle);
}
.sidebar-reset-all-btn {
    width: 100%;
    height: 26px;
    padding: 0 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border-radius: 6px;
    border: none;
    background: transparent;
    color: var(--color-gray-500);
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    transition: background-color 120ms ease, color 120ms ease;
    cursor: pointer;
}
.sidebar-reset-all-btn svg {
    opacity: 0.85;
}
.sidebar-reset-all-btn:hover {
    background: var(--bg-hover);
    color: var(--color-gray-200);
}
.sidebar-reset-all-btn:focus-visible {
    outline: 2px solid var(--color-gray-400);
    outline-offset: 2px;
}

/* Sidebar section headers */
.section-label {
    font-size: var(--text-xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--color-gray-400);
    margin-bottom: 8px;
}

/* Sidebar collapsible sections */
.sidebar-section {
    border-bottom: 1px solid var(--border-subtle);
    padding-bottom: 16px;
}
.sidebar-section:last-child {
    border-bottom: none;
}
.sidebar-section summary {
    font-size: var(--text-xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--color-gray-400);
    cursor: pointer;
    padding: 4px 0;
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    user-select: none;
}
.sidebar-section summary::-webkit-details-marker {
    display: none;
}
.sidebar-section summary::after {
    content: '';
    width: 16px;
    height: 16px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238E8E99' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6l6-6'/%3E%3C/svg%3E");
    background-size: contain;
    background-repeat: no-repeat;
    transition: transform 200ms ease;
}
.sidebar-section[open] summary::after {
    transform: rotate(180deg);
}

/* 7.5 Component Restyling */

/* Dark sliders */
.range::-webkit-slider-runnable-track {
    background: var(--color-gray-700) !important;
    height: 4px !important;
    border-radius: 2px;
}
.range::-webkit-slider-thumb {
    width: 14px !important;
    height: 14px !important;
    background: #fff !important;
    border: 2px solid rgba(255, 255, 255, 0.50) !important;
    margin-top: -5px;
}
.range::-webkit-slider-thumb:hover {
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.12) !important;
}
.range::-moz-range-track {
    background: var(--color-gray-700);
    height: 4px;
    border-radius: 2px;
}
.range::-moz-range-thumb {
    width: 14px;
    height: 14px;
    background: #fff;
    border: 2px solid rgba(255, 255, 255, 0.50);
    border-radius: 50%;
}

/* Dark option chips (radio cards) — scoped to sidebar */
.studio-sidebar .option-chip,
.studio-sidebar .custom-option,
.studio-sidebar .custom-label-option {
    background: var(--bg-elevated);
    border-color: var(--border-default);
    color: var(--color-gray-200);
    transition: all 150ms ease;
}
.studio-sidebar .option-chip:hover,
.studio-sidebar .custom-option:hover,
.studio-sidebar .custom-label-option:hover {
    border-color: var(--border-strong) !important;
    background: var(--bg-hover);
}
.studio-sidebar .option-chip:has(:checked),
.studio-sidebar .custom-option:has(:checked),
.studio-sidebar .custom-label-option:has(:checked) {
    background: rgba(255, 255, 255, 0.08) !important;
    border-color: rgba(255, 255, 255, 0.30) !important;
    color: var(--color-gray-100);
}

/* Layout dropdown — constrain to viewport. max-height on .dropdown-menu is
   also set dynamically in demo.js (open handler) based on the toggle
   button's actual position so the menu never overflows the viewport bottom.
   The customScrollbar cap below is the inner scroll-area limit; JS only
   tightens the outer container further when vertical space is short. */
#dropdown-layout-wrapper .dropdown-menu:not(.hidden) {
    display: flex !important;
    flex-direction: column;
    overflow: hidden;
}
#dropdown-layout-wrapper .customScrollbar {
    max-height: calc(100vh - 300px) !important;
    height: auto !important;
}
/* WS3: mCustomScrollbar removed — .customScrollbar containers scroll
   natively via their own overflow-y-auto utilities. */
#dropdown-layout-wrapper .customScrollbar {
    max-height: calc(100vh - 300px);
}

/* Dark dropdowns — scoped to sidebar context */
.studio-sidebar .dropdown-menu {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
    border-radius: 10px !important;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.2) !important;
}
.studio-sidebar .dropdown-menu a,
.studio-sidebar .dropdown-menu button:not(.dropdown-toggle),
.studio-sidebar .dropdown-menu li {
    color: var(--color-gray-200) !important;
}
.studio-sidebar .dropdown-menu a:hover,
.studio-sidebar .dropdown-menu button:not(.dropdown-toggle):hover {
    background: var(--bg-hover) !important;
    color: var(--color-gray-50) !important;
}

/* Dark inputs — scoped to sidebar, excluding color picker internals */
.studio-sidebar input:not([type="radio"]):not([type="checkbox"]):not([type="range"]):not([type="file"]):not([type="hidden"]):not(.picker_editor input),
.studio-sidebar select,
.studio-sidebar textarea {
    background: var(--bg-input) !important;
    border-color: var(--border-default) !important;
    color: var(--color-gray-100) !important;
    border-radius: 8px;
}
.studio-sidebar input:not([type="radio"]):not([type="checkbox"]):not([type="range"]):not([type="file"]):not([type="hidden"]):focus,
.studio-sidebar select:focus,
.studio-sidebar textarea:focus {
    border-color: rgba(255, 255, 255, 0.30) !important;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.10) !important;
    outline: none;
}

/* Dark gradient swatches */
.gradient-swatches {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 6px;
}
.gradient-swatches label {
    border-radius: 8px !important;
    transition: all 150ms ease;
}
.gradient-swatches label:hover {
    transform: scale(1.08);
}
.gradient-swatches label:has(:checked) {
    outline: 2px solid rgba(255, 255, 255, 0.40);
    outline-offset: 1px;
}

/* Gradient/Pattern label checked state in background dropdown */
#background-gradient label:has(:checked),
#background-patterns label:has(:checked) {
    outline: 2px solid rgba(255, 255, 255, 0.40);
    outline-offset: 1px;
    border-radius: 12px;
}

/* Canvas size dropdown */
#dropdown-canvas-size-wrapper {
    width: 100%;
}
#dropdown-canvas-size-wrapper .dropdown-menu:not(.hidden) {
    display: flex !important;
    flex-direction: column;
}
/* Toggle: frosted-glass icon with dynamic aspect-ratio shape */
.canvas-size-glass {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 28px;
    width: 28px;
    height: 28px;
    border-radius: 7px;
    background: linear-gradient(155deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0.04) 100%);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}
.canvas-size-preview-shape {
    display: block;
    width: 14px;
    height: 10px;
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.55);
    transition: width 150ms ease, height 150ms ease;
}
.canvas-size-toggle-text {
    display: flex;
    align-items: baseline;
    gap: 6px;
    min-width: 0;
    flex: 1 1 auto;
    text-align: left;
}
.canvas-size-toggle-title {
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.1px;
    color: var(--color-gray-300);
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.canvas-size-toggle-subtitle {
    font-size: 12px;
    color: var(--color-gray-500);
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    flex-shrink: 0;
}
/* Menu groups */
.canvas-size-group + .canvas-size-group {
    margin-top: 4px;
    padding-top: 6px;
}
.canvas-size-group-title {
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--color-gray-500);
    padding: 6px 8px 4px;
}
/* Collapsible sub-group (App Store screenshots, Video) */
.canvas-size-subgroup-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 8px;
    cursor: pointer;
    text-align: left;
    color: var(--color-gray-500);
    transition: background 120ms ease, color 120ms ease;
}
/* Specificity boost: beats .studio-sidebar .dropdown-menu button:not(.dropdown-toggle)
   above, which would otherwise paint these accordion toggles in gray-200 and make them
   look like menu items. */
.studio-sidebar .dropdown-menu button.canvas-size-subgroup-toggle {
    color: var(--color-gray-500) !important;
}
.studio-sidebar .dropdown-menu button.canvas-size-subgroup-toggle:hover {
    color: var(--color-gray-300) !important;
    background: rgba(255, 255, 255, 0.04) !important;
}
.canvas-size-subgroup-title {
    padding: 6px 8px 4px;
    margin: 0;
    flex: 1 1 auto;
    color: inherit;
}
.canvas-size-subgroup-chevron {
    margin-right: 8px;
    color: var(--color-gray-500);
    transition: transform 160ms ease, color 120ms ease;
    flex-shrink: 0;
}
.canvas-size-subgroup-toggle:hover .canvas-size-subgroup-chevron {
    color: var(--color-gray-300);
}
.canvas-size-subgroup-toggle[aria-expanded="true"] .canvas-size-subgroup-chevron {
    transform: rotate(180deg);
}
.canvas-size-subgroup-body {
    display: flex;
    flex-direction: column;
    gap: 0;
}
.canvas-size-subgroup-body[hidden] {
    display: none;
}
.canvas-size-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    padding: 7px 8px;
    border-radius: 8px;
    color: var(--color-gray-200);
    background: transparent;
    border: 0;
    cursor: pointer;
    text-align: left;
    transition: background 120ms ease, color 120ms ease;
}
.canvas-size-option:hover {
    background: rgba(255, 255, 255, 0.04);
    color: var(--color-gray-50);
}
.canvas-size-option.canvas-size-active {
    background: rgba(255, 255, 255, 0.05);
    color: var(--color-gray-50);
}
.canvas-size-option.canvas-size-active .canvas-size-label {
    color: var(--color-gray-50);
}
.canvas-size-label {
    font-size: 13px;
    font-weight: 500;
    line-height: 1.2;
}
.canvas-size-dims {
    font-size: 12px;
    color: var(--color-gray-500);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.canvas-size-custom-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 8px 2px;
}
.canvas-size-custom-row input[type="number"] {
    flex: 1 1 0;
    min-width: 0;
    height: 30px;
    padding: 0 8px;
    font-size: 13px;
    border-radius: 8px;
    background: var(--bg-input) !important;
    border: 1px solid var(--border-default) !important;
    color: var(--color-gray-100) !important;
    font-variant-numeric: tabular-nums;
    -moz-appearance: textfield;
}
.canvas-size-custom-row input[type="number"]::-webkit-outer-spin-button,
.canvas-size-custom-row input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.canvas-size-custom-row input[type="number"]:focus {
    /* No glow ring: the focused input looked like a different control than
       its twin (user-reported W vs H mismatch). Border-only focus. */
    outline: none;
    border-color: rgba(255, 255, 255, 0.30) !important;
    box-shadow: none !important;
}
.canvas-size-custom-x {
    color: var(--color-gray-400);
    font-size: 13px;
}
.canvas-size-custom-apply {
    height: 30px;
    padding: 0 10px;
    border-radius: 8px;
    font-size: 12px;
    font-weight: 500;
    color: var(--color-gray-50);
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid var(--border-default);
    cursor: pointer;
    transition: background 120ms ease;
}
.canvas-size-custom-apply:hover {
    background: rgba(255, 255, 255, 0.16);
}

/* 7.6 Canvas Area — dark backdrop (position comes from the WS3 full-bleed
   block near the top of this file). */
.canvas-area {
    background: var(--bg-base);
    scrollbar-width: none;
}
.canvas-area::-webkit-scrollbar {
    display: none;
}
/* Canvas decoration removed for performance */

/* 7.7 Export Button — lime identity */
.export-button {
    background: var(--color-lime-500) !important;
    color: var(--color-lime-950) !important;
    font-weight: 600;
    border: none !important;
    position: relative;
    overflow: hidden;
    transition: all 150ms ease;
}
.export-button:hover {
    background: var(--color-lime-400) !important;
    box-shadow: 0 0 20px rgba(202, 252, 0, 0.25);
}
.export-button:active {
    background: var(--color-lime-600) !important;
}
/* Shimmer removed for performance */
/* Export progress bar */
.export-button .export-progress {
    position: absolute;
    bottom: 0;
    left: 0;
    height: 3px;
    background: rgba(255, 255, 255, 0.4);
    border-radius: 0 0 0 10px;
    transition: width 200ms ease;
}

/* Export dropdown trigger (right side) */
.export-dropdown-trigger {
    background: var(--color-lime-500) !important;
    color: var(--color-lime-950) !important;
    border-left: 1px solid rgba(26, 33, 0, 0.15) !important;
}
.export-dropdown-trigger:hover {
    background: var(--color-lime-400) !important;
}

/* 7.8 Motion & Micro-interactions */

/* Sidebar section collapse/expand with grid trick */
.sidebar-section-content {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows 200ms ease;
}
.sidebar-section:not([open]) .sidebar-section-content {
    grid-template-rows: 0fr;
}
.sidebar-section-content > div {
    overflow: hidden;
}

/* Layout change animation */
.layout-transition {
    animation: layoutSettle 150ms ease;
}
@keyframes layoutSettle {
    0% { transform: scale(0.97); opacity: 0.8; }
    100% { transform: scale(1); opacity: 1; }
}

/* Staggered fade-in for sidebar sections */
.sidebar-section {
    animation: fadeInUp 300ms ease both;
}
.sidebar-section:nth-child(1) { animation-delay: 0ms; }
.sidebar-section:nth-child(2) { animation-delay: 30ms; }
.sidebar-section:nth-child(3) { animation-delay: 60ms; }
.sidebar-section:nth-child(4) { animation-delay: 90ms; }
.sidebar-section:nth-child(5) { animation-delay: 120ms; }
.sidebar-section:nth-child(6) { animation-delay: 150ms; }
.sidebar-section:nth-child(7) { animation-delay: 180ms; }
.sidebar-section:nth-child(8) { animation-delay: 210ms; }
@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

/* All hover transitions: 100-150ms — scoped to studio UI */
.studio-sidebar .custom-option,
.studio-sidebar .custom-label-option,
.studio-sidebar label {
    transition: all 150ms ease;
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* Global dark theme overrides for Tailwind utility classes */
/* Override text-black in sidebar context */
.studio-sidebar .text-black {
    color: var(--color-gray-100) !important;
}
.studio-sidebar .bg-white {
    background-color: var(--bg-surface) !important;
}
/* Style preview card/stack decorative layers need visible contrast */
.studio-sidebar .style-wrap .item-card.bg-white,
.studio-sidebar .style-wrap .custom-option .bg-white {
    background-color: var(--color-gray-600) !important;
}
/* Style & border preview — make border-black visible on dark bg */
.studio-sidebar .style-wrap .custom-option .border-black,
.studio-sidebar .border-wrap .custom-option .border-black {
    border-color: var(--color-gray-300) !important;
}
.studio-sidebar .style-wrap .custom-option .bg-black,
.studio-sidebar .border-wrap .custom-option .bg-black {
    background-color: var(--color-gray-700) !important;
}
/* Style preview screenshot surface mirrors the live uploaded image. The nine
   preset cards were flat white boxes; --style-thumb-img (set from the active
   .output-1 src in demo.js) paints the real screenshot onto each .bg-empty
   front surface while the decorative frame (glass/outline/border/retro/stack)
   stays put. Falls back to the flat white bg-color when the var is unset. */
.studio-sidebar .style-wrap .custom-option .bg-empty {
    background-image: var(--style-thumb-img, none);
    background-size: cover;
    background-position: top center;
    background-repeat: no-repeat;
}
.studio-sidebar .border-stroke-primary-alpha {
    border-color: var(--border-subtle) !important;
}
.studio-sidebar .border-stroke-primary-alpha-hover {
    border-color: var(--border-strong) !important;
}
.studio-sidebar .hover\:bg-\[\#EFEFEF\]:hover,
.studio-sidebar .hover\:bg-\[\#e4e4e4\]:hover {
    background-color: var(--bg-hover) !important;
}
.studio-sidebar .text-text-icons-secondary {
    color: var(--color-gray-400) !important;
}
.studio-sidebar .text-icons-tertiary,
.studio-sidebar .text-sm.text-icons-tertiary {
    color: var(--color-gray-500) !important;
}
/* Override white BG classes inside the sidebar */
.studio-sidebar .bg-\[\#EFEFEF\] {
    background-color: var(--bg-hover) !important;
}
/* Labels and section titles */
.studio-sidebar h2,
.studio-sidebar h3,
.studio-sidebar .font-medium {
    color: var(--color-gray-200);
}
.studio-sidebar .bg-\[\#F8F8F8\],
.studio-sidebar .bg-bg {
    background-color: var(--bg-elevated) !important;
}
.studio-sidebar .bg-\[\#FAFAFA\] {
    background-color: var(--bg-elevated) !important;
}
.studio-sidebar .bg-gray {
    background-color: var(--color-gray-800) !important;
}
/* Sidebar section title text */
.studio-sidebar .text-gray-text {
    color: var(--color-gray-400) !important;
}
/* Tab active states in sidebar */
.studio-sidebar [role="tab"][aria-selected="true"],
.studio-sidebar .hs-tab-active {
    background-color: var(--bg-hover) !important;
    color: var(--color-gray-50) !important;
}
/* Output resolution text */
#output-resolution {
    color: var(--color-gray-400);
}

/* Shadow position grid — dark theme */
.shadow-position-wrap .custom-option {
    background: var(--bg-elevated);
    border-color: var(--border-default);
}
.shadow-position-wrap .custom-option:has(:checked) span {
    background: var(--color-gray-100) !important;
    border-color: var(--color-gray-100) !important;
}
.shadow-position-wrap .custom-option span {
    background: var(--color-gray-600);
    border-color: var(--color-gray-600);
}

/* Color picker dark theme */
.color-background-wrap .dropdown-menu,
.color-shadow-wrap .dropdown-menu,
.color-stroke-wrap .dropdown-menu {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
}
.color-background-wrap .picker_editor input,
.color-shadow-wrap .picker_editor input,
.color-stroke-wrap .picker_editor input {
    background: var(--bg-input) !important;
    box-shadow: 0 0 0 1px var(--border-default) !important;
    color: var(--color-gray-100) !important;
}
/* Color picker button — dark text overrides */
.color-background-wrap .dropdown-toggle,
.color-shadow-wrap .dropdown-toggle,
.color-stroke-wrap .dropdown-toggle {
    border-color: var(--border-default) !important;
}
.color-background-wrap .dropdown-toggle:hover,
.color-shadow-wrap .dropdown-toggle:hover,
.color-stroke-wrap .dropdown-toggle:hover {
    border-color: var(--border-strong) !important;
}
/* Tab bar inside color/gradient picker */
.studio-sidebar [role="tablist"] {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
}
.studio-sidebar [role="tab"] {
    color: var(--color-gray-400) !important;
}
.studio-sidebar [role="tab"]:hover {
    color: var(--color-gray-200) !important;
}
.studio-sidebar [role="tab"][aria-selected="true"],
.studio-sidebar [role="tab"].active,
.studio-sidebar [data-tab].active.active-tab\:bg-white {
    color: var(--color-gray-50) !important;
    background: var(--bg-hover) !important;
}
/* Override active-tab:text-black in compiled Tailwind */
.studio-sidebar [data-tab].active.active-tab\:text-black {
    color: var(--color-gray-50) !important;
}
/* Override active-tab:border-stroke in compiled Tailwind */
.studio-sidebar [data-tab].active.active-tab\:border-stroke {
    border-color: var(--border-default) !important;
}
/* Override active-tab:shadow-card in compiled Tailwind */
.studio-sidebar [data-tab].active.active-tab\:shadow-card {
    box-shadow: none !important;
}

/* ── Join/toggle groups (Image Format, Image Quality) ── */
.studio-sidebar .join {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
}
.studio-sidebar .join .join-item.btn {
    color: var(--color-gray-400) !important;
    background: transparent !important;
}
.studio-sidebar .join .join-item.btn:checked,
.studio-sidebar .join input[type="radio"]:checked {
    background: var(--bg-hover) !important;
    color: var(--color-gray-50) !important;
}

/* ── bg-[#f1f1f3] and bg-[#EFEFEF] overrides ── */
.studio-sidebar .bg-\[\#f1f1f3\],
.studio-sidebar .bg-\[\#EFEFEF\] {
    background-color: var(--bg-elevated) !important;
}

/* ── Size Preset select ── */
.studio-sidebar select[name="img-preset"] {
    background: var(--bg-elevated) !important;
    color: var(--color-gray-200) !important;
    border: 1px solid var(--border-default) !important;
}
.studio-sidebar select[name="img-preset"]:focus {
    border-color: rgba(255, 255, 255, 0.30) !important;
}
.studio-sidebar select option {
    background: var(--bg-elevated);
    color: var(--color-gray-200);
}

/* ── Output Resolution box ── */
#output-resolution {
    color: var(--color-gray-200) !important;
}

/* ── Export dropdown (file format/quality) ── */
.studio-sidebar .dropdown-menu.bg-white {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
}

/* ── Device search input ── */
#device-search-input {
    background: var(--bg-elevated) !important;
    color: var(--color-gray-200) !important;
    border-color: var(--border-default) !important;
}
#device-search-input:focus {
    border-color: rgba(255, 255, 255, 0.30) !important;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.10) !important;
}
#device-search-input::placeholder {
    color: var(--color-gray-500) !important;
}

/* ── Device category tabs / custom-ratio presets ──
   WS4a war-zone dissolution: the light-theme !important overrides are gone.
   The tablist now renders as select rows (.tc-select-menu .device-category-tab)
   and the presets as ghost chips — both at the bottom of this file. */

/* ── Device cards in layout dropdown ── */
.studio-sidebar .device-card {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
    color: var(--color-gray-200) !important;
}
.studio-sidebar .device-card:hover {
    border-color: var(--border-strong) !important;
}
.studio-sidebar .device-card.active,
.studio-sidebar .device-card:has(:checked) {
    border-color: rgba(255, 255, 255, 0.30) !important;
    background: rgba(255, 255, 255, 0.06) !important;
}

/* ── Style chips (Floating / Stacked / Flat) ── */
.studio-sidebar .style-chip,
.studio-sidebar .border-style-option {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
    color: var(--color-gray-300) !important;
}
.studio-sidebar .style-chip:hover,
.studio-sidebar .border-style-option:hover {
    border-color: var(--border-strong) !important;
}
.studio-sidebar .style-chip.active,
.studio-sidebar .style-chip:has(:checked),
.studio-sidebar .border-style-option.active,
.studio-sidebar .border-style-option:has(:checked) {
    border-color: rgba(255, 255, 255, 0.30) !important;
    background: rgba(255, 255, 255, 0.06) !important;
    color: var(--color-gray-100) !important;
}

/* ── All remaining text-black inside sidebar ── */
.studio-sidebar .text-black {
    color: var(--color-gray-200) !important;
}
/* Override compiled hover:text-black */
.studio-sidebar .hover\:text-black:hover {
    color: var(--color-gray-200) !important;
}
/* Exception: dark text on lime/brand background is intentional */
.studio-sidebar .bg-brand.text-black,
#custom-ratio-apply.text-black,
.studio-sidebar .export-button .text-black {
    color: #000 !important;
}

/* ── Export dropdown: override compiled checked:!bg-white and checked:!text-black ── */
.studio-sidebar .join input[type="radio"]:checked,
.studio-sidebar .checked\:\!bg-white:checked {
    background-color: var(--bg-hover) !important;
}
.studio-sidebar .checked\:\!text-black:checked {
    color: var(--color-gray-50) !important;
}
.studio-sidebar .join input[type="radio"]:checked:hover,
.studio-sidebar .checked\:hover\:\!bg-white:hover:checked {
    background-color: var(--bg-hover) !important;
}

/* ── Transform preset buttons hover state ── */
.studio-sidebar .transform-preset-btn:hover {
    color: var(--color-gray-200) !important;
    border-color: var(--border-strong) !important;
}
.studio-sidebar .transform-preset-btn.transform-preset-active {
    background: rgba(255, 255, 255, 0.08) !important;
    border-color: rgba(255, 255, 255, 0.30) !important;
    color: var(--color-gray-100) !important;
}

/* ── DOF mode buttons — WS4b: now .tc-seg-item faces inside a .tc-segmented
   (#dof-modes). The .dof-mode-active class demo.js toggles maps onto the
   segmented active fill, mirroring the FRAME stroke-style precedent (SPEC §3).
   Higher specificity than the base .tc-seg-item rules, so no !important. ── */
.studio-sidebar .dof-mode-btn {
    color: var(--label);
}
.studio-sidebar .dof-mode-btn:hover {
    color: var(--foreground);
}
.studio-sidebar .dof-mode-btn.dof-mode-active {
    background: var(--selection-bg);
    color: var(--foreground);
}
/* ── Dark mode: DOF range sliders ── */
.studio-sidebar .dof-range {
    background: rgba(255, 255, 255, 0.1) !important;
}
.studio-sidebar .dof-range::-webkit-slider-thumb {
    background: var(--color-gray-100) !important;
    border-color: var(--color-gray-600) !important;
}
.studio-sidebar .dof-range::-moz-range-thumb {
    background: var(--color-gray-100) !important;
    border-color: var(--color-gray-600) !important;
}
.studio-sidebar .dof-range::-moz-range-track {
    background: rgba(255, 255, 255, 0.1) !important;
}
.studio-sidebar .dof-val {
    color: var(--color-gray-300) !important;
}

/* FilePond dark theme */
.filepond--root {
    font-family: "Inter", sans-serif;
}
.studio-sidebar .filepond--panel-root {
    background-color: var(--bg-elevated) !important;
    border: 1px dashed var(--border-default);
}
.mockup-module .filepond--panel-root {
    background-color: transparent !important;
    border: none !important;
}
.filepond--drop-label {
    color: var(--color-gray-400) !important;
}

/* Hide FilePond label when image is showing */
.dropzone:has(img.show-img) .empty-drop {
    opacity: 0;
}

/* Upload placeholder — icon only */
.upload-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
.upload-placeholder svg {
    color: rgba(0, 0, 0, 0.12);
    transition: all 0.25s ease;
}
.mockup-module .filepond--root:hover .upload-placeholder svg {
    color: rgba(0, 0, 0, 0.20);
}

/* Scrollbar — native thin */
.panel-scroll-view {
    scrollbar-width: thin;
    scrollbar-color: var(--color-gray-700) transparent;
}
.panel-scroll-view::-webkit-scrollbar {
    width: 6px;
    display: block !important;
}
.panel-scroll-view::-webkit-scrollbar-track {
    background: transparent;
}
.panel-scroll-view::-webkit-scrollbar-thumb {
    background: var(--color-gray-700);
    border-radius: 3px;
}
.panel-scroll-view::-webkit-scrollbar-thumb:hover {
    background: var(--color-gray-600);
}

/* Dark tooltips */
.tooltip .tooltip-body {
    background: var(--bg-elevated) !important;
    border: 1px solid var(--border-default) !important;
    color: var(--color-gray-200) !important;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3) !important;
}

/* Reset button — dark variant */
#reset-button {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
    color: var(--color-gray-200) !important;
}
#reset-button:hover:not(:disabled) {
    border-color: var(--border-strong) !important;
    color: var(--color-gray-50) !important;
}

/* Adaptive alert — dark */
.adaptive-alert .shadow-dropdown {
    background: var(--bg-elevated) !important;
    color: var(--color-gray-100) !important;
    border: 1px solid var(--border-default) !important;
}
.adaptive-alert::before {
    background: rgba(12, 12, 14, 0.7) !important;
}

/* ── Dark mode overrides: bg-white dropdowns in sidebar ── */
.studio-sidebar .dropdown-menu.bg-white,
.studio-sidebar .bg-white:not(.background-device-wrap) {
    background-color: var(--bg-elevated) !important;
}

/* ── Dark mode: tab buttons inside sidebar (Color/Gradient/Image tabs) ── */
/* Override active-tab:bg-white, active-tab:text-black, hover:text-black */
.studio-sidebar [role="tab"].active,
.studio-sidebar [role="tab"][aria-selected="true"],
.studio-sidebar .active-tab\:bg-white.active,
.studio-sidebar [role="tab"]:where([class*="active-tab:bg-white"]).active {
    background-color: var(--bg-hover) !important;
    color: var(--color-gray-50) !important;
    border-color: var(--border-default) !important;
    box-shadow: none !important;
}
.studio-sidebar [role="tab"]:hover {
    color: var(--color-gray-200) !important;
}
/* Tab container bar (bg-background-surface-4) */
.studio-sidebar .bg-background-surface-4,
.studio-sidebar nav[role="tablist"] {
    background-color: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
}

/* ── Dark mode: transform preset buttons hover ── */
.studio-sidebar .transform-preset-btn:hover {
    color: var(--color-gray-200) !important;
    border-color: var(--border-strong) !important;
}
.studio-sidebar .transform-preset-btn {
    color: var(--color-gray-400) !important;
    border-color: var(--border-default) !important;
}

/* ── Dark mode: shadow-dropdown class used in dropdowns ── */
.studio-sidebar .shadow-dropdown {
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.2) !important;
}

/* ── Dark mode: border-stroke class in sidebar ── */
.studio-sidebar .border-stroke {
    border-color: var(--border-default) !important;
}

/* ── Canvas area dark mode ── */
.canvas-area {
    background: var(--bg-base);
    border-color: transparent;
}

/* ── Dark mode: all dropdown menus with bg-white inside sidebar ── */
.studio-sidebar .dropdown-menu {
    background: var(--bg-elevated) !important;
    border-color: var(--border-default) !important;
}

/* ── Dark mode: text-black labels inside sidebar (shadow controls, export) ── */
.studio-sidebar .text-xs.text-black,
.studio-sidebar .text-sm.text-black,
.studio-sidebar .text-\[10px\].text-black {
    color: var(--color-gray-200) !important;
}

/* ── Dark mode: select with text-black ── */
.studio-sidebar select.text-black {
    color: var(--color-gray-200) !important;
    background-color: var(--bg-elevated) !important;
}

/* ── Dark mode: bg-[#f1f1f3] in export panel ── */
.studio-sidebar .bg-\[\#f1f1f3\] {
    background-color: var(--bg-elevated) !important;
}

/* ── Dark mode: layout preview item-card thumbnails ── */
.studio-sidebar .item-card.bg-white {
    background-color: var(--color-gray-300) !important;
}

/* ── Dark mode: FilePond dropzone text ── */
.filepond--drop-label .text-black {
    color: var(--color-gray-200) !important;
}
.studio-sidebar .filepond--panel-root {
    background-color: var(--bg-elevated) !important;
}

/* ── Dark mode: #output-resolution text ── */
#output-resolution.text-black {
    color: var(--color-gray-200) !important;
}

/* ── Hide unused device categories ── */
.device-category-tab[data-category="tablet"],
.device-category-tab[data-category="laptop"],
.device-category-tab[data-category="desktop"],
.device-category-tab[data-category="watch"] {
    display: none !important;
}
#category-panel-tablet,
#category-panel-laptop,
#category-panel-desktop,
#category-panel-watch {
    display: none !important;
}

/* ── Dark mode: upload area icon fixes ── */
.icon-dnd {
    background-color: transparent !important;
}

/* ── Auto Blur Background Layer ── */
.blur-bg-layer {
    background-size: cover;
    background-position: center center;
    filter: blur(70px) saturate(1.8) brightness(0.7);
    transform: scale(1.4);
    will-change: filter, transform;
    transition: opacity 0.6s ease;
}

/* ── Pattern preview labels ── */
.pattern-preview-label {
    background-color: var(--bg-elevated, #fff);
    transition: border-color 0.15s, box-shadow 0.15s;
}
.pattern-preview-label:hover {
    border-color: var(--border-strong) !important;
}
.pattern-preview-label:has(input:checked) {
    border-color: var(--color-lime-500) !important;
    box-shadow: 0 0 0 1px var(--color-lime-500);
}

/* ── Pattern controls range sliders ── */
.pattern-controls input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    height: 4px;
    border-radius: 999px;
    background: var(--bg-hover, #333);
    outline: none;
    cursor: pointer;
}
.pattern-controls input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #fff;
    border: 2px solid var(--color-lime-500);
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
    cursor: pointer;
}
.pattern-controls input[type="range"]::-moz-range-thumb {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #fff;
    border: 2px solid var(--color-lime-500);
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
    cursor: pointer;
}

/* ── Pattern overlay layer ── */
.pattern-overlay-layer {
    background-color: transparent;
}

/* ── Gradient PNG skeleton loading ── */
#background-gradient-classic label {
    background-color: var(--bg-elevated, #222226);
    position: relative;
    overflow: hidden;
}
#background-gradient-classic label::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.05) 40%, rgba(255,255,255,0.08) 50%, rgba(255,255,255,0.05) 60%, transparent 100%);
    animation: gradient-skeleton-shimmer 1.8s ease-in-out infinite;
    z-index: 1;
    pointer-events: none;
}
@keyframes gradient-skeleton-shimmer {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(100%); }
}

/* ─── CARDS (STACKED COMPOSITIONS) ─────────────────────── */

/* Cards base: mirror screenshot layout system exactly */
/* Cards knobs:
   --card-gap  → spacing multiplier applied to every per-card translate
                 (1 = designed default; the "Card spacing" slider writes it
                 inline on .mockup-module).
   --cards-fit → overall down-scale of the whole 3-card group so cards read
                 as distinct, well-spaced cards (like the picker previews)
                 instead of oversized overlapping slabs. */
.mockup-module.cards {
    --card-gap: 1;
    --cards-fit: 0.72;
}
/* Coverflow's steep rotateY projects the side cards wide; pull the whole
   group in a little more so they stay on the artboard. */
.mockup-module.cards.cards-carousel {
    --cards-fit: 0.58;
}
.mockup-module.cards .layouts {
    aspect-ratio: 1.6 / 1;
    position: absolute;
    inset: 0;
    max-height: 100%;
    margin: auto;
    display: flex;
    justify-content: center;
    align-items: center;
    pointer-events: all;
    transform: translateZ(0);
    will-change: contents, transform, opacity;
    user-select: none;
    border: none !important;
    outline: none !important;
}
.mockup-module.cards .layouts.lay-2-items {
    aspect-ratio: 1.4 / 1;
}
.mockup-module.cards .layouts.lay-3-items {
    aspect-ratio: 1.2 / 1;
}
.mockup-module.cards .layouts .layouts-item {
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
    width: 100%;
    height: 100%;
    pointer-events: all;
    border: none !important;
    outline: none !important;
    transform: scale(var(--cards-fit, 0.72));
    transform-origin: center center;
}
.mockup-module.cards .item {
    position: relative;
    width: 100%;
    height: 100%;
    container-type: size;
    container-name: item-container;
}
.cards .item,
.cards .devices {
    aspect-ratio: unset !important;
    width: 100%;
    height: 100%;
    max-height: 100%;
    max-width: 100%;
}
.cards .item .item-container {
    width: unset;
    height: max-content;
    position: absolute;
    inset: 0;
    max-height: 100%;
    margin: auto;
}
.cards .devices .item .item-container {
    aspect-ratio: var(--dropzone-1-ratio, unset);
}

/* All card compositions: .devices overlap via absolute positioning */
.mockup-module.cards .layouts-item .devices {
    position: absolute;
    inset: 0;
}

/* ── Stack: offset stack with shadow depth ── */
.cards.cards-stack .devices:nth-child(1) .item {
    z-index: 3;
}
.cards.cards-stack .devices:nth-child(2) .item {
    transform: translate(calc(6% * var(--card-gap)), calc(5% * var(--card-gap))) scale(0.92);
    z-index: 2;
}
.cards.cards-stack .devices:nth-child(3) .item {
    transform: translate(calc(12% * var(--card-gap)), calc(10% * var(--card-gap))) scale(0.84);
    z-index: 1;
    opacity: 0.55;
}

/* ── Fan: fanned cards from center bottom ── */
.cards.cards-fan .devices:nth-child(1) .item {
    transform: rotate(-12deg) translateX(calc(-15% * var(--card-gap)));
    transform-origin: 50% 100%;
    z-index: 3;
}
.cards.cards-fan .devices:nth-child(2) .item {
    transform: rotate(0deg);
    transform-origin: 50% 100%;
    z-index: 2;
}
.cards.cards-fan .devices:nth-child(3) .item {
    transform: rotate(12deg) translateX(calc(15% * var(--card-gap)));
    transform-origin: 50% 100%;
    z-index: 1;
}

/* ── Cascade: diagonal cascade ── */
.cards.cards-cascade .devices:nth-child(1) .item {
    transform: translate(calc(-20% * var(--card-gap)), calc(-12% * var(--card-gap))) scale(0.85);
    z-index: 3;
}
.cards.cards-cascade .devices:nth-child(2) .item {
    transform: translate(calc(5% * var(--card-gap)), calc(5% * var(--card-gap))) scale(0.85);
    z-index: 2;
}
.cards.cards-cascade .devices:nth-child(3) .item {
    transform: translate(calc(20% * var(--card-gap)), calc(14% * var(--card-gap))) scale(0.85);
    z-index: 1;
    opacity: 0.7;
}

/* ── Overlap: horizontal shift ── */
.cards.cards-overlap .devices:nth-child(1) .item {
    transform: translateX(calc(18% * var(--card-gap)));
    z-index: 2;
}
.cards.cards-overlap .devices:nth-child(2) .item {
    transform: translateX(calc(-18% * var(--card-gap)));
    z-index: 1;
}

/* ── Spread: cards spread horizontally with slight rotation ── */
.cards.cards-spread .devices:nth-child(1) .item {
    transform: translateX(calc(-25% * var(--card-gap))) rotate(-5deg) scale(0.85);
    z-index: 3;
}
.cards.cards-spread .devices:nth-child(2) .item {
    transform: scale(0.9);
    z-index: 2;
}
.cards.cards-spread .devices:nth-child(3) .item {
    transform: translateX(calc(25% * var(--card-gap))) rotate(5deg) scale(0.85);
    z-index: 1;
}

/* ── Perspective: dramatic 3D showcase — hero center, sides angled away ── */
.cards.cards-perspective .devices:nth-child(1) .item {
    transform: perspective(1000px) rotateY(-30deg) translateX(calc(-22% * var(--card-gap))) scale(0.78);
    transform-origin: right center;
    z-index: 1;
}
.cards.cards-perspective .devices:nth-child(2) .item {
    transform: perspective(1000px) scale(0.95) translateY(-2%);
    z-index: 3;
}
.cards.cards-perspective .devices:nth-child(3) .item {
    transform: perspective(1000px) rotateY(30deg) translateX(calc(22% * var(--card-gap))) scale(0.78);
    transform-origin: left center;
    z-index: 1;
}

/* ── Mosaic: overlapping grid-like arrangement ── */
.cards.cards-mosaic .devices:nth-child(1) .item {
    transform: translate(calc(-18% * var(--card-gap)), calc(-14% * var(--card-gap))) scale(0.75);
    z-index: 3;
}
.cards.cards-mosaic .devices:nth-child(2) .item {
    transform: translate(calc(14% * var(--card-gap)), calc(-6% * var(--card-gap))) scale(0.70);
    z-index: 2;
}
.cards.cards-mosaic .devices:nth-child(3) .item {
    transform: translate(calc(-4% * var(--card-gap)), calc(16% * var(--card-gap))) scale(0.72);
    z-index: 1;
}

/* ── Float: cards floating at different sizes and positions ── */
.cards.cards-float .devices:nth-child(1) .item {
    transform: translate(calc(-22% * var(--card-gap)), calc(-10% * var(--card-gap))) scale(0.78) rotate(-3deg);
    z-index: 3;
}
.cards.cards-float .devices:nth-child(2) .item {
    transform: translate(calc(16% * var(--card-gap)), calc(8% * var(--card-gap))) scale(0.68) rotate(4deg);
    z-index: 2;
}
.cards.cards-float .devices:nth-child(3) .item {
    transform: translate(calc(2% * var(--card-gap)), calc(-18% * var(--card-gap))) scale(0.60) rotate(-6deg);
    z-index: 1;
    opacity: 0.85;
}

/* ── Carousel: 3D coverflow — center hero, sides angled back ── */
.cards.cards-carousel .devices:nth-child(1) .item {
    transform: perspective(1000px) rotateY(35deg) translateX(calc(-18% * var(--card-gap))) scale(0.78);
    transform-origin: right center;
    z-index: 1;
}
.cards.cards-carousel .devices:nth-child(2) .item {
    transform: scale(0.92);
    z-index: 3;
}
.cards.cards-carousel .devices:nth-child(3) .item {
    transform: perspective(1000px) rotateY(-35deg) translateX(calc(18% * var(--card-gap))) scale(0.78);
    transform-origin: left center;
    z-index: 1;
}

/* ── Peek: vertical ascending stagger, first card always on top ── */
.cards.cards-peek .devices:nth-child(1) .item {
    transform: translate(calc(-2% * var(--card-gap)), calc(-10% * var(--card-gap))) scale(0.88);
    z-index: 3;
}
.cards.cards-peek .devices:nth-child(2) .item {
    transform: translate(calc(4% * var(--card-gap)), calc(4% * var(--card-gap))) scale(0.85);
    z-index: 2;
}
.cards.cards-peek .devices:nth-child(3) .item {
    transform: translate(calc(-6% * var(--card-gap)), calc(16% * var(--card-gap))) scale(0.80);
    z-index: 1;
    opacity: 0.65;
}

/* ── Tilt: isometric 3D plane — all cards share the same tilt angle ── */
.cards.cards-tilt .devices:nth-child(1) .item {
    transform: perspective(800px) rotateX(10deg) rotateY(-6deg) rotateZ(-2deg) translate(calc(-14% * var(--card-gap)), calc(-10% * var(--card-gap))) scale(0.80);
    z-index: 3;
}
.cards.cards-tilt .devices:nth-child(2) .item {
    transform: perspective(800px) rotateX(10deg) rotateY(-6deg) rotateZ(-2deg) translate(calc(2% * var(--card-gap)), calc(3% * var(--card-gap))) scale(0.80);
    z-index: 2;
}
.cards.cards-tilt .devices:nth-child(3) .item {
    transform: perspective(800px) rotateX(10deg) rotateY(-6deg) rotateZ(-2deg) translate(calc(18% * var(--card-gap)), calc(16% * var(--card-gap))) scale(0.80);
    z-index: 1;
    opacity: 0.7;
}

/* ── Showcase: asymmetric hero + accent composition ── */
.cards.cards-showcase .devices:nth-child(1) .item {
    transform: translate(calc(-6% * var(--card-gap)), 0%) scale(0.92);
    z-index: 2;
}
.cards.cards-showcase .devices:nth-child(2) .item {
    transform: translate(calc(28% * var(--card-gap)), calc(18% * var(--card-gap))) scale(0.52);
    z-index: 3;
}

/* ── Wave: sine-wave arrangement — left high, center low, right high ── */
.cards.cards-wave .devices:nth-child(1) .item {
    transform: translate(calc(-26% * var(--card-gap)), calc(-10% * var(--card-gap))) scale(0.78) rotate(-3deg);
    z-index: 2;
}
.cards.cards-wave .devices:nth-child(2) .item {
    transform: translate(0%, calc(12% * var(--card-gap))) scale(0.82);
    z-index: 3;
}
.cards.cards-wave .devices:nth-child(3) .item {
    transform: translate(calc(26% * var(--card-gap)), calc(-10% * var(--card-gap))) scale(0.78) rotate(3deg);
    z-index: 2;
}

/* ── Flip: progressive X-axis rotation, first card always on top ── */
.cards.cards-flip .devices:nth-child(1) .item {
    transform: perspective(600px) rotateX(0deg) translate(calc(2% * var(--card-gap)), calc(-8% * var(--card-gap))) scale(0.90);
    transform-origin: center bottom;
    z-index: 3;
}
.cards.cards-flip .devices:nth-child(2) .item {
    transform: perspective(600px) rotateX(15deg) translate(0%, calc(5% * var(--card-gap))) scale(0.85);
    transform-origin: center bottom;
    z-index: 2;
}
.cards.cards-flip .devices:nth-child(3) .item {
    transform: perspective(600px) rotateX(30deg) translate(calc(-12% * var(--card-gap)), calc(15% * var(--card-gap))) scale(0.78);
    transform-origin: center bottom;
    z-index: 1;
    opacity: 0.6;
}

/* ── Stair: clean diagonal steps, equal-sized cards ── */
.cards.cards-stair .devices:nth-child(1) .item {
    transform: translate(calc(-18% * var(--card-gap)), calc(-14% * var(--card-gap))) scale(0.78);
    z-index: 3;
}
.cards.cards-stair .devices:nth-child(2) .item {
    transform: scale(0.78);
    z-index: 2;
}
.cards.cards-stair .devices:nth-child(3) .item {
    transform: translate(calc(18% * var(--card-gap)), calc(14% * var(--card-gap))) scale(0.78);
    z-index: 1;
    opacity: 0.7;
}

/* ── Scatter: organic photo-dump, cards thrown on a desk ── */
.cards.cards-scatter .devices:nth-child(1) .item {
    transform: translate(calc(-16% * var(--card-gap)), calc(4% * var(--card-gap))) rotate(-8deg) scale(0.75);
    z-index: 3;
}
.cards.cards-scatter .devices:nth-child(2) .item {
    transform: translate(calc(14% * var(--card-gap)), calc(-8% * var(--card-gap))) rotate(5deg) scale(0.72);
    z-index: 2;
}
.cards.cards-scatter .devices:nth-child(3) .item {
    transform: translate(calc(-2% * var(--card-gap)), calc(16% * var(--card-gap))) rotate(-2deg) scale(0.68);
    z-index: 1;
    opacity: 0.8;
}

/* ── Shelf: side-by-side with subtle upward perspective tilt ── */
.cards.cards-shelf .devices:nth-child(1) .item {
    transform: perspective(800px) rotateX(-6deg) translate(calc(-28% * var(--card-gap)), calc(2% * var(--card-gap))) scale(0.62);
    z-index: 2;
}
.cards.cards-shelf .devices:nth-child(2) .item {
    transform: perspective(800px) rotateX(-6deg) scale(0.68);
    z-index: 3;
}
.cards.cards-shelf .devices:nth-child(3) .item {
    transform: perspective(800px) rotateX(-6deg) translate(calc(28% * var(--card-gap)), calc(2% * var(--card-gap))) scale(0.62);
    z-index: 2;
}

/* ── Trio: inverted triangle — hero on top, two supporting below ── */
.cards.cards-trio .devices:nth-child(1) .item {
    transform: translate(0%, calc(-16% * var(--card-gap))) scale(0.80);
    z-index: 3;
}
.cards.cards-trio .devices:nth-child(2) .item {
    transform: translate(calc(-20% * var(--card-gap)), calc(12% * var(--card-gap))) scale(0.68) rotate(-3deg);
    z-index: 2;
}
.cards.cards-trio .devices:nth-child(3) .item {
    transform: translate(calc(20% * var(--card-gap)), calc(12% * var(--card-gap))) scale(0.68) rotate(3deg);
    z-index: 2;
}

/* ── Card device grid preview thumbnails ── */
/* The preview mirrors the real composition: N real .dp-card nodes (emitted by
   devices-config.js) positioned with the SAME per-card transforms as the live
   layout (style_v17.css §cards transforms, gap = 1). translate offsets are in
   % of the card box, so a small card + the same % reproduces the exact
   arrangement the canvas shows. 3D perspective is scaled down to the tile. */
.device-preview-cards {
    display: block;
    position: relative;
    width: 100%;
    height: 100%;
}
.device-preview-cards .dp-card {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 48px;
    height: 34px;
    margin: -17px 0 0 -24px;   /* center the card box on the tile */
    border-radius: 5px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    background: linear-gradient(155deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.05) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.08),
        0 3px 6px rgba(0, 0, 0, 0.28);
}

/* Stack */
.device-preview-cards[data-card-style="cards-stack"] .dp-card:nth-child(1) { z-index: 3; }
.device-preview-cards[data-card-style="cards-stack"] .dp-card:nth-child(2) { transform: translate(6%, 5%) scale(0.92); z-index: 2; }
.device-preview-cards[data-card-style="cards-stack"] .dp-card:nth-child(3) { transform: translate(12%, 10%) scale(0.84); z-index: 1; opacity: 0.55; }
/* Fan */
.device-preview-cards[data-card-style="cards-fan"] .dp-card:nth-child(1) { transform: rotate(-12deg) translateX(-15%); transform-origin: 50% 100%; z-index: 3; }
.device-preview-cards[data-card-style="cards-fan"] .dp-card:nth-child(2) { transform: rotate(0deg); transform-origin: 50% 100%; z-index: 2; }
.device-preview-cards[data-card-style="cards-fan"] .dp-card:nth-child(3) { transform: rotate(12deg) translateX(15%); transform-origin: 50% 100%; z-index: 1; }
/* Cascade */
.device-preview-cards[data-card-style="cards-cascade"] .dp-card:nth-child(1) { transform: translate(-20%, -12%) scale(0.85); z-index: 3; }
.device-preview-cards[data-card-style="cards-cascade"] .dp-card:nth-child(2) { transform: translate(5%, 5%) scale(0.85); z-index: 2; }
.device-preview-cards[data-card-style="cards-cascade"] .dp-card:nth-child(3) { transform: translate(20%, 14%) scale(0.85); z-index: 1; opacity: 0.7; }
/* Overlap (2 cards) */
.device-preview-cards[data-card-style="cards-overlap"] .dp-card:nth-child(1) { transform: translateX(18%); z-index: 2; }
.device-preview-cards[data-card-style="cards-overlap"] .dp-card:nth-child(2) { transform: translateX(-18%); z-index: 1; }
/* Spread */
.device-preview-cards[data-card-style="cards-spread"] .dp-card:nth-child(1) { transform: translateX(-25%) rotate(-5deg) scale(0.85); z-index: 3; }
.device-preview-cards[data-card-style="cards-spread"] .dp-card:nth-child(2) { transform: scale(0.9); z-index: 2; }
.device-preview-cards[data-card-style="cards-spread"] .dp-card:nth-child(3) { transform: translateX(25%) rotate(5deg) scale(0.85); z-index: 1; }
/* Perspective (3D) */
.device-preview-cards[data-card-style="cards-perspective"] .dp-card:nth-child(1) { transform: perspective(170px) rotateY(-30deg) translateX(-22%) scale(0.78); transform-origin: right center; z-index: 1; }
.device-preview-cards[data-card-style="cards-perspective"] .dp-card:nth-child(2) { transform: perspective(170px) scale(0.95) translateY(-2%); z-index: 3; }
.device-preview-cards[data-card-style="cards-perspective"] .dp-card:nth-child(3) { transform: perspective(170px) rotateY(30deg) translateX(22%) scale(0.78); transform-origin: left center; z-index: 1; }
/* Mosaic */
.device-preview-cards[data-card-style="cards-mosaic"] .dp-card:nth-child(1) { transform: translate(-18%, -14%) scale(0.75); z-index: 3; }
.device-preview-cards[data-card-style="cards-mosaic"] .dp-card:nth-child(2) { transform: translate(14%, -6%) scale(0.70); z-index: 2; }
.device-preview-cards[data-card-style="cards-mosaic"] .dp-card:nth-child(3) { transform: translate(-4%, 16%) scale(0.72); z-index: 1; }
/* Float */
.device-preview-cards[data-card-style="cards-float"] .dp-card:nth-child(1) { transform: translate(-22%, -10%) scale(0.78) rotate(-3deg); z-index: 3; }
.device-preview-cards[data-card-style="cards-float"] .dp-card:nth-child(2) { transform: translate(16%, 8%) scale(0.68) rotate(4deg); z-index: 2; }
.device-preview-cards[data-card-style="cards-float"] .dp-card:nth-child(3) { transform: translate(2%, -18%) scale(0.60) rotate(-6deg); z-index: 1; opacity: 0.85; }
/* Carousel (3D) */
.device-preview-cards[data-card-style="cards-carousel"] .dp-card:nth-child(1) { transform: perspective(170px) rotateY(35deg) translateX(-18%) scale(0.78); transform-origin: right center; z-index: 1; }
.device-preview-cards[data-card-style="cards-carousel"] .dp-card:nth-child(2) { transform: scale(0.92); z-index: 3; }
.device-preview-cards[data-card-style="cards-carousel"] .dp-card:nth-child(3) { transform: perspective(170px) rotateY(-35deg) translateX(18%) scale(0.78); transform-origin: left center; z-index: 1; }
/* Peek */
.device-preview-cards[data-card-style="cards-peek"] .dp-card:nth-child(1) { transform: translate(-2%, -10%) scale(0.88); z-index: 3; }
.device-preview-cards[data-card-style="cards-peek"] .dp-card:nth-child(2) { transform: translate(4%, 4%) scale(0.85); z-index: 2; }
.device-preview-cards[data-card-style="cards-peek"] .dp-card:nth-child(3) { transform: translate(-6%, 16%) scale(0.80); z-index: 1; opacity: 0.65; }
/* Tilt (3D) */
.device-preview-cards[data-card-style="cards-tilt"] .dp-card:nth-child(1) { transform: perspective(150px) rotateX(10deg) rotateY(-6deg) rotateZ(-2deg) translate(-14%, -10%) scale(0.80); z-index: 3; }
.device-preview-cards[data-card-style="cards-tilt"] .dp-card:nth-child(2) { transform: perspective(150px) rotateX(10deg) rotateY(-6deg) rotateZ(-2deg) translate(2%, 3%) scale(0.80); z-index: 2; }
.device-preview-cards[data-card-style="cards-tilt"] .dp-card:nth-child(3) { transform: perspective(150px) rotateX(10deg) rotateY(-6deg) rotateZ(-2deg) translate(18%, 16%) scale(0.80); z-index: 1; opacity: 0.7; }
/* Showcase (2 cards) */
.device-preview-cards[data-card-style="cards-showcase"] .dp-card:nth-child(1) { transform: translate(-6%, 0%) scale(0.92); z-index: 2; }
.device-preview-cards[data-card-style="cards-showcase"] .dp-card:nth-child(2) { transform: translate(28%, 18%) scale(0.52); z-index: 3; }
/* Wave */
.device-preview-cards[data-card-style="cards-wave"] .dp-card:nth-child(1) { transform: translate(-26%, -10%) scale(0.78) rotate(-3deg); z-index: 2; }
.device-preview-cards[data-card-style="cards-wave"] .dp-card:nth-child(2) { transform: translate(0%, 12%) scale(0.82); z-index: 3; }
.device-preview-cards[data-card-style="cards-wave"] .dp-card:nth-child(3) { transform: translate(26%, -10%) scale(0.78) rotate(3deg); z-index: 2; }
/* Flip (3D) */
.device-preview-cards[data-card-style="cards-flip"] .dp-card:nth-child(1) { transform: perspective(110px) rotateX(0deg) translate(2%, -8%) scale(0.90); transform-origin: center bottom; z-index: 3; }
.device-preview-cards[data-card-style="cards-flip"] .dp-card:nth-child(2) { transform: perspective(110px) rotateX(15deg) translate(0%, 5%) scale(0.85); transform-origin: center bottom; z-index: 2; }
.device-preview-cards[data-card-style="cards-flip"] .dp-card:nth-child(3) { transform: perspective(110px) rotateX(30deg) translate(-12%, 15%) scale(0.78); transform-origin: center bottom; z-index: 1; opacity: 0.6; }
/* Stair */
.device-preview-cards[data-card-style="cards-stair"] .dp-card:nth-child(1) { transform: translate(-18%, -14%) scale(0.78); z-index: 3; }
.device-preview-cards[data-card-style="cards-stair"] .dp-card:nth-child(2) { transform: scale(0.78); z-index: 2; }
.device-preview-cards[data-card-style="cards-stair"] .dp-card:nth-child(3) { transform: translate(18%, 14%) scale(0.78); z-index: 1; opacity: 0.7; }
/* Scatter */
.device-preview-cards[data-card-style="cards-scatter"] .dp-card:nth-child(1) { transform: translate(-16%, 4%) rotate(-8deg) scale(0.75); z-index: 3; }
.device-preview-cards[data-card-style="cards-scatter"] .dp-card:nth-child(2) { transform: translate(14%, -8%) rotate(5deg) scale(0.72); z-index: 2; }
.device-preview-cards[data-card-style="cards-scatter"] .dp-card:nth-child(3) { transform: translate(-2%, 16%) rotate(-2deg) scale(0.68); z-index: 1; opacity: 0.8; }
/* Shelf (3D) */
.device-preview-cards[data-card-style="cards-shelf"] .dp-card:nth-child(1) { transform: perspective(150px) rotateX(-6deg) translate(-28%, 2%) scale(0.62); z-index: 2; }
.device-preview-cards[data-card-style="cards-shelf"] .dp-card:nth-child(2) { transform: perspective(150px) rotateX(-6deg) scale(0.68); z-index: 3; }
.device-preview-cards[data-card-style="cards-shelf"] .dp-card:nth-child(3) { transform: perspective(150px) rotateX(-6deg) translate(28%, 2%) scale(0.62); z-index: 2; }
/* Trio */
.device-preview-cards[data-card-style="cards-trio"] .dp-card:nth-child(1) { transform: translate(0%, -16%) scale(0.80); z-index: 3; }
.device-preview-cards[data-card-style="cards-trio"] .dp-card:nth-child(2) { transform: translate(-20%, 12%) scale(0.68) rotate(-3deg); z-index: 2; }
.device-preview-cards[data-card-style="cards-trio"] .dp-card:nth-child(3) { transform: translate(20%, 12%) scale(0.68) rotate(3deg); z-index: 2; }

/* ─── Text Elements (Typography Layer) — Phase 1 ─── */
.text-layer {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
.text-layer[data-z="below"] { z-index: 15; }
.text-layer[data-z="above"] { z-index: 100; }
/* When a text-layer has no children, drop it from the rendering tree
   so it doesn't spawn an extra stacking context that the compositor
   has to walk on every wheel-zoom frame. */
.text-layer:empty {
    display: none;
}

.text-element {
    position: absolute;
    pointer-events: auto;
    cursor: default;
    transform: translate(-50%, -50%);
    white-space: pre-wrap;
    word-wrap: break-word;
    box-sizing: border-box;
    user-select: none;
    border-radius: 6px;
    /* Subtle highlight fades in on hover / selection. Dark-bg defaults
       to white-alpha; the data-bg-light override below flips it to
       black-alpha for light backdrops so the highlight stays visible. */
    transition: background-color 130ms ease;
    /* Phase 3: prevent the browser from interpreting a pointer drag as
       page pan/zoom on touch devices — pointer capture handles the rest. */
    touch-action: none;
}
.text-element:hover {
    background-color: rgba(255, 255, 255, 0.03);
}
.text-element[data-selected="true"] {
    background-color: rgba(255, 255, 255, 0.05);
    cursor: move;
}
/* a11y: keyboard focus on a text node — only render when the user is
   navigating with Tab, not on click/drag. */
.text-element:focus { outline: none; }
.text-element:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.55);
    outline-offset: 4px;
}
.text-element[data-editing="true"] {
    background-color: rgba(255, 255, 255, 0.08);
    cursor: text;
    user-select: text;
    outline: none;
}
/* Soften the browser-native text selection when editing a text element.
   The default OS blue is dominant on top of large display text. Use a
   thin white-alpha (or black-alpha on light bg, see override below) so
   the selection feels like part of the app theme. */
.text-element ::selection,
.text-element-content::selection {
    background-color: rgba(255, 255, 255, 0.18);
    color: inherit;
}
.artboard[data-bg-light="true"] .text-element ::selection,
.artboard[data-bg-light="true"] .text-element-content::selection {
    background-color: rgba(0, 0, 0, 0.14);
    color: inherit;
}
/* Caret fix for empty contenteditable: an empty inline <span> has no
   baseline box, so the browser falls back to placing the caret at the
   bottom of the parent's line-box, which makes it look "too tall and
   shifted down" right after the user deletes all text. A zero-width
   space gives the span a stable baseline; pseudo content is invisible
   to innerText so commit/cancel still read the right value. */
.text-element[data-editing="true"] .text-element-content:empty::before {
    content: '\200B';
}
.artboard[data-bg-light="true"] .text-element:hover {
    background-color: rgba(0, 0, 0, 0.03);
}
.artboard[data-bg-light="true"] .text-element[data-selected="true"] {
    background-color: rgba(0, 0, 0, 0.05);
}
.artboard[data-bg-light="true"] .text-element[data-editing="true"] {
    background-color: rgba(0, 0, 0, 0.08);
}

/* ── Side resize handles (visible only when selected/editing) ── */
.text-resize-handle {
    position: absolute;
    top: 50%;
    width: 5px;
    height: 26px;
    margin-top: -13px;
    background: #FFFFFF;
    border: 1px solid rgba(0, 0, 0, 0.25);
    border-radius: 999px;
    cursor: ew-resize;
    opacity: 0;
    pointer-events: none;
    transition: opacity 130ms ease;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
    z-index: 1;
    /* User-select must not fire on drag */
    user-select: none;
    -webkit-user-select: none;
    touch-action: none;
}
.text-resize-handle--left  { left: -3px;  transform: translateX(-100%); }
.text-resize-handle--right { right: -3px; transform: translateX(100%); }
/* Bottom-right circular handle — overrides the pill defaults to a 14px
   disc, identical visual language to .image-resize-handle so users
   recognize "corner-circle = scale me". Mapped to fontSize in JS, not
   widthPct. */
.text-resize-handle--corner {
    top: -3px;
    bottom: auto;
    right: -3px;
    left: auto;
    width: 14px;
    height: 14px;
    margin-top: 0;
    border-radius: 50%;
    cursor: nesw-resize;
    transform: translate(100%, -100%);
}
.text-element[data-selected="true"] .text-resize-handle,
.text-element[data-editing="true"] .text-resize-handle {
    opacity: 1;
    pointer-events: auto;
}
.artboard[data-bg-light="true"] .text-resize-handle {
    background: #1A1A1E;
    border-color: rgba(255, 255, 255, 0.35);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
/* Promote to its own layer only during the entrance animation so
   the GPU doesn't keep a layer pinned for the lifetime of the element. */
.text-element--enter {
    animation: text-element-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
    will-change: filter, opacity;
}
@keyframes text-element-in {
    0% {
        opacity: 0;
        filter: blur(12px);
        transform: translate(-50%, -50%) translateY(8px);
    }
    100% {
        opacity: 1;
        filter: blur(0px);
        transform: translate(-50%, -50%) translateY(0);
    }
}

/* ── Typography sidebar panel ── */
.typography-wrap .text-input,
.typography-wrap .text-select {
    width: 100%;
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    padding: 0 10px;
    height: 32px;
    color: var(--color-gray-100);
    font-size: 13px;
    transition: border-color 150ms ease, background 150ms ease;
    box-sizing: border-box;
}
.typography-wrap .text-input:hover,
.typography-wrap .text-select:hover {
    border-color: var(--border-default);
    background: rgba(255, 255, 255, 0.04);
}
.typography-wrap .text-input:focus,
.typography-wrap .text-select:focus {
    outline: none;
    border-color: var(--color-gray-400);
    background: rgba(255, 255, 255, 0.04);
}
.typography-wrap textarea.text-input {
    height: auto;
    padding: 8px 10px;
    resize: none;
    font-family: inherit;
    line-height: 1.4;
}
.typography-wrap .text-select {
    appearance: none;
    -webkit-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 12 12' fill='none' stroke='%23a0a0a0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M3 4.5l3 3 3-3'/></svg>");
    background-position: right 10px center;
    background-repeat: no-repeat;
    background-size: 12px 12px;
    padding-right: 28px;
    cursor: pointer;
}
/* Icon-only button (delete in actions row) */
.text-icon-btn {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 8px;
    border: 1px solid var(--border-subtle);
    background: rgba(255, 255, 255, 0.02);
    color: var(--color-gray-400);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
    box-sizing: border-box;
    padding: 0;
}
.text-icon-btn:hover {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--border-default);
    color: var(--color-gray-50);
}
.text-icon-btn--danger:hover {
    color: #ff7a7a;
    border-color: rgba(255, 122, 122, 0.4);
    background: rgba(255, 122, 122, 0.08);
}

/* Compact color chip — sits in the Font row */
.typography-wrap .text-color-wrap {
    position: relative;
}
.typography-wrap .text-color-chip {
    width: 32px;
    height: 32px;
    padding: 3px;
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    background:
        linear-gradient(45deg, rgba(255,255,255,0.06) 25%, transparent 25%, transparent 75%, rgba(255,255,255,0.06) 75%) 0 0/10px 10px,
        linear-gradient(45deg, rgba(255,255,255,0.06) 25%, transparent 25%, transparent 75%, rgba(255,255,255,0.06) 75%) 5px 5px/10px 10px;
    cursor: pointer;
    flex-shrink: 0;
    box-sizing: border-box;
    transition: border-color 150ms ease, transform 150ms ease;
}
.typography-wrap .text-color-chip:hover {
    border-color: var(--border-default);
}
.typography-wrap .text-color-chip > span {
    border-radius: 5px;
    box-shadow: inset 0 0 0 1px rgba(0,0,0,0.25);
}
.typography-wrap .text-color-wrap[data-open="true"] .text-color-chip {
    border-color: var(--color-gray-300);
}

/* Color popover */
.typography-wrap .text-color-popover {
    position: absolute;
    right: 0;
    bottom: calc(100% + 8px);
    z-index: 200;
    background: #1f1f23;
    border: 1px solid var(--border-default);
    border-radius: 14px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
    padding: 14px;
    width: 248px;
    box-sizing: border-box;
    animation: text-color-pop-in 140ms cubic-bezier(0.22, 1, 0.36, 1);
}
.typography-wrap .text-color-popover[hidden] { display: none; }
@keyframes text-color-pop-in {
    0% { opacity: 0; transform: translateY(4px) scale(0.98); }
    100% { opacity: 1; transform: translateY(0) scale(1); }
}
.typography-wrap .text-color-hex-row {
    margin-top: 12px;
    display: flex;
    gap: 6px;
    align-items: center;
}
.typography-wrap .text-color-hex-input {
    margin-top: 12px;
    width: 100%;
    height: 34px;
    padding: 0 12px;
    background: rgba(255, 255, 255, 0.04);
    border: 0;
    border-radius: 9px;
    color: var(--color-gray-100);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 13px;
    text-align: center;
    letter-spacing: 1px;
    text-transform: uppercase;
    box-sizing: border-box;
    transition: background 150ms ease, box-shadow 150ms ease;
}
.typography-wrap .text-color-hex-row .text-color-hex-input {
    margin-top: 0;
    flex: 1 1 auto;
    min-width: 0;
}
.typography-wrap .text-color-hex-input:focus {
    outline: none;
    background: rgba(255, 255, 255, 0.06);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}

/* ── Eyedropper button (used inside every color picker next to HEX) ── */
.color-eyedropper-btn {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border: 1px solid var(--border-default);
    border-radius: 8px;
    background: var(--bg-input);
    color: var(--color-gray-300);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
}
.color-eyedropper-btn:hover {
    border-color: var(--border-strong);
    color: var(--color-gray-100);
}
.color-eyedropper-btn:active {
    background: rgba(255, 255, 255, 0.06);
}
.color-eyedropper-btn:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.55);
    outline-offset: 1px;
}
.color-eyedropper-btn svg {
    width: 14px;
    height: 14px;
    pointer-events: none;
}
/* Text-color popover variant — bigger to match the 34px hex input. */
.typography-wrap .text-color-hex-row .color-eyedropper-btn {
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.04);
}
.typography-wrap .text-color-hex-row .color-eyedropper-btn:hover {
    background: rgba(255, 255, 255, 0.08);
}

/* Background color picker — "Pick from screen" eyedropper row below the picker. */
.bg-color-eyedropper-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
}
.bg-color-eyedropper-row span {
    font-size: 13px;
    color: var(--color-gray-300);
    user-select: none;
}

/* Vanilla-picker overrides — dark theme, mirrors shadow picker layout */
.typography-wrap .picker_wrapper.popup,
.typography-wrap .picker_wrapper {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    width: 220px !important;
    min-width: 0 !important;
    font-family: inherit !important;
    display: flex !important;
    flex-direction: column !important;
}
.typography-wrap .picker_arrow { display: none !important; }
.typography-wrap .picker_sl {
    width: 220px !important;
    height: 168px !important;
    min-height: 168px !important;
    border-radius: 10px !important;
    overflow: visible !important;
    margin: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    flex: 0 0 168px !important;
    order: 1;
    position: relative;
}
/* SL square's gradient layer — some vanilla-picker builds size internal
   nodes via inline style. Force the layer to fully fill the box so the
   square doesn't render shorter than its declared height. */
.typography-wrap .picker_sl > *:not(.picker_selector) {
    width: 100% !important;
    height: 100% !important;
}
.typography-wrap .picker_hue {
    width: 220px !important;
    height: 12px !important;
    border-radius: 999px !important;
    margin: 14px 0 0 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    flex: none !important;
    order: 2;
    position: relative;
}
.typography-wrap .picker_alpha {
    display: none !important;
}
.typography-wrap .picker_sl .picker_selector,
.typography-wrap .picker_hue .picker_selector {
    width: 18px !important;
    height: 18px !important;
    border-radius: 999px !important;
    border: 2px solid #fff !important;
    box-shadow: 0 2px 6px rgba(0,0,0,0.45), 0 0 0 1px rgba(0,0,0,0.25) !important;
    padding: 0 !important;
    background: transparent !important;
    box-sizing: border-box;
}
.typography-wrap .picker_hue .picker_selector {
    top: 50% !important;
}
.typography-wrap .picker_editor,
.typography-wrap .picker_sample,
.typography-wrap .picker_done {
    display: none !important;
}
.typography-wrap .picker_wrapper * { box-sizing: border-box; }

/* Segmented controls (align / z-layer) */
.text-seg-group {
    display: flex;
    gap: 2px;
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    padding: 2px;
    height: 32px;
    box-sizing: border-box;
}
.text-seg-btn {
    flex: 1;
    border-radius: 6px;
    background: transparent;
    color: var(--color-gray-400);
    font-size: 11px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 150ms ease, color 150ms ease;
    border: 0;
    padding: 0 6px;
    min-width: 0;
}
.text-seg-btn:hover { color: var(--color-gray-200); }
.text-seg-btn.text-seg-active {
    background: rgba(255, 255, 255, 0.08);
    color: var(--color-gray-50);
}
.text-seg-btn svg { width: 14px; height: 14px; flex-shrink: 0; }

.text-action-btn {
    width: 100%;
    height: 32px;
    border-radius: 8px;
    border: 1px solid var(--border-subtle);
    background: rgba(255, 255, 255, 0.02);
    color: var(--color-gray-200);
    font-size: 12px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
    box-sizing: border-box;
    font-family: inherit;
    padding: 0 12px;
}
.text-action-btn:hover {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--border-default);
    color: var(--color-gray-50);
}
.text-action-btn svg { flex-shrink: 0; }
.text-action-btn--danger { color: var(--color-gray-400); }
.text-action-btn--danger:hover { color: #ff7a7a; border-color: rgba(255, 122, 122, 0.4); background: rgba(255, 122, 122, 0.08); }

/* Hide controls entirely when no text element is selected */
.typography-wrap[data-no-selection="true"] .text-controls-grid {
    display: none !important;
}

/* ── Chip list (Phase 2 — multi-element) ── */
.text-chip-list {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: center;
}
.text-chip-list:empty { display: none; }

.text-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    max-width: 100%;
    height: 26px;
    padding: 0 4px 0 8px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    color: var(--color-gray-200);
    font-size: 11px;
    line-height: 1;
    cursor: pointer;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
    overflow: hidden;
    flex: 0 1 auto;
    min-width: 0;
}
.text-chip:hover {
    background: rgba(255, 255, 255, 0.07);
    border-color: var(--border-default);
    color: var(--color-gray-50);
}
.text-chip[data-active="true"] {
    /* Mirrors .text-seg-active (white-alpha) so chips read like the
       segmented controls already used in the Text panel. */
    background: rgba(255, 255, 255, 0.08);
    border-color: var(--border-default);
    color: var(--color-gray-50);
}
.text-chip-label {
    max-width: 110px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.text-chip-x {
    width: 16px;
    height: 16px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-gray-400);
    transition: background 120ms ease, color 120ms ease;
    flex-shrink: 0;
    margin-left: 2px;
}
.text-chip-x:hover {
    background: rgba(255, 122, 122, 0.18);
    color: #ff9a9a;
}
.text-chip-x svg { width: 9px; height: 9px; }

.text-chip-add {
    width: 26px;
    height: 26px;
    border-radius: 999px;
    border: 1px dashed var(--border-subtle);
    background: transparent;
    color: var(--color-gray-400);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: border-color 150ms ease, color 150ms ease, background 150ms ease;
    flex-shrink: 0;
}
.text-chip-add:hover {
    border-style: solid;
    border-color: var(--border-default);
    color: var(--color-gray-50);
    background: rgba(255, 255, 255, 0.04);
}
.text-chip-add svg { width: 10px; height: 10px; }

/* Hint shown when the user has text elements but nothing selected. */
.text-empty-hint {
    color: var(--color-gray-400);
    font-size: 12px;
    line-height: 1.4;
    padding: 6px 4px 0;
}

/* Hide the empty hint by default — JS toggles it on. */
.typography-wrap .text-empty-hint { display: none; }
.typography-wrap[data-empty-hint="true"] .text-empty-hint { display: block; }

/* When the panel has chips, the standalone Add button becomes redundant
   (the "+" tail of the chip row takes over). */
.typography-wrap[data-has-elements="true"] #text-add-btn { display: none !important; }

/* Hide entire sidebar section when its element list is empty — adding new
   elements lives in the bottom floating toolbar (#quickAddText / #quickAddImage
   / #quickAddShape), so an empty section with just a header is pure noise. */
.typography-wrap[data-has-elements="false"],
.images-wrap[data-has-elements="false"],
.shapes-wrap[data-has-elements="false"] { display: none; }

/* ── Custom font picker (Phase 4) ──
   Replaces the native <select> so the dropdown menu can render each font's
   name in its own face. Trigger has its own styling (not .text-select) so
   the chevron is an inline SVG child rather than a background-image — much
   more predictable inside a flex layout. */
.text-font-picker { position: relative; }
.text-font-picker-trigger {
    width: 100%;
    height: 32px;
    box-sizing: border-box;
    padding: 0 10px;
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    color: var(--color-gray-100);
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    transition: border-color 150ms ease, background 150ms ease;
}
.text-font-picker-trigger:hover {
    border-color: var(--border-default);
    background: rgba(255, 255, 255, 0.04);
}
.text-font-picker-current {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.text-font-picker-chevron {
    flex-shrink: 0;
    color: var(--color-gray-400, #a0a0a0);
    transition: transform 150ms ease;
}
.text-font-picker-trigger[aria-expanded="true"] .text-font-picker-chevron {
    transform: rotate(180deg);
}
/* position: fixed lets the popover escape the sidebar's overflow-y: auto
   so the Download button (and any other surrounding chrome) doesn't clip
   it. Coordinates are written by JS from the trigger's bounding rect; the
   popover also auto-flips above the trigger when there's not enough room
   below. Background and shadow mirror .context-menu for visual parity. */
.text-font-picker-popover {
    position: fixed;
    z-index: 10003;
    /* Width is set by JS at open time to span the whole Font row
       (font trigger → color chip). Clamps are wide so the JS-computed
       width isn't truncated on any reasonable sidebar width. */
    min-width: 200px;
    max-width: 480px;
    max-height: 360px;
    overflow-y: auto;
    padding: 6px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-default);
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
    scrollbar-width: thin;
}
.text-font-picker-popover[hidden] { display: none; }
.text-font-picker-group-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-gray-500, #6b6b6b);
    padding: 10px 10px 4px;
    font-family: 'EuclidCircularA', system-ui, sans-serif;
}
.text-font-picker-group-label:first-child { padding-top: 6px; }
.text-font-picker-item {
    width: 100%;
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 9px 10px;
    border: none;
    background: transparent;
    color: var(--color-gray-100);
    border-radius: 6px;
    cursor: pointer;
    font-size: 17px;
    line-height: 1.2;
    text-align: left;
    transition: background 120ms ease;
}
.text-font-picker-item:hover,
.text-font-picker-item:focus-visible {
    background: var(--bg-hover);
    outline: none;
}
.text-font-picker-item[data-active="true"] {
    background: var(--bg-hover);
    color: var(--color-gray-50);
}
.text-font-picker-item-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* fontFamily is set inline so each preview renders in its own face. */
}
.text-font-picker-item-tag {
    flex-shrink: 0;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-gray-500, #6b6b6b);
    /* Keep tag in the UI font, not the previewed font. */
    font-family: 'EuclidCircularA', system-ui, sans-serif;
    align-self: center;
}

/* ── a11y: keyboard focus rings for typography panel controls ── */
.typography-wrap .text-input:focus-visible,
.typography-wrap .text-select:focus-visible,
.typography-wrap .text-color-chip:focus-visible,
.typography-wrap .text-action-btn:focus-visible,
.typography-wrap .text-icon-btn:focus-visible,
.typography-wrap .text-seg-btn:focus-visible,
.typography-wrap .text-chip:focus-visible,
.typography-wrap .text-chip-add:focus-visible,
.typography-wrap .text-font-picker-trigger:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.55);
    outline-offset: 2px;
    border-color: transparent;
}

/* ── Export dropdown segmented tabs (Image Format / Resolution) ── */
.studio-sidebar .export-tab-group {
    background: #18181b !important;
    border-radius: 11px !important;
    padding: 3px !important;
    gap: 2px;
    box-shadow: inset 0 0 0 1px var(--border-subtle);
}
.studio-sidebar .export-tab-group .join-item.btn {
    background: transparent !important;
    color: var(--color-gray-500) !important;
    border: 0 !important;
    border-radius: 8px !important;
    height: 34px !important;
    min-height: 34px !important;
    padding: 0 10px !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    letter-spacing: 0.04em !important;
    box-shadow: none !important;
    transition:
        color 140ms ease,
        background-color 140ms ease,
        box-shadow 140ms ease !important;
}
.studio-sidebar .export-tab-group .join-item.btn:hover {
    background: transparent !important;
    color: var(--color-gray-300) !important;
}
.studio-sidebar .export-tab-group input[type="radio"].join-item.btn:checked,
.studio-sidebar .export-tab-group input[type="radio"].join-item.btn:checked:hover {
    background: var(--bg-hover) !important;
    color: var(--color-gray-50) !important;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.40),
        inset 0 0 0 1px var(--border-default),
        inset 0 1px 0 rgba(255, 255, 255, 0.04) !important;
}
.studio-sidebar .export-tab-group .join-item.btn:focus-visible {
    outline: 2px solid var(--color-lime-500);
    outline-offset: 1px;
}

/* 3D rotate gizmo — flat handle pinned to the artboard's top-left
   corner, visual twin of the delete (×) button in the top-right.
   Always visible on the active artboard (discoverability: it's the
   on-canvas entry point to 3D rotation; cmd+drag stays as the power
   shortcut). Position is purely CSS; the ball does not follow the
   mockup. Stripped from export via renderExport filter. */
.gizmo-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 9997;
    opacity: 0;
    transition: opacity 160ms ease;
}
.artboard[data-active="true"] .gizmo-overlay {
    opacity: 0.85;
}
.artboard[data-active="true"]:hover .gizmo-overlay,
.gizmo-overlay.is-dragging {
    opacity: 1;
}
.gizmo3d-ball {
    position: absolute;
    left: 10px;
    top: 10px;
    width: 28px;
    height: 28px;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(20, 20, 20, 0.4);
    color: rgba(255, 255, 255, 0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    pointer-events: auto;
    cursor: grab;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    user-select: none;
    -webkit-user-select: none;
    transition: background 150ms ease, color 150ms ease, transform 150ms ease;
}
.gizmo3d-ball:hover {
    background: rgba(20, 20, 20, 0.65);
    color: rgba(255, 255, 255, 0.9);
}
.gizmo3d-ball:active,
.gizmo-overlay.is-dragging .gizmo3d-ball {
    cursor: grabbing;
    transform: scale(0.96);
}
.gizmo3d-ball:focus-visible {
    outline: 2px solid var(--color-lime-500, #84cc16);
    outline-offset: 2px;
}
body.gizmo-dragging {
    cursor: grabbing;
    user-select: none;
}
body.gizmo-dragging * {
    cursor: grabbing !important;
}

/* Cmd/Ctrl held over the artboard → 3D rotate gesture is armed. */
body.cmd-rotate-ready .artboard,
body.cmd-rotate-ready .artboard * {
    cursor: grab !important;
}
body.cmd-rotate-dragging {
    cursor: grabbing;
    user-select: none;
}
body.cmd-rotate-dragging * {
    cursor: grabbing !important;
}

/* ─── Images on Layout (docs/13-images.md, branch `Images`) ───────────────── */
/* Mirror of .text-layer / .text-element. Two sibling layers inside
   the artboard: image-below sits under text-below (z 13), image-above sits
   under text-above (z 99) — text always wins inside the same plane. */
.image-layer {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
.image-layer[data-z="below"] { z-index: 13; }
/* z=23 sits below the DOF viewport overlay (z=25) so backdrop-filter
   actually blurs the image in the live preview — matching the export
   pipeline's canvas-pass DOF. Still above devices (z=20), so visually
   the image stays on top of the mockup. Text-above (z=100) is intentionally
   above DOF and therefore unaffected by the blur. */
.image-layer[data-z="above"] { z-index: 23; }
.image-layer:empty { display: none; }

.image-element {
    position: absolute;
    pointer-events: auto;
    /* Centering is done via computed offsets in renderImageElements
       (left = xPct - widthPct/2, top = yPct - heightPct/2). NOT via
       transform, because transform creates a compositor layer that the
       DOF backdrop-filter overlay cannot sample — image stays sharp in
       preview while export's canvas-pass DOF blurs it. */
    box-sizing: border-box;
    user-select: none;
    display: block;
    cursor: default;
    touch-action: none;
}
.image-element:hover,
.image-element[data-selected="true"] {
    cursor: move;
}
/* Keyboard focus ring (Tab/Shift+Tab) — only renders when navigating with
   the keyboard, not on click or drag. Mouse-selected state is indicated
   by the resize handle appearing in the top-right corner. */
.image-element:focus { outline: none; }
.image-element:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.55);
    outline-offset: 2px;
}
.image-element-content {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: fill;
    pointer-events: none;
    -webkit-user-drag: none;
}

/* Top-right resize handle — single, aspect-locked. Mirrors the visual
   language of .text-resize-handle (white pill on dark bg, dark pill on
   light), just round and corner-anchored instead of side-pill. Sits fully
   outside the corner with a 3px gap, matching the text handles' offset. */
.image-resize-handle {
    position: absolute;
    top: -3px;
    right: -3px;
    width: 14px;
    height: 14px;
    transform: translate(100%, -100%);
    background: #FFFFFF;
    border: 1px solid rgba(0, 0, 0, 0.25);
    border-radius: 50%;
    cursor: nesw-resize;
    opacity: 0;
    pointer-events: none;
    transition: opacity 130ms ease;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
    z-index: 2;
    user-select: none;
    -webkit-user-select: none;
    touch-action: none;
}
.image-element[data-selected="true"] .image-resize-handle {
    opacity: 1;
    pointer-events: auto;
}
.artboard[data-bg-light="true"] .image-resize-handle {
    background: #1A1A1E;
    border-color: rgba(255, 255, 255, 0.35);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}

/* ─── Shapes on Layout (mirror of image-layer/text-layer) ──────────────── */
/* Two sibling layers inside #exportBlock. shape-below sits between
   image-below (z 13) and text-below (z 15). shape-above sits between
   image-above (z 23) and DOF overlay (z 25), so backdrop-filter blurs
   shape too in the live preview — matching the canvas-pass DOF in export.
   Text-above (z 100) intentionally remains above DOF and shapes. */
.shape-layer {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
.shape-layer[data-z="below"] { z-index: 14; }
.shape-layer[data-z="above"] { z-index: 24; }
.shape-layer:empty { display: none; }

.shape-element {
    position: absolute;
    pointer-events: auto;
    box-sizing: border-box;
    user-select: none;
    -webkit-user-select: none;
    display: block;
    cursor: default;
    touch-action: none;
}
.shape-element:hover,
.shape-element[data-selected="true"] {
    cursor: move;
}
.shape-element:focus { outline: none; }
.shape-element:focus-visible,
.shape-element[data-selected="true"] {
    outline: 2px solid rgba(255, 255, 255, 0.55);
    outline-offset: 2px;
}
/* Light backgrounds get a darker selection ring for contrast. */
.artboard[data-bg-light="true"] .shape-element:focus-visible,
.artboard[data-bg-light="true"] .shape-element[data-selected="true"] {
    outline-color: #2563eb;
}

/* Line / arrow get a hit-area expander so a 4px line is still grabbable. */
.shape-element[data-shape-type="line"]::before,
.shape-element[data-shape-type="arrow"]::before {
    content: "";
    position: absolute;
    inset: -8px 0;
    pointer-events: auto;
}

/* Bottom-right resize handle — single corner, free aspect. Visual language
   mirrors .image-resize-handle but anchored to bottom-right instead of
   top-right; on rect/ellipse it gives unrestricted resize, on line/arrow
   only the horizontal delta is used (vertical motion is ignored). */
.shape-resize-handle {
    position: absolute;
    bottom: -3px;
    right: -3px;
    width: 14px;
    height: 14px;
    transform: translate(100%, 100%);
    background: #FFFFFF;
    border: 1px solid rgba(0, 0, 0, 0.25);
    border-radius: 50%;
    cursor: nwse-resize;
    opacity: 0;
    pointer-events: none;
    transition: opacity 130ms ease;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
    z-index: 2;
    user-select: none;
    -webkit-user-select: none;
    touch-action: none;
}
.shape-element[data-shape-type="line"] .shape-resize-handle,
.shape-element[data-shape-type="arrow"] .shape-resize-handle {
    cursor: ew-resize;
    top: 50%;
    bottom: auto;
    transform: translate(100%, -50%);
}
.shape-element[data-selected="true"] .shape-resize-handle {
    opacity: 1;
    pointer-events: auto;
}
.artboard[data-bg-light="true"] .shape-resize-handle {
    background: #1A1A1E;
    border-color: rgba(255, 255, 255, 0.35);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}

/* Arrow head — CSS triangle rendered at the right edge of the bounding
   rect. Color follows the line via currentColor (set on .shape-element).
   Sized so the head is ~3× line thickness, like Figma's default. */
.shape-element[data-shape-type="arrow"]::after {
    content: "";
    position: absolute;
    right: 0;
    top: 50%;
    transform: translate(50%, -50%);
    width: 0;
    height: 0;
    border-top: var(--shape-arrow-head, 8px) solid transparent;
    border-bottom: var(--shape-arrow-head, 8px) solid transparent;
    border-left: var(--shape-arrow-head, 10px) solid currentColor;
    pointer-events: none;
}

/* ─── Images / Shapes sidebar panel (Phase 4) ──────────────────────────── */
/* Visual language mirrors .text-chip / .text-action-btn. Image chip adds a
   tiny thumb; shape chip uses a glyph (rect/ellipse/line/arrow) instead. */
.image-chip-list,
.shape-chip-list {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: center;
}
.image-chip-list:empty,
.shape-chip-list:empty { display: none; }

.image-chip,
.shape-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 26px;
    padding: 0 4px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    color: var(--color-gray-200);
    font-size: 11px;
    line-height: 1;
    cursor: pointer;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
    flex: 0 0 auto;
}
.image-chip:hover,
.shape-chip:hover {
    background: rgba(255, 255, 255, 0.07);
    border-color: var(--border-default);
    color: var(--color-gray-50);
}
.image-chip[data-active="true"],
.shape-chip[data-active="true"] {
    background: rgba(255, 255, 255, 0.08);
    border-color: var(--border-default);
    color: var(--color-gray-50);
}

/* Shape chip glyph — small icon representing the shape type. */
.shape-chip-glyph {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    color: currentColor;
}
.shape-chip-glyph svg {
    width: 100%;
    height: 100%;
    display: block;
}
.image-chip-thumb {
    width: 18px;
    height: 18px;
    border-radius: 999px;
    object-fit: cover;
    flex-shrink: 0;
    background: rgba(255, 255, 255, 0.06);
    /* Disable native drag — chip itself handles selection. */
    -webkit-user-drag: none;
    user-select: none;
}
.image-chip-label {
    max-width: 84px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.image-chip-x {
    width: 16px;
    height: 16px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-gray-400);
    transition: background 120ms ease, color 120ms ease;
    flex-shrink: 0;
    margin-left: 2px;
}
.image-chip-x:hover {
    background: rgba(255, 122, 122, 0.18);
    color: #ff9a9a;
}
.image-chip-x svg { width: 9px; height: 9px; }

/* Empty hint shown when there are no items (or none selected).
   No own padding — the parent card already provides equal 10px on every
   side. Adding extra here makes top/bottom uneven (see screenshot bug). */
.image-empty-hint,
.shape-empty-hint {
    color: var(--color-gray-400);
    font-size: 12px;
    line-height: 1.4;
    padding: 0;
}
.images-wrap .image-empty-hint,
.shapes-wrap .shape-empty-hint { display: none; }
.images-wrap[data-empty-hint="true"] .image-empty-hint,
.shapes-wrap[data-empty-hint="true"] .shape-empty-hint { display: block; }


/* Hide the controls grid until something is selected. */
.images-wrap .image-controls-grid,
.shapes-wrap .shape-controls-grid { display: none; }
.images-wrap[data-has-selection="true"] .image-controls-grid,
.shapes-wrap[data-has-selection="true"] .shape-controls-grid { display: flex; }

/* Layer (above/below) segmented control — shared between Images and Shapes. */
.image-seg-group,
.shape-seg-group {
    display: inline-flex;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    padding: 2px;
    gap: 2px;
    align-self: flex-start;
}
.image-seg-btn,
.shape-seg-btn {
    height: 24px;
    padding: 0 12px;
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: var(--color-gray-400);
    font-size: 11px;
    line-height: 1;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
}
.image-seg-btn:hover,
.shape-seg-btn:hover { color: var(--color-gray-50); }
.image-seg-btn[data-active="true"],
.shape-seg-btn[data-active="true"] {
    background: rgba(255, 255, 255, 0.08);
    color: var(--color-gray-50);
}
.image-seg-btn:focus-visible,
.shape-seg-btn:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.55);
    outline-offset: 2px;
}

/* ─── Shape sidebar Phase 5: color chip + popover (mirrors text picker) ── */
/* Color chip — a small swatch button that opens the vanilla-picker popover.
   Matches the visual language of .text-color-chip (typography panel). */
.shape-color-chip {
    width: 26px;
    height: 26px;
    border-radius: 8px;
    border: 1px solid var(--border-default);
    padding: 2px;
    background: transparent;
    cursor: pointer;
    flex-shrink: 0;
    box-sizing: border-box;
    transition: border-color 120ms ease;
}
.shape-color-chip:hover { border-color: var(--border-strong); }
.shape-color-chip:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.55);
    outline-offset: 2px;
}
.shape-color-row[data-open="true"] .shape-color-chip {
    border-color: var(--color-gray-300);
}
.shape-color-swatch {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 5px;
}

.shape-hex-input {
    flex: 1;
    height: 26px;
    padding: 0 8px;
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: 8px;
    color: var(--color-gray-100);
    font-family: 'JetBrains Mono', 'Inter', monospace;
    font-size: 11px;
    line-height: 1;
    text-transform: uppercase;
    transition: border-color 120ms ease;
    min-width: 0;
}
.shape-hex-input:focus {
    outline: none;
    border-color: var(--border-strong);
}
.shape-hex-input:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.55);
    outline-offset: 1px;
}

/* Popover wrapper — same layout as .text-color-popover. */
.shape-color-popover {
    position: absolute;
    right: 0;
    top: calc(100% + 8px);
    z-index: 200;
    background: #1f1f23;
    border: 1px solid var(--border-default);
    border-radius: 14px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
    padding: 14px;
    width: 248px;
    box-sizing: border-box;
    animation: shape-color-pop-in 140ms cubic-bezier(0.22, 1, 0.36, 1);
}
.shape-color-popover[hidden] { display: none; }
@keyframes shape-color-pop-in {
    0% { opacity: 0; transform: translateY(-4px) scale(0.98); }
    100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* Scope vanilla-picker overrides to the shapes panel too — same look as
   the text panel (set up earlier at .typography-wrap .picker_*). */
.shapes-wrap .picker_wrapper.popup,
.shapes-wrap .picker_wrapper {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    width: 220px !important;
    min-width: 0 !important;
    font-family: inherit !important;
    display: flex !important;
    flex-direction: column !important;
}
.shapes-wrap .picker_arrow { display: none !important; }
.shapes-wrap .picker_sl {
    width: 220px !important;
    height: 168px !important;
    min-height: 168px !important;
    border-radius: 10px !important;
    overflow: visible !important;
    margin: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    flex: 0 0 168px !important;
    order: 1;
    position: relative;
}
.shapes-wrap .picker_sl > *:not(.picker_selector) {
    width: 100% !important;
    height: 100% !important;
}
.shapes-wrap .picker_hue {
    width: 220px !important;
    height: 12px !important;
    border-radius: 999px !important;
    margin: 14px 0 0 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    flex: none !important;
    order: 2;
    position: relative;
}
.shapes-wrap .picker_alpha { display: none !important; }
.shapes-wrap .picker_sl .picker_selector,
.shapes-wrap .picker_hue .picker_selector {
    width: 18px !important;
    height: 18px !important;
    border-radius: 999px !important;
    border: 2px solid #fff !important;
    box-shadow: 0 2px 6px rgba(0,0,0,0.45), 0 0 0 1px rgba(0,0,0,0.25) !important;
    padding: 0 !important;
    background: transparent !important;
    box-sizing: border-box;
}
.shapes-wrap .picker_hue .picker_selector { top: 50% !important; }
.shapes-wrap .picker_editor,
.shapes-wrap .picker_sample,
.shapes-wrap .picker_done { display: none !important; }
.shapes-wrap .picker_wrapper * { box-sizing: border-box; }

/* Gradient/solid toggle — show only the active row inside .shape-fill-section.
   data-fill-type lives on the section wrapper; JS toggles it in sync with
   the seg button state. */
.shape-fill-section[data-fill-type="solid"] .shape-fill-gradient-row,
.shape-fill-section[data-fill-type="gradient"] .shape-fill-solid-row { display: none; }

/* Type-gated visibility — Fill only for rect/ellipse, Radius only for rect.
   Line/arrow swap labels: "Stroke" / "Width" become "Color" / "Thickness". */
.shapes-wrap:not([data-active-type="rect"]):not([data-active-type="ellipse"]) .shape-fill-section {
    display: none;
}
.shapes-wrap:not([data-active-type="rect"]) .shape-radius-row { display: none; }

.shape-stroke-label-line { display: none; }
.shapes-wrap[data-active-type="line"] .shape-stroke-label-fill,
.shapes-wrap[data-active-type="arrow"] .shape-stroke-label-fill { display: none; }
.shapes-wrap[data-active-type="line"] .shape-stroke-label-line,
.shapes-wrap[data-active-type="arrow"] .shape-stroke-label-line { display: inline; }

/* ─── Bottom toolbar shift var (WS3): full-bleed scene — toolbar, trash
   zone and upload bar center on the true viewport middle now. ─── */
:root {
    --quick-toolbar-shift: 0px;
}

/* ─── Drag-to-delete trash zone ─────────────────────────────────────────── */
/* Sits in the same bottom-center spot as the floating toolbar. The toolbar
   fades out and trash fades in while body has .app-dragging — visually one
   transforms into the other. pointer-events:none on the zone itself; we
   hit-test by client coordinates inside drag handlers, which keeps the
   pointer capture on the dragged element working. */
.trash-zone {
    position: fixed;
    bottom: 24px;
    left: calc(50% + var(--quick-toolbar-shift));
    width: 56px;
    height: 56px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(20, 20, 22, 0.92);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 50%;
    color: #d6d6d8;
    box-shadow: 0 10px 32px rgba(0, 0, 0, 0.35), 0 2px 6px rgba(0, 0, 0, 0.25);
    z-index: 201;
    pointer-events: none;
    opacity: 0;
    transform: translate(-50%, 16px) scale(0.85);
    transition: opacity 180ms ease, transform 180ms ease,
                background-color 130ms ease, color 130ms ease,
                border-color 130ms ease,
                left 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
.trash-zone svg { width: 22px; height: 22px; display: block; }

body.app-dragging .trash-zone {
    opacity: 1;
    transform: translate(-50%, 0) scale(1);
}
body.app-dragging .tc-toolbar {
    opacity: 0;
    transform: translate(-50%, 12px) scale(0.92);
    pointer-events: none;
    transition: opacity 160ms ease, transform 160ms ease;
}
.trash-zone.is-armed {
    background: rgba(220, 53, 69, 0.95);
    border-color: rgba(255, 122, 122, 0.6);
    color: #fff;
    transform: translate(-50%, 0) scale(1.08);
    box-shadow: 0 12px 36px rgba(220, 53, 69, 0.45);
}


/* ── App-menu entry (#pro-toggle) — subtle lime tint among gray siblings ── */
.tc-app-menu #pro-toggle {
    color: var(--color-lime-500);
}
.tc-app-menu #pro-toggle:hover {
    background: rgba(var(--brand-rgb), 0.08);
    color: var(--color-lime-400);
}

/* ── Reusable PRO chip — gates Pro feature buttons ── */
.pro-chip {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    padding: 2px 4px;
    border-radius: 4px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: var(--text-2xs);
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-lime-500);
    background: rgba(202, 252, 0, 0.10);
    border: 1px solid rgba(202, 252, 0, 0.28);
}

/* ── Background Removal button (Pro) ─────────────────────────────────
   Reuses .text-action-btn; only the disabled/busy states are new. */
#bg-remove-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}
#bg-remove-btn:disabled:hover {
    /* neutralize .text-action-btn:hover while disabled */
    background: rgba(255, 255, 255, 0.02);
    border-color: var(--border-subtle);
    color: var(--color-gray-200);
}
#bg-remove-btn.is-busy {
    cursor: progress;
    color: var(--color-gray-400);
    opacity: 1;
}
#bg-remove-btn.is-busy #bg-remove-label {
    animation: bg-remove-pulse 1.2s ease-in-out infinite;
}
@keyframes bg-remove-pulse {
    50% { opacity: 0.55; }
}

/* ── Transparent artboard background (Pro at export) ─────────────────
   `data-bg-transparent="true"` on .artboard turns every background layer
   off; the alpha checkerboard below shows through in the EDITOR only —
   renderExport's options.filter drops .bg-alpha-checker from the export
   clone, so PNG/WebP keep real alpha (JPG composites onto white). */
.artboard[data-bg-transparent="true"] .background-device-wrap,
.artboard[data-bg-transparent="true"] .pattern-overlay-layer,
.artboard[data-bg-transparent="true"] .blur-bg-layer {
    display: none !important;
}
.bg-alpha-checker {
    position: absolute;
    inset: 0;
    z-index: 5; /* under .background-device-wrap (z-10), see docs/15 §1.7 */
    display: none;
    pointer-events: none;
    background-color: var(--color-gray-850);
    background-image:
        linear-gradient(45deg, var(--color-gray-700) 25%, transparent 25%),
        linear-gradient(-45deg, var(--color-gray-700) 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, var(--color-gray-700) 75%),
        linear-gradient(-45deg, transparent 75%, var(--color-gray-700) 75%);
    background-size: 16px 16px;
    background-position: 0 0, 0 8px, 8px -8px, -8px 0;
}
.artboard[data-bg-transparent="true"] .bg-alpha-checker {
    display: block;
}
/* On-canvas Pro-trial badge: free-tier cue on artboards whose exports carry
   the watermark (Site Shots / bg removal). Editor-only — renderExport's
   clone filter drops it, and body.is-pro hides it once a license activates. */
.pro-trial-badge {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 80;
    pointer-events: none;
    padding: 3px 7px;
    border-radius: 6px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: var(--text-2xs);
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-lime-500);
    background: rgba(20, 20, 22, 0.72);
    border: 1px solid rgba(202, 252, 0, 0.35);
}
body.is-pro .pro-trial-badge { display: none; }
/* Toggle pressed state — same lime "active" language as #auto-bg-btn
   ([&.active]:border-brand [&.active]:bg-brand/5). */
#bg-transparent-btn[aria-pressed="true"] {
    border-color: var(--color-lime-500);
    background: rgba(202, 252, 0, 0.05);
    color: var(--color-gray-50);
}
/* While transparent mode is on, the background pickers do nothing visible —
   dim them so users aren't confused (settings themselves are preserved).
   The toggle itself lives INSIDE the dropdown now, so dim the inner controls
   individually: the trigger stays clickable (it opens the dropdown) and
   #bg-transparent-btn stays fully interactive to switch the mode back off. */
.bg-controls-dimmed #dropdown-bg-color {
    opacity: 0.6;
}
.bg-controls-dimmed #auto-bg-btn,
.bg-controls-dimmed #tabs-bg,
.bg-controls-dimmed #tabs-bg-1,
.bg-controls-dimmed #tabs-bg-2,
.bg-controls-dimmed #tabs-bg-3,
.bg-controls-dimmed #tabs-bg-4 {
    opacity: 0.45;
    pointer-events: none;
}

/* Header entry point: the Pro chip inside the header button should not
   inherit the button's gray hover color. */
#siteshots-toggle .pro-chip {
    color: var(--color-lime-500);
}
/* Lime-branded like #pro-toggle, so the gated entry reads as Pro on hover too. */
.tc-app-menu #siteshots-toggle {
    color: var(--color-lime-500);
}
.tc-app-menu #siteshots-toggle:hover {
    background: rgba(var(--brand-rgb), 0.08);
    color: var(--color-lime-400);
}

/* ═══════════════════════════════════════════════════════════════════════════
   WS2 — Toolcraft control kit (SPEC §3): one skin for every control.
   Base input skin adapted from toolcraft-ref/src/toolcraft/ui/lib/
   input-control-style.ts (MIT — attribution in the file header).
   The .tc-* classes are the canonical primitives; the five legacy button
   classes are mapped onto the same skin at the bottom of this block.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Base input ── */
.tc-input {
    width: 100%;
    min-width: 0;
    height: 28px;
    box-sizing: border-box;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    background: var(--ghost-5);
    background-clip: padding-box;
    color: var(--foreground);
    padding: 2px 8px;
    font-family: inherit;
    font-size: 12px;
    line-height: 1.625;
    outline: none;
    cursor: text;
    transition-property: color, background-color, border-color;
    transition-duration: var(--dur-fast);
    transition-timing-function: ease-out;
}
.tc-input::placeholder { color: var(--muted-foreground); opacity: 1; }
.tc-input:not(:disabled):not(:focus):hover { border-color: var(--ghost-20); color: var(--foreground); }
.tc-input:not(:disabled):focus { border-color: var(--ghost-30); }
.tc-input:disabled { pointer-events: none; cursor: not-allowed; opacity: 0.5; }
.tc-input[aria-invalid="true"] { border-color: var(--destructive); }
.tc-input--sm { height: 24px; padding: 0 8px; }
.tc-input--mono {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
}

/* ── Input group: borderless inner input + right unit suffix ── */
.tc-input-group {
    display: flex;
    align-items: center;
    width: 100%;
    min-width: 0;
    height: 28px;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    background: var(--ghost-5);
    background-clip: padding-box;
    transition: border-color var(--dur-fast) ease-out;
}
.tc-input-group:hover { border-color: var(--ghost-20); }
.tc-input-group:focus-within { border-color: var(--ghost-30); }
.tc-input-group .tc-input {
    border: none;
    background: transparent;
    height: 100%;
    flex: 1 1 auto;
}
.tc-input-unit {
    flex: none;
    padding-left: 4px;
    padding-right: 12px;
    font-size: 12px;
    font-weight: 500;
    color: var(--muted-foreground);
    transition: color var(--dur-fast) ease-out;
    user-select: none;
    -webkit-user-select: none;
}
.tc-input-group:hover .tc-input-unit,
.tc-input-group:focus-within .tc-input-unit { color: var(--foreground); }

/* ── Color control: [28px swatch | mono hex (no #) | 56px alpha%] ── */
.tc-color-control {
    display: flex;
    align-items: stretch;
    width: 100%;
    min-width: 0;
    height: 28px;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    background: var(--ghost-5);
    background-clip: padding-box;
    overflow: hidden;
    transition: border-color var(--dur-fast) ease-out;
}
.tc-color-control:hover { border-color: var(--ghost-20); }
.tc-color-control:focus-within { border-color: var(--ghost-30); }
.tc-color-swatch {
    flex: none;
    width: 28px;
    height: 100%;
    padding: 5px;
    background: transparent;
    border: none;
    border-right: 1px solid var(--ghost-8);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}
.tc-color-swatch > span {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: var(--r-sm);
    box-shadow: inset 0 0 0 1px var(--ghost-10);
}
.tc-color-hex {
    flex: 1 1 auto;
    min-width: 0;
    height: 100%;
    border: none;
    background: transparent;
    color: var(--foreground);
    padding: 0 8px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    text-transform: uppercase;
    outline: none;
}
.tc-color-alpha {
    flex: none;
    width: 56px;
    height: 100%;
    border: none;
    border-left: 1px solid var(--ghost-8);
    background: transparent;
    color: var(--muted-foreground);
    padding: 0 8px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    text-align: right;
    outline: none;
}

/* ── Gradient editor (new primitive) — output feeds the name="gradient" pipeline.
   Math ported from toolcraft-ref .../gradient/gradient-control-utils.ts (MIT). ── */
.tc-gradient-editor { display: flex; flex-direction: column; gap: 12px; padding-bottom: 6px; }
.tc-grad-toolbar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.tc-grad-track {
    position: relative;
    width: 100%;
    height: 48px;
    touch-action: none;
    cursor: crosshair;
    -webkit-user-select: none;
    user-select: none;
}
.tc-grad-bar {
    position: absolute;
    left: 0; right: 0; top: 24px;
    height: 24px;
    border-radius: var(--r-md);
    border: 1px solid var(--ghost-10);
    background-clip: padding-box;
    overflow: hidden;
    /* alpha checkerboard behind translucent stops */
    background-color: #ffffff;
    background-image:
        linear-gradient(45deg, #d0d0d0 25%, transparent 25%),
        linear-gradient(-45deg, #d0d0d0 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, #d0d0d0 75%),
        linear-gradient(-45deg, transparent 75%, #d0d0d0 75%);
    background-size: 10px 10px;
    background-position: 0 0, 0 5px, 5px -5px, -5px 0;
}
.tc-grad-bar-fill { position: absolute; inset: 0; }
.tc-grad-pin {
    position: absolute;
    top: 0;
    z-index: 2;
    transform: translateX(-50%);
    width: 22px; height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: var(--r-md);
    background: var(--muted);
    cursor: grab;
    box-shadow: 0 4px 7px color-mix(in oklab, var(--background) 30%, transparent);
    transition: background-color var(--dur-fast) ease-out;
}
.tc-grad-pin:active { cursor: grabbing; }
.tc-grad-pin:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
.tc-grad-pin.is-selected { background: var(--accent); }
.tc-grad-pin::after {
    content: '';
    position: absolute;
    top: 100%; left: 50%;
    transform: translateX(-50%);
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 4px solid var(--muted);
    transition: border-top-color var(--dur-fast) ease-out;
}
.tc-grad-pin.is-selected::after { border-top-color: var(--accent); }
.tc-grad-pin > span {
    width: 14px; height: 14px;
    border-radius: var(--r-sm);
    border: 1px solid var(--ghost-10);
}
.tc-grad-pin.is-selected > span { border-color: var(--accent-contrast); }
.tc-grad-stops-head { display: flex; align-items: center; justify-content: space-between; }
.tc-grad-stops { display: flex; flex-direction: column; gap: 4px; }
.tc-grad-stop-row {
    display: grid;
    grid-template-columns: 3.25rem minmax(0, 1fr) 24px;
    align-items: center;
    gap: 6px;
}
.tc-grad-stop-row .tc-color-alpha { width: 46px; }
.tc-grad-stop-row .tc-color-swatch { position: relative; }
/* invisible native picker overlays the swatch so a click opens it directly */
.tc-grad-color-native { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: none; opacity: 0; cursor: pointer; }
.tc-icon-btn:disabled { opacity: 0.35; pointer-events: none; }

/* ── Segmented: joined 28px items, active = selection fill ── */
.tc-segmented {
    display: flex;
    align-items: stretch;
    width: 100%;
    height: 28px;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    background: var(--ghost-5);
    background-clip: padding-box;
    overflow: hidden;
}
.tc-seg-item {
    flex: 1 1 0;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    border: none;
    background: transparent;
    color: var(--label);
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
    padding: 0 6px;
    transition: color var(--dur-fast) ease-out, background-color var(--dur-fast) ease-out;
}
.tc-seg-item + .tc-seg-item { border-left: 1px solid var(--ghost-8); }
/* Hover only lightens NON-active items — hovering the active segment used to
   repaint its selection fill with the white hover wash (looked like a second,
   inconsistent active style). */
.tc-seg-item:not(.active):not([aria-selected="true"]):hover { color: var(--foreground); background: var(--ghost-3); }
.tc-seg-item.active,
.tc-seg-item[aria-selected="true"] {
    color: var(--foreground);
    background: var(--selection-bg);
}
.tc-seg-item svg { width: 14px; height: 14px; flex: none; }

/* ── Select (FlyonUI HSDropdown skin): input-look trigger + popup menu ── */
.tc-select-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    min-width: 0;
    height: 28px;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    background: var(--ghost-5);
    background-clip: padding-box;
    color: var(--foreground);
    padding: 0 8px;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
    transition: border-color var(--dur-fast) ease-out, color var(--dur-fast) ease-out;
}
.tc-select-trigger:hover { border-color: var(--ghost-20); }
.tc-select-trigger[aria-expanded="true"] { border-color: var(--ghost-30); }
.tc-select-caret {
    flex: none;
    width: 14px;
    height: 14px;
    color: var(--muted-foreground);
    transition: transform var(--dur-fast) ease-out;
}
.tc-select-trigger[aria-expanded="true"] .tc-select-caret { transform: rotate(180deg); }
.tc-select-menu {
    /* NOT min-width:100% — FlyonUI positions menus with strategy:fixed, and
       since the panel's backdrop-filter moved to ::before (fix 2a) there is no
       containing block, so 100% resolved against the VIEWPORT: menus stretched
       edge-to-edge and their left-aligned labels landed off-panel. Anchor to a
       sane popup width instead (inline widths, e.g. the Aspect menu's 310px,
       still apply within the clamp). */
    min-width: 240px;
    max-width: min(310px, calc(100vw - 24px));
    background: var(--popup-surface);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    padding: 4px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
.tc-select-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    border-radius: var(--r-md);
    padding: 6px 8px;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--foreground);
    cursor: pointer;
    background: transparent;
    border: none;
    text-align: left;
    transition: background-color var(--dur-fast) ease-out;
}
.tc-select-item:hover { background: var(--ghost-5); }
.tc-select-item .tc-select-check {
    flex: none;
    width: 14px;
    height: 14px;
    color: var(--foreground);
    opacity: 0;
}
.tc-select-item[aria-selected="true"] .tc-select-check { opacity: 1; }

/* ── Switch: 28×16 pill, checked = lime ── */
.tc-switch {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    flex: none;
    width: 28px;
    height: 16px;
    border-radius: var(--r-full);
    background: color-mix(in oklab, var(--input) 20%, transparent);
    border: none;
    cursor: pointer;
    outline: none;
    transition: background-color var(--dur-fast) ease-out;
}
.tc-switch::before {
    content: '';
    position: absolute;
    top: 1px;
    left: 1px;
    width: 14px;
    height: 14px;
    border-radius: var(--r-full);
    background: var(--foreground);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
    transition: transform var(--dur-fast) var(--ease-snap);
}
.tc-switch:checked { background: var(--accent); }
.tc-switch:checked::before { transform: translateX(12px); }
.tc-switch:focus-visible { box-shadow: 0 0 0 2px var(--ring); }

/* ── Anchor grid (9-dot): 3×3 of 36px tiles (shadow snap positions) ── */
.tc-anchor-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
}
.tc-anchor-cell {
    height: 36px;
    border: 1px solid transparent;
    border-radius: var(--r-md);
    background: var(--ghost-5);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color var(--dur-fast) ease-out, border-color var(--dur-fast) ease-out, transform 80ms ease-out;
}
.tc-anchor-cell::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: var(--r-full);
    background: var(--muted-foreground);
    transition: background-color var(--dur-fast) ease-out;
}
.tc-anchor-cell:hover { background: var(--ghost-10); }
.tc-anchor-cell:active { transform: scale(0.98); }
.tc-anchor-cell.active,
.tc-anchor-cell[aria-pressed="true"] {
    background: var(--selection-bg);
    border-color: var(--ghost-10);
}
.tc-anchor-cell.active::before,
.tc-anchor-cell[aria-pressed="true"]::before { background: var(--foreground); }

/* ── Dropzone (panel-side): dashed ghost, selection tint on drag-over ── */
.tc-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    min-height: 72px;
    border: 1px dashed var(--ghost-18);
    border-radius: var(--r-lg);
    background: var(--ghost-3);
    color: var(--muted-foreground);
    font-size: 12px;
    cursor: pointer;
    transition: border-color var(--dur-fast) ease-out, background-color var(--dur-fast) ease-out, color var(--dur-fast) ease-out;
}
.tc-dropzone:hover {
    border-color: var(--ghost-30);
    color: var(--foreground);
}
.tc-dropzone.is-dragover {
    border-color: color-mix(in oklab, var(--selection) 28%, transparent);
    background: color-mix(in oklab, var(--selection) 13%, transparent);
    color: var(--foreground);
}
.tc-dropzone svg { width: 24px; height: 24px; }

/* ── Thumbnail grid: tiles, selected = 1px white outline offset 2px ── */
.tc-thumb-grid {
    display: grid;
    gap: 10px;
    grid-template-columns: repeat(3, 1fr);
}
.tc-thumb-grid--2 { grid-template-columns: repeat(2, 1fr); }
.tc-thumb-grid--4 { grid-template-columns: repeat(4, 1fr); }
.tc-thumb {
    position: relative;
    border: 1px solid var(--ghost-10);
    border-radius: var(--r-lg);
    background: var(--muted);
    cursor: pointer;
    overflow: hidden;
    transition: border-color var(--dur-fast) ease-out;
}
.tc-thumb:hover { border-color: color-mix(in oklab, var(--border) 22%, transparent); }
.tc-thumb.selected,
.tc-thumb[aria-pressed="true"] {
    outline: 1px solid var(--foreground);
    outline-offset: 2px;
}

/* ── Buttons ── */
.tc-btn-brand {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 32px;
    padding: 0 14px;
    border: none;
    border-radius: var(--r-full);
    background: var(--accent);
    color: var(--accent-contrast);
    font-size: 13px;
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out, box-shadow var(--dur-fast) ease-out;
}
.tc-btn-brand:hover {
    background: var(--accent-hover);
    box-shadow: 0 0 20px rgba(var(--brand-rgb), 0.25);
}
.tc-btn-brand:active { background: var(--accent-pressed); }
.tc-btn-outline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 28px;
    padding: 0 10px;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    background: color-mix(in oklab, var(--input) 10%, transparent);
    color: var(--foreground);
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out, border-color var(--dur-fast) ease-out;
}
.tc-btn-outline:hover {
    background: color-mix(in oklab, var(--input) 15%, transparent);
    border-color: var(--ghost-20);
}
.tc-btn-outline:active { background: var(--selection-bg); }
.tc-btn-outline--danger {
    border-color: color-mix(in oklab, var(--destructive) 30%, transparent);
    background: color-mix(in oklab, var(--destructive) 15%, transparent);
    color: var(--destructive);
}
.tc-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 28px;
    height: 28px;
    padding: 0;
    border: none;
    border-radius: var(--r-md);
    background: transparent;
    color: var(--muted-foreground);
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out, color var(--dur-fast) ease-out;
}
.tc-icon-btn:hover {
    background: var(--ghost-10);
    color: var(--foreground);
}
.tc-icon-btn--sm { width: 24px; height: 24px; }
.tc-icon-btn svg { width: 14px; height: 14px; opacity: 0.6; transition: opacity var(--dur-fast) ease-out; }
.tc-icon-btn:hover svg { opacity: 1; }

/* ── Tooltip skin (FlyonUI tooltips restyled) ── */
.tooltip .tooltip-body {
    background: var(--tooltip-surface) !important;
    border: 1px solid var(--ghost-10) !important;
    border-radius: var(--r-lg) !important;
    color: var(--foreground) !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    letter-spacing: -0.01em;
}

/* ── Legacy class mapping (retire into the tc-set; token-level only —
   geometry changes land with the WS3/WS4 panel rebuild) ── */
.export-button:hover {
    box-shadow: 0 0 20px rgba(var(--brand-rgb), 0.25);
}
.studio-sidebar .filepond--panel-root {
    background-color: var(--ghost-3) !important;
    border: 1px dashed var(--ghost-18);
    border-radius: var(--r-lg);
}

/* ═══════════════════════════════════════════════════════════════════════
   WS3 — SHELL CHROME: floating panels, scenes panel, app menu, bottom
   toolbar, insert popover. Elevation doctrine (SPEC #1.4): no drop shadows
   on panels — panel-surface + blur + 1px ghost-12 border. z ladder:
   panels 30, toolbar 70, dialogs 10000+.
   ═══════════════════════════════════════════════════════════════════════ */

.tc-panel {
    position: fixed;
    z-index: 30;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-xl);
}
/* The panel surface (panel-surface fill + blur) lives on ::before, NOT the
   panel itself. backdrop-filter on the panel would make it the containing
   block for its fixed-position descendants — the HSDropdown/Popper
   strategy:fixed menus resolve viewport coords against the panel origin and
   land off-viewport (verify-2a blocker 1). A pseudo-element has no
   descendants, so the blur is containing-block-safe. */
.tc-panel::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: calc(var(--r-xl) - 1px);
    background: var(--panel-surface);
    -webkit-backdrop-filter: blur(40px) saturate(1.5);
    backdrop-filter: blur(40px) saturate(1.5);
    pointer-events: none;
}
@supports not ((backdrop-filter: blur(40px)) or (-webkit-backdrop-filter: blur(40px))) {
    .tc-panel::before { background: var(--panel); }
}

.tc-panel-header {
    flex: 0 0 auto;
    height: 36px;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 6px 0 12px;
}
.tc-panel-title {
    flex: 1 1 auto;
    font-size: 13px;
    font-weight: 500;
    color: var(--foreground);
    line-height: 1;
    user-select: none;
    -webkit-user-select: none;
}
.tc-panel-collapse svg {
    transition: transform var(--dur-fast) ease-out;
}

/* ── Scenes panel (top-left, 240px) ── */
.tc-scenes-panel {
    top: 10px;
    left: 10px;
    width: 240px;
    max-height: calc(100vh - 120px);
    /* overflow stays visible: the app-menu dropdown must escape the panel
       box. Content rounding is handled on the body below. */
    overflow: visible;
}
.tc-scenes-panel .tc-panel-header {
    padding-left: 6px;
}
.tc-scenes-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    border-top: 1px solid var(--ghost-8);
    border-radius: 0 0 var(--r-xl) var(--r-xl);
    padding: 6px;
    scrollbar-width: thin;
    scrollbar-color: var(--ghost-10) transparent;
}
.tc-scenes-body::-webkit-scrollbar { width: 4px; }
.tc-scenes-body::-webkit-scrollbar-thumb {
    background: var(--ghost-10);
    border-radius: var(--r-full);
}
.tc-scenes-panel.is-collapsed .tc-scenes-body { display: none; }
.tc-scenes-panel.is-collapsed #scenes-collapse svg { transform: rotate(-90deg); }

/* Artboard rows */
.tc-scene-row {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 28px;
    padding: 0 6px;
    border-radius: var(--r-lg);
    cursor: pointer;
    color: var(--color-gray-200);
    user-select: none;
    -webkit-user-select: none;
    transition: background-color var(--dur-fast) ease-out, color var(--dur-fast) ease-out;
}
.tc-scene-row:hover { background: var(--ghost-5); }
.tc-scene-row.is-active {
    background: var(--selection-bg);
    color: var(--foreground);
}
.tc-scene-idx {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-sm);
    background: var(--ghost-5);
    font-size: 10px;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    color: var(--muted-foreground);
}
.tc-scene-row.is-active .tc-scene-idx {
    background: color-mix(in oklab, var(--selection) 22%, transparent);
    color: var(--foreground);
}
.tc-scene-name {
    flex: 1 1 auto;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tc-scene-del {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: var(--r-md);
    background: transparent;
    color: var(--muted-foreground);
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--dur-fast) ease-out, color var(--dur-fast) ease-out,
                background-color var(--dur-fast) ease-out;
}
.tc-scene-row:hover .tc-scene-del,
.tc-scene-row:focus-within .tc-scene-del { opacity: 1; }
.tc-scene-del:hover {
    background: color-mix(in oklab, var(--destructive) 15%, transparent);
    color: var(--destructive);
}
.tc-scene-add {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    height: 28px;
    margin-top: 2px;
    padding: 0 6px;
    border: 0;
    border-radius: var(--r-lg);
    background: transparent;
    color: var(--muted-foreground);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.01em;
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out, color var(--dur-fast) ease-out;
}
.tc-scene-add:hover:not(:disabled) {
    background: var(--ghost-5);
    color: var(--foreground);
}
.tc-scene-add:disabled { opacity: 0.4; cursor: not-allowed; }
.tc-scene-add svg { margin-left: 2px; }

/* ── App menu (Presenta mark → popup) ── */
.tc-app-menu-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    height: 28px;
    padding: 0 6px;
    border: 0;
    border-radius: var(--r-lg);
    background: transparent;
    color: var(--foreground);
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out;
}
.tc-app-menu-btn:hover,
.tc-app-menu-btn[aria-expanded="true"] { background: var(--ghost-5); }
.tc-app-menu-caret {
    color: var(--muted-foreground);
    transition: transform var(--dur-fast) ease-out;
}
.tc-app-menu-btn[aria-expanded="true"] .tc-app-menu-caret { transform: rotate(180deg); }

.tc-app-menu {
    min-width: 236px;
    padding: 6px;
    background: var(--popup-surface);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
    z-index: 90;
}
.tc-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 30px;
    padding: 5px 8px;
    border: 0;
    border-radius: var(--r-md);
    background: transparent;
    color: var(--color-gray-200);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.01em;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out, color var(--dur-fast) ease-out;
}
.tc-menu-item:hover {
    background: var(--ghost-5);
    color: var(--foreground);
}
.tc-menu-item svg { flex: 0 0 auto; opacity: 0.7; }
.tc-menu-item:hover svg { opacity: 1; }
.tc-menu-item > span:first-of-type { flex: 1 1 auto; }
.tc-menu-item--quiet { color: var(--muted-foreground); }
.tc-menu-item .pro-chip { margin-left: auto; }
.tc-menu-kbd {
    flex: 0 0 auto;
    min-width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 5px;
    border-radius: var(--r-sm);
    background: var(--ghost-5);
    color: var(--muted-foreground);
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
}
.tc-menu-divider {
    height: 1px;
    margin: 5px 2px;
    background: var(--ghost-8);
}
.tc-promo-favicon {
    width: 16px;
    height: 16px;
    border-radius: var(--r-sm);
    flex: 0 0 auto;
    filter: brightness(0) invert(1);
    opacity: 0.55;
    transition: opacity var(--dur-fast) ease-out;
}
.tc-menu-item:hover .tc-promo-favicon { opacity: 0.9; }
.tc-promo-icon { flex: 0 0 auto; opacity: 0.7; }
.tc-menu-promo .tc-menu-promo-text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}
.tc-menu-promo .tc-menu-promo-text small {
    font-size: 10.5px;
    font-weight: 400;
    color: var(--muted-foreground);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Bottom toolbar (SPEC #2.1) ── */
.tc-toolbar {
    left: 50%;
    bottom: 10px;
    transform: translateX(-50%);
    z-index: 70;
    flex-direction: row;
    align-items: center;
    gap: 2px;
    padding: 4px;
    overflow: visible;
}
.tc-toolbar-divider {
    width: 1px;
    height: 20px;
    margin: 0 4px;
    background: var(--ghost-8);
    flex: 0 0 auto;
}
.tc-toolbar .tc-icon-btn:disabled {
    opacity: 0.35;
    pointer-events: none;
}
.tc-zoom-readout {
    height: 28px;
    min-width: 5ch;
    padding: 0 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: var(--r-md);
    background: transparent;
    color: var(--muted-foreground);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    transition: color var(--dur-fast) ease-out, background-color var(--dur-fast) ease-out;
}
.tc-zoom-readout:hover {
    color: var(--foreground);
    background: var(--ghost-5);
}

/* Insert popover — absorbs the old quick-add toolbar */
.tc-insert-wrap { position: relative; display: inline-flex; }
.tc-insert-popover {
    position: absolute;
    bottom: calc(100% + 12px);
    left: 50%;
    transform: translateX(-50%) translateY(4px) scale(0.97);
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 6px;
    background: var(--popup-surface);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-pop) ease-out, transform var(--dur-pop) ease-out;
    z-index: 90;
}
.tc-insert-popover[aria-hidden="false"] {
    opacity: 1;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0) scale(1);
}
.tc-insert-row {
    display: flex;
    align-items: stretch;
    gap: 4px;
}
.tc-insert-tile {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: 62px;
    height: 52px;
    padding: 0;
    border: 0;
    border-radius: var(--r-md);
    background: transparent;
    color: var(--color-gray-200);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: -0.01em;
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out, color var(--dur-fast) ease-out;
}
.tc-insert-tile:hover {
    background: var(--ghost-5);
    color: var(--foreground);
}
.tc-insert-tile svg {
    width: 18px;
    height: 18px;
    display: block;
    opacity: 0.75;
}
.tc-insert-tile:hover svg { opacity: 1; }
.tc-insert-tile[aria-expanded="true"] {
    background: var(--ghost-10);
    color: var(--foreground);
}
/* Nested shape row — expands above the Text/Image/Shape row. */
.tc-insert-shapes {
    display: none;
    align-items: stretch;
    gap: 4px;
    padding-bottom: 4px;
    border-bottom: 1px solid var(--ghost-8);
    margin-bottom: 2px;
}
.tc-insert-shapes[aria-hidden="false"] { display: flex; }
.tc-insert-shapes .tc-insert-tile { height: 40px; width: 46px; }

/* Overview: hide the insert popover if it was open (grid mode is a pick
   surface, not an edit surface). */
body.artboards-overview .tc-insert-popover { display: none; }

/* Overview grid height: percentages don't resolve against the auto-height
   world layer — pin the stack to the viewport height directly. */
.artboard-stack.is-overview { min-height: 100vh; }

/* ═══════════════════════════════════════════════════════════════════════════
   WS6 — DIALOG SYSTEM (SPEC §6): one template behind every popup.
   Structure ported from toolcraft-ref/src/toolcraft/ui/composites/dialog.tsx
   (MIT — attribution in this file's header) as plain HTML/CSS: overlay
   rgba(0,0,0,.72) + blur, --popup-surface content at r-16 / p-16, ghost close
   button top-right, 100ms fade + zoom-95, plus a `sections` variant.

   Mechanics are unchanged: every dialog is still an `.open`-class toggle and
   every panel id survives. `window.PresentaModal` (demo.js) owns the stack —
   z-index is assigned there, so nesting order is data, not CSS.
   ═══════════════════════════════════════════════════════════════════════════ */

.tc-dialog {
    position: fixed;
    inset: 0;
    z-index: 10001;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, 0.72);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--dur-pop) ease-out,
                visibility 0s linear var(--dur-pop);
}
.tc-dialog.open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity var(--dur-pop) ease-out, visibility 0s;
}

/* Content box — r-16, p-16, popup surface, ghost border. */
.tc-dialog-box {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 400px;              /* max-w-sm */
    max-height: calc(100vh - 48px);
    padding: 16px;
    background: var(--popup-surface);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-2xl);
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
    color: var(--foreground);
    text-align: left;
    opacity: 0;
    transform: scale(0.95);
    transition: opacity var(--dur-pop) ease-out, transform var(--dur-pop) ease-out;
}
.tc-dialog.open .tc-dialog-box { opacity: 1; transform: scale(1); }

.tc-dialog-box--md  { max-width: 480px; }
.tc-dialog-box--lg  { max-width: 560px; }
.tc-dialog-box--xl  { max-width: 640px; }
.tc-dialog-box--2xl { max-width: 780px; }

/* `sections` variant: padding moves into the sections, dividers are ghost-8. */
.tc-dialog-box--sections { padding: 0; }
.tc-dialog-box--sections > .tc-dialog-head { padding: 16px 16px 12px; }
.tc-dialog-section {
    padding: 14px 16px;
    border-top: 1px solid var(--ghost-8);
}
.tc-dialog-box--sections > .tc-dialog-body > .tc-dialog-section:first-child,
.tc-dialog-box--sections > .tc-dialog-section:first-child { border-top: none; }
.tc-dialog-section-label {
    display: block;
    margin-bottom: 10px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    text-transform: uppercase;
    color: var(--title);
}

/* Ghost close, top-3 right-3. */
.tc-dialog-close {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 3;
}

.tc-dialog-head {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-right: 32px;           /* clear of the close button */
    margin-bottom: 12px;
}
.tc-dialog-title {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: var(--foreground);
}
.tc-dialog-sub {
    margin: 0;
    font-size: 12px;
    font-weight: 400;
    line-height: 1.5;
    color: var(--muted-foreground);
}

/* Scrollable body with the panel scrollbar treatment. */
.tc-dialog-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}
.tc-dialog-body::-webkit-scrollbar { width: 4px; }
.tc-dialog-body::-webkit-scrollbar-track { background: transparent; }
.tc-dialog-body::-webkit-scrollbar-thumb {
    background: color-mix(in oklab, var(--foreground) 10%, transparent);
    border-radius: var(--r-full);
}
.tc-dialog-body::-webkit-scrollbar-thumb:hover {
    background: color-mix(in oklab, var(--foreground) 20%, transparent);
}

.tc-dialog-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 16px;
}
.tc-dialog-actions--stack { flex-direction: column; align-items: stretch; }
.tc-dialog-actions .tc-btn-outline,
.tc-dialog-actions .tc-btn-brand { flex: 0 0 auto; }

/* Text sheets (Privacy / Terms / License / About copy). */
.tc-dialog-prose {
    font-size: 12.5px;
    line-height: 1.65;
    color: var(--muted-foreground);
}
.tc-dialog-prose h4 {
    margin: 18px 0 6px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.4;
    color: var(--foreground);
}
.tc-dialog-prose h4:first-child { margin-top: 0; }
.tc-dialog-prose p { margin: 0 0 10px; }
.tc-dialog-prose ul { margin: 0 0 10px; padding-left: 18px; list-style: disc; }
.tc-dialog-prose li { margin-bottom: 4px; }
.tc-dialog-prose a { color: var(--foreground); text-decoration: underline; text-underline-offset: 2px; }
.tc-dialog-prose a:hover { color: var(--accent); }
.tc-dialog-prose strong { color: var(--foreground); font-weight: 500; }
.tc-dialog-updated {
    margin: 0 0 14px;
    font-size: 11px;
    color: color-mix(in oklab, var(--muted-foreground) 70%, transparent);
}

/* kbd chip — mono 11px on ghost-5, r-4. */
.tc-kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    background: var(--ghost-5);
    border: 1px solid var(--ghost-8);
    border-radius: var(--r-sm);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 11px;
    font-weight: 500;
    line-height: 1;
    color: var(--foreground);
}

/* Definition rows (shortcuts, about meta, siteshots hints). */
.tc-dialog-list { display: flex; flex-direction: column; gap: 2px; }
.tc-dialog-kv {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 26px;
    padding: 2px 0;
}
.tc-dialog-kv > span:first-child {
    font-size: 12px;
    color: var(--muted-foreground);
}
.tc-dialog-kv-keys {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex: 0 0 auto;
}
.tc-dialog-kv-keys .tc-dialog-kv-plus,
.tc-dialog-kv-keys .tc-dialog-kv-word {
    font-size: 11px;
    color: var(--muted-foreground);
}

/* Link rows — "More by Craftwork", About credits. */
.tc-dialog-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 40px;
    padding: 6px 8px;
    margin: 0 -8px;
    border-radius: var(--r-lg);
    color: var(--foreground);
    text-decoration: none;
    transition: background-color var(--dur-fast) ease-out;
}
.tc-dialog-row:hover { background: var(--ghost-5); }
.tc-dialog-row img,
.tc-dialog-row > svg {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    border-radius: var(--r-xs);
    opacity: 0.75;
}
.tc-dialog-row:hover img,
.tc-dialog-row:hover > svg { opacity: 1; }
.tc-dialog-row-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tc-dialog-row-text > span {
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    color: var(--foreground);
}
.tc-dialog-row-text > small {
    font-size: 11px;
    line-height: 1.3;
    color: var(--muted-foreground);
}
.tc-dialog-row-go {
    margin-left: auto;
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    opacity: 0.4;
}
.tc-dialog-row:hover .tc-dialog-row-go { opacity: 0.8; }

.tc-dialog-divider {
    height: 1px;
    margin: 14px 0;
    background: var(--ghost-8);
}
.tc-dialog-footnote {
    margin: 12px 0 0;
    font-size: 11px;
    line-height: 1.5;
    color: color-mix(in oklab, var(--muted-foreground) 75%, transparent);
}
.tc-dialog-linkrow {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.tc-dialog-linkbtn {
    background: none;
    border: none;
    padding: 0;
    font-size: 11.5px;
    color: var(--muted-foreground);
    cursor: pointer;
    transition: color var(--dur-fast) ease-out;
}
.tc-dialog-linkbtn:hover { color: var(--foreground); }

/* Status chips (changelog kinds). */
.tc-chip {
    display: inline-flex;
    align-items: center;
    height: 18px;
    padding: 0 7px;
    border-radius: var(--r-full);
    font-size: 10.5px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--selection);
    background: var(--selection-bg);
}
.tc-chip--attention {
    color: var(--attention);
    background: color-mix(in oklab, var(--attention) 12%, transparent);
}
.tc-chip--accent {
    color: var(--accent);
    background: rgba(var(--brand-rgb), 0.12);
}

/* ── Dialog-scoped thin-track slider ──────────────────────────────────────
   Mirrors the .panel-scroll-view skin (SPEC §3) for sliders that live in a
   dialog instead of the controls panel (Site Shots count). cssClasses blobs
   in the markup stay byte-identical. */
.tc-dialog .noUi-target {
    height: 18px !important;
    border-radius: 0 !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    cursor: pointer;
    position: relative;
}
.tc-dialog .noUi-base { width: 100%; height: 100% !important; position: relative; z-index: 1; }
.tc-dialog .noUi-origin { height: 100% !important; }
.tc-dialog .noUi-connects {
    position: absolute !important;
    top: 50% !important;
    left: 0;
    right: 0;
    width: auto !important;
    height: 1px !important;
    margin-top: -0.5px;
    border-radius: var(--r-full) !important;
    overflow: hidden;
    background: color-mix(in oklab, var(--muted-foreground) 38%, transparent);
    z-index: 0;
}
.tc-dialog .noUi-connect {
    background: var(--foreground) !important;
    box-shadow: none !important;
    height: 100% !important;
}
.tc-dialog .noUi-handle {
    width: 9px !important;
    height: 9px !important;
    background: var(--foreground) !important;
    border: 0 !important;
    border-radius: var(--r-xs) !important;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4) !important;
    transform: translate(50%, -50%) !important;
    cursor: grab;
    outline: none;
    top: 50% !important;
    transition: transform 120ms var(--ease-snap);
}
.tc-dialog .noUi-handle:hover,
.tc-dialog .noUi-handle:active { transform: translate(50%, -50%) scale(1.4) !important; }
.tc-dialog .noUi-handle:active { cursor: grabbing; }
.tc-dialog .noUi-touch-area {
    width: 200% !important;
    height: 200% !important;
    transform: translate(-25%, -25%);
}
.tc-dialog .noUi-tooltip { display: none !important; }
.tc-dialog .noUi-target,
.tc-dialog .noUi-target * { touch-action: pan-y; }
.tc-dialog .noUi-handle { touch-action: none; }

/* ═══ Shortcuts dialog ═══ */
#shortcuts-panel .tc-dialog-body { padding-bottom: 4px; }

/* ═══ Changelog dialog ═══ */
.changelog-entry {
    padding: 14px 16px;
    border-top: 1px solid var(--ghost-8);
}
.changelog-entry:first-child { border-top: none; }
.changelog-entry-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
}
.changelog-version-num {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    font-weight: 500;
    color: var(--foreground);
}
.changelog-date {
    margin-left: auto;
    font-size: 11px;
    color: var(--muted-foreground);
}
.changelog-entry-title {
    margin: 0 0 4px;
    font-size: 13px;
    font-weight: 500;
    color: var(--foreground);
}
.changelog-entry-desc {
    margin: 0 0 10px;
    font-size: 12px;
    line-height: 1.55;
    color: var(--muted-foreground);
}
.changelog-group { margin-top: 10px; }
.changelog-group > .tc-chip { margin-bottom: 6px; }
.changelog-list { margin: 0; padding-left: 16px; list-style: none; }
.changelog-list li {
    position: relative;
    margin-bottom: 5px;
    font-size: 12px;
    line-height: 1.55;
    color: var(--muted-foreground);
}
.changelog-list li::before {
    content: '';
    position: absolute;
    left: -12px;
    top: 8px;
    width: 3px;
    height: 3px;
    border-radius: var(--r-full);
    background: color-mix(in oklab, var(--muted-foreground) 60%, transparent);
}

/* ═══ About dialog ═══ */
.about-mark {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}
.about-mark svg { width: 26px; height: 26px; color: var(--foreground); }
.about-mark-text { display: flex; flex-direction: column; gap: 1px; }
.about-mark-name { font-size: 14px; font-weight: 600; color: var(--foreground); line-height: 1; }
.about-mark-from { font-size: 11px; color: var(--muted-foreground); line-height: 1; }

/* ═══ Toast — panel-surface pill (SPEC §6) ═══ */
.toast-container {
    position: fixed;
    left: 50%;
    bottom: 64px;
    transform: translateX(-50%);
    z-index: 10050;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    pointer-events: none;
}
.toast {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    max-width: 420px;
    padding: 8px 14px;
    border-radius: var(--r-full);
    background: var(--panel-surface);
    backdrop-filter: blur(40px) saturate(1.5);
    -webkit-backdrop-filter: blur(40px) saturate(1.5);
    border: 1px solid var(--ghost-12);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--foreground);
    pointer-events: auto;
    animation: tcToastIn 180ms var(--ease-snap);
}
.toast-icon {
    display: inline-flex;
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    color: var(--muted-foreground);
}
/* Escape the `[class*="icon-"]` mask/tint rule (style_v17 §258 + output_.css):
   these are real inline SVGs, not mask-icon spans. */
.toast-icon,
.siteshots-generate .ss-cta-icon {
    background-color: transparent;
    -webkit-mask-image: none;
    mask-image: none;
}
.toast-icon svg { width: 16px; height: 16px; }
.toast-success .toast-icon { color: var(--accent); }
.toast-error   .toast-icon { color: var(--destructive); }
.toast-info    .toast-icon { color: var(--selection); }
.toast-exit { animation: tcToastOut 220ms ease-out forwards; }
@keyframes tcToastIn {
    from { opacity: 0; transform: translateY(8px) scale(0.96); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes tcToastOut {
    from { opacity: 1; transform: translateY(0) scale(1); }
    to   { opacity: 0; transform: translateY(6px) scale(0.96); }
}

/* ═══ Context menu — popup-surface rows ═══ */
.context-menu {
    position: fixed;
    z-index: 10060;
    min-width: 176px;
    padding: 4px;
    background: var(--popup-surface);
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    opacity: 0;
    visibility: hidden;
    transform: scale(0.95);
    transform-origin: top left;
    transition: opacity var(--dur-pop) ease-out,
                transform var(--dur-pop) ease-out,
                visibility 0s linear var(--dur-pop);
}
.context-menu.open {
    opacity: 1;
    visibility: visible;
    transform: scale(1);
    transition: opacity var(--dur-pop) ease-out, transform var(--dur-pop) ease-out, visibility 0s;
}
.context-menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 28px;
    padding: 0 8px;
    border-radius: var(--r-md);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--foreground);
    cursor: pointer;
    white-space: nowrap;
    transition: background-color var(--dur-fast) ease-out;
}
.context-menu-item:hover { background: var(--ghost-5); }
.context-menu-item > span:first-child { flex: 1 1 auto; }
.context-menu-hint {
    flex: 0 0 auto;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 11px;
    font-weight: 400;
    color: var(--muted-foreground);
}
.context-menu-divider {
    height: 1px;
    margin: 4px 2px;
    background: var(--ghost-8);
}

/* ═══════════════════════════════════════════════════════════════════════════
   WS6 — STARTER CARD (SPEC §7.3). Replaces #welcome-panel + .canvas-hint +
   .canvas-upload-bar: three overlapping onboarding surfaces collapse to one
   floating card, bottom-center, above the toolbar. Lives OUTSIDE .artboard,
   so renderExport never sees it. `pointer-events` is scoped to the card so a
   closed (or open) starter never swallows a canvas mousedown.
   ═══════════════════════════════════════════════════════════════════════════ */
.tc-starter {
    position: fixed;
    left: 50%;
    bottom: 62px;
    z-index: 60;
    width: 360px;
    max-width: calc(100vw - 20px);
    padding: 14px;
    background: var(--panel-surface);
    backdrop-filter: blur(40px) saturate(1.5);
    -webkit-backdrop-filter: blur(40px) saturate(1.5);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-xl);
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
    color: var(--foreground);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translate(-50%, 8px);
    transition: opacity var(--dur-pop) ease-out,
                transform 220ms var(--ease-snap),
                visibility 0s linear 220ms;
}
.tc-starter.open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translate(-50%, 0);
    transition: opacity var(--dur-pop) ease-out, transform 220ms var(--ease-snap), visibility 0s;
}
.tc-starter[hidden] { display: none; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .tc-starter { background: var(--panel); }
}
.tc-starter-close { position: absolute; top: 8px; right: 8px; }
.tc-starter-title {
    margin: 0 0 2px;
    padding-right: 26px;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--foreground);
}
.tc-starter-sub {
    margin: 0 0 12px;
    font-size: 11.5px;
    line-height: 1.45;
    color: var(--muted-foreground);
}
.tc-starter-block + .tc-starter-block { margin-top: 12px; }
.tc-starter-label {
    display: block;
    margin-bottom: 6px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    text-transform: uppercase;
    color: var(--title);
}
/* Row 1 — drop / paste / upload */
.tc-starter-drop {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px;
    background: var(--ghost-3);
    border: 1px dashed var(--ghost-18);
    border-radius: var(--r-lg);
    color: var(--foreground);
    text-align: left;
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out, border-color var(--dur-fast) ease-out;
}
.tc-starter-drop:hover { background: var(--ghost-5); border-color: var(--ghost-30); }
.tc-starter-drop svg { width: 20px; height: 20px; flex: 0 0 auto; opacity: 0.7; }
.tc-starter-drop-text { display: flex; flex-direction: column; gap: 1px; }
.tc-starter-drop-text > span { font-size: 12px; font-weight: 500; line-height: 1.3; }
.tc-starter-drop-text > small { font-size: 11px; line-height: 1.3; color: var(--muted-foreground); }
/* Row 2 — 4 template thumbs */
.tc-starter-thumbs {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
}
.tc-starter-thumb {
    position: relative;
    aspect-ratio: 4 / 3;
    padding: 0;
    overflow: hidden;
    background: var(--muted);
    border: 1px solid var(--ghost-10);
    border-radius: var(--r-md);
    cursor: pointer;
    transition: border-color var(--dur-fast) ease-out;
}
.tc-starter-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tc-starter-thumb:hover { border-color: var(--ghost-30); }
/* Row 3 — tour */
.tc-starter-tour {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    justify-content: center;
}
.tc-starter-foot {
    margin: 12px 0 0;
    padding-top: 10px;
    border-top: 1px solid var(--ghost-8);
    font-size: 10.5px;
    line-height: 1.5;
    color: color-mix(in oklab, var(--muted-foreground) 78%, transparent);
}
.tc-starter-foot .tc-kbd { height: 16px; min-width: 16px; padding: 0 4px; font-size: 10px; }

/* Guided-tour coach card — a small pinned dialog the user pages through. */
.tc-tour-bar {
    position: fixed;
    left: 50%;
    bottom: 62px;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 14px;
    width: min(420px, calc(100vw - 32px));
    padding: 12px 14px;
    background: var(--panel-surface);
    backdrop-filter: blur(40px) saturate(1.5);
    -webkit-backdrop-filter: blur(40px) saturate(1.5);
    border: 1px solid var(--ghost-12);
    border-radius: 14px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
    transform: translateX(-50%);
    font-size: 12px;
    color: var(--foreground);
}
.tc-tour-bar[hidden] { display: none; }
.tc-tour-close { flex: none; order: 3; }
.tc-tour-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
}
.tc-tour-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}
.tc-tour-step { font-weight: 600; font-size: 13px; color: var(--title); }
.tc-tour-count {
    flex: none;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    color: var(--muted-foreground);
}
.tc-tour-desc {
    margin: 0;
    font-size: 12px;
    line-height: 1.45;
    color: color-mix(in oklab, var(--muted-foreground) 88%, transparent);
}
.tc-tour-track {
    position: relative;
    width: 100%;
    height: 2px;
    margin-top: 2px;
    border-radius: var(--r-full);
    background: var(--ghost-12);
    overflow: hidden;
}
.tc-tour-fill {
    position: absolute;
    inset: 0;
    transform-origin: left center;
    transform: scaleX(0);
    background: var(--accent);
    transition: transform 400ms cubic-bezier(0.4, 0, 0.2, 1);
}
.tc-tour-next {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 34px;
    padding: 0 14px;
    border: none;
    border-radius: var(--r-full);
    background: var(--foreground);
    color: var(--background);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 120ms ease, transform 120ms ease;
}
.tc-tour-next:hover { opacity: 0.88; }
.tc-tour-next:active { transform: scale(0.97); }

/* ═══════════════════════════════════════════════════════════════════════════
   WS6 — TEMPLATES gallery on the dialog template (2-col thumb grid, lime Pro
   dots). Class names are templates.js's contract — reskinned, never renamed.
   ═══════════════════════════════════════════════════════════════════════════ */
#templates-grid { display: flex; flex-direction: column; gap: 18px; }
.templates-section { display: flex; flex-direction: column; gap: 8px; }
.templates-cat {
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    text-transform: uppercase;
    color: var(--title);
}
.templates-cat-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
}
.template-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
}
.template-card__preview {
    position: relative;
    display: block;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background: var(--muted);
    border: 1px solid color-mix(in oklab, var(--border) 10%, transparent);
    border-radius: var(--r-lg);
    transition: border-color var(--dur-fast) ease-out, outline-color var(--dur-fast) ease-out;
    outline: 1px solid transparent;
    outline-offset: 2px;
}
.template-card:hover .template-card__preview {
    border-color: color-mix(in oklab, var(--border) 22%, transparent);
}
.template-card:focus-visible { outline: none; }
.template-card:focus-visible .template-card__preview { outline-color: var(--foreground); }
.template-card__img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Pro tiles: a lime dot badge, not a full pill. */
.template-card__badge {
    position: absolute;
    top: 6px;
    right: 6px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 18px;
    padding: 0 6px 0 5px;
    border-radius: var(--r-full);
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--accent);
}
.template-card__badge svg { width: 10px; height: 10px; }
.template-card__badge::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: var(--r-full);
    background: var(--accent);
    box-shadow: 0 0 6px rgba(var(--brand-rgb), 0.8);
}
.template-card__name {
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    color: var(--muted-foreground);
}
.template-card:hover .template-card__name { color: var(--foreground); }

/* ═══════════════════════════════════════════════════════════════════════════
   WS6 — SITE SHOTS on the dialog template (max-w-xl). All siteshots-* ids
   are pro.js's contract and survive untouched.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Showcase collage — one URL becomes a whole collection. Two desktop shots
   fan out behind, angled to opposite edges; the phone stands upright in front.
   The mixed desktop/phone ratios become a feature (a layered set) instead of
   a problem (three mismatched crops in a flat grid). Sits on a soft gradient
   bar so the colourful cards pop. */
.siteshots-examples {
    position: relative;
    height: 192px;
    margin-bottom: 18px;
    border-radius: 14px;
    overflow: hidden;
    border: 1px solid var(--ghost-10);
    background:
        radial-gradient(120% 150% at 12% -10%, rgba(150, 130, 255, 0.16), transparent 55%),
        radial-gradient(120% 150% at 92% 110%, rgba(255, 120, 190, 0.14), transparent 55%),
        linear-gradient(160deg, #18181d, #101013);
    display: flex;
    align-items: center;
    justify-content: center;
    perspective: 1100px;
}
.ss-shot {
    position: absolute;
    margin: 0;
    overflow: hidden;
    background: var(--muted);
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 10px;
    box-shadow: 0 18px 40px -12px rgba(0, 0, 0, 0.65);
    transition: transform 320ms var(--ease-snap), box-shadow 320ms var(--ease-snap);
}
.ss-shot img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ss-shot--desk { width: 208px; height: 130px; }
.ss-shot--desk img { object-position: left top; }
.ss-shot--left  { transform: translate(-60%, -7%) rotateY(16deg) rotate(-4deg); z-index: 1; }
.ss-shot--right { transform: translate(60%, 9%) rotateY(-16deg) rotate(4deg); z-index: 1; }
.ss-shot--right img { object-position: right top; }
.ss-shot--phone {
    width: 104px;
    height: 178px;
    z-index: 3;
    box-shadow: 0 22px 44px -10px rgba(0, 0, 0, 0.7);
}
.ss-shot--phone img { object-position: center; }
/* the collection fans open slightly on hover */
.siteshots-examples:hover .ss-shot--left  { transform: translate(-66%, -7%) rotateY(12deg) rotate(-5deg); }
.siteshots-examples:hover .ss-shot--right { transform: translate(66%, 9%) rotateY(-12deg) rotate(5deg); }
.siteshots-examples:hover .ss-shot--phone { transform: translateY(-5px); }
.siteshots-field + .siteshots-field { margin-top: 14px; }
.siteshots-field .tc-dialog-section-label { margin-bottom: 8px; }
.siteshots-field.siteshots-size-row[hidden] { display: none; }
.siteshots-mode-hint {
    margin: 6px 0 0;
    font-size: 11px;
    line-height: 1.45;
    color: var(--muted-foreground);
}
/* Mode segmented — pro.js toggles .is-active on .siteshots-mode-btn. */
.siteshots-mode {
    display: flex;
    width: 100%;
    background: var(--ghost-5);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    overflow: hidden;
    isolation: isolate;
}
.siteshots-mode-btn {
    flex: 1 1 0;
    height: 28px;
    padding: 0 8px;
    /* spans now (see index.html note) — restore button-like centering */
    display: flex;
    align-items: center;
    justify-content: center;
    user-select: none;
    /* appearance:none is load-bearing: without it Chrome paints the native
       light button face UNDER the transparent author background — the inactive
       segment rendered near-white on the dark dialog. */
    -webkit-appearance: none;
    appearance: none;
    /* SOLID fills (not transparent-over-container): an unexplained light
       phantom kept rendering under transparent segments in this dialog —
       opaque paint + z above ends it deterministically. */
    position: relative;
    z-index: 1;
    background: var(--popover);
    border: none;
    font-size: 12px;
    font-weight: 400;
    color: var(--muted-foreground);
    cursor: pointer;
    transition: color var(--dur-fast) ease-out, background-color var(--dur-fast) ease-out;
}
.siteshots-mode-btn + .siteshots-mode-btn { border-left: 1px solid var(--ghost-8); }
.siteshots-mode-btn:hover:not(.is-active) { color: var(--foreground); background: color-mix(in oklab, var(--foreground) 4%, var(--popover)); }
.siteshots-mode-btn.is-active { background: color-mix(in oklab, var(--selection) 14%, var(--popover)); color: var(--foreground); }
.siteshots-mode-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.siteshots-mode-btn:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
/* Size select — FlyonUI dropdown, reskinned onto the .tc-select look. */
.ss-size-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    height: 28px;
    padding: 0 8px;
    background: var(--ghost-5);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    font-size: 12px;
    color: var(--foreground);
    cursor: pointer;
    transition: border-color var(--dur-fast) ease-out;
}
.ss-size-toggle:hover { border-color: var(--ghost-20); }
.ss-size-toggle[aria-expanded="true"] { border-color: var(--ghost-30); }
.ss-size-glass {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 13px;
    flex: 0 0 auto;
}
.ss-size-preview-shape {
    display: block;
    background: color-mix(in oklab, var(--foreground) 45%, transparent);
    border-radius: 1px;
}
.ss-size-toggle-text { display: inline-flex; align-items: baseline; gap: 6px; min-width: 0; }
.ss-size-toggle-title { font-size: 12px; color: var(--foreground); }
.ss-size-toggle-sub {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 11px;
    color: var(--muted-foreground);
}
.ss-size-chevron { opacity: 0.6; transition: transform var(--dur-fast) ease-out; }
.ss-size-toggle[aria-expanded="true"] .ss-size-chevron { transform: rotate(180deg); }
.ss-size-menu {
    z-index: 10070;
    min-width: 100%;
    max-height: 260px;
    overflow-y: auto;
    padding: 4px;
    background: var(--popup-surface);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}
.ss-size-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    height: 28px;
    padding: 0 8px;
    background: none;
    border: none;
    border-radius: var(--r-md);
    font-size: 12px;
    color: var(--foreground);
    cursor: pointer;
    transition: background-color var(--dur-fast) ease-out;
}
.ss-size-option:hover { background: var(--ghost-5); }
.ss-size-option.is-active { background: var(--selection-bg); }
.ss-size-dims {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 11px;
    color: var(--muted-foreground);
}
/* Progress — a lime hairline per step, not a spinner stack. */
.siteshots-steps {
    display: flex;
    gap: 6px;
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
}
.siteshots-steps[hidden] { display: none; }
.siteshots-steps li {
    flex: 1 1 0;
    padding-top: 8px;
    border-top: 2px solid var(--ghost-12);
    font-size: 11px;
    color: var(--muted-foreground);
    transition: border-color 260ms ease-out, color var(--dur-fast) ease-out;
}
.siteshots-steps li.is-active {
    border-top-color: var(--accent);
    color: var(--foreground);
}
.siteshots-steps li.is-done {
    border-top-color: rgba(var(--brand-rgb), 0.45);
    color: var(--muted-foreground);
}
.siteshots-step-icon { display: none; }
.siteshots-generate { width: 100%; margin-top: 16px; }
.siteshots-generate:disabled { opacity: 0.55; cursor: not-allowed; }
.siteshots-generate .ss-cta-icon { width: 16px; height: 16px; flex: 0 0 auto; }
.siteshots-generate .ss-cta-icon-lock { display: none; }
.siteshots-generate.is-locked .ss-cta-icon-generate { display: none; }
.siteshots-generate.is-locked .ss-cta-icon-lock { display: inline-flex; }
.siteshots-build-overlay {
    position: fixed;
    inset: 0;
    z-index: 10080;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.72);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    opacity: 0;
    transition: opacity var(--dur-pop) ease-out;
    pointer-events: none;
}
.siteshots-build-overlay.is-visible { opacity: 1; pointer-events: auto; }
.siteshots-build-overlay__inner { text-align: center; }
.siteshots-build-overlay__spinner {
    display: block;
    width: 28px;
    height: 28px;
    margin: 0 auto 14px;
    border: 2px solid var(--ghost-12);
    border-top-color: var(--accent);
    border-radius: var(--r-full);
    animation: tcSpin 700ms linear infinite;
}
@keyframes tcSpin { to { transform: rotate(360deg); } }
.siteshots-build-overlay__title {
    margin: 0 0 4px;
    font-size: 13px;
    font-weight: 500;
    color: var(--foreground);
}
.siteshots-build-overlay__sub { margin: 0; font-size: 12px; color: var(--muted-foreground); }

/* ═══════════════════════════════════════════════════════════════════════════
   WS6 — PRO panel: template-level reskin only. The full paywall rebuild
   (SPEC §11) is WS9; every pro-* id and pro.js view-switching stays as-is.
   ═══════════════════════════════════════════════════════════════════════════ */
.pro-view[hidden] { display: none; }
.pro-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 18px;
    padding: 0 7px;
    margin-bottom: 10px;
    border-radius: var(--r-full);
    background: rgba(var(--brand-rgb), 0.12);
    border: 1px solid rgba(var(--brand-rgb), 0.28);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--accent);
}
.pro-eyebrow svg { flex-shrink: 0; }
/* The dialog head is a column flexbox — keep the chip hugging its content. */
.tc-dialog-head > .pro-eyebrow { align-self: flex-start; }
.pro-title {
    margin: 0 0 4px;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--foreground);
}
.pro-sub {
    margin: 0 0 14px;
    font-size: 12px;
    line-height: 1.55;
    color: var(--muted-foreground);
}
.pro-checklist { margin: 0 0 16px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 7px; }
.pro-checklist li {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--muted-foreground);
}
.pro-checklist li svg { flex: 0 0 auto; width: 14px; height: 14px; margin-top: 3px; color: var(--accent); }
.pro-plans { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.pro-plan-card {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    background: var(--ghost-5);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    color: var(--foreground);
    text-align: left;
    cursor: pointer;
    transition: border-color var(--dur-fast) ease-out, background-color var(--dur-fast) ease-out;
}
.pro-plan-card:hover { border-color: var(--ghost-20); }
.pro-plan-card.is-selected { border-color: var(--ghost-30); background: var(--selection-bg); }
.pro-plan-radio {
    position: relative;
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    border: 1px solid var(--ghost-30);
    border-radius: var(--r-full);
}
.pro-plan-card.is-selected .pro-plan-radio { border-color: var(--accent); }
.pro-plan-card.is-selected .pro-plan-radio::after {
    content: '';
    position: absolute;
    inset: 3px;
    border-radius: var(--r-full);
    background: var(--accent);
}
.pro-plan-head { display: flex; align-items: center; gap: 6px; }
.pro-plan-name { font-size: 12px; font-weight: 500; }
.pro-plan-tag {
    display: inline-flex;
    align-items: center;
    height: 16px;
    padding: 0 6px;
    border-radius: var(--r-full);
    background: rgba(var(--brand-rgb), 0.12);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--accent);
}
.pro-plan-price { margin-left: auto; display: flex; align-items: baseline; gap: 2px; }
.pro-plan-amount { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 14px; font-weight: 500; }
.pro-plan-period { font-size: 11px; color: var(--muted-foreground); }
.pro-cta { width: 100%; }
.pro-ghost-link {
    display: block;
    width: 100%;
    margin-top: 10px;
    padding: 0;
    background: none;
    border: none;
    font-size: 11.5px;
    color: var(--muted-foreground);
    text-align: center;
    cursor: pointer;
    transition: color var(--dur-fast) ease-out;
}
.pro-ghost-link:hover { color: var(--foreground); }
.pro-footnote {
    margin: 12px 0 0;
    font-size: 11px;
    line-height: 1.5;
    text-align: center;
    color: color-mix(in oklab, var(--muted-foreground) 75%, transparent);
}
.pro-back-link { margin: 0 0 14px; text-align: left; }
.pro-field-label {
    display: block;
    margin-bottom: 6px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    text-transform: uppercase;
    color: var(--title);
}
.pro-key-input {
    width: 100%;
    height: 32px;
    padding: 0 10px;
    background: var(--ghost-5);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    color: var(--foreground);
    outline: none;
    transition: border-color var(--dur-fast) ease-out;
}
.pro-key-input::placeholder { color: var(--muted-foreground); }
.pro-key-input:hover { border-color: var(--ghost-20); }
.pro-key-input:focus { border-color: var(--ghost-30); }
.pro-status { margin: 10px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--muted-foreground); }
.pro-status.is-error { color: var(--destructive); }
.pro-status.is-success { color: var(--accent); }
.pro-active-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    margin-bottom: 12px;
    border-radius: var(--r-full);
    background: rgba(var(--brand-rgb), 0.12);
    color: var(--accent);
}
.pro-key-masked {
    padding: 8px 10px;
    margin-bottom: 14px;
    background: var(--ghost-5);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 12px;
    color: var(--muted-foreground);
}
.pro-active-actions { display: flex; flex-direction: column; gap: 8px; }
.pro-active-actions .tc-btn-outline { width: 100%; }
.pro-trial-note {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 10px;
    margin-bottom: 14px;
    background: var(--ghost-3);
    border: 1px solid var(--ghost-8);
    border-radius: var(--r-lg);
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--muted-foreground);
}
.pro-trial-note[hidden] { display: none; }
.pro-trial-note svg { flex: 0 0 auto; margin-top: 2px; color: var(--accent); }

/* ═══ Below-1200px alert — on the dialog template (mobile out of scope) ═══ */
.adaptive-alert {
    position: fixed;
    inset: 0;
    z-index: 10090;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, 0.72);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
/* Visibility is still the @media (max-width:1000px) rule further up, which
   overrides Tailwind's `.hidden` on this node — the box just needs to opt out
   of the dialog's enter animation since it has no `.open` ancestor. */
.adaptive-alert .tc-dialog-box { opacity: 1; transform: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   WS4 — Panel sections (SPEC §4 anatomy).
   `.tc-section` wraps existing control markup; collapse state persists to
   localStorage['presenta_ui_sections'] via controls-manifest.js (UI pref,
   never artboard state). Per-section reset is manifest-driven.
   ═══════════════════════════════════════════════════════════════════════════ */
.tc-section {
    /* No compensating margins: the .sidebar-form wrapper is zero-padding /
       zero-gap now (polish 3) — the old -12px inline bleed made sections
       overhang the panel's LEFT edge and leave a dead strip on the right. */
    margin-inline: 0;
    border-top: 1px solid var(--ghost-8);
    display: flex;
    flex-direction: column;
}
.tc-section + .tc-section { margin-top: 0; }
.tc-section:first-child { border-top: none; }
/* No section-wide hover band: it read as a stuck lighter strip on whichever
   section the cursor happened to rest over (user-reported). The reset/caret
   icons still reveal on hover via the rules below. */

.tc-section-header {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 36px;
    flex: none;
    padding-inline: 12px;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    background: transparent;
    border: none;
    width: 100%;
    text-align: left;
    transition: background-color var(--dur-fast) ease-out;
}
/* The title is its own button so the reset/caret buttons stay valid siblings
   (no nested <button>). It fills the header row. */
.tc-section-toggle {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    height: 100%;
    padding: 0;
    background: transparent;
    border: none;
    cursor: pointer;
    text-align: left;
}
.tc-section-title {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    text-transform: uppercase;
    color: var(--title);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tc-section-header .tc-icon-btn { flex: none; }
/* Reset ↺ appears on section hover / keyboard focus only. */
.tc-section-reset { opacity: 0; transition: opacity var(--dur-fast) ease-out; }
.tc-section:hover .tc-section-reset,
.tc-section:focus-within .tc-section-reset { opacity: 1; }
.tc-section-reset.is-spinning svg {
    transition: transform var(--dur-spin) var(--ease-snap);
    transform: rotate(-360deg);
}
.tc-section-caret svg { transition: transform var(--dur-collapse) ease-out; }
.tc-section.is-collapsed .tc-section-caret svg { transform: rotate(-90deg); }

/* Empty collection section (TEXT / IMAGES / SHAPES with nothing added):
   nothing to expand, so the caret reads as inert and only "+" stays live.
   The reset ↺ is meaningless with no elements — keep it fully hidden. */
.tc-section.is-empty .tc-section-caret {
    opacity: 0.28;
    pointer-events: none;
    cursor: default;
}
.tc-section.is-empty .tc-section-toggle { cursor: default; }
.tc-section.is-empty .tc-section-reset,
.tc-section.is-empty:hover .tc-section-reset,
.tc-section.is-empty:focus-within .tc-section-reset {
    opacity: 0;
    pointer-events: none;
}

/* 180ms grid-rows collapse (SPEC #1.4). */
.tc-section-body {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows var(--dur-collapse) ease-out;
}
.tc-section.is-collapsed > .tc-section-body { grid-template-rows: 0fr; }
.tc-section-body > .tc-section-body-inner {
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 8px 12px 24px;
}
.tc-section.is-collapsed > .tc-section-body > .tc-section-body-inner {
    /* Kill the residual padding so a collapsed section is exactly the header. */
    padding-top: 0;
    padding-bottom: 0;
}
/* controls-manifest.js adds this to #controls-panel for one frame while it
   restores persisted collapse state, so a section saved collapsed does not
   animate open→closed on load. */
.tc-collapse-init .tc-section-body,
.tc-collapse-init .tc-section-caret svg { transition: none !important; }
/* Field label above a non-slider control. */
.tc-field-label {
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    color: var(--label);
}
.tc-field { display: flex; flex-direction: column; gap: 6px; }
.tc-row { display: flex; align-items: center; gap: 8px; }
.tc-row > * { min-width: 0; }
/* Vertical divider separating value inputs from a trailing action (e.g. the
   Size row's W/H fields vs the Apply button) so they don't read as one glued
   cluster. Sits inside .tc-row, gets its own 8px gap on both sides. */
.tc-row-divider {
  flex: 0 0 auto;
  align-self: stretch;
  width: 1px;
  margin: 3px 2px;
  background: var(--border-default);
}
/* hide-don't-disable: conditional controls keep their values in the DOM. */
.tc-hidden { display: none !important; }

/* Radio-backed segmented item (border / format / treatment): the label IS the
   face, the radio stays in the DOM as the state carrier. */
label.tc-seg-item { position: relative; }
label.tc-seg-item:has(> input:checked) {
    color: var(--foreground);
    background: var(--selection-bg);
}
.tc-seg-item > input.sr-only,
.tc-seg-item > input.radio {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── SETUP ── */
.tc-select-menu .canvas-size-group + .canvas-size-group { margin-top: 2px; }

/* ── MOCKUP: device panels inline (were inside the layout dropdown) ── */
.tc-device-panels {
    height: 236px;
    min-height: 0;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    background: var(--ghost-3);
    padding: 6px;
}
.tc-device-panels .customScrollbar { padding-right: 2px; }
/* The legacy layout dropdown trigger survives as a state carrier — demo.js
   writes the current layout/device preview into .button-layout*. */
.tc-legacy-carrier { display: none !important; }
/* Thumbnail selection per SPEC §3: 1px white outline offset 2px (overrides
   the lime ring in devices.css without editing that file). */
.studio-sidebar .device-grid-item.active {
    border-color: var(--ghost-20);
    box-shadow: none;
    outline: 1px solid var(--foreground);
    outline-offset: 2px;
}
.studio-sidebar .device-grid-item { background: var(--muted); }

/* ── SCREEN ── */
.tc-screen-slots { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.tc-screen-slots[data-slots="1"] { grid-template-columns: 1fr; }
.tc-screen-slots[data-slots="2"] { grid-template-columns: repeat(2, 1fr); }
.tc-screen-slot {
    position: relative;
    aspect-ratio: 4 / 3;
    border: 1px dashed var(--ghost-18);
    border-radius: var(--r-lg);
    background: var(--ghost-3);
    color: var(--muted-foreground);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    overflow: hidden;
    padding: 0;
    transition: border-color var(--dur-fast) ease-out, background-color var(--dur-fast) ease-out, color var(--dur-fast) ease-out;
}
.tc-screen-slot:hover { border-color: var(--ghost-30); color: var(--foreground); }
.tc-screen-slot.is-dragover {
    border-color: color-mix(in oklab, var(--selection) 28%, transparent);
    background: color-mix(in oklab, var(--selection) 13%, transparent);
    color: var(--foreground);
}
.tc-screen-slot.is-filled { border-style: solid; border-color: var(--ghost-12); }
.tc-screen-slot img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
    border-radius: var(--r-sm);
    display: block;
}
.tc-screen-slot svg { width: 20px; height: 20px; opacity: 0.7; }
.tc-screen-slot-idx {
    position: absolute;
    left: 4px;
    bottom: 4px;
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
    padding: 2px 4px;
    border-radius: var(--r-xs);
    background: color-mix(in oklab, #000 55%, transparent);
    color: var(--foreground);
    pointer-events: none;
}
.tc-screen-slot-clear {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 18px;
    height: 18px;
    display: none;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--r-sm);
    background: color-mix(in oklab, #000 55%, transparent);
    color: var(--foreground);
    cursor: pointer;
}
.tc-screen-slot.is-filled .tc-screen-slot-clear { display: flex; }
.tc-screen-slot-clear svg { width: 12px; height: 12px; opacity: 0.85; }
.tc-screen-slot-clear:hover svg { opacity: 1; }
/* Treatment segmented: 5 icon-only items, tooltip via title. */
#screen-treatment .tc-seg-item { padding: 0 4px; font-size: 11px; }

/* ── STYLE: the three legacy `flex gap-3` rows pass through to one 3-col grid
   so the radio labels keep their exact DOM position. ── */
.tc-grid-passthrough { display: contents; }
.tc-thumb-grid .flex.flex-col.gap-2.flex-1 { padding: 0; }

/* ── FRAME ── */
#border-segmented .tc-seg-item { font-size: 11px; padding: 0 4px; }
/* The color control also renders as read-only spans (stroke trigger) — keep
   the text vertically centred in the 28px row. */
span.tc-color-hex, span.tc-color-alpha {
    display: flex;
    align-items: center;
    white-space: nowrap;
    overflow: hidden;
}
span.tc-color-alpha { justify-content: flex-end; }
button.tc-color-control { cursor: pointer; text-align: left; }

/* ── WS4a war-zone dissolution (scoped to the five rebuilt sections) ── */

/* Beat the legacy `.studio-sidebar input {… !important}` light-theme rule so
   the tc-input skin actually lands on SETUP / MOCKUP fields. */
.studio-sidebar input.tc-input {
    background: var(--ghost-5) !important;
    border-color: var(--ghost-12) !important;
    color: var(--foreground) !important;
    border-radius: var(--r-lg) !important;
}
.studio-sidebar input.tc-input:hover { border-color: var(--ghost-20) !important; }
.studio-sidebar input.tc-input:focus {
    border-color: var(--ghost-30) !important;
    box-shadow: none !important;
}
/* The generic `.studio-sidebar input:not(…)` rule (line 2834) carries an
   opaque --bg-input at specificity 0,7,1 — so the inner input of a group kept
   a solid fill whose square corners showed through the group's rounding as a
   seam. Match that :not chain here to out-specify it and let the group own the
   background + radius. */
.studio-sidebar .tc-input-group input.tc-input:not([type="radio"]):not([type="checkbox"]):not([type="range"]):not([type="file"]):not([type="hidden"]),
.studio-sidebar .tc-input-group input.tc-input:not([type="radio"]):not([type="checkbox"]):not([type="range"]):not([type="file"]):not([type="hidden"]):hover,
.studio-sidebar .tc-input-group input.tc-input:not([type="radio"]):not([type="checkbox"]):not([type="range"]):not([type="file"]):not([type="hidden"]):focus {
    background: transparent !important;
    border-color: transparent !important;
    border-radius: 0 !important;
    box-shadow: none !important;
}
/* Number spinners are noise at 12px mono. */
.tc-input[type="number"]::-webkit-outer-spin-button,
.tc-input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.tc-input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

/* SETUP: the aspect select trigger keeps its ratio-glass preview. */
.tc-select-trigger .canvas-size-glass { flex: none; }
.tc-select-trigger .canvas-size-toggle-text {
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
}
.tc-select-trigger .canvas-size-toggle-title {
    font-size: 12px;
    color: var(--foreground);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tc-select-trigger .canvas-size-toggle-subtitle {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 11px;
    color: var(--muted-foreground);
    white-space: nowrap;
}

/* MOCKUP: the unwrapped layout dropdown body. */
.tc-mockup-panel {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}
.tc-mockup-panel .device-panels-wrapper {
    height: 236px;
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-lg);
    background: var(--ghost-3);
    padding: 6px;
}
/* Category tablist re-expressed as select rows (the pill strip in devices.css
   is left untouched — it just never renders in that context any more). */
.tc-select-menu .device-category-tabs {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 0;
    overflow: visible;
}
.tc-select-menu .device-category-tab {
    width: 100%;
    justify-content: flex-start;
    gap: 8px;
    padding: 6px 8px;
    border-radius: var(--r-md);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--foreground);
    background: transparent;
    transition: background-color var(--dur-fast) ease-out;
}
.tc-select-menu .device-category-tab svg { opacity: 0.7; }
.tc-select-menu .device-category-tab:hover { background: var(--ghost-5); }
.tc-select-menu .device-category-tab.active { background: var(--selection-bg); }
.tc-select-menu .device-category-tab.active svg { opacity: 1; }

/* MOCKUP: custom-ratio quick presets as ghost chips. */
.custom-ratio-preset {
    height: 22px;
    padding: 0 8px;
    font-size: 11px;
    font-weight: 500;
    line-height: 1;
    color: var(--muted-foreground);
    background: var(--ghost-5);
    border: 1px solid var(--ghost-12);
    border-radius: var(--r-md);
    cursor: pointer;
    transition: color var(--dur-fast) ease-out, border-color var(--dur-fast) ease-out;
}
.custom-ratio-preset:hover { color: var(--foreground); border-color: var(--ghost-20); }

/* SCREEN: keep the transform row's three buttons even. */
#screen-transform-row .tc-btn-outline { flex: 1 1 0; min-width: 0; }

/* ─── WS5 — Export settings menu on the dark popup surface ────────────────────
 * The format/resolution popover was bg-white (a light-theme leak next to the
 * lime Export pill). Reskin the container to the dark popup surface; the
 * format/resolution segmented radios inside keep the existing
 * .studio-sidebar .export-tab-group styling. */
.tc-export-menu {
  background: var(--popup-surface, var(--popover, #171717)) !important;
  -webkit-backdrop-filter: blur(24px) saturate(1.4);
  backdrop-filter: blur(24px) saturate(1.4);
  border: 1px solid var(--ghost-12) !important;
  color: var(--foreground);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.3);
}
.tc-export-menu .text-icons-tertiary { color: var(--title); }

/* WS5 — lime indeterminate progress hairline on the sticky export footer while
 * an export/copy runs (setExportLoading toggles .is-exporting). */
.export-footer-progress {
  position: absolute; top: 0; left: 0; height: 2px; width: 40%;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: 0; pointer-events: none; will-change: transform;
  transition: opacity 150ms ease;
}
#export-actions-row.is-exporting .export-footer-progress {
  opacity: 1; animation: exportProgressSlide 0.9s linear infinite;
}
@keyframes exportProgressSlide {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(360%); }
}

/* ── Panel layout normalization (user-reported spacing/loading fixes) ───────
 * 1. The legacy sidebar wrapper kept Tailwind px-5/pt-5/gap-5 — 20px gaps
 *    BETWEEN sections on top of the sections' own borders/padding read as
 *    random indents. Sections sit flush (SPEC §4); they carry their own
 *    12px inline padding.
 * 2. The inline layouts panel (#tabs-segment-1, ex-dropdown content) used
 *    flex-1 and stretched into a giant empty box — cap it, inner scrolls. */
.studio-sidebar .sidebar-form.panel-scroll-view {
  padding: 0 !important;
  gap: 0 !important;
}
.studio-sidebar #tabs-segment-1 { max-height: 380px; }

/* The dropdown-era loading overlay is obsolete inline — kill it at the CSS
 * level so even a stale cached demo.js can never show the eternal loader
 * over the layout previews. */
#preloader-segment-item-1 { display: none !important; }

/* The Controls panel scroller is .tc-panel-content (WS3 shell) — its
 * scrollbar was unstyled (default ~13px gutter read as dead space to the
 * right of the sections). SPEC §1.4: 4px, subtle thumb. */
.studio-sidebar .tc-panel-content::-webkit-scrollbar { width: 4px; }
.studio-sidebar .tc-panel-content::-webkit-scrollbar-track { background: transparent; }
.studio-sidebar .tc-panel-content::-webkit-scrollbar-thumb {
  background: color-mix(in oklab, var(--foreground) 10%, transparent);
  border-radius: var(--r-full);
}
.studio-sidebar .tc-panel-content::-webkit-scrollbar-thumb:hover {
  background: color-mix(in oklab, var(--foreground) 18%, transparent);
}

/* Chromium paints a native light widget face under buttons that rely on
 * transparent backgrounds (seen on the Site Shots segmented and the SETUP
 * Apply). Kill native appearance for every button in the app chrome. */
.studio-sidebar button,
.tc-dialog button,
.tc-panel button,
.tc-toolbar button {
  -webkit-appearance: none;
  appearance: none;
}

/* Boot guard: no transitions while the first layout settles — the artboard
 * letterbox + panel init caused a visible jump on load. demo.js removes
 * .tc-boot shortly after the load phase. */
body.tc-boot .viewport-world,
body.tc-boot .artboard,
body.tc-boot .mockup-module,
body.tc-boot .tc-section-body,
body.tc-boot .tc-panel {
  transition: none !important;
  animation: none !important;
}

/* ── Panel audit fixes (hand pass) ──────────────────────────────────────────
 * 1. Open dropdown menus must paint ABOVE later sections: several conditional
 *    fields kept legacy z-[100] stacking, while FlyonUI menus resolve ~z-10 —
 *    an open Aspect/category menu was being overprinted by the sections below.
 * 2. Slider thumbs: enforce the canonical white 9px square thumb cascade-last —
 *    some sliders were resolving a dark --muted thumb from an older rule.
 * 3. Promo/about logos (Storytale/Circa favicons) are dark marks on the dark
 *    surface — normalize them to white silhouettes. */
.studio-sidebar .dropdown-menu,
.tc-select-menu {
  z-index: 320 !important;
}
.studio-sidebar .noUi-handle.noUi-handle,
.studio-sidebar .dropdown-menu .noUi-handle {
  width: 9px !important;
  height: 9px !important;
  background: var(--foreground) !important;
  border: 0 !important;
  border-radius: var(--r-xs) !important;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4) !important;
}
.tc-promo-favicon,
#about-panel .tc-dialog-row img {
  filter: grayscale(1) brightness(0) invert(1);
  opacity: 0.92;
}
/* 4. Device category panels: devices.css (loaded AFTER this file) hides
 *    inactive panels via opacity/visibility only — visibility:hidden boxes
 *    still occupy layout, so every panel reserved ~700px of empty space in
 *    the flowing panel (the giant empty box in MOCKUP). Beat it on
 *    specificity: inactive panels are display:none; only .active flows. */
.studio-sidebar .device-category-panel {
  display: none;
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: none;
}
.studio-sidebar .device-category-panel.active { display: flex; flex-direction: column; min-height: 0; }

/* ── WS7b(2): BakeLab generative preset tiles (thumbnail grid, SPEC §3) ── */
.bg-gen-tile {
  aspect-ratio: 3 / 2;
  border-radius: var(--r-lg, 8px);
  background-size: cover;
  background-position: center;
  background-color: var(--muted, #262626);
  border: 1px solid var(--ghost-10, rgba(255, 255, 255, 0.10));
  outline: 1px solid transparent;
  outline-offset: 2px;
  cursor: pointer;
  transition: outline-color 150ms ease-out, border-color 150ms ease-out;
}
.bg-gen-tile:hover { border-color: var(--ghost-20, rgba(255, 255, 255, 0.20)); }
.bg-gen-tile.is-selected { outline-color: var(--foreground, #fafafa); }

/* ═══ Polish(7) — user punch list (Jul 31): gray actives, white export,
   deterministic menu geometry, segmented corners, Size row ═══ */

/* 1. Active fills: light-gray instead of the dark-blue selection tint —
      applies to segmented actives, select rows, size options, category rows.
      (Canvas element selection keeps blue; this is UI chrome only.) */
:root { --active-bg: color-mix(in oklab, var(--foreground) 11%, transparent); }
.tc-seg-item.active,
.tc-seg-item[aria-selected="true"],
label.tc-seg-item:has(> input:checked) { background: var(--active-bg); }
.tc-select-menu .device-category-tab.active { background: var(--active-bg); }
.canvas-size-option.canvas-size-active { background: var(--active-bg); }
.siteshots-mode-btn.is-active { background: color-mix(in oklab, var(--foreground) 11%, var(--popover)); }
/* Selected tiles (devices / layouts / styles): white outline, not violet. */
.studio-sidebar .custom-option:has(:checked) {
  border-color: color-mix(in oklab, var(--foreground) 55%, transparent) !important;
  outline-color: color-mix(in oklab, var(--foreground) 55%, transparent) !important;
}

/* 2. Select menus: EXACTLY the panel's inner width — no viewport-relative
      sizing (strategy:fixed made % viewport-based: the Aspect menu overhung
      the sidebar's right edge, the category menu came up short). Height
      capped, inner scroll. */
.studio-sidebar .tc-select-menu {
  width: 294px !important;
  min-width: 294px !important;
  max-width: 294px !important;
  max-height: min(480px, 62vh) !important; /* beats the JS popover clamp's inline maxHeight */
  overflow-y: auto;
}
.studio-sidebar .tc-select-menu::-webkit-scrollbar { width: 4px; }
.studio-sidebar .tc-select-menu::-webkit-scrollbar-thumb {
  background: color-mix(in oklab, var(--foreground) 10%, transparent);
  border-radius: var(--r-full);
}

/* 3. Segmented corners: container clips, items never carry their own radius —
      kills the mismatched rounding on FRAME Sharp/Curved/Round and Solid/Dashed. */
.tc-segmented {
  border-radius: var(--r-lg);
  overflow: hidden;
}
.tc-segmented .tc-seg-item { border-radius: 0 !important; }

/* 4. Size row: Apply matches the inputs (28px, r-8, real padding), units one
      color, inputs one radius. */
.canvas-size-custom-apply,
#canvas-size-custom-apply {
  height: 28px !important;
  padding: 0 14px !important;
  border-radius: var(--r-lg) !important;
  font-size: 12px;
  font-weight: 500;
  background: color-mix(in oklab, var(--foreground) 10%, transparent);
}
.canvas-size-custom-apply:hover { background: color-mix(in oklab, var(--foreground) 16%, transparent); }
.canvas-size-custom-row input[type="number"] { border-radius: var(--r-lg) !important; }
.tc-input-group .tc-input-unit { color: var(--muted-foreground) !important; }

/* 5. Export split button: WHITE primary (user call — lime retires here),
      dark label, caret shares the face with a hairline divider. */
.export-button {
  background: var(--foreground) !important;
  color: #141414 !important;
  box-shadow: none !important;
}
.export-button:hover { background: #ffffff !important; }
.export-button .icon-download { filter: brightness(0); }
.export-dropdown-trigger {
  background: var(--foreground) !important;
  color: #141414 !important;
  border-left: 1px solid rgba(0, 0, 0, 0.18) !important;
}
.export-dropdown-trigger:hover { background: #ffffff !important; }
.export-dropdown-trigger .icon-dropdown { filter: brightness(0); }
#file-format { color: #141414 !important; }

/* 6. Layouts panel aligns to the same 13px content grid as everything else. */
.studio-sidebar #tabs-segment-1 { margin-inline: -7px; }

/* ═══ Polish(8) — mockup picker as a dropdown + Aspect trigger + slots +
   color popover fit (user punch list, Aug 1) ═══ */

/* Category tabs render horizontally at the top of the device menu. */
.tc-select-menu .device-category-tabs {
  display: flex !important;
  flex-direction: row !important;
  gap: 0;
  padding: 2px;
  background: var(--ghost-5);
  border: 1px solid var(--ghost-12);
  border-radius: var(--r-lg);
  overflow: hidden;
  margin-bottom: 8px;
}
.tc-select-menu .device-category-tab {
  flex: 1 1 0;
  justify-content: center;
  border-radius: 6px !important;
  padding: 5px 8px !important;
}
/* Panels lose their standalone card chrome inside the menu. */
.tc-select-menu .device-panels-wrapper,
.tc-mockup-panel .tc-select-menu .device-panels-wrapper {
  height: auto !important;
  max-height: 400px;
  overflow-y: auto;
  border: 0 !important;
  background: none !important;
  padding: 0 !important;
}
.tc-select-menu #tabs-segment-1 { margin-inline: 0; max-height: none; }

/* Aspect trigger: the glass preview gets real room (user: "квадратик плохо
   вписан"). */
#dropdown-canvas-size {
  height: 40px;
  padding: 5px 10px 5px 5px;
  gap: 10px;
}
#dropdown-canvas-size .canvas-size-glass {
  width: 30px;
  height: 30px;
  border-radius: 7px;
  flex: none;
}

/* SCREEN slots: uniform compact tiles — a single slot no longer stretches
   into a full-width hero image. */
.tc-screen-slots[data-slots="1"],
.tc-screen-slots[data-slots="2"] { grid-template-columns: repeat(3, 1fr); }

/* Backdrop color popover fits the panel (was overflowing the sidebar). */
#dropdown-bg-color-wrapper > .dropdown-menu {
  width: 294px !important;
  min-width: 0 !important;
  max-width: 294px !important;
  overflow: hidden;
}
#dropdown-bg-color-wrapper > .dropdown-menu img,
#dropdown-bg-color-wrapper > .dropdown-menu canvas { max-width: 100%; }

/* ═══ Polish(9) — paywall price rhythm + dialog slider hardening ═══ */

/* Price block: quieter scale, tight baseline pair, breathing room that
   matches the checklist above and the CTA below (was a 34px giant crammed
   between them via inline styles). */
.pro-price-row {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin: 18px 0 12px;
}
.pro-price-amount {
  font-size: 28px;
  font-weight: 650;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--foreground);
  font-variant-numeric: tabular-nums;
}
.pro-price-note { font-size: 13px; color: var(--muted-foreground); }
.pro-checklist { margin-bottom: 2px; }
.pro-ghost-link { margin-top: 10px; }
.pro-footnote { margin-top: 8px; }

/* ═══ Paywall — monochrome premium reskin (no brand-lime) ═══
   The Pro offer is a selling surface, so it stays quiet and confident.
   Lime is the in-editor "act" color (Export, switches, progress); on a
   pricing card it read loud and salesy. Eyebrow, checks and CTA all move
   onto the neutral foreground ramp — the panel now sells on typography
   and rhythm rather than color. Scoped to pro-* so nothing else shifts. */

/* Eyebrow: quiet neutral chip (was a lime tint + lime border) */
.pro-eyebrow {
    background: var(--ghost-5);
    border-color: var(--ghost-12);
    color: var(--title);
    letter-spacing: 0.08em;
}
.pro-eyebrow svg { color: var(--muted-foreground); }

/* Checklist ticks: crisp neutral foreground, not brand-lime */
.pro-checklist li svg { color: color-mix(in oklab, var(--foreground) 55%, transparent); }

/* Hero typography — the headline + price carry the sell, so scale them up
   from the cramped template defaults (title 15→22, price 28→34). */
.pro-title {
    font-size: 22px;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -0.02em;
    margin-bottom: 7px;
}
.pro-sub {
    font-size: 13.5px;
    line-height: 1.5;
    margin-bottom: 18px;
}
#pro-view-offer .pro-price-amount { font-size: 34px; }
#pro-view-offer .pro-price-note { font-size: 13.5px; }

/* Primary CTA colour: solid light button — green-free, both Pro views. */
.pro-cta.tc-btn-brand,
.pro-cta {
    background: var(--foreground);
    color: var(--background);
    font-weight: 600;
    letter-spacing: -0.005em;
}
.pro-cta.tc-btn-brand:hover,
.pro-cta:hover {
    background: color-mix(in oklab, var(--foreground) 90%, var(--background));
    box-shadow: none;
}
.pro-cta.tc-btn-brand:active,
.pro-cta:active {
    background: color-mix(in oklab, var(--foreground) 82%, var(--background));
}
/* Offer view = selling surface: tall, confident pill. */
#pro-view-offer .pro-cta {
    height: 46px;
    border-radius: var(--r-full);
    font-size: 14px;
}
/* Activate view: match the 32px input rhythm — compact button, same corner
   as the field, with real breathing room above (this is what broke). */
#pro-view-activate .pro-cta {
    height: 38px;
    border-radius: var(--r-lg);
    font-size: 13px;
    margin-top: 14px;
}

/* Belt-and-suspenders: no dialog slider may ever paint its FlyonUI utility
   pill (bg-neutral track) — the tc hairline skin is the only track. */
.tc-dialog .noUi-target,
#siteshots-count-slider.noUi-target {
  background: transparent !important;
  border: 0 !important;
  height: 18px !important;
}


/* Late actives that carried their own selection-blue (missed by the generic
   .tc-seg-item.active override): DOF modes + FRAME stroke style → same light
   gray as every other segmented active. */
.studio-sidebar .dof-mode-btn.dof-mode-active,
.dof-mode-btn.dof-mode-active,
.studio-sidebar .stroke-style-btn.stroke-style-active {
  background: var(--active-bg) !important;
  color: var(--foreground) !important;
}

/* Export settings popover → tc design: flat segmented groups (ghost surface,
   gray actives) instead of the legacy FlyonUI join pills. */
.tc-export-menu { padding: 10px 12px 12px; }
.tc-export-menu .flex.items-start { gap: 12px; }
.tc-export-menu .text-icons-tertiary { font-size: 11px; letter-spacing: 0.05em; color: var(--title); }
.tc-export-menu .export-tab-group {
  display: flex;
  background: var(--ghost-5);
  border: 1px solid var(--ghost-12);
  border-radius: var(--r-lg);
  overflow: hidden;
  padding: 2px;
}
.tc-export-menu .export-tab-group .join-item.btn {
  flex: 1 1 0;
  height: 26px;
  min-height: 0;
  border: 0 !important;
  border-radius: 6px !important;
  background: transparent !important;
  color: var(--muted-foreground) !important;
  font-size: 12px;
  font-weight: 500;
  box-shadow: none !important;
  outline: none !important;
}
.tc-export-menu .export-tab-group .join-item.btn:hover {
  color: var(--foreground) !important;
  background: var(--ghost-3) !important;
}
.tc-export-menu .export-tab-group input.join-item.btn:checked,
.tc-export-menu .export-tab-group input.join-item.btn:checked:hover {
  background: var(--active-bg) !important;
  color: var(--foreground) !important;
}
#export-px-readout { margin-top: 10px; }

/* Duotone Shadow/Highlight (vanilla-picker inline in .tc-fx-color-wrap):
   the picker mounted with its default chrome — the SL/sample selector dots
   floated over the labels ("налипли кружки"). Keep only the hue strip +
   hex editor; everything else is hidden and the wrapper flows normally. */
.tc-fx-color-wrap { position: relative; }
.tc-fx-color-wrap .picker_wrapper {
  position: static !important;
  width: 100% !important;
  background: transparent !important;
  box-shadow: none !important;
  border: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.tc-fx-color-wrap .picker_sl,
.tc-fx-color-wrap .picker_alpha,
.tc-fx-color-wrap .picker_sample,
.tc-fx-color-wrap .picker_done,
.tc-fx-color-wrap .picker_cancel,
.tc-fx-color-wrap .picker_arrow { display: none !important; }
.tc-fx-color-wrap .picker_hue {
  order: 1;
  height: 14px !important;
  border-radius: 999px;
  border: 0;
  box-shadow: none;
}
.tc-fx-color-wrap .picker_hue .picker_selector {
  width: 16px; height: 16px;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,.5);
}
.tc-fx-color-wrap .picker_editor { order: 2; width: 100%; }
.tc-fx-color-wrap .picker_editor input {
  width: 100%;
  height: 28px;
  border: 1px solid var(--ghost-12);
  border-radius: var(--r-lg);
  background: var(--ghost-5);
  color: var(--foreground);
  font: 500 12px/1 'JetBrains Mono', monospace;
  padding: 0 10px;
  box-shadow: none;
}

/* Scenes list: active row goes light gray like every other UI active
   (the selection-blue tint was still hardwired here). */
.tc-scene-row.is-active,
.tc-scenes-list .tc-scene-row.is-active {
  background: var(--active-bg) !important;
}
.tc-scene-row.is-active .tc-scene-num {
  background: color-mix(in oklab, var(--foreground) 16%, transparent) !important;
  color: var(--foreground) !important;
}
.tc-scene-row.is-active .tc-scene-idx {
  background: color-mix(in oklab, var(--foreground) 16%, transparent) !important;
  color: var(--foreground) !important;
}

/* Duotone rows: kill the picker parts' library margins/pseudo-spacers so the
   label sits 8px above the hue strip (titles were floating far away). */
.tc-fx-color-wrap .picker_wrapper::before,
.tc-fx-color-wrap .picker_wrapper::after { display: none !important; }
.tc-fx-color-wrap .picker_wrapper > * { margin: 0 !important; }
.tc-fx-color-wrap .picker_hue { margin: 4px 0 0 !important; }
.tc-fx-color-wrap .picker_editor { margin: 0 !important; }
