/* ── Controls — transform wrapper (panel + tab slide together) ────────────────── */
/* Backdrop-filter lives on the panel and tab individually so the blur area
   is confined to each element's own footprint — no ghost blur when closed.    */

#controls-wrapper {
    position: fixed;
    top: 0;
    right: 0;
    width: calc(var(--panel-width) + var(--tab-width) - 1px);
    height: 100%;
    z-index: var(--z-panel);
    transition: transform var(--ease-panel);
    pointer-events: none;        /* children opt back in individually */
    user-select: none;
}
#controls-wrapper.closed {
    transform: translateX(var(--panel-width));
}

/* ── Panel ───────────────────────────────────────────────────────────────────── */
#controls-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: var(--panel-width);
    background: var(--panel-bg);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border-left: var(--border-panel);
    display: flex;
    flex-direction: column;
    font-family: var(--font-main);
    font-size: var(--font-size-base);
    color: var(--text-primary);
    pointer-events: auto;
    transition: transform var(--ease-panel);   /* slides left when extended */
}

/* ── Tab — rides panel 1's left edge; slides with it when extended ───────────── */
#controls-tab {
    position: absolute;
    left: calc(-1 * var(--tab-width));
    top: 50%;
    transform: translateY(-50%);
    width: var(--tab-width);
    height: var(--tab-height);
    background: var(--panel-bg);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border: var(--border-panel);
    border-right: none;
    border-radius: var(--radius-1) 0 0 var(--radius-1);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    pointer-events: auto;
    transition: background var(--ease-hover);
}
#controls-tab:hover {
    background: var(--panel-bg-hover);
}

#controls-wrapper.closed #controls-tab .tab-arrow-icon { transform: rotate(180deg); }

/* ── Header ──────────────────────────────────────────────────────────────────── */
#controls-header {
    padding: var(--pad-header) var(--pad-outer) var(--pad-inner);
    border-bottom: var(--border-panel);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
#controls-title {   /* s1 — heading: panel title */
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--letter-spacing-ui);
    text-transform: uppercase;
    color: var(--t-sidebar-title-color);
}
#controls-extend-btn {   /* s3 — button: extend toggle */
    font-size: var(--font-size-sm);
    letter-spacing: var(--letter-spacing-sm);
    text-transform: uppercase;
    background: none;
    border: var(--border-input);
    border-radius: var(--radius-2);
    color: var(--t-btn-color);
    padding: 3px 8px;
    cursor: pointer;
    transition: all var(--ease-hover);
    font-family: inherit;
}
#controls-extend-btn:hover {
    border-color: var(--border-color-on);
    color: var(--text-hover);
}
#controls-extend-btn.is-active {
    background: var(--surface-active);
    border-color: var(--border-color-on);
    color: var(--text-hover);
}
/* Extend needs room for a second panel — hide the toggle on narrow viewports. */
@media (max-width: 1199px) {
    #controls-extend-btn { display: none; }
}

/* ── Scrollable body ─────────────────────────────────────────────────────────── */
#controls-body,
#controls-body-2 {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding-bottom: 20px;
    scrollbar-width: none;
    -ms-overflow-style: none;
}
#controls-body::-webkit-scrollbar,
#controls-body-2::-webkit-scrollbar { display: none; }

/* ── Secondary panel (Extend) ─────────────────────────────────────────────────
   A second sidebar of equal width, flush against the primary panel's left edge.
   Hidden until body.controls-split is set (toggled by the Extend button). */
#controls-panel-2 {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;                       /* shares the right edge; transform offsets it */
    width: var(--panel-width);
    background: var(--panel-bg);
    backdrop-filter: blur(var(--panel-blur));
    -webkit-backdrop-filter: blur(var(--panel-blur));
    border-left: var(--border-panel);
    display: flex;
    flex-direction: column;
    font-family: var(--font-main);
    font-size: var(--font-size-base);
    color: var(--text-primary);
    pointer-events: auto;
    transform: translateX(100%);    /* parked off-screen right until extended */
    transition: transform var(--ease-panel);
}
/* Empty header bar — keeps panel 2's first row aligned with panel 1's. */
.controls-header-spacer {
    padding: var(--pad-header) var(--pad-outer) var(--pad-inner);
    border-bottom: var(--border-panel);
    flex-shrink: 0;
}
.controls-header-spacer::before {
    content: 'Controls';
    visibility: hidden;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--letter-spacing-ui);
    text-transform: uppercase;
}

/* ── Split active — slide panel 1 left, slide panel 2 in from the right ──────────
   Panel 1 shifts one panel-width left; panel 2 (parked off-screen right) returns
   to the right edge. Both share a transform transition, so they glide in lockstep.
   The wrapper still drives open/close; its closed slide deepens to clear both. */
body.controls-split #controls-wrapper {
    width: calc(2 * var(--panel-width) + var(--tab-width) - 1px);
}
body.controls-split #controls-wrapper.closed {
    transform: translateX(calc(2 * var(--panel-width)));
}
body.controls-split #controls-panel {
    transform: translateX(calc(-1 * var(--panel-width)));
}
body.controls-split #controls-panel-2 {
    transform: translateX(0);
}

/* ── Transition lock — invisible overlay absorbs all pointer events ──────────── */
/* Applied to #controls-panel while a palette transition is running.             */
/* position:absolute is already set on the panel so ::after positions correctly. */
#controls-panel.is-transitioning::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 50;           /* above all panel content                            */
    border-radius: inherit;
    cursor: default;
    /* No background — the panel stays fully visible, it just can't be clicked. */
}

/* ── Preset browse button + gradient bar ─────────────────────────────────────── */
.preset-select-wrap {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
}
.preset-select-wrap select {
    width: 100%;
}
.preset-grad-bar {
    height: 4px;
    border-radius: 999px;
    opacity: 0.8;
}

/* ── Group note text + button rows (Export & Publish, etc.) ──────────────────── */
.group-note {   /* s4 — body: descriptive note text inside groups */
    margin: 0;
    font-size: var(--font-size-base);
    color: var(--t-info-color);
    line-height: 1.4;
}
.ctrl-btn-row {
    display: flex;
    gap: 8px;
}
.ctrl-btn-row > button { flex: 1; }
/* ── Primary action buttons — Browse Presets / Publish / Export JSON / Import JSON ─
   These are "big buttons": base font size + more padding, unlike the
   compact ctrl-full-btn default. IDs ensure the override is specific.         */
#controls-browse-btn {   /* s3 — button (primary): open preset gallery */
    font-size: var(--font-size-base);
    padding: 8px 0;
}
#controls-publish-btn,
#controls-save-btn,
#controls-load-btn {   /* s3 — button (primary): publish + JSON save/load */
    font-size: var(--font-size-base);
    padding: 8px 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
#controls-publish-btn::before {
    content: '';
    display: block;
    width: var(--icon-size);
    height: var(--icon-size);
    flex-shrink: 0;
    background-color: currentColor;
    -webkit-mask-image: url('/assets/icons/ui/ui_publish.svg');
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-image: url('/assets/icons/ui/ui_publish.svg');
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
}
#controls-save-btn::before,
#controls-load-btn::before {
    content: '';
    display: block;
    width: var(--icon-size);
    height: var(--icon-size);
    flex-shrink: 0;
    background-color: currentColor;
    -webkit-mask-image: url('/assets/icons/ui/ui_download.svg');
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-image: url('/assets/icons/ui/ui_download.svg');
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
}
#controls-load-btn::before {
    transform: rotate(180deg);
}

/* ── Groups (collapsible <details>) ──────────────────────────────────────────── */
.ctrl-group {
    border-bottom: var(--border-sub);
}
.ctrl-group > summary {   /* s1 — heading: group title */
    padding: 8px var(--pad-outer);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--letter-spacing-ui);
    text-transform: uppercase;
    color: var(--t-section-color);
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    gap: var(--gap-row);
    background: var(--surface-panel);
    /* Full-opacity accent stripe on the header only (inner, centre-facing edge). */
    box-shadow: inset 3px 0 0 var(--group-accent);
    transition: color var(--ease-fast), background var(--ease-fast);
}
.ctrl-group > summary::-webkit-details-marker { display: none; }
/* Group identity icon (left) — per-group SVG + accent colour, set via the
   --group-icon / --group-accent custom properties in group(). */
.ctrl-group > summary::before {
    content: '';
    display: inline-block;
    width: var(--ctrl-group-icon-size);
    height: var(--ctrl-group-icon-size);
    flex-shrink: 0;
    background-color: var(--group-accent, currentColor);
    -webkit-mask-image: var(--group-icon);
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-image: var(--group-icon);
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
}
/* Collapse indicator (right) — +/- toggled by the open state. */
.ctrl-group > summary::after {
    content: '';
    margin-left: auto;
    width: var(--icon-size);
    height: var(--icon-size);
    flex-shrink: 0;
    background-color: currentColor;
    -webkit-mask-image: url('/assets/icons/ui/ui_plus.svg');
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-image: url('/assets/icons/ui/ui_plus.svg');
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
    opacity: 0.6;
    transition: opacity var(--ease-fast);
}
.ctrl-group[open] > summary::after {
    -webkit-mask-image: url('/assets/icons/ui/ui_minus.svg');
    mask-image: url('/assets/icons/ui/ui_minus.svg');
    opacity: 0.8;
}
.ctrl-group > summary:hover {
    color: var(--text-primary);
    background: var(--surface-hover);
}

/* ── Group content ───────────────────────────────────────────────────────────── */
.ctrl-content {
    padding: var(--pad-top) var(--pad-inner) var(--pad-inner);
    display: flex;
    flex-direction: column;
    gap: var(--gap-content);
    box-shadow: inset 3px 0 0 color-mix(in srgb, var(--group-accent) var(--group-accent-dim), var(--group-dim-base));
}

/* ── Rows ────────────────────────────────────────────────────────────────────── */
.ctrl-row {
    display: flex;
    align-items: center;
    gap: var(--gap-row);
    min-height: var(--row-height);
}
/* A control with no effect in the current displacement mode (e.g. Freq Y in
   Radial / Noise). Dimmed for feedback; `inert` (set in JS) blocks interaction. */
.ctrl-row.is-disabled {
    opacity: 0.35;
    transition: opacity var(--ease-hover);
}
.ctrl-row label {   /* s2 — label: slider and control labels */
    width: var(--label-width);
    flex-shrink: 0;
    font-size: var(--font-size-base);
    color: var(--t-label-color);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Inline hint text inside a group ────────────────────────────────────────── */
.ctrl-note {   /* s4 — body: inline hint text inside groups */
    margin: 0;
    padding: 0 var(--pad-outer) var(--pad-inner);
    font-size: var(--font-size-base);
    color: var(--t-info-color);
    line-height: 1.4;
}

/* ── Slider + overlaid value wrapper ────────────────────────────────────────── */
.ctrl-slider-wrap {
    position: relative;
    flex: 1;
    min-width: 0;
}
/* Value floated inside the track. mix-blend-mode: difference makes each text
   pixel the inverse of whatever's behind it, so it stays legible over both the
   bright fill and the dark empty track with no shadow needed. Pure white is
   required for a clean invert; a shadow is omitted (it would blend + halo). */
.ctrl-slider-wrap .ctrl-val {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-right: 6px;
    pointer-events: none;
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
    font-family: var(--font-numeric);   /* numeric: live slider value overlay */
    color: #fff;
    mix-blend-mode: difference;
    white-space: nowrap;
}

/* ── Sub-divider labels (Wave 1, 2, 3 / Color 1, 2, 3) ─────────────────────── */
.ctrl-divider {   /* s1 — heading (compact): sub-group labels e.g. "Wave 1", "Color 2" */
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--letter-spacing-sm);
    text-transform: uppercase;
    color: var(--t-divider-color);
    padding-top: 6px;
    margin-top: 2px;
    border-top: var(--border-sub);
}

/* ── Range sliders (fill style) ──────────────────────────────────────────────── */
.ctrl-slider-wrap input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    display: block;
    width: 100%;
    height: var(--ctrl-height);
    background: linear-gradient(to right,
        color-mix(in srgb, var(--group-accent, var(--slider-fill)) var(--group-accent-dim), var(--group-dim-base)) 0%,
        color-mix(in srgb, var(--group-accent, var(--slider-fill)) var(--group-accent-dim), var(--group-dim-base)) var(--fill, 50%),
        var(--slider-empty) var(--fill, 50%),
        var(--slider-empty) 100%
    );
    border-radius: var(--radius-2);
    outline: none;
    cursor: pointer;
    padding: 0;
}
/* Webkit: thin vertical-line thumb */
.ctrl-slider-wrap input[type="range"]::-webkit-slider-runnable-track {
    height: var(--ctrl-height);
    background: transparent;
    border-radius: var(--radius-2);
}
.ctrl-slider-wrap input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: var(--slider-thumb-width);
    height: var(--ctrl-height);
    border-radius: 0;
    background: var(--group-accent, var(--slider-thumb-color));
    cursor: pointer;
    transition: width 0.1s;
}
.ctrl-slider-wrap input[type="range"]:hover::-webkit-slider-thumb  { width: calc(var(--slider-thumb-width) + 1px); }
.ctrl-slider-wrap input[type="range"]:active::-webkit-slider-thumb { width: calc(var(--slider-thumb-width) + 1px); }
/* Firefox */
.ctrl-slider-wrap input[type="range"]::-moz-range-track {
    height: var(--ctrl-height);
    background: var(--slider-empty);
    border-radius: var(--radius-2);
}
.ctrl-slider-wrap input[type="range"]::-moz-range-progress {
    height: var(--ctrl-height);
    background: color-mix(in srgb, var(--group-accent, var(--slider-fill)) var(--group-accent-dim), var(--group-dim-base));
    border-radius: var(--radius-2) 0 0 var(--radius-2);
}
.ctrl-slider-wrap input[type="range"]::-moz-range-thumb {
    width: var(--slider-thumb-width);
    height: var(--ctrl-height);
    border-radius: 0;
    background: var(--group-accent, var(--slider-thumb-color));
    border: none;
    cursor: pointer;
}

/* ── Color pickers ───────────────────────────────────────────────────────────── */
.ctrl-row input[type="color"] {
    -webkit-appearance: none;
    appearance: none;
    width: var(--swatch-width);
    height: 22px;
    border: var(--border-swatch);
    border-radius: var(--radius-2);
    padding: 1px;
    background: none;
    cursor: pointer;
    flex-shrink: 0;
    transition: border-color var(--ease-fast);
}
.ctrl-row input[type="color"]:hover { border-color: var(--border-color-hover); }
.ctrl-row input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.ctrl-row input[type="color"]::-webkit-color-swatch { border: none; border-radius: calc(var(--radius-2) - 1px); }

/* ── Toggle buttons ──────────────────────────────────────────────────────────── */
.ctrl-toggle {   /* s3 — button: ON / OFF state toggles */
    font-size: var(--font-size-sm);
    letter-spacing: var(--letter-spacing-sm);
    text-transform: uppercase;
    background: var(--surface-input);
    border: var(--border-input);
    border-radius: var(--radius-2);
    color: var(--text-muted);
    padding: 3px 9px;
    cursor: pointer;
    transition: all var(--ease-hover);
    font-family: inherit;
    flex-shrink: 0;
}
.ctrl-toggle.on {
    background: var(--surface-active);
    border-color: var(--border-color-on);
    color: var(--text-hover);
}
.ctrl-toggle:hover {
    border-color: var(--border-color-hover);
    color: var(--text-icon);
}

/* ── Select dropdowns ────────────────────────────────────────────────────────── */
.ctrl-row select {   /* s2 — label: dropdown menus */
    flex: 1;
    background: var(--surface-input);
    border: var(--border-input);
    border-radius: var(--radius-2);
    color: var(--text-primary);
    font-size: var(--font-size-base);
    font-family: inherit;
    padding: 3px 6px;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='rgba(255,255,255,0.4)'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 6px center;
    padding-right: 20px;
}
.ctrl-row select:hover { border-color: var(--border-color-hover); }
/* Ensure the native popup options are readable on dark-themed pages */
.ctrl-row select option {
    background: var(--select-option-bg);
    color: var(--text-hover);
}

/* ── Full-width action button (used in Colors group etc.) ────────────────────── */
.ctrl-full-btn {   /* s3 — button: full-width action buttons */
    width: 100%;
    font-size: var(--font-size-sm);
    letter-spacing: var(--letter-spacing-sm);
    text-transform: uppercase;
    font-family: inherit;
    background: var(--surface-input);
    border: var(--border-input);
    border-radius: var(--radius-2);
    color: var(--t-btn-color);
    padding: 5px 0;
    cursor: pointer;
    transition: all var(--ease-hover);
}
.ctrl-full-btn:hover {
    background: var(--surface-hover);
    border-color: var(--border-color-hover);
    color: var(--text-primary);
}

/* ── Compact color blocks — CSS grid: swatch spans both rows ─────────────────── */
.ctrl-color-block {
    display: grid;
    grid-template-columns: var(--swatch-width) 1fr;
    grid-template-rows: var(--ctrl-height) var(--ctrl-height);
    column-gap: var(--gap-row);
    row-gap: var(--slider-gap);
    padding: 5px 0 5px 8px;
    border-left: var(--border-sub);
    margin-bottom: 3px;
}

/* Swatch spans both rows — height = calc(2 × --ctrl-height + --slider-gap) */
.ctrl-color-swatch {
    -webkit-appearance: none;
    appearance: none;
    width: var(--swatch-width);
    height: auto;
    grid-column: 1;
    grid-row: 1 / 3;
    align-self: stretch;
    border: var(--border-swatch);
    border-radius: calc(var(--radius-2) - 1px);
    padding: 1px;
    background: none;
    cursor: pointer;
    transition: border-color var(--ease-fast);
}
.ctrl-color-swatch:hover { border-color: var(--border-color-hover); }
.ctrl-color-swatch::-webkit-color-swatch-wrapper { padding: 0; }
.ctrl-color-swatch::-webkit-color-swatch { border: none; border-radius: 1px; }

/* Grid placement for slider wraps inside color blocks */
.ctrl-color-x { grid-column: 2; grid-row: 1; }
.ctrl-color-y { grid-column: 2; grid-row: 2; }

/* ── UV colour-placement canvas (inside Colors group) ────────────────────────── */

/* 4-column grid: swatches + add button flow predictably at any colour count. */
.uv-swatch-row {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 6px;
}

/* Wrapper div handles the square aspect-ratio so input[type="color"]
   (a replaced element) fills it reliably across browsers.
   border-radius + overflow:hidden clip the color fill to rounded corners. */
.uv-swatch-wrap {
    aspect-ratio: 1;
    position: relative;
    min-width: 0;
    border-radius: var(--radius-2);
    overflow: hidden;
}

.uv-swatch {
    -webkit-appearance: none;
    appearance: none;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
    border-radius: 0;
    padding: 0;
    background: none;
    cursor: pointer;
}
.uv-swatch::-webkit-color-swatch-wrapper { padding: 0; }
.uv-swatch::-webkit-color-swatch        { border: none; border-radius: 0; }

/* ── Swatch index label — faint number in the bottom-left corner ────────────── */
.uv-swatch-label {
    position: absolute;
    bottom: 3px;
    left: 4px;
    font-size: var(--font-size-sm);
    font-family: var(--font-main);
    font-weight: var(--font-weight-bold);
    color: #fff;
    mix-blend-mode: difference;
    pointer-events: none;
    line-height: 1;
    opacity: 0.55;
    z-index: 2;
}

/* ── Remove button — bare icon, inside top-right corner, always visible ─────── */
.uv-swatch-remove {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 14px;
    height: 14px;
    padding: 0;
    border: none;
    background: none;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: color var(--ease-fast);
    z-index: 2;
}
.uv-swatch-remove::before {
    content: '';
    display: block;
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
    background-color: currentColor;
    -webkit-mask-image: url('/assets/icons/ui/ui_close.svg');
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-image: url('/assets/icons/ui/ui_close.svg');
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
}
.uv-swatch-remove:hover { color: var(--text-hover); }
.uv-swatch-remove:disabled {
    opacity: 0 !important;
    pointer-events: none;
}

/* ── Add button — dashed border, same grid cell size as a swatch ─────────── */
.uv-add-btn {
    aspect-ratio: 1;
    min-width: 0;
    background: var(--surface-input);
    border: 1px dashed var(--border-color-input);
    border-radius: var(--radius-2);
    color: var(--text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background var(--ease-fast), border-color var(--ease-fast),
                color var(--ease-fast);
}
.uv-add-btn::before {
    content: '';
    display: block;
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
    background-color: currentColor;
    -webkit-mask-image: url('/assets/icons/ui/ui_plus.svg');
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-image: url('/assets/icons/ui/ui_plus.svg');
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
}
.uv-add-btn:hover {
    background: var(--surface-hover);
    border-color: var(--border-color-hover);
    color: var(--text-hover);
}
.uv-add-btn:disabled {
    display: none;
}

/* ── Shuffle row — two equal-width icon+text buttons below the UV canvas ────── */
.uv-shuffle-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
}

.uv-shuffle-btn {   /* s3 — button: shuffle / randomize actions */
    font-size: var(--font-size-sm);
    letter-spacing: var(--letter-spacing-sm);
    text-transform: uppercase;
    font-family: inherit;
    background: var(--surface-input);
    border: var(--border-input);
    border-radius: var(--radius-2);
    color: var(--t-btn-color);
    padding: 5px 6px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    transition: all var(--ease-hover);
}
.uv-shuffle-btn::before {
    content: '';
    display: block;
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
    flex-shrink: 0;
    background-color: currentColor;
    -webkit-mask-image: url('/assets/icons/ui/ui_shuffle.svg');
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-image: url('/assets/icons/ui/ui_shuffle.svg');
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
}
.uv-shuffle-btn:hover {
    background: var(--surface-hover);
    border-color: var(--border-color-hover);
    color: var(--text-primary);
}

/* ── Cycling mute — dims swatches + UV canvas while auto-cycle drives the render */
.uv-swatch-row,
.uv-canvas-wrap {
    transition: opacity var(--ease-hover);
}
.ctrl-group.is-cycling .uv-swatch-row,
.ctrl-group.is-cycling .uv-canvas-wrap {
    opacity: 0.3;
}

.uv-canvas {
    display: block;
    width: 100%;
    aspect-ratio: 1;
    border: var(--border-input);
    border-radius: var(--radius-2);
    touch-action: none;   /* let pointer-drag move the colour dots on touch instead of the browser claiming it as a scroll (matches .freq-pad) */
}

/* ── Displacement: per-wave tabs + frequency XY pad ──────────────────────────── */
.wave-tabs {
    display: flex;
    gap: 2px;
    padding: 2px;
    background: var(--surface-input);
    border: var(--border-input);
    border-radius: var(--radius-2);
}
.wave-tab {   /* s3 — button: wave layer selector tabs */
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 4px 0;
    font-family: inherit;
    font-size: var(--font-size-sm);
    letter-spacing: var(--letter-spacing-sm);
    text-transform: uppercase;
    color: var(--text-secondary);
    background: transparent;
    border: none;
    border-radius: calc(var(--radius-2) - 1px);
    cursor: pointer;
    transition: background var(--ease-fast), color var(--ease-fast);
}
.wave-tab::before {   /* wave-colour swatch — ties the tab to its dot */
    content: '';
    width: 7px;
    height: 7px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--wave-color);
}
.wave-tab:hover     { color: var(--text-primary); background: var(--surface-hover); }
.wave-tab.is-active { color: var(--text-hover);   background: var(--surface-active); }

.wave-sliders { display: flex; flex-direction: column; gap: var(--gap-content); }
.wave-sliders[hidden] { display: none; }   /* override display:flex */

.freq-pad-wrap { display: flex; flex-direction: column; gap: 4px; }
.freq-pad-label { font-size: var(--font-size-base); color: var(--text-label); }
.freq-pad {
    position: relative;
    width: 100%;
    aspect-ratio: 1;
    border: var(--border-input);
    border-radius: var(--radius-2);
    background: var(--slider-empty);
    cursor: crosshair;
    touch-action: none;
    overflow: hidden;
}
/* Centre crosshair: ::before = vertical (Y) axis, ::after = horizontal (X) axis */
.freq-pad::before, .freq-pad::after {
    content: '';
    position: absolute;
    background: rgba(255, 255, 255, 0.12);
    pointer-events: none;
}
.freq-pad::before { left: 50%; top: 0; bottom: 0; width: 1px; }
.freq-pad::after  { top: 50%; left: 0; right: 0; height: 1px; }
/* One dot per wave, coloured by --wave-color. Dimmed = reference, active = editable. */
.freq-pad-dot {
    position: absolute;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--wave-color);
    box-shadow: 0 0 0 1.5px rgba(0, 0, 0, 0.5);
    transform: translate(-50%, -50%);
    pointer-events: none;
    opacity: 0.4;
    z-index: 1;
    transition: opacity var(--ease-fast), width var(--ease-fast), height var(--ease-fast);
}
.freq-pad-dot.is-active {
    opacity: 1;
    width: 16px;
    height: 16px;
    box-shadow: 0 0 0 1.5px rgba(0, 0, 0, 0.55), 0 0 8px 1px var(--wave-color);
    z-index: 2;
}
.freq-pad-cap {   /* numeric: X / Y value readout on the frequency pad */
    font-size: var(--font-size-sm);
    font-family: var(--font-numeric);
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}
/* Radial / Noise modes — Y axis has no effect: lock to centre + dim the guide. */
.freq-pad-wrap.is-y-disabled .freq-pad          { cursor: ew-resize; }
.freq-pad-wrap.is-y-disabled .freq-pad::before  { opacity: 0.25; }
