/* Modal Styles */
.modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: radial-gradient(1200px 800px at 50% 40%,
        rgba(0, 0, 0, 0.7) 0%,
        rgba(0, 0, 0, 0.88) 100%);
    z-index: var(--z-modal);
    align-items: center;
    justify-content: center;
    animation: fadeIn 0.2s ease-out;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

/* Confirm dialog must stack above all other modals */
#confirm-modal {
    z-index: var(--z-confirm);
}

/* Audio test spectrum canvas */
.audio-test-canvas {
    display: block;
    width: 100%;
    height: 200px;
    background: #111;
    border-radius: 6px;
}

.audio-test-stats {
    display: flex;
    gap: 20px;
    align-items: center;
    padding: 10px 0 0;
    font-family: monospace;
}

.audio-test-stat {
    display: flex;
    align-items: center;
    gap: 6px;
}

.audio-test-stat-label {
    color: var(--text-muted, #888);
    font-size: 0.85em;
}

.audio-test-stat-value {
    font-weight: 600;
    min-width: 50px;
}

.audio-test-beat-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #444;
    transition: background 0.1s;
}

.audio-test-beat-dot.active {
    background: #ff4444;
    box-shadow: 0 0 8px #ff4444;
}

.audio-test-status {
    text-align: center;
    padding: 8px 0;
    color: var(--text-muted, #888);
    font-size: 0.9em;
}

/* Value source test chart canvas */
.vs-test-canvas {
    display: block;
    width: 100%;
    height: 200px;
    background: #111;
    border-radius: 6px;
}

.vs-test-color-swatch {
    margin-top: 8px;
}

.vs-test-color-canvas {
    display: block;
    width: 100%;
    height: 32px;
    border-radius: 6px;
}

.vs-test-stats {
    display: flex;
    gap: 20px;
    align-items: center;
    padding: 10px 0 0;
    font-family: monospace;
    flex-wrap: wrap;
}

.vs-test-stat {
    display: flex;
    align-items: center;
    gap: 6px;
}

.vs-test-stat-label {
    color: var(--text-muted, #888);
    font-size: 0.85em;
}

.vs-test-stat-value {
    font-weight: 600;
    min-width: 50px;
}

.vs-test-value-large {
    font-size: 1.3em;
    color: var(--primary-text-color);
}

.vs-test-status {
    text-align: center;
    padding: 8px 0;
    color: var(--text-muted, #888);
    font-size: 0.9em;
}

/* Color strip test preview */
.css-test-strip-wrap {
    position: relative;
}

.css-test-strip-canvas {
    display: block;
    width: 100%;
    height: 48px;
    background: #111;
    border-radius: 6px;
    image-rendering: pixelated;
}

.css-test-strip-axis {
    display: block;
    width: 100%;
    height: 20px;
}

.css-test-fire-btn {
    position: absolute;
    right: 6px;
    top: 24px;
    transform: translateY(-50%);
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
    font-size: 1rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s;
    line-height: 1;
}

.css-test-fire-btn:hover {
    background: rgba(255, 255, 255, 0.25);
}

.css-test-rect-outer {
    position: relative;
    padding: 22px 30px;
}

.css-test-rect-ticks {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 2;
}

.css-test-rect {
    display: grid;
    grid-template-columns: 14px 1fr 14px;
    grid-template-rows: 14px 1fr 14px;
    width: 100%;
    aspect-ratio: 16 / 9;
    max-height: 70vh;
    overflow: hidden;
    border-radius: 4px;
}

.css-test-rect-corner {
    background: transparent;
}

.css-test-rect-screen {
    position: relative;
    background-image: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    background-size: cover;
    background-position: center;
    border-radius: 2px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    overflow: hidden;
}

.css-test-rect-screen::after {
    content: '';
    position: absolute;
    inset: 0;
    border: 2px solid var(--primary-color);
    border-radius: 2px;
    pointer-events: none;
    z-index: 10;
}

.css-test-border-label {
    position: absolute;
    bottom: 4px;
    right: 4px;
    background: rgba(0, 0, 0, 0.6);
    color: var(--primary-color);
    font-size: 0.65rem;
    font-family: monospace;
    padding: 1px 5px;
    border-radius: 3px;
    z-index: 5;
}

.css-test-rect-label {
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.8rem;
    font-weight: 600;
    text-align: center;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 90%;
}

.css-test-rect-leds {
    font-size: 0.7rem;
    font-weight: 400;
    opacity: 0.75;
}

.css-test-edge-wrap {
    position: relative;
    overflow: hidden;
    min-width: 0;
    min-height: 0;
}

.css-test-edge {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    image-rendering: pixelated;
    display: block;
}

/* Key Colors test view — frame with region overlays */
.css-test-kc-wrap {
    position: relative;
    width: 100%;
    border-radius: 4px;
    overflow: hidden;
    background: #000;
    min-height: 120px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.css-test-kc-canvas {
    display: block;
    width: 100%;
    height: auto;
    max-height: 70vh;
    object-fit: contain;
}

.css-test-kc-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px 12px;
    padding: 8px 0 2px;
    font-size: 0.8rem;
    color: var(--text-color-muted, #aaa);
}

.css-test-kc-swatch {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 6px 2px 2px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--border-color, #333);
    border-radius: 999px;
    font-size: 0.78rem;
    color: var(--text-color, #e0e0e0);
}

.css-test-kc-swatch-chip {
    display: inline-block;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.25);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3);
}

.css-test-kc-swatch-hex {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.72rem;
    opacity: 0.65;
}

.css-test-kc-mode {
    opacity: 0.7;
    font-variant: small-caps;
    letter-spacing: 0.04em;
}

.css-test-status {
    text-align: center;
    padding: 8px 0;
    color: var(--text-muted, #888);
    font-size: 0.9em;
}

/* FPS chart for api_input test preview — reuses .target-fps-row from cards.css */

/* Composite layers preview */
.css-test-layers {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.css-test-layer {
    position: relative;
}

.css-test-layer-canvas {
    display: block;
    width: 100%;
    height: 48px;
    border-radius: 4px;
    image-rendering: pixelated;
    background: #111;
}

.css-test-layer-label {
    position: absolute;
    left: 4px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.6rem;
    font-family: var(--font-mono, monospace);
    color: #fff;
    text-shadow: 0 0 3px rgba(0,0,0,0.9), 0 0 6px rgba(0,0,0,0.6);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s;
    white-space: nowrap;
}

.css-test-layers:hover .css-test-layer-label {
    opacity: 1;
}

.css-test-layer-brightness {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.6rem;
    font-family: var(--font-mono, monospace);
    color: #fff;
    text-shadow: 0 0 3px rgba(0,0,0,0.9), 0 0 6px rgba(0,0,0,0.6);
    pointer-events: none;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 2px;
}
.css-test-layer-brightness svg { width: 12px; height: 12px; }

.css-test-layer-cal {
    position: absolute;
    right: 6px;
    bottom: 4px;
    font-size: 0.6rem;
    font-family: var(--font-mono, monospace);
    color: #fff;
    text-shadow: 0 0 3px rgba(0,0,0,0.9), 0 0 6px rgba(0,0,0,0.6);
    pointer-events: none;
    white-space: nowrap;
    opacity: 0.7;
    display: flex;
    align-items: center;
    gap: 2px;
}
.css-test-layer-cal svg { width: 12px; height: 12px; }
.css-test-layer-cal-warn {
    color: var(--warning-color, #ff9800);
    opacity: 1;
}

/* ── Settings modal tabs ───────────────────────────────────── */

.settings-tab-bar {
    display: flex;
    justify-content: space-around;
    gap: 0;
    border-bottom: 2px solid var(--border-color);
    padding: 0 0.5rem;
}

.settings-tab-btn {
    background: none;
    border: none;
    padding: 10px 0;
    flex: 1 1 0;
    min-width: 0;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.2s ease, border-color 0.25s ease, background 0.2s ease;
}

.settings-tab-btn .icon {
    width: 18px;
    height: 18px;
    transition: transform 0.2s ease, filter 0.2s ease;
}

.settings-tab-btn:hover {
    color: var(--text-color);
    background: color-mix(in srgb, var(--primary-color) 6%, transparent);
}

.settings-tab-btn:hover .icon {
    transform: translateY(-1px);
}

.settings-tab-btn.active {
    color: var(--primary-text-color);
    border-bottom-color: var(--primary-color);
}

.settings-tab-btn.active .icon {
    filter: drop-shadow(0 0 6px color-mix(in srgb, var(--primary-color) 50%, transparent));
}

.settings-tab-btn:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: -2px;
}

.settings-panel {
    display: none;
}

.settings-panel.active {
    display: block;
    animation: tabFadeIn 0.25s ease-out;
}

/* About panel — see Lumenworks .about-hero block lower in this file. */

/* ── Log viewer overlay (full-screen) — instrument rack aesthetic ──
   The overlay borrows the .module shell from dashboard.css for its
   header, then frames the live tail in a recessed "console" surface
   with scanlines + signal-flow at the top edge. */

.log-overlay {
    --ch: var(--ch-cyan, #00d8ff);
    position: fixed;
    inset: 0;
    z-index: var(--z-log-overlay);
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 28px 28px 24px;
    /* Atmospheric backdrop: deep base + signal-tinted glow + faint
       grid texture so the surface reads as a piece of equipment, not
       an empty pane. */
    background:
        radial-gradient(900px 600px at 18% -8%,
            color-mix(in srgb, var(--ch) 14%, transparent) 0%,
            transparent 65%),
        radial-gradient(700px 500px at 92% 108%,
            color-mix(in srgb, var(--ch) 10%, transparent) 0%,
            transparent 60%),
        repeating-linear-gradient(0deg,
            transparent 0,
            transparent 23px,
            color-mix(in srgb, var(--lux-ink, #fff) 3%, transparent) 23px,
            color-mix(in srgb, var(--lux-ink, #fff) 3%, transparent) 24px),
        var(--lux-bg-0, #000);
    animation: logOverlayIn 0.24s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes logOverlayIn {
    from { opacity: 0; backdrop-filter: blur(0); }
    to   { opacity: 1; backdrop-filter: blur(0); }
}

[data-theme="light"] .log-overlay {
    background:
        radial-gradient(900px 600px at 18% -8%,
            color-mix(in srgb, var(--ch) 18%, transparent) 0%,
            transparent 65%),
        radial-gradient(700px 500px at 92% 108%,
            color-mix(in srgb, var(--ch) 14%, transparent) 0%,
            transparent 60%),
        repeating-linear-gradient(0deg,
            transparent 0,
            transparent 23px,
            color-mix(in srgb, var(--lux-ink, #000) 3%, transparent) 23px,
            color-mix(in srgb, var(--lux-ink, #000) 3%, transparent) 24px),
        var(--bg-page, var(--bg-color, #f0f1f4));
}

/* Top-right close — square mod-icon-btn vocabulary. Floats over the
   header module so the corner bracket on the module sits underneath. */
.log-overlay-close {
    position: absolute;
    top: 14px;
    right: 14px;
    background: var(--lux-bg-1, var(--card-bg));
    border: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    color: var(--lux-ink-dim, var(--text-secondary));
    cursor: pointer;
    width: 30px;
    height: 30px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--lux-r-sm, 3px);
    z-index: 5;
    transition: color 0.15s, background 0.15s, border-color 0.15s,
                box-shadow 0.15s;
}
.log-overlay-close svg {
    width: 14px;
    height: 14px;
}
.log-overlay-close:hover,
.log-overlay-close:focus-visible {
    color: var(--ch-coral, var(--danger-color));
    border-color: color-mix(in srgb, var(--ch-coral, var(--danger-color)) 50%, transparent);
    background: color-mix(in srgb, var(--ch-coral, var(--danger-color)) 10%, var(--lux-bg-1, var(--card-bg)));
    box-shadow: 0 0 14px color-mix(in srgb, var(--ch-coral, var(--danger-color)) 25%, transparent);
    outline: none;
}

/* ── Header module ── only the head row reserves a slot on the right
   for the absolutely-positioned close button; metrics and footer span
   the full module width so no horizontal space is wasted beside them. */
.log-overlay .log-module {
    flex-shrink: 0;
}
.log-overlay .log-module > .mod-head {
    padding-right: 56px;
}

/* The filter <select> is replaced at runtime by an IconSelect (per
   project convention — no plain <select>). Style the resulting
   `.icon-select-trigger` so it reads as a chip-sized instrument
   control inside the mod-foot, matching the mod-btn vocabulary. */
.log-overlay .icon-select-trigger {
    width: auto;
    flex: 0 0 auto;
    gap: 6px;
    padding: 6px 10px;
    font-family: var(--font-mono, monospace);
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    border: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    background: var(--lux-bg-2, var(--card-bg));
    color: var(--lux-ink-dim, var(--text-secondary));
}
.log-overlay .icon-select-trigger:hover,
.log-overlay .icon-select-trigger:focus-visible {
    color: var(--lux-ink, var(--text-color));
    border-color: color-mix(in srgb, var(--ch) 45%, var(--lux-line-bold, var(--border-color)));
    background: var(--lux-bg-3, var(--border-color));
    outline: none;
}
.log-overlay .icon-select-trigger-icon { font-size: 0.78rem; }
.log-overlay .icon-select-trigger-arrow {
    color: var(--lux-ink-mute, var(--text-secondary));
    margin-left: 2px;
}

/* The mod-foot has filter + buttons. Push the filter alongside the
   action buttons (right side); patch indicator stays on the far left
   via its own margin-right:auto already in dashboard.css. */
.log-overlay .log-mod-foot {
    flex-wrap: wrap;
}

/* Coral tint on warn/err metric cells once their counters move
   beyond zero — same .has-errors hook pattern as the dashboard. */
.log-overlay .mod-metric.has-warn .v,
.log-overlay .mod-metric.has-warn .k,
.log-overlay .mod-metric.has-warn .k svg {
    color: var(--ch-amber, #ffb800);
}
.log-overlay .mod-metric.has-warn .k svg { opacity: 1; }

.log-overlay .mod-metric.has-errors .v,
.log-overlay .mod-metric.has-errors .k,
.log-overlay .mod-metric.has-errors .k svg {
    color: var(--ch-coral, var(--danger-color));
}
.log-overlay .mod-metric.has-errors .k svg { opacity: 1; }

/* ── Console surface — recessed bezel hosting the live <pre>. ── */
.log-console {
    --ch: var(--ch-cyan, #00d8ff);
    flex: 1;
    min-height: 0;
    position: relative;
    display: flex;
    background: var(--lux-bg-0, #000);
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    overflow: hidden;
    box-shadow:
        inset 0 1px 0 rgba(0, 0, 0, 0.6),
        inset 0 0 0 1px color-mix(in srgb, var(--ch) 8%, transparent),
        0 12px 32px rgba(0, 0, 0, 0.5);
}

/* Signal-flow strip at the top edge — only animates while connected. */
.log-console::before {
    content: '';
    position: absolute;
    left: 0; right: 0; top: 0;
    height: 2px;
    background: linear-gradient(90deg,
        transparent 0%,
        color-mix(in srgb, var(--ch) 90%, transparent) 50%,
        transparent 100%);
    background-size: 30% 100%;
    background-repeat: no-repeat;
    background-position: -30% 0;
    opacity: 0;
    transition: opacity 0.2s;
    pointer-events: none;
}
.log-overlay.is-streaming .log-console::before {
    opacity: 0.85;
    animation: signalFlow 2.4s linear infinite;
}

/* Faint scanline texture on the console — subtle CRT vibe. */
.log-console::after {
    content: '';
    position: absolute;
    inset: 0;
    background: repeating-linear-gradient(
        180deg,
        transparent 0,
        transparent 2px,
        color-mix(in srgb, var(--ch) 6%, transparent) 2px,
        color-mix(in srgb, var(--ch) 6%, transparent) 3px
    );
    pointer-events: none;
    mix-blend-mode: screen;
    opacity: 0.35;
}
[data-theme="light"] .log-console::after {
    mix-blend-mode: multiply;
    opacity: 0.18;
}

/* Left rail — silkscreened "TAIL" label with caret cursor. */
.log-console__rail {
    flex-shrink: 0;
    width: 40px;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 8px 0;
    border-right: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--ch) 10%, transparent),
        transparent 40%,
        transparent);
    font-family: var(--font-mono, monospace);
    color: var(--lux-ink-mute, var(--text-secondary));
    z-index: 1;
}
.log-console__caret {
    color: var(--ch);
    font-size: 0.85rem;
    line-height: 1;
    margin-bottom: 8px;
    filter: drop-shadow(0 0 4px color-mix(in srgb, var(--ch) 70%, transparent));
}
.log-console__rail-label {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-size: 0.55rem;
    font-weight: 600;
    letter-spacing: 0.32em;
    text-transform: uppercase;
    margin-top: 4px;
}

/* Empty state — sits over the <pre>, hidden once the first line lands. */
.log-console__empty {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    color: var(--lux-ink-mute, var(--text-secondary));
    font-family: var(--font-mono, monospace);
    pointer-events: none;
    z-index: 2;
    transition: opacity 0.2s;
}
.log-overlay.has-data .log-console__empty { opacity: 0; }
.log-console__empty-mark {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ch) 35%, var(--lux-line, var(--border-color)));
    position: relative;
}
.log-console__empty-mark::before,
.log-console__empty-mark::after {
    content: '';
    position: absolute;
    inset: -8px;
    border-radius: 50%;
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ch) 22%, transparent);
    animation: emptyPing 2.4s cubic-bezier(0, 0, 0.2, 1) infinite;
}
.log-console__empty-mark::after {
    animation-delay: 1.2s;
    inset: -16px;
}
@keyframes emptyPing {
    0%   { transform: scale(0.6); opacity: 0.9; }
    100% { transform: scale(1.4); opacity: 0; }
}
.log-console__empty-title {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--lux-ink-dim, var(--text-secondary));
}
.log-console__empty-sub {
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    color: var(--lux-ink-mute, var(--text-secondary));
    max-width: 32ch;
    text-align: center;
    line-height: 1.5;
}

/* The <pre> sits inside the console, taking remaining horizontal space. */
.log-overlay .log-viewer-output {
    flex: 1;
    margin: 0;
    border: none;
    border-radius: 0;
    padding: 14px 18px 14px 14px;
    background: transparent;
    max-height: none;
    min-height: 0;
    overflow: auto;
    z-index: 1;
    /* Crisp font + extra leading for readability */
    font-family: var(--font-mono, 'JetBrains Mono', 'Cascadia Code', monospace);
    font-size: 0.78rem;
    line-height: 1.55;
    color: var(--lux-ink, #d4d4d4);
    /* Custom scrollbar (WebKit) tinted to match channel */
    scrollbar-color: color-mix(in srgb, var(--ch) 30%, var(--lux-bg-2, #15181d))
                     transparent;
    scrollbar-width: thin;
}
.log-overlay .log-viewer-output::-webkit-scrollbar { width: 10px; height: 10px; }
.log-overlay .log-viewer-output::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--ch) 28%, var(--lux-bg-2, #15181d));
    border-radius: 99px;
    border: 2px solid var(--lux-bg-0, #000);
}
.log-overlay .log-viewer-output::-webkit-scrollbar-track { background: transparent; }

/* Per-line styling: each <span> becomes its own row with a thin
   left edge tinted by severity. The mono colors are kept close to
   the original VS-Code-ish palette so existing muscle memory works. */
.log-overlay .log-viewer-output > span {
    display: block;
    position: relative;
    padding: 2px 6px 2px 12px;
    border-radius: 2px;
    transition: background 0.12s;
}
.log-overlay .log-viewer-output > span::before {
    content: '';
    position: absolute;
    left: 0; top: 4px; bottom: 4px;
    width: 2px;
    border-radius: 2px;
    background: color-mix(in srgb, var(--lux-ink-faint, #3a414c) 70%, transparent);
}
.log-overlay .log-viewer-output > span:hover {
    background: color-mix(in srgb, var(--ch) 6%, transparent);
}
.log-overlay .log-viewer-output > span.log-line-error::before {
    background: var(--ch-coral, #ff5e5e);
    box-shadow: 0 0 6px color-mix(in srgb, var(--ch-coral, #ff5e5e) 60%, transparent);
}
.log-overlay .log-viewer-output > span.log-line-warning::before {
    background: var(--ch-amber, #ffb800);
    box-shadow: 0 0 5px color-mix(in srgb, var(--ch-amber, #ffb800) 50%, transparent);
}
.log-overlay .log-viewer-output > span.log-line-debug::before {
    background: color-mix(in srgb, var(--lux-ink-faint, #3a414c) 80%, transparent);
}

/* Compact layout on narrow viewports (mobile/portrait) */
@media (max-width: 640px) {
    .log-overlay { padding: 14px 12px 12px; gap: 10px; }
    .log-overlay .log-module > .mod-head { padding-right: 48px; }
    .log-console__rail { width: 28px; }
    .log-overlay .log-viewer-output {
        padding: 10px 12px;
        font-size: 0.72rem;
    }
}

/* ── Release notes content ─────────────────────────────────── */

/*
 * Scoped to `.release-notes-shell` so the log overlay is unaffected.
 * Uses --lux-* / --ch-* / --font-display tokens shared with cards-redesign-v2
 * (see docs/cards-redesign-demo-v2.html). Channel: signal (configurable via
 * data-ch on the shell).
 */

.release-notes-shell {
    --rn-ch: var(--ch-signal);
    background: var(--lux-bg-0, var(--bg-color, #000));
    padding: 0;
    overflow: hidden;
    color: var(--lux-ink, var(--text-color));
    font-family: var(--font-body, -apple-system, BlinkMacSystemFont, sans-serif);
}
.release-notes-shell[data-ch="cyan"]    { --rn-ch: var(--ch-cyan); }
.release-notes-shell[data-ch="magenta"] { --rn-ch: var(--ch-magenta); }
.release-notes-shell[data-ch="amber"]   { --rn-ch: var(--ch-amber); }
.release-notes-shell[data-ch="coral"]   { --rn-ch: var(--ch-coral); }
.release-notes-shell[data-ch="violet"]  { --rn-ch: var(--ch-violet); }

/* The default .log-overlay-close is hidden — we render our own .rn-act--close. */
.release-notes-shell > .log-overlay-close { display: none; }

/* Always-on left channel stripe (mirrors .module::before from v2) */
.rn-shell__stripe {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 4px;
    background: var(--rn-ch);
    box-shadow: 0 0 18px color-mix(in srgb, var(--rn-ch) 55%, transparent),
                0 0 4px color-mix(in srgb, var(--rn-ch) 90%, transparent);
    opacity: .85;
    z-index: 2;
}

/* Silkscreen corner brackets — instrument detail */
.rn-shell__bracket {
    position: absolute;
    width: 18px; height: 18px;
    pointer-events: none;
    z-index: 2;
    opacity: .55;
}
.rn-shell__bracket--tl {
    top: 14px; left: 18px;
    border-top: 1px solid var(--lux-line-bold, var(--border-color));
    border-left: 1px solid var(--lux-line-bold, var(--border-color));
}
.rn-shell__bracket--br {
    bottom: 14px; right: 14px;
    border-bottom: 1px solid var(--lux-line-bold, var(--border-color));
    border-right: 1px solid var(--lux-line-bold, var(--border-color));
}

/* ── Header rack ────────────────────────────────────────────────── */
/* Header padding-left matches body padding-left so the title and the
 * markdown content share a single left edge / column. The header acts
 * as a fixed masthead — body scrolls underneath it — so its height
 * directly steals from the visible reading area. Keep it compact. */
.rn-head {
    position: relative;
    /* Paint above the scrollable body so any body content that scrolls
     * up to the head's y-range is masked by the head's solid bg. */
    z-index: 2;
    /* Opt out of layout.css's global `header { height: 60px; display:
     * grid; ... }` rule that's intended for the page transport bar.
     * Without these resets the masthead panel collapses to 60px and
     * its grid template fights our flex layout. */
    height: auto;
    grid-template-columns: none;
    display: flex;
    /* flex-start (not center) so the lede column — eyebrow, title,
     * chips — stacks from the top of the panel. The actions get
     * pinned to the title's vertical centre via align-self below. */
    align-items: flex-start;
    gap: 18px;
    /* Generous vertical padding — the head must wrap the title AND
     * the badge strip. Bigger top/bottom offset so the title doesn't
     * crash into the panel border. */
    padding: 20px 24px 18px 36px;
    border-bottom: 1px solid var(--lux-line, var(--border-color));
    flex-shrink: 0;
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--rn-ch) 4%, transparent) 0%,
            transparent 60%),
        var(--lux-bg-1, var(--bg-secondary));
}
/* Suppress the global `header::before` rainbow gradient line from
 * layout.css — it was painting a horizontal accent line through the
 * masthead, near the title baseline. */
.rn-head::before {
    content: none;
}
/* Vertically center the action cluster against the lede column so the
 * close button sits at roughly title-height — neither pinned to the
 * top corner nor dragged down by the chip strip. */
.rn-head__actions {
    align-self: center;
}
/* No gradient bar at the bottom of the header — the header carries its
 * hairline border-bottom alone, so the eyebrow + meta strip read as a
 * compact instrument readout without an extra section divider. */

.rn-head__lede {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Eyebrow row — mono uppercase + pulsing dot */
.rn-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .28em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    line-height: 1;
}
.rn-eyebrow__dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--rn-ch);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--rn-ch) 22%, transparent);
    animation: rnPulse 2s ease-in-out infinite;
}
.rn-eyebrow__sep {
    width: 1px; height: 10px;
    background: var(--lux-line-bold, var(--border-color));
}
.rn-eyebrow__channel {
    color: var(--rn-ch);
    letter-spacing: .22em;
}
@keyframes rnPulse {
    0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--rn-ch) 22%, transparent); }
    50%      { box-shadow: 0 0 0 6px color-mix(in srgb, var(--rn-ch)  0%, transparent); }
}

/* Metadata chip strip */
.rn-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}
.rn-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .62rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--lux-ink-dim, var(--text-secondary));
    background: var(--lux-bg-0, var(--bg-color, #000));
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: 3px;
    line-height: 1.4;
    white-space: nowrap;
}
.rn-chip__dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--rn-ch);
    box-shadow: 0 0 6px color-mix(in srgb, var(--rn-ch) 70%, transparent);
}
.rn-chip__k {
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: .18em;
}
.rn-chip__v {
    color: var(--lux-ink, var(--text-color));
    font-variant-numeric: tabular-nums;
}
.rn-chip--pre {
    color: var(--ch-amber);
    border-color: color-mix(in srgb, var(--ch-amber) 50%, var(--lux-line-bold));
    /* Solid amber-tinted fill — mixes with the panel bg, never with
     * transparent, so the chip reads as a real opaque badge. */
    background: color-mix(in srgb, var(--ch-amber) 22%, var(--lux-bg-1, #0e1014));
}
.rn-chip--pre .rn-chip__k { color: var(--ch-amber); }

/* Header actions — square mono icon buttons */
.rn-head__actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}
.rn-act {
    appearance: none;
    background: var(--lux-bg-2, var(--bg-tertiary, #1c2027));
    border: 1px solid var(--lux-line-bold, var(--border-color));
    border-radius: 3px;
    width: 36px; height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--lux-ink-dim, var(--text-secondary));
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease,
                background .15s ease, box-shadow .15s ease;
    text-decoration: none;
}
.rn-act svg { width: 16px; height: 16px; }
.rn-act:hover {
    color: var(--lux-ink, var(--text-color));
    border-color: color-mix(in srgb, var(--rn-ch) 45%, var(--lux-line-bold));
    background: var(--lux-bg-3, var(--bg-tertiary, #1c2027));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--rn-ch) 18%, transparent),
                0 0 14px color-mix(in srgb, var(--rn-ch) 22%, transparent);
}
.rn-act:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--rn-ch) 55%, transparent);
}
.rn-act--close:hover {
    color: var(--ch-coral);
    border-color: color-mix(in srgb, var(--ch-coral) 45%, var(--lux-line-bold));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--ch-coral) 18%, transparent);
}

/* ── Body / scroll area ─────────────────────────────────────────── */
.rn-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    background: var(--lux-bg-0, var(--bg-color, #000));
    padding: 28px 36px 48px;
    scrollbar-width: thin;
    scrollbar-color: var(--lux-line-bold, var(--border-color)) transparent;
}
.rn-body::-webkit-scrollbar { width: 10px; }
.rn-body::-webkit-scrollbar-thumb {
    background: var(--lux-line-bold, var(--border-color));
    border-radius: 99px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
.rn-body::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--rn-ch) 50%, var(--lux-line-bold));
    background-clip: padding-box;
}

/* ── Asset rack ─────────────────────────────────────────────────
 * Populated from release.assets — sits above the markdown body and
 * lists every downloadable file as a rack-style chip with icon,
 * filename, size, and extension badge. Centered in the same column
 * as the prose so it reads as a header above the article. */
.rn-assets {
    max-width: 78ch;
    margin: 0 auto 28px;
    padding: 14px 16px 16px;
    background: var(--lux-bg-1, var(--bg-secondary));
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    box-shadow: inset 3px 0 0 var(--rn-ch);
    position: relative;
}
.rn-assets::after {
    /* Silkscreen corner bracket — instrument detail shared with v2 cards. */
    content: '';
    position: absolute;
    top: 8px; right: 8px;
    width: 12px; height: 12px;
    border-top: 1px solid var(--lux-line-bold, var(--border-color));
    border-right: 1px solid var(--lux-line-bold, var(--border-color));
    opacity: .6;
    pointer-events: none;
}
.rn-assets__head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--lux-line, var(--border-color));
}
.rn-assets__dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--rn-ch);
    box-shadow: 0 0 6px color-mix(in srgb, var(--rn-ch) 60%, transparent);
    flex-shrink: 0;
}
.rn-assets__title {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .26em;
    color: var(--lux-ink, var(--text-color));
}
.rn-assets__count {
    margin-left: auto;
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .14em;
    color: var(--rn-ch);
    padding: 2px 8px;
    border: 1px solid color-mix(in srgb, var(--rn-ch) 30%, var(--lux-line));
    border-radius: 99px;
    background: color-mix(in srgb, var(--rn-ch) 14%, var(--lux-bg-1, #0e1014));
    font-variant-numeric: tabular-nums;
}
.rn-assets__list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* Each asset row — full-width rack chip, hover lifts and glows. */
.rn-asset {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: 12px;
    padding: 9px 12px 9px 14px;
    background: var(--lux-bg-0, var(--bg-color, #000));
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    color: var(--lux-ink, var(--text-color));
    text-decoration: none;
    transition: border-color .18s ease, background .18s ease,
                transform .18s ease, box-shadow .18s ease;
    position: relative;
    overflow: hidden;
}
.rn-asset::before {
    /* Per-row left stripe in the channel hue (same idiom as .module). */
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 2px;
    background: var(--rn-ch);
    opacity: .55;
    transition: opacity .18s ease, width .18s ease,
                box-shadow .18s ease;
}
.rn-asset:hover {
    border-color: color-mix(in srgb, var(--rn-ch) 55%, var(--lux-line-bold));
    background: color-mix(in srgb, var(--rn-ch) 6%, var(--lux-bg-0));
    transform: translateY(-1px);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--rn-ch) 22%, transparent);
}
.rn-asset:hover::before {
    opacity: 1;
    width: 3px;
    box-shadow: 0 0 12px color-mix(in srgb, var(--rn-ch) 75%, transparent);
}
.rn-asset:focus-visible {
    outline: none;
    border-color: var(--rn-ch);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--rn-ch) 55%, transparent);
}

.rn-asset__icon {
    display: inline-flex;
    width: 16px; height: 16px;
    color: var(--rn-ch);
    transition: transform .25s var(--ease, cubic-bezier(.16, 1, .3, 1));
    flex-shrink: 0;
}
.rn-asset__icon svg { width: 100%; height: 100%; }
.rn-asset:hover .rn-asset__icon { transform: translateY(2px); }

/* Filename + description live in a stacked column inside the 1fr grid
 * cell so the size + extension chips stay anchored to the right edge. */
.rn-asset__col {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    overflow: hidden;
}
.rn-asset__name {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .9rem;
    font-weight: 600;
    color: var(--lux-ink, var(--text-color));
    letter-spacing: .02em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.rn-asset__desc {
    /* Sans-serif for the human-readable subtitle so it reads as a
     * caption, distinct from the mono filename it labels. */
    font-family: var(--font-body, 'Manrope', sans-serif);
    font-size: .78rem;
    font-weight: 400;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: .01em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.rn-asset:hover .rn-asset__desc {
    color: var(--lux-ink-dim, var(--text-secondary));
}
.rn-asset__size {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .68rem;
    font-weight: 600;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: .08em;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
    white-space: nowrap;
}
.rn-asset__ext {
    padding: 2px 8px;
    background: var(--lux-bg-2, var(--bg-tertiary, #1c2027));
    border: 1px solid color-mix(in srgb, var(--rn-ch) 28%, var(--lux-line));
    border-radius: 2px;
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .62rem;
    font-weight: 700;
    color: var(--rn-ch);
    letter-spacing: .14em;
    text-transform: uppercase;
    flex-shrink: 0;
    white-space: nowrap;
}

/* Narrow viewports — drop the size column so the filename gets all the room. */
@media (max-width: 540px) {
    .rn-asset { grid-template-columns: auto 1fr auto; }
    .rn-asset__size { display: none; }
}

/* ── Markdown content (scoped to .release-notes-shell) ────────── */
.release-notes-shell .release-notes-content {
    /* Article-style centered prose column. The header stays a full-width
     * masthead (title at left, actions at far right) while the body is
     * centered like a long-form article for comfortable reading. */
    max-width: 78ch;
    margin: 0 auto;
    font-family: var(--font-body, 'Manrope', sans-serif);
    font-size: .96rem;
    line-height: 1.65;
    color: var(--lux-ink, var(--text-color));
    background: transparent;
    padding: 0;
    border-radius: 0;
    counter-reset: rn-section;
}

/* Stagger reveal — each direct child fades in with a small delay */
.release-notes-shell .release-notes-content > * {
    animation: rnRise .55s var(--ease, cubic-bezier(.16, 1, .3, 1)) both;
}
.release-notes-shell .release-notes-content > *:nth-child(1)  { animation-delay: .04s; }
.release-notes-shell .release-notes-content > *:nth-child(2)  { animation-delay: .09s; }
.release-notes-shell .release-notes-content > *:nth-child(3)  { animation-delay: .14s; }
.release-notes-shell .release-notes-content > *:nth-child(4)  { animation-delay: .19s; }
.release-notes-shell .release-notes-content > *:nth-child(5)  { animation-delay: .24s; }
.release-notes-shell .release-notes-content > *:nth-child(6)  { animation-delay: .29s; }
.release-notes-shell .release-notes-content > *:nth-child(7)  { animation-delay: .34s; }
.release-notes-shell .release-notes-content > *:nth-child(8)  { animation-delay: .38s; }
.release-notes-shell .release-notes-content > *:nth-child(n+9){ animation-delay: .42s; }
@keyframes rnRise {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

/* H1 — display font, channel-tinted decorative bar */
.release-notes-shell .release-notes-content h1 {
    font-family: var(--font-display, 'Big Shoulders Display', sans-serif);
    font-size: 2.1rem;
    font-weight: 900;
    letter-spacing: -.02em;
    line-height: 1.05;
    color: var(--lux-ink, var(--text-color));
    margin: 1.6em 0 .55em;
    padding-bottom: .35em;
    border-bottom: 1px solid var(--lux-line, var(--border-color));
    position: relative;
}
.release-notes-shell .release-notes-content h1::after {
    content: '';
    position: absolute;
    left: 0; bottom: -1px;
    width: 64px; height: 2px;
    background: linear-gradient(90deg, var(--rn-ch), transparent);
}
.release-notes-shell .release-notes-content h1:first-child { margin-top: 0; }

/* H2 — display font with leading mono index counter */
.release-notes-shell .release-notes-content h2 {
    font-family: var(--font-display, 'Big Shoulders Display', sans-serif);
    font-size: 1.55rem;
    font-weight: 800;
    letter-spacing: -.015em;
    color: var(--lux-ink, var(--text-color));
    margin: 1.7em 0 .5em;
    display: flex;
    align-items: center;
    gap: 14px;
    counter-increment: rn-section;
}
.release-notes-shell .release-notes-content h2::before {
    content: counter(rn-section, decimal-leading-zero);
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .12em;
    color: var(--rn-ch);
    padding-right: 12px;
    border-right: 1px solid var(--lux-line, var(--border-color));
    line-height: 1;
}

/* H3/H4 — mono uppercase, channel-bracketed */
.release-notes-shell .release-notes-content h3,
.release-notes-shell .release-notes-content h4 {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .22em;
    color: var(--lux-ink, var(--text-color));
    margin: 1.5em 0 .55em;
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
.release-notes-shell .release-notes-content h3 { font-size: .82rem; }
.release-notes-shell .release-notes-content h4 { font-size: .72rem; color: var(--lux-ink-dim, var(--text-secondary)); }
.release-notes-shell .release-notes-content h3::before,
.release-notes-shell .release-notes-content h4::before {
    content: '';
    width: 14px; height: 1px;
    background: var(--rn-ch);
    flex-shrink: 0;
    box-shadow: 0 0 6px color-mix(in srgb, var(--rn-ch) 60%, transparent);
}

/* Paragraphs */
.release-notes-shell .release-notes-content p {
    margin: 0 0 1em;
    color: var(--lux-ink-dim, var(--text-secondary));
}
.release-notes-shell .release-notes-content p strong,
.release-notes-shell .release-notes-content li strong { color: var(--lux-ink, var(--text-color)); }

/* Lists — channel-tinted bullets/numerals */
.release-notes-shell .release-notes-content ul,
.release-notes-shell .release-notes-content ol {
    margin: 0 0 1.1em;
    padding-left: 1.6em;
    color: var(--lux-ink-dim, var(--text-secondary));
}
.release-notes-shell .release-notes-content li { margin: .25em 0; }
.release-notes-shell .release-notes-content ul { list-style: none; padding-left: 1.4em; }
.release-notes-shell .release-notes-content ul > li { position: relative; }
.release-notes-shell .release-notes-content ul > li::before {
    content: '';
    position: absolute;
    left: -1.1em; top: .65em;
    width: 6px; height: 6px;
    background: var(--rn-ch);
    transform: rotate(45deg);
    box-shadow: 0 0 6px color-mix(in srgb, var(--rn-ch) 55%, transparent);
}
.release-notes-shell .release-notes-content ul > li > ul > li::before {
    background: var(--lux-ink-mute, var(--text-secondary));
    box-shadow: none;
}
.release-notes-shell .release-notes-content ol > li::marker {
    color: var(--rn-ch);
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-weight: 700;
}

/* Task-list checkboxes (GitHub-flavoured) */
.release-notes-shell .release-notes-content li input[type="checkbox"] {
    accent-color: var(--rn-ch);
    margin-right: .4em;
    transform: translateY(1px);
}
.release-notes-shell .release-notes-content ul.contains-task-list { list-style: none; padding-left: .4em; }
.release-notes-shell .release-notes-content ul.contains-task-list > li::before { display: none; }

/* Inline code — hairline-bordered mono pill */
.release-notes-shell .release-notes-content code {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .85em;
    background: color-mix(in srgb, var(--rn-ch) 10%, var(--lux-bg-2, var(--bg-tertiary)));
    color: var(--lux-ink, var(--text-color));
    padding: .12em .42em;
    border: 1px solid color-mix(in srgb, var(--rn-ch) 22%, var(--lux-line));
    border-radius: 3px;
}

/* Code fences — instrument readout block with corner bracket */
.release-notes-shell .release-notes-content pre {
    position: relative;
    background: var(--lux-bg-1, #0e1014);
    color: var(--lux-ink, #e6ebf2);
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    padding: 14px 18px 14px 22px;
    margin: 1.1em 0 1.4em;
    overflow-x: auto;
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .82rem;
    line-height: 1.55;
    box-shadow: inset 3px 0 0 var(--rn-ch);
}
.release-notes-shell .release-notes-content pre::after {
    content: '';
    position: absolute;
    top: 8px; right: 8px;
    width: 10px; height: 10px;
    border-top: 1px solid var(--lux-line-bold, var(--border-color));
    border-right: 1px solid var(--lux-line-bold, var(--border-color));
    opacity: .65;
}
.release-notes-shell .release-notes-content pre code {
    background: transparent;
    padding: 0;
    border: none;
    color: inherit;
    font-size: inherit;
}

/* Blockquotes — channel-tinted callout */
.release-notes-shell .release-notes-content blockquote {
    margin: 1.2em 0;
    padding: 12px 18px;
    border-left: 3px solid var(--rn-ch);
    background: color-mix(in srgb, var(--rn-ch) 6%, var(--lux-bg-1, var(--bg-secondary)));
    color: var(--lux-ink-dim, var(--text-secondary));
    border-radius: 0 var(--lux-r-sm, 3px) var(--lux-r-sm, 3px) 0;
    font-style: italic;
}
.release-notes-shell .release-notes-content blockquote > p:last-child { margin-bottom: 0; }

/* Links — dashed-underline reveal on hover */
.release-notes-shell .release-notes-content a {
    color: var(--rn-ch);
    text-decoration: none;
    border-bottom: 1px dashed color-mix(in srgb, var(--rn-ch) 45%, transparent);
    transition: border-color .15s ease, color .15s ease;
}
.release-notes-shell .release-notes-content a:hover {
    border-bottom-style: solid;
    border-bottom-color: var(--rn-ch);
    color: color-mix(in srgb, var(--rn-ch) 80%, var(--lux-ink));
}

/* Horizontal rule — patch-bay dot leader */
.release-notes-shell .release-notes-content hr {
    border: none;
    height: 8px;
    margin: 2em 0;
    background-image: radial-gradient(circle, var(--lux-line-bold, var(--border-color)) 1px, transparent 1px);
    background-size: 12px 8px;
    background-repeat: repeat-x;
    background-position: center;
    opacity: .6;
}

/* Tables — rack-style, mono uppercase headers */
.release-notes-shell .release-notes-content table {
    width: 100%;
    border-collapse: collapse;
    margin: 1.2em 0;
    background: var(--lux-bg-1, var(--bg-secondary));
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    overflow: hidden;
}
.release-notes-shell .release-notes-content thead { background: var(--lux-bg-2, var(--bg-tertiary)); }
.release-notes-shell .release-notes-content th {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .18em;
    color: var(--lux-ink-mute, var(--text-secondary));
    text-align: left;
    padding: 10px 14px;
    border-bottom: 1px solid var(--lux-line, var(--border-color));
}
.release-notes-shell .release-notes-content td {
    padding: 11px 14px;
    border-bottom: 1px solid var(--lux-line, var(--border-color));
    font-size: .94rem;
    line-height: 1.5;
    color: var(--lux-ink-dim, var(--text-secondary));
}
.release-notes-shell .release-notes-content tr:last-child td { border-bottom: none; }
.release-notes-shell .release-notes-content tr:hover td {
    background: color-mix(in srgb, var(--rn-ch) 5%, transparent);
    color: var(--lux-ink, var(--text-color));
}

/* Images / asset embeds */
.release-notes-shell .release-notes-content img {
    max-width: 100%;
    border-radius: var(--lux-r-sm, 3px);
    border: 1px solid var(--lux-line, var(--border-color));
    box-shadow: 0 6px 20px rgba(0, 0, 0, .3);
}

/* ── Inline asset-code links ───────────────────────────────────
 * `<code>` elements containing a filename that matches an entry in
 * release.assets get wrapped in <a class="rn-code-link"> by
 * _linkInlineAssetCode(). The wrapper is invisible so the existing
 * <code> visual is preserved, but the cursor + hover treatment make
 * the chip feel actionable. Strips the default dashed-underline link
 * styling so it doesn't fight the <code> background. */
.release-notes-shell .release-notes-content a.rn-code-link {
    text-decoration: none;
    border-bottom: none;
    color: inherit;
    cursor: pointer;
    transition: filter .15s ease;
}
.release-notes-shell .release-notes-content a.rn-code-link > code {
    transition: border-color .15s ease, background .15s ease,
                color .15s ease, box-shadow .15s ease;
}
.release-notes-shell .release-notes-content a.rn-code-link:hover > code {
    color: var(--rn-ch);
    border-color: color-mix(in srgb, var(--rn-ch) 65%, var(--lux-line-bold));
    background: color-mix(in srgb, var(--rn-ch) 18%, var(--lux-bg-2, var(--bg-tertiary)));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--rn-ch) 30%, transparent),
                0 4px 14px color-mix(in srgb, var(--rn-ch) 22%, transparent);
}
/* Tiny ⤓ glyph after the code chip — the download affordance. */
.release-notes-shell .release-notes-content a.rn-code-link::after {
    content: '⤓';
    margin-left: 4px;
    color: var(--rn-ch);
    opacity: .7;
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .9em;
    transition: opacity .15s ease, transform .2s var(--ease, cubic-bezier(.16, 1, .3, 1));
    display: inline-block;
}
.release-notes-shell .release-notes-content a.rn-code-link:hover::after {
    opacity: 1;
    transform: translateY(2px);
}
.release-notes-shell .release-notes-content a.rn-code-link:focus-visible {
    outline: none;
}
.release-notes-shell .release-notes-content a.rn-code-link:focus-visible > code {
    border-color: var(--rn-ch);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--rn-ch) 55%, transparent);
}

/* ── Download links ─────────────────────────────────────────────
 * Anchors classified as `.rn-dl` by _decorateReleaseNotesLinks() get
 * a rack-style chip treatment with a leading download icon and a
 * trailing mono extension badge. Inline-flex so they sit happily
 * inside paragraphs OR as standalone list items. */
.release-notes-shell .release-notes-content a.rn-dl {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    vertical-align: baseline;
    padding: 7px 10px 7px 12px;
    margin: 1px 2px;
    background: color-mix(in srgb, var(--rn-ch) 8%, var(--lux-bg-1, var(--bg-secondary)));
    border: 1px solid color-mix(in srgb, var(--rn-ch) 30%, var(--lux-line));
    border-radius: var(--lux-r-sm, 3px);
    color: var(--lux-ink, var(--text-color));
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: .92em;
    font-weight: 600;
    letter-spacing: .02em;
    line-height: 1.25;
    text-decoration: none;
    box-shadow: inset 3px 0 0 var(--rn-ch);
    transition: border-color .18s ease, background .18s ease,
                transform .18s ease, box-shadow .18s ease;
    /* Override the default dashed-underline link treatment */
    border-bottom: 1px solid color-mix(in srgb, var(--rn-ch) 30%, var(--lux-line));
}
/* When the markdown source wraps the filename in backticks, an inner
 * <code> ends up inside the chip. The chip itself is already the visual
 * container, so the nested <code> styling (small font, extra border /
 * background) just makes the text look cramped and doubly-pilled. Reset
 * it to inherit so the chip reads as one unified element. */
.release-notes-shell .release-notes-content a.rn-dl > code {
    font-size: inherit;
    background: transparent;
    border: none;
    padding: 0;
    color: inherit;
    border-radius: 0;
}
.release-notes-shell .release-notes-content a.rn-dl:hover {
    border-color: color-mix(in srgb, var(--rn-ch) 75%, var(--lux-line-bold));
    background: color-mix(in srgb, var(--rn-ch) 14%, var(--lux-bg-1, var(--bg-secondary)));
    transform: translateY(-1px);
    box-shadow: inset 3px 0 0 var(--rn-ch),
                0 4px 14px color-mix(in srgb, var(--rn-ch) 28%, transparent);
}
.release-notes-shell .release-notes-content a.rn-dl:focus-visible {
    outline: none;
    border-color: var(--rn-ch);
    box-shadow: inset 3px 0 0 var(--rn-ch),
                0 0 0 2px color-mix(in srgb, var(--rn-ch) 55%, transparent);
}
.rn-dl__icon {
    display: inline-flex;
    width: 15px; height: 15px;
    color: var(--rn-ch);
    flex-shrink: 0;
    transition: transform .25s var(--ease, cubic-bezier(.16, 1, .3, 1));
}
.rn-dl__icon svg { width: 100%; height: 100%; }
.release-notes-shell .release-notes-content a.rn-dl:hover .rn-dl__icon {
    transform: translateY(2px);
}
.rn-dl__ext {
    margin-left: 2px;
    padding: 2px 7px;
    background: var(--lux-bg-0, var(--bg-color, #000));
    border: 1px solid color-mix(in srgb, var(--rn-ch) 28%, var(--lux-line));
    border-radius: 2px;
    font-size: .86em;
    font-weight: 700;
    color: var(--rn-ch);
    letter-spacing: .14em;
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
    line-height: 1.15;
    flex-shrink: 0;
}

/* Standalone download link as a single list item — promote to a
 * larger "primary action" pill when it's the only child of <li>. */
.release-notes-shell .release-notes-content li > a.rn-dl:only-child {
    padding: 8px 12px 8px 14px;
    font-size: .86em;
}
.release-notes-shell .release-notes-content li > a.rn-dl:only-child .rn-dl__icon {
    width: 15px; height: 15px;
}

/* External-link decoration — small ↗ glyph after links pointing
 * outside the current origin (and not classified as downloads). */
.release-notes-shell .release-notes-content a.rn-ext::after {
    content: '↗';
    margin-left: 3px;
    color: var(--rn-ch);
    font-size: .9em;
    opacity: .85;
    transition: transform .15s ease;
    display: inline-block;
}
.release-notes-shell .release-notes-content a.rn-ext:hover::after {
    transform: translate(1px, -1px);
    opacity: 1;
}

/* Reduced-motion: kill staggered animation, keep aesthetic */
@media (prefers-reduced-motion: reduce) {
    .release-notes-shell .release-notes-content > * { animation: none; }
    .rn-eyebrow__dot { animation: none; }
}

/* Narrow viewports — collapse header to stack */
@media (max-width: 640px) {
    .rn-head { flex-direction: column; align-items: stretch; padding: 18px 18px 14px 24px; }
    .rn-head__actions { align-self: flex-end; }
    .rn-body { padding: 22px 18px 36px; }
    .release-notes-shell .release-notes-content h1 { font-size: 1.7rem; }
    .release-notes-shell .release-notes-content h2 { font-size: 1.3rem; }
}

/* ── Log viewer base ───────────────────────────────────────── */

.log-viewer-output {
    background: var(--lux-bg-0, #0d0d0d);
    color: var(--lux-ink, #d4d4d4);
    font-family: var(--font-mono, 'Consolas', 'Courier New', monospace);
    font-size: 0.75rem;
    line-height: 1.5;
    padding: 0.6rem 0.75rem;
    border-radius: var(--lux-r-sm, 3px);
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    max-height: 400px;
    overflow-y: auto;
    overflow-x: auto;
    white-space: pre;
    margin: 0;
}

/* Severity tint applied to the line text. Inside the overlay these
   pair with the channel-tinted left edge added by .log-overlay rules
   above; outside the overlay they stand alone. */
.log-viewer-output .log-line-error {
    color: color-mix(in srgb, var(--ch-coral, #ff5e5e) 80%, var(--lux-ink, #d4d4d4));
}

.log-viewer-output .log-line-warning {
    color: color-mix(in srgb, var(--ch-amber, #ffb800) 78%, var(--lux-ink, #d4d4d4));
}

.log-viewer-output .log-line-debug {
    color: color-mix(in srgb, var(--lux-ink-faint, #6a9955) 70%, var(--lux-ink-mute, #888));
}

/* LED count control */
.css-test-led-control {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 0 0;
    font-size: 0.85em;
}

.css-test-led-control label {
    display: inline;
    margin-bottom: 0;
}

.css-test-led-input {
    width: 70px;
    flex: 0 0 70px;
    padding: 3px 6px;
    border: 1px solid var(--border-color, #333);
    border-radius: 4px;
    background: var(--input-bg, #1a1a2e);
    color: var(--text-color, #e0e0e0);
    font-size: 0.85em;
    text-align: center;
}

.css-test-led-apply {
    padding: 2px 6px;
    font-size: 0.85em;
    line-height: 1;
}

#css-test-led-group {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.css-test-separator {
    width: 1px;
    height: 18px;
    background: var(--border-color, #333);
    margin: 0 4px;
}

#test-css-source-modal .modal-content,
#test-stream-modal .modal-content {
    max-width: 700px;
}

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

.modal-content {
    --modal-ch: var(--ch-signal, var(--primary-color));
    background: linear-gradient(180deg,
        var(--lux-bg-1, var(--card-bg)) 0%,
        var(--lux-bg-2, var(--card-bg)) 100%);
    border: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    border-radius: var(--lux-r-lg, var(--radius-lg));
    max-width: 500px;
    width: 90%;
    max-height: calc(100vh - 40px);
    display: flex;
    flex-direction: column;
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.02),
        0 20px 60px rgba(0, 0, 0, 0.5),
        0 8px 32px var(--shadow-color);
    animation: slideUp 0.3s cubic-bezier(0.16, 1, 0.3, 1);
    position: relative;
    overflow: hidden;
}

/* Channel accent rule across the top edge of every modal. Type-specific
   modals can override `--modal-ch` to get a different stripe color. */
.modal-content::before {
    content: '';
    position: absolute;
    left: 0; right: 0; top: 0;
    height: 2px;
    background: linear-gradient(90deg,
        transparent 0%,
        var(--modal-ch) 20%,
        var(--modal-ch) 80%,
        transparent 100%);
    opacity: 0.9;
    box-shadow: 0 0 12px color-mix(in srgb, var(--modal-ch) 50%, transparent);
    pointer-events: none;
    z-index: 2;
}

/* Corner bracket — silkscreened panel feel, bottom-right this time so
   it doesn't clash with the header-actions row in the top-right. */
.modal-content::after {
    content: '';
    position: absolute;
    right: 10px; bottom: 10px;
    width: 12px; height: 12px;
    border-bottom: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    border-right: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    opacity: 0.5;
    pointer-events: none;
    z-index: 1;
}

/* Per-modal channel colors — map well-known modal IDs to channel lanes.
   Modals not listed keep the default green stripe. */
#target-editor-modal .modal-content,
#add-device-modal .modal-content,
#device-settings-modal .modal-content,
#ha-light-editor-modal .modal-content,
#calibration-modal .modal-content                 { --modal-ch: var(--ch-signal, var(--primary-color)); }

#stream-modal .modal-content,
#test-stream-modal .modal-content,
#capture-template-modal .modal-content,
#test-template-modal .modal-content,
#pp-template-modal .modal-content,
#test-pp-template-modal .modal-content,
#cspt-modal .modal-content,
#css-editor-modal .modal-content,
#test-css-source-modal .modal-content,
#pattern-template-modal .modal-content,
#gradient-editor-modal .modal-content,
#value-source-editor-modal .modal-content,
#test-value-source-modal .modal-content,
#asset-editor-modal .modal-content,
#asset-upload-modal .modal-content,
#ha-source-editor-modal .modal-content,
#mqtt-source-editor-modal .modal-content,
#sync-clock-editor-modal .modal-content,
#weather-source-editor-modal .modal-content       { --modal-ch: var(--ch-cyan, var(--info-color)); }

#audio-source-editor-modal .modal-content,
#audio-template-modal .modal-content,
#audio-processing-template-modal .modal-content,
#test-audio-source-modal .modal-content,
#test-audio-template-modal .modal-content         { --modal-ch: var(--ch-magenta, #ff4ade); }

#automation-editor-modal .modal-content,
#scene-preset-editor-modal .modal-content,
#game-integration-editor-modal .modal-content     { --modal-ch: var(--ch-violet, #8b7eff); }

#settings-modal .modal-content,
#api-key-modal .modal-content,
#setup-required-modal .modal-content,
#notification-history-modal .modal-content        { --modal-ch: var(--ch-amber, var(--warning-color)); }

#confirm-modal .modal-content                     { --modal-ch: var(--ch-coral, var(--danger-color)); }

#template-modal .modal-content {
    max-width: 500px !important;
    width: 100% !important;
}

#test-template-modal .modal-content {
    max-width: 420px;
}

@keyframes slideUp {
    from {
        transform: translateY(20px) scale(0.98);
        opacity: 0;
    }
    to {
        transform: translateY(0) scale(1);
        opacity: 1;
    }
}

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

@keyframes slideDown {
    from {
        transform: translateY(0) scale(1);
        opacity: 1;
    }
    to {
        transform: translateY(12px) scale(0.97);
        opacity: 0;
    }
}

/* Exit animation — applied by Modal.forceClose() before display:none.
   Symmetric to fadeIn/slideUp, slightly faster on the way out for a
   responsive feel. */
.modal.closing {
    animation: fadeOut 0.18s ease-in forwards;
    pointer-events: none;
}

.modal.closing .modal-content {
    animation: slideDown 0.2s cubic-bezier(0.7, 0, 0.84, 0) forwards;
}

@media (prefers-reduced-motion: reduce) {
    .modal,
    .modal.closing,
    .modal-content,
    .modal.closing .modal-content {
        animation: none !important;
    }
}

.modal-header {
    padding: 18px 24px 16px 28px;
    border-bottom: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: relative;
}

/* Tiny channel-color square to the left of the title, consistent with
   the sidebar's section-label marker. */
.modal-header::before {
    content: '';
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 22px;
    background: var(--modal-ch, var(--ch-signal, var(--primary-color)));
    border-radius: 2px;
    box-shadow: 0 0 10px color-mix(in srgb, var(--modal-ch, var(--ch-signal, var(--primary-color))) 50%, transparent);
    opacity: 0.85;
}

.modal-header h2 {
    margin: 0;
    font-family: var(--font-body, inherit);
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--lux-ink, var(--text-color));
    display: flex;
    align-items: center;
    gap: 8px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    min-width: 0;
}
.modal-header h2 .icon {
    color: var(--modal-ch, var(--ch-signal, var(--primary-color)));
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

.modal-header-actions {
    display: flex;
    align-items: center;
    gap: 4px;
}

.modal-header-btn {
    background: none;
    border: none;
    font-size: 1.1rem;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border-radius: 4px;
    transition: background 0.2s;
    flex-shrink: 0;
}
.modal-header-btn:hover {
    background: rgba(128, 128, 128, 0.15);
}
.modal-header-btn:disabled {
    opacity: 0.4;
    cursor: default;
}

.modal-close-btn {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.2rem;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border-radius: 4px;
    transition: color 0.2s, background 0.2s;
    flex-shrink: 0;
}

.modal-close-btn:hover {
    color: var(--text-color);
    background: rgba(128, 128, 128, 0.15);
}

.modal-body {
    padding: 24px;
    overflow-y: auto;
    scrollbar-gutter: stable;
    flex: 1 1 auto;
    min-height: 0;
}

.modal-description {
    color: var(--text-secondary);
    margin-bottom: 20px;
    line-height: 1.6;
}

.password-input-wrapper {
    position: relative;
    display: flex;
    align-items: center;
}

.password-input-wrapper input {
    flex: 1;
    padding-right: 45px;
}

.password-toggle {
    position: absolute;
    right: 8px;
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.2rem;
    padding: 8px;
    color: var(--text-color);
    opacity: 0.6;
    transition: opacity 0.2s;
}

.password-toggle:hover {
    opacity: 1;
}

.label-row {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 5px;
}

.label-row label {
    margin-bottom: 0;
}

.hint-toggle {
    background: none;
    border: 1px solid var(--border-color);
    border-radius: 50%;
    width: 18px;
    height: 18px;
    font-size: 0.7rem;
    line-height: 1;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0.6;
    transition: opacity 0.2s;
    flex-shrink: 0;
}

.hint-toggle:hover {
    opacity: 1;
}

.hint-toggle.active {
    opacity: 1;
    color: var(--primary-text-color);
    border-color: var(--primary-color);
    background: color-mix(in srgb, var(--primary-color) 18%, transparent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary-color) 22%, transparent);
}

/* Compact action button slotted into a .label-row alongside .hint-toggle.
   Pushes itself to the trailing edge so the label and hint stay grouped
   left while utility actions (e.g. refresh) sit at the row end. */
.label-row-action {
    margin-left: auto;
    flex-shrink: 0;
    background: none;
    border: 1px solid var(--border-color);
    border-radius: 50%;
    width: 20px;
    height: 20px;
    font-size: 0.85rem;
    line-height: 1;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0.7;
    transition: opacity 0.2s, color 0.2s, border-color 0.2s;
}

.label-row-action:hover {
    opacity: 1;
    color: var(--lux-ink, var(--text-color));
    border-color: var(--lux-line-bold, var(--border-color));
}

.label-row-action:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

/* Floating hint tooltip — anchored to the active `.hint-toggle` button.
   Replaces the legacy inline small.input-hint reveal which pushed the
   form below it down on every help click. The popover is `position:
   fixed` and lives at the body level so it can escape modal overflow
   and never reflow the form. */
.hint-popover {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 10005;
    max-width: min(320px, calc(100vw - 24px));
    padding: 10px 13px;
    background: linear-gradient(180deg,
        var(--lux-bg-3, var(--bg-secondary)) 0%,
        var(--lux-bg-2, var(--card-bg)) 100%);
    border: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    box-shadow:
        0 14px 36px rgba(0, 0, 0, 0.55),
        0 0 0 1px rgba(255, 255, 255, 0.02),
        inset 0 1px 0 rgba(255, 255, 255, 0.04);
    color: var(--lux-ink, var(--text-color));
    font-size: 0.82rem;
    line-height: 1.5;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.14s ease;
    white-space: normal;
    word-break: break-word;
}

.hint-popover.open {
    opacity: 1;
    pointer-events: auto;
}

/* Channel-color accent stripe along the edge nearest the anchor. */
.hint-popover::before {
    content: '';
    position: absolute;
    left: 10px;
    right: 10px;
    height: 1px;
    background: linear-gradient(90deg,
        transparent 0%,
        color-mix(in srgb, var(--ch-signal, var(--primary-color)) 70%, transparent) 50%,
        transparent 100%);
    pointer-events: none;
}
.hint-popover[data-placement="bottom"]::before { top: 0; }
.hint-popover[data-placement="top"]::before    { bottom: 0; }

/* Diamond arrow pointing back at the `?` button. Inherits the panel's
   border + background so the seam reads as a continuous edge. */
.hint-popover::after {
    content: '';
    position: absolute;
    left: var(--hint-arrow-x, 50%);
    width: 9px;
    height: 9px;
    background: var(--lux-bg-3, var(--bg-secondary));
    border: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    transform: translateX(-50%) rotate(45deg);
    pointer-events: none;
}

.hint-popover[data-placement="bottom"]::after {
    top: -5px;
    border-right: none;
    border-bottom: none;
}

.hint-popover[data-placement="top"]::after {
    bottom: -5px;
    border-left: none;
    border-top: none;
}

@media (prefers-reduced-motion: reduce) {
    .hint-popover {
        transition: none;
    }
}

.input-hint {
    display: block;
    margin: 0 0 6px 0;
    color: var(--text-muted);
    font-size: 0.85rem;
}

.field-desc {
    display: block;
    margin: 4px 0 0 0;
    color: var(--text-secondary);
    font-size: 0.82rem;
    font-style: italic;
}

.inline-fields {
    display: flex;
    gap: 12px;
}

.inline-field {
    flex: 1;
}

.inline-field label {
    display: block;
    margin-bottom: 4px;
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.inline-field input[type="number"] {
    width: 100%;
}

/* Segment rows in target editor */
.segment-row {
    border: 1px solid var(--border-color, #333);
    border-radius: 6px;
    padding: 8px 10px;
    margin-bottom: 6px;
    background: var(--card-bg, #1e1e1e);
}

.device-led-info {
    display: block;
    margin-top: 4px;
    color: var(--text-muted);
    font-size: 0.85em;
}

.segment-row-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;
}

.segment-index-label {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-secondary);
}

.btn-icon-inline {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
}

.btn-icon-inline .icon {
    width: 16px;
    height: 16px;
}

.btn-danger-text {
    color: var(--danger-color, #f44336);
}

.btn-danger-text:hover {
    color: #ff6659;
}

.segment-row-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.segment-row-fields select {
    flex: 1 1 100%;
}

.segment-range-fields {
    display: flex;
    gap: 6px;
    align-items: center;
    flex: 1;
}

.segment-range-fields label {
    font-size: 0.82rem;
    color: var(--text-secondary);
    white-space: nowrap;
}

.segment-range-fields input[type="number"] {
    width: 70px;
}

.segment-reverse-label {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.85rem;
    color: var(--text-secondary);
    cursor: pointer;
    white-space: nowrap;
}

.segment-reverse-label input[type="checkbox"] {
    margin: 0;
}

.btn-sm {
    font-size: 0.8rem;
    padding: 4px 10px;
    min-width: auto;
}


.fps-hint {
    display: block;
    margin-top: 4px;
    font-size: 0.82rem;
    color: var(--info-color, #2196F3);
}

.slider-row {
    display: flex;
    align-items: center;
    gap: 12px;
}

.slider-row input[type="range"] {
    flex: 1;
}

.slider-value {
    min-width: 28px;
    text-align: center;
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text-primary);
}

.form-collapse {
    margin-bottom: 12px;
    border-top: 1px solid var(--border-color);
    padding-top: 8px;
}

.form-collapse > summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--text-secondary);
    padding: 4px 0;
    user-select: none;
}

.form-collapse > summary::-webkit-details-marker { display: none; }

.form-collapse > summary::before {
    content: '';
    display: inline-block;
    width: 0;
    height: 0;
    border-left: 0.35em solid currentColor;
    border-top: 0.25em solid transparent;
    border-bottom: 0.25em solid transparent;
    opacity: 0.6;
    transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    flex-shrink: 0;
}

.form-collapse[open] > summary::before {
    transform: rotate(90deg);
}

.form-collapse > summary:hover {
    color: var(--text-color);
}

.form-collapse-body {
    padding-top: 8px;
}

.error-message {
    background: color-mix(in srgb, var(--danger-color) 10%, transparent); /* --danger-color tint */
    border: 1px solid var(--danger-color);
    color: var(--danger-color);
    padding: 12px;
    border-radius: 4px;
    margin-top: 15px;
    font-size: 0.9rem;
}

.modal-footer {
    padding: 16px 24px 20px 24px;
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    border-top: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    background: linear-gradient(180deg,
        transparent 0%,
        color-mix(in srgb, var(--lux-bg-0, transparent) 30%, transparent) 100%);
}

.modal-footer .btn-icon {
    min-width: 60px;
    padding: 10px 20px;
    font-size: 1.4rem;
}

.btn-display-picker {
    width: 100%;
    padding: 10px;
    border: 1px solid var(--border-color);
    border-radius: 4px;
    background: var(--bg-color);
    color: var(--text-color);
    font-size: 1rem;
    cursor: pointer;
    text-align: left;
    transition: border-color 0.2s, box-shadow 0.2s;
    font-weight: 400;
}

.btn-display-picker:hover {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary-color) 15%, transparent); /* --primary-color tint */
}

.modal-content-wide {
    width: fit-content;
    max-width: calc(100vw - 40px);
    max-height: calc(100vh - 40px);
    display: flex;
    flex-direction: column;
}

@media (min-width: 769px) {
    .modal-content-wide {
        min-width: 500px;
    }
}

.modal-content-wide .modal-body {
    overflow-y: auto;
    scrollbar-gutter: stable;
    flex: 1 1 auto;
    min-height: 0;
}

@media (max-width: 768px) {
    .modal-content {
        width: 95%;
        margin: 20px;
    }

    .modal-footer .btn {
        min-width: 80px;
    }
}

/* ── Lightbox shell — Lumenworks studio-console vocabulary ─────────────
 *
 * Both lightboxes (image preview, display picker) share a single shell so
 * they read as the same instrument: vignette backdrop, panel with hairline
 * border, channel stripe + glow on the left, silkscreened corner brackets
 * (TL + BR), mono uppercase eyebrow with a pulsing channel dot, and a
 * Big-Shoulders display title with a channel-tinted accent word.
 *
 * Channel is set per shell via `data-ch="cyan|magenta|amber|coral|violet"`
 * (mirrors release-notes-shell). Default is signal-green.
 * ─────────────────────────────────────────────────────────────────────── */
.lightbox {
    /* Always rendered to flex so entry/exit transitions can animate
     * smoothly (visibility-based hide). */
    display: flex;
    visibility: hidden;
    pointer-events: none;
    position: fixed;
    inset: 0;
    z-index: var(--z-lightbox);
    justify-content: center;
    align-items: center;
    cursor: zoom-out;
    /* Vignette backdrop — radial fade from translucent center to dense
     * edge. Tinted by the active channel via .lightbox[data-ch]. */
    --lb-ch: var(--ch-signal);
    background:
        radial-gradient(ellipse at center,
            rgba(0, 0, 0, 0.78) 0%,
            rgba(0, 0, 0, 0.94) 70%),
        radial-gradient(circle at 18% 24%,
            color-mix(in srgb, var(--lb-ch) 7%, transparent) 0%,
            transparent 55%),
        var(--lux-bg-0, #000);
    backdrop-filter: blur(2px);
    /* Backdrop fades; visibility flips after fade-out so clicks don't
     * bleed through during the exit animation. */
    opacity: 0;
    transition:
        opacity 220ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)),
        visibility 0s linear 240ms,
        backdrop-filter 220ms ease;
}

.lightbox[data-ch="cyan"]    { --lb-ch: var(--ch-cyan); }
.lightbox[data-ch="magenta"] { --lb-ch: var(--ch-magenta); }
.lightbox[data-ch="amber"]   { --lb-ch: var(--ch-amber); }
.lightbox[data-ch="coral"]   { --lb-ch: var(--ch-coral); }
.lightbox[data-ch="violet"]  { --lb-ch: var(--ch-violet); }

.lightbox.active {
    visibility: visible;
    pointer-events: auto;
    opacity: 1;
    transition:
        opacity 260ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)),
        visibility 0s linear 0s,
        backdrop-filter 260ms ease;
}

/* ── Panel shell — slides up + scales in on entry, drops + fades on exit ── */
.lightbox-content {
    position: relative;
    max-width: 95%;
    max-height: 95%;
    cursor: default;
    background: var(--lux-bg-1, #0e1014);
    border: 1px solid var(--lux-line-bold, var(--border-color));
    border-radius: var(--lux-r-lg, 10px);
    box-shadow: var(--lux-shadow-rack, 0 8px 24px rgba(0, 0, 0, 0.5));
    overflow: hidden;
    isolation: isolate;
    /* Exit pose — also the initial pose. The transition fires both ways
     * so closing the shell mirrors the opening choreography. */
    transform: translateY(14px) scale(0.97);
    opacity: 0.85;
    transition:
        transform 320ms var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)),
        opacity 240ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)),
        box-shadow 260ms ease;
}
.lightbox.active .lightbox-content {
    transform: translateY(0) scale(1);
    opacity: 1;
}

/* Always-on left channel stripe with dual-glow (mirrors .rn-shell__stripe) */
.lightbox-content::before {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 4px;
    background: var(--lb-ch);
    box-shadow:
        0 0 18px color-mix(in srgb, var(--lb-ch) 55%, transparent),
        0 0 4px  color-mix(in srgb, var(--lb-ch) 90%, transparent);
    z-index: 3;
    pointer-events: none;
}

/* Silkscreen corner brackets — instrument detail */
.lightbox-content::after {
    content: "";
    position: absolute;
    top: 12px; left: 16px;
    width: 18px; height: 18px;
    border-top: 1px solid var(--lux-line-bold, var(--border-color));
    border-left: 1px solid var(--lux-line-bold, var(--border-color));
    opacity: 0.55;
    pointer-events: none;
    z-index: 3;
}
.lightbox-content > .lightbox-bracket-br {
    position: absolute;
    bottom: 12px; right: 12px;
    width: 18px; height: 18px;
    border-bottom: 1px solid var(--lux-line-bold, var(--border-color));
    border-right: 1px solid var(--lux-line-bold, var(--border-color));
    opacity: 0.55;
    pointer-events: none;
    z-index: 3;
}

/* Image lightbox is a degenerate variant — the <img> *is* the body, so
 * we let it size itself and let the shell hug it. */
.lightbox-content > img {
    max-width: 100%;
    max-height: 86vh;
    object-fit: contain;
    display: block;
    border-radius: 0;
}

/* ── Close button ────────────────────────────────────────────────────── */
.lightbox-close {
    position: absolute;
    top: 10px;
    right: 10px;
    background: color-mix(in srgb, var(--lux-bg-2, #15181d) 88%, transparent);
    border: 1px solid var(--lux-line, var(--border-color));
    color: var(--lux-ink, #e6ebf2);
    font-family: var(--font-mono, monospace);
    font-size: 1.05rem;
    line-height: 1;
    width: 32px;
    height: 32px;
    border-radius: var(--lux-r-sm, 3px);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: border-color 160ms ease, color 160ms ease, box-shadow 160ms ease;
    z-index: 4;
    backdrop-filter: blur(6px);
}
.lightbox-close:hover {
    border-color: var(--lb-ch);
    color: var(--lb-ch);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--lb-ch) 18%, transparent);
}
.lightbox-close:focus-visible {
    outline: 2px solid var(--lb-ch);
    outline-offset: 2px;
}

/* ── Eyebrow + readout strip (image lightbox) ────────────────────────── */
.lightbox-stats {
    position: absolute;
    bottom: 12px;
    left: 16px;
    background: color-mix(in srgb, var(--lux-bg-1, #0e1014) 78%, transparent);
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    backdrop-filter: blur(8px);
    color: var(--lux-ink, var(--text-color));
    padding: 8px 14px;
    font-family: var(--font-mono, monospace);
    font-size: 0.74rem;
    letter-spacing: 0.02em;
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
    z-index: 3;
}
.lightbox-stats .stat-item {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
}
.lightbox-stats .stat-item span {
    color: var(--lux-ink-mute, var(--text-secondary));
    text-transform: uppercase;
    font-size: 0.62rem;
    letter-spacing: 0.18em;
}
.lightbox-stats .stat-item strong {
    color: var(--lux-ink, var(--text-color));
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* ── Display picker — extends the shell with a header rack ──────────── */
.display-picker-content {
    max-width: 920px;
    width: min(92vw, 920px);
    display: flex;
    flex-direction: column;
    text-align: left;
}

.display-picker-head {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 18px;
    padding: 18px 24px 16px 36px;
    border-bottom: 1px solid var(--lux-line, var(--border-color));
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--lb-ch) 5%, transparent) 0%,
            transparent 70%),
        var(--lux-bg-1, var(--bg-secondary));
    flex-shrink: 0;
    z-index: 2;
}

.display-picker-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    line-height: 1;
    margin-bottom: 8px;
}
.display-picker-eyebrow__dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--lb-ch);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--lb-ch) 22%, transparent);
    animation: lbPulse 2s ease-in-out infinite;
}
.display-picker-eyebrow__sep {
    width: 1px; height: 10px;
    background: var(--lux-line-bold, var(--border-color));
}
.display-picker-eyebrow__channel {
    color: var(--lb-ch);
    letter-spacing: 0.22em;
}
@keyframes lbPulse {
    0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--lb-ch) 22%, transparent); }
    50%      { box-shadow: 0 0 0 6px color-mix(in srgb, var(--lb-ch) 0%, transparent); }
}

.display-picker-lede {
    flex: 1;
    min-width: 0;
}

.display-picker-title {
    font-family: var(--font-display, 'Big Shoulders Display', sans-serif);
    font-size: clamp(1.55rem, 3vw, 2.25rem);
    font-weight: 900;
    letter-spacing: -0.02em;
    line-height: 1.1;
    color: var(--lux-ink, var(--text-color));
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
}
.display-picker-title__accent {
    font-style: normal;
    color: var(--lb-ch);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

/* Device-picker variants drop the big title — the eyebrow alone carries
 * the heading, so the head pads down to a single strip. */
.display-picker-content--no-title .display-picker-title {
    display: none;
}
.display-picker-content--no-title .display-picker-head {
    padding-top: 14px;
    padding-bottom: 14px;
}
.display-picker-content--no-title .display-picker-eyebrow {
    margin-bottom: 0;
}

.display-picker-canvas {
    position: relative;
    background:
        repeating-linear-gradient(0deg,
            transparent 0,
            transparent 18px,
            color-mix(in srgb, var(--lux-line, var(--border-color)) 35%, transparent) 18px,
            color-mix(in srgb, var(--lux-line, var(--border-color)) 35%, transparent) 19px),
        var(--lux-bg-0, var(--bg-color, #000));
    background-size: 100% 19px, 100% 100%;
    padding: 28px 28px 24px;
    width: 100%;
    box-sizing: border-box;
    flex: 1;
    overflow: auto;
    scrollbar-gutter: stable;
}

.display-picker-foot {
    border-top: 1px solid var(--lux-line, var(--border-color));
    padding: 10px 28px 12px 36px;
    background: var(--lux-bg-1, var(--bg-secondary));
    font-family: var(--font-mono, monospace);
    font-size: 0.7rem;
    color: var(--lux-ink-mute, var(--text-secondary));
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
    align-items: center;
    letter-spacing: 0.06em;
    flex-shrink: 0;
}
.display-picker-foot kbd {
    display: inline-block;
    padding: 1px 6px;
    border: 1px solid var(--lux-line-bold, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    background: var(--lux-bg-2, transparent);
    color: var(--lux-ink, var(--text-color));
    font-family: var(--font-mono, monospace);
    font-size: 0.66rem;
    line-height: 1;
    margin-right: 4px;
}

/* ── Display layout — instrument-panel rectangles ───────────────────── */
.layout-display-pickable {
    cursor: pointer !important;
    border: 1px solid var(--lux-line-bold, var(--border-color)) !important;
    border-radius: var(--lux-r-md, 6px) !important;
    background:
        linear-gradient(135deg,
            color-mix(in srgb, var(--lux-bg-2, #15181d) 65%, transparent),
            color-mix(in srgb, var(--lux-bg-1, #0e1014) 90%, transparent)) !important;
    box-shadow:
        inset 0 0 0 1px color-mix(in srgb, var(--lux-bg-0, #000) 40%, transparent),
        0 4px 14px rgba(0, 0, 0, 0.35) !important;
    transition: border-color 160ms ease, box-shadow 200ms ease, transform 200ms var(--ease-out);
}

.layout-display-pickable:hover {
    border-color: var(--lb-ch) !important;
    box-shadow:
        inset 0 0 0 1px color-mix(in srgb, var(--lb-ch) 25%, transparent),
        0 0 0 1px color-mix(in srgb, var(--lb-ch) 40%, transparent),
        0 0 28px color-mix(in srgb, var(--lb-ch) 35%, transparent) !important;
    transform: translateY(-1px);
    z-index: 11;
}

.layout-display-pickable.selected {
    border-color: var(--lb-ch) !important;
    box-shadow:
        inset 0 0 0 1px color-mix(in srgb, var(--lb-ch) 35%, transparent),
        0 0 0 2px color-mix(in srgb, var(--lb-ch) 55%, transparent),
        0 0 32px color-mix(in srgb, var(--lb-ch) 45%, transparent) !important;
    background:
        linear-gradient(135deg,
            color-mix(in srgb, var(--lb-ch) 14%, var(--lux-bg-2, #15181d)),
            color-mix(in srgb, var(--lb-ch) 4%, var(--lux-bg-1, #0e1014))) !important;
}

/* Pickable layout overrides for inner labels (the picker re-uses
 * .layout-position-label / .layout-index-label / .layout-display-label
 * from cards.css — adapt them to the lux palette so they read on the
 * dark instrument backdrop). */
.display-picker-canvas .layout-position-label {
    color: var(--lux-ink-mute, var(--text-secondary));
    font-family: var(--font-mono, monospace);
    font-size: 0.62rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
}
.display-picker-canvas .layout-index-label {
    background: var(--lux-bg-0, var(--display-badge-bg));
    border: 1px solid var(--lux-line, var(--border-color));
    color: var(--lb-ch);
    font-family: var(--font-mono, monospace);
    font-weight: 700;
    font-size: 0.78rem;
    padding: 2px 7px;
    border-radius: var(--lux-r-sm, 3px);
    letter-spacing: 0.05em;
}
.display-picker-canvas .layout-display-label strong {
    color: var(--lux-ink, var(--text-color));
    font-family: var(--font-display, 'Big Shoulders Display', sans-serif);
    font-weight: 700;
    letter-spacing: 0.01em;
    font-size: 1rem;
}
.display-picker-canvas .layout-display-label small {
    color: var(--lux-ink-dim, var(--text-secondary));
    font-family: var(--font-mono, monospace);
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    font-variant-numeric: tabular-nums;
}

/* Loading + empty states use the lux palette inside the canvas. */
.display-picker-canvas .loading {
    color: var(--lux-ink-dim, var(--text-secondary));
    font-family: var(--font-mono, monospace);
    font-size: 0.85rem;
    text-align: center;
    padding: 32px 16px;
    letter-spacing: 0.04em;
}

@media (max-width: 640px) {
    .display-picker-head {
        padding: 14px 18px 12px 28px;
    }
    .display-picker-foot {
        padding: 10px 18px 12px 28px;
        font-size: 0.66rem;
        gap: 12px;
    }
    .display-picker-canvas {
        padding: 18px;
    }
    .lightbox-content::after {
        top: 8px; left: 12px;
    }
    .lightbox-content > .lightbox-bracket-br {
        bottom: 8px; right: 8px;
    }
}

/* ── Lightbox in/out choreography ────────────────────────────────────
 *
 * The shell + panel transitions handle the primary in/out motion. These
 * keyframes layer staggered reveals on the head pieces (eyebrow, title)
 * and the layout instruments so the panel feels assembled — pieces snap
 * into place rather than appearing all at once. They run only on entry
 * (animation runs once when `.active` is added); exit is a clean fade
 * driven by the panel transition above.
 *
 * Channel stripe runs its own scaleY entrance so the glow line "draws"
 * down the side of the panel. The corner brackets fade in last to feel
 * like a silkscreen finish stamp.
 * ───────────────────────────────────────────────────────────────────── */

@keyframes lbStripeDraw {
    from { transform: scaleY(0); opacity: 0; }
    to   { transform: scaleY(1); opacity: 1; }
}
@keyframes lbBracketStamp {
    0%   { opacity: 0; transform: scale(1.4); }
    60%  { opacity: 0.6; }
    100% { opacity: 0.55; transform: scale(1); }
}
@keyframes lbHeadReveal {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes lbCanvasReveal {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes lbInstrumentReveal {
    from { opacity: 0; transform: scale(0.92); filter: blur(1px); }
    to   { opacity: 1; transform: scale(1);    filter: blur(0); }
}
@keyframes lbImageReveal {
    from { opacity: 0; transform: scale(0.96); }
    to   { opacity: 1; transform: scale(1); }
}

/* Channel stripe — origin top so it draws downward */
.lightbox-content::before {
    transform-origin: top;
}
.lightbox.active .lightbox-content::before {
    animation: lbStripeDraw 360ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 80ms backwards;
}

/* Silkscreen brackets — fade-in stamp after the panel seats */
.lightbox.active .lightbox-content::after,
.lightbox.active .lightbox-content > .lightbox-bracket-br {
    animation: lbBracketStamp 480ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) backwards;
}
.lightbox.active .lightbox-content::after { animation-delay: 280ms; }
.lightbox.active .lightbox-content > .lightbox-bracket-br { animation-delay: 340ms; }

/* Header pieces — eyebrow first, then title */
.lightbox.active .display-picker-eyebrow {
    animation: lbHeadReveal 380ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 140ms backwards;
}
.lightbox.active .display-picker-title {
    animation: lbHeadReveal 460ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 200ms backwards;
}
.lightbox.active .display-picker-canvas {
    animation: lbCanvasReveal 480ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 240ms backwards;
}
.lightbox.active .display-picker-foot {
    animation: lbHeadReveal 360ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 320ms backwards;
}

/* Layout instruments stagger in — gives the picker a "rack assembling"
 * feel. Use nth-child for predictable delays without JS. */
.lightbox.active .layout-display-pickable,
.lightbox.active .device-picker-item {
    animation: lbInstrumentReveal 420ms var(--ease-spring, cubic-bezier(0.34, 1.56, 0.64, 1)) backwards;
}
.lightbox.active .layout-display-pickable:nth-child(1),
.lightbox.active .device-picker-item:nth-child(1)  { animation-delay: 320ms; }
.lightbox.active .layout-display-pickable:nth-child(2),
.lightbox.active .device-picker-item:nth-child(2)  { animation-delay: 360ms; }
.lightbox.active .layout-display-pickable:nth-child(3),
.lightbox.active .device-picker-item:nth-child(3)  { animation-delay: 400ms; }
.lightbox.active .layout-display-pickable:nth-child(4),
.lightbox.active .device-picker-item:nth-child(4)  { animation-delay: 440ms; }
.lightbox.active .layout-display-pickable:nth-child(n+5),
.lightbox.active .device-picker-item:nth-child(n+5) { animation-delay: 480ms; }

/* Image lightbox — image fades + zooms in */
.lightbox.active .lightbox-content > img {
    animation: lbImageReveal 380ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 120ms backwards;
}
.lightbox.active .lightbox-stats {
    animation: lbHeadReveal 360ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 240ms backwards;
}

/* Reduced-motion fallback — keep the basic fade only, drop animations */
@media (prefers-reduced-motion: reduce) {
    .lightbox,
    .lightbox-content,
    .lightbox.active * {
        transition-duration: 120ms !important;
        animation: none !important;
    }
    .lightbox-content {
        transform: none;
        opacity: 1;
    }
    .lightbox.active .lightbox-content {
        transform: none;
    }
}

/* ── Device picker list (cameras, scrcpy) ─────────────────────── */

.device-picker-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Row variant — `.device-picker-item.layout-display-pickable` (set by
 * displays.ts for the engine-owned device list). The .layout-display-pickable
 * rectangle styles use !important; we re-assert them here at higher
 * specificity so the row gets a horizontal-gradient row treatment with
 * a left channel stripe instead of the rectangle's diagonal fill. */
.device-picker-item,
.device-picker-item.layout-display-pickable {
    position: relative;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 14px 12px 22px;
    border: 1px solid var(--lux-line-bold, var(--border-color)) !important;
    border-radius: var(--lux-r-md, 6px) !important;
    background:
        linear-gradient(90deg,
            color-mix(in srgb, var(--lux-bg-2, #15181d) 70%, transparent),
            var(--lux-bg-1, #0e1014)) !important;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3) !important;
    cursor: pointer !important;
    overflow: hidden;
    transform: none;
}
.device-picker-item.layout-display-pickable:hover {
    border-color: var(--lb-ch, var(--ch-signal)) !important;
    box-shadow:
        0 0 0 1px color-mix(in srgb, var(--lb-ch, var(--ch-signal)) 40%, transparent),
        0 0 18px color-mix(in srgb, var(--lb-ch, var(--ch-signal)) 25%, transparent) !important;
    transform: none;
}
.device-picker-item.layout-display-pickable.selected {
    border-color: var(--lb-ch, var(--ch-signal)) !important;
    background:
        linear-gradient(90deg,
            color-mix(in srgb, var(--lb-ch, var(--ch-signal)) 14%, var(--lux-bg-2, #15181d)),
            var(--lux-bg-1, #0e1014)) !important;
    box-shadow:
        0 0 0 1px color-mix(in srgb, var(--lb-ch, var(--ch-signal)) 50%, transparent),
        0 0 22px color-mix(in srgb, var(--lb-ch, var(--ch-signal)) 30%, transparent) !important;
}
.device-picker-item::before {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--lux-line-bold, var(--border-color));
    transition: background 160ms ease, box-shadow 200ms ease;
}
.device-picker-item:hover::before,
.device-picker-item.selected::before {
    background: var(--lb-ch, var(--ch-signal));
    box-shadow: 0 0 14px color-mix(in srgb, var(--lb-ch, var(--ch-signal)) 55%, transparent);
}

.device-picker-item .layout-index-label {
    position: static;
    flex-shrink: 0;
}

.device-picker-item .layout-display-label {
    text-align: left;
    padding: 0;
}

/* ADB connect form — restyled for the new shell */
.display-picker-canvas .adb-connect-form {
    margin-top: 18px;
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: center;
    padding: 14px;
    border: 1px dashed var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    background: color-mix(in srgb, var(--lux-bg-2, #15181d) 50%, transparent);
}
.display-picker-canvas .adb-connect-form input {
    flex: 0 1 240px;
    padding: 8px 10px;
    border-radius: var(--lux-r-sm, 3px);
    border: 1px solid var(--lux-line-bold, var(--border-color));
    background: var(--lux-bg-0, var(--input-bg));
    color: var(--lux-ink, var(--text-color));
    font-family: var(--font-mono, monospace);
    font-size: 0.82rem;
    letter-spacing: 0.04em;
}
.display-picker-canvas .adb-connect-form input:focus {
    outline: none;
    border-color: var(--lb-ch);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--lb-ch) 18%, transparent);
}

/* ── Gradient editor ────────────────────────────────────────────── */

.gradient-editor {
    position: relative;
    width: 100%;
    user-select: none;
}

#gradient-canvas,
#ge-gradient-canvas {
    width: 100%;
    height: 44px;
    display: block;
    border-radius: 6px 6px 0 0;
    cursor: crosshair;
    border: 1px solid var(--border-color);
    border-bottom: none;
}

.gradient-markers-track {
    position: relative;
    height: 28px;
    border: 1px solid var(--border-color);
    border-radius: 0 0 6px 6px;
    background: var(--card-bg);
    cursor: crosshair;
    margin-bottom: 12px;
}

.gradient-marker {
    position: absolute;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 2px solid #fff;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
    cursor: grab;
    transform: translateX(-50%);
    top: 6px;
    transition: box-shadow 0.1s;
}

.gradient-marker.selected {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px var(--primary-color), 0 1px 4px rgba(0, 0, 0, 0.5);
}

.gradient-marker:active {
    cursor: grabbing;
}

.gradient-stop-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 8px;
    margin-bottom: 6px;
    border: 1px solid var(--border-color);
    border-radius: 4px;
    background: var(--card-bg);
}

.gradient-stop-row.selected {
    border-color: var(--primary-color);
}

.gradient-stop-pos {
    width: 76px;
    max-width: 76px;
    flex-shrink: 0;
}

.gradient-stop-color {
    width: 38px;
    height: 28px;
    flex-shrink: 0;
    border: 1px solid var(--border-color);
    padding: 1px;
    border-radius: 4px;
    cursor: pointer;
    background: transparent;
}

.gradient-stop-bidir-btn {
    font-size: 0.75rem;
    padding: 0;
    width: 26px;
    height: 26px;
    flex: 0 0 26px;
    opacity: 0.6;
}

.gradient-stop-remove-btn {
    padding: 0;
    width: 26px;
    height: 26px;
    flex: 0 0 26px;
}

.gradient-stop-remove-btn .icon {
    width: 14px;
    height: 14px;
}

.gradient-stop-bidir-btn.active {
    background: var(--primary-color);
    color: var(--primary-contrast);
    border-color: var(--primary-color);
    opacity: 1;
}

.gradient-stop-spacer {
    flex: 1;
}

/* ── HA Light Mapping rows ──────────────────────────────────────
   Cyan rack-fixture channels, paired with the Routing section
   (data-ch="cyan") in ha-light-editor.html. Each row reads as a
   numbered fixture: counter · lightbulb plate · entity name · remove.
   Slot indices are rendered via CSS counter so removing a middle row
   automatically renumbers the rest — no JS bookkeeping needed. */

#ha-light-mappings-list {
    --hm-ch: var(--ch-cyan, var(--info-color, #00d8ff));
    counter-reset: hm-slot;
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 4px;
}

.ha-light-mapping-row {
    --hm-ch: var(--ch-cyan, var(--info-color, #00d8ff));
    counter-increment: hm-slot;
    position: relative;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--hm-ch) 4%, var(--lux-bg-2, var(--bg-secondary))) 0%,
            color-mix(in srgb, var(--lux-bg-1, var(--card-bg)) 70%, transparent) 100%);
    overflow: hidden;
    transition:
        border-color 0.15s ease,
        box-shadow 0.15s ease;
}
.ha-light-mapping-row:hover {
    border-color: color-mix(in srgb, var(--hm-ch) 50%, var(--lux-line, var(--border-color)));
    box-shadow:
        inset 2px 0 0 color-mix(in srgb, var(--hm-ch) 80%, transparent),
        0 1px 0 color-mix(in srgb, var(--hm-ch) 14%, transparent);
}

.ha-mapping-header {
    display: grid;
    grid-template-columns: 28px 32px 1fr auto;
    align-items: center;
    gap: 10px;
    padding: 6px 8px 6px 6px;
    border-bottom: 1px solid color-mix(in srgb, var(--hm-ch) 18%, var(--lux-line, var(--border-color)));
}
.ha-mapping-header::before {
    content: counter(hm-slot, decimal-leading-zero);
    grid-column: 1;
    justify-self: center;
    font-family: var(--font-mono);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    color: color-mix(in srgb, var(--hm-ch) 75%, var(--lux-ink-dim, var(--text-secondary)));
    opacity: 0.85;
}

.ha-mapping-icon {
    grid-column: 2;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--hm-ch);
    background: color-mix(in srgb, var(--hm-ch) 9%, transparent);
    border: 1px solid color-mix(in srgb, var(--hm-ch) 22%, transparent);
    border-radius: 5px;
    flex-shrink: 0;
}
.ha-mapping-icon svg,
.ha-mapping-icon .icon { width: 18px; height: 18px; }

.ha-mapping-name {
    grid-column: 3;
    min-width: 0;
    font-weight: 600;
    color: var(--lux-ink, var(--text-color));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.25;
}
.ha-mapping-name.is-empty {
    font-weight: 500;
    color: var(--lux-ink-dim, var(--text-secondary));
    font-style: italic;
}

.ha-mapping-remove-btn {
    grid-column: 4;
    background: none;
    border: 1px solid transparent;
    color: var(--lux-ink-dim, var(--text-secondary));
    cursor: pointer;
    width: 26px;
    height: 26px;
    border-radius: 5px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0.7;
    transition:
        opacity 0.15s ease,
        color 0.15s ease,
        background 0.15s ease,
        border-color 0.15s ease;
}
.ha-mapping-remove-btn:hover,
.ha-mapping-remove-btn:focus-visible {
    opacity: 1;
    color: var(--ch-coral, var(--danger-color, #ff5e5e));
    background: color-mix(in srgb, var(--ch-coral, var(--danger-color, #ff5e5e)) 10%, transparent);
    border-color: color-mix(in srgb, var(--ch-coral, var(--danger-color, #ff5e5e)) 35%, transparent);
    outline: none;
}
.ha-mapping-remove-btn .icon,
.ha-mapping-remove-btn svg { width: 14px; height: 14px; }

/* HA Light color swatches */
.ha-light-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}
.ha-light-swatch {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 8px;
    border-radius: 4px;
    background: var(--bg-color);
    border: 1px solid var(--border-color);
    font-size: 0.75rem;
}
.ha-light-swatch .swatch-color {
    display: inline-block;
    width: 16px;
    height: 16px;
    border-radius: 3px;
    border: 1px solid rgba(255,255,255,0.2);
    transition: background 0.3s;
}
.ha-light-swatch .swatch-label {
    opacity: 0.8;
}

.btn-remove-mapping:hover {
    opacity: 1;
}

.ha-mapping-fields {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px 10px 10px;
}

.ha-mapping-field label,
.ha-mapping-range-row label {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.6rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin-bottom: 4px;
    color: color-mix(in srgb, var(--hm-ch, var(--ch-cyan, #00d8ff)) 60%, var(--lux-ink-dim, var(--text-secondary)));
}

.ha-mapping-range-row {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 8px;
}

/* When color_vs mode renders only the brightness column, don't stretch
   it across the full width — keep it natural-sized so the field reads
   as a value, not a billboard. */
.ha-mapping-range-row > div:only-child {
    grid-column: 1 / 2;
    max-width: 180px;
}

/* "+ Add Mapping" slot — full-width dashed cyan channel, mirrors the
   scene-target add slot for vocabulary consistency. */
.ha-mapping-add-slot {
    --hm-ch: var(--ch-cyan, var(--info-color, #00d8ff));
    margin-top: 6px;
    width: 100%;
    padding: 9px 12px;
    background:
        repeating-linear-gradient(135deg,
            color-mix(in srgb, var(--hm-ch) 5%, transparent) 0 6px,
            transparent 6px 12px);
    border: 1px dashed color-mix(in srgb, var(--hm-ch) 50%, var(--lux-line, var(--border-color)));
    border-radius: var(--lux-r-md, 6px);
    color: color-mix(in srgb, var(--hm-ch) 80%, var(--lux-ink, var(--text-color)));
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    transition:
        background 0.15s ease,
        border-color 0.15s ease,
        color 0.15s ease,
        transform 0.15s ease;
}
.ha-mapping-add-slot::before {
    content: '+';
    font-family: var(--font-mono);
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1;
}
.ha-mapping-add-slot:hover {
    background:
        repeating-linear-gradient(135deg,
            color-mix(in srgb, var(--hm-ch) 12%, transparent) 0 6px,
            transparent 6px 12px);
    border-color: color-mix(in srgb, var(--hm-ch) 75%, transparent);
    color: var(--hm-ch);
}
.ha-mapping-add-slot:active {
    transform: translateY(1px);
}

/* ── Custom gradient presets list ───────────────────────────── */

.custom-presets-list {
    margin-top: 6px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.custom-preset-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px;
    border-radius: 6px;
    background: var(--surface-2, rgba(255,255,255,0.04));
    border: 1px solid var(--border-color, rgba(255,255,255,0.1));
}

.custom-preset-name {
    flex: 1;
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Animated Color · single-row chip strip ──────────────────── */

.animated-color-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
    padding: 6px;
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: 8px;
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--lux-bg-2, var(--bg-secondary)) 92%, transparent) 0%,
        color-mix(in srgb, var(--lux-bg-1, var(--card-bg)) 92%, transparent) 100%
    );
}

.animated-color-chip {
    --chip-color: #ffffff;
    position: relative;
    width: 36px;
    height: 36px;
    border-radius: 8px;
    overflow: visible;
    transition: transform var(--duration-fast, 120ms) ease;
}

.animated-color-chip:hover {
    transform: translateY(-1px);
}

.animated-color-chip input[type="color"] {
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 1px solid color-mix(in srgb, var(--chip-color) 40%, var(--lux-line, var(--border-color)));
    border-radius: 8px;
    background: var(--chip-color);
    cursor: pointer;
    box-shadow:
        inset 0 0 0 1px color-mix(in srgb, #ffffff 14%, transparent),
        0 0 0 0 color-mix(in srgb, var(--chip-color) 0%, transparent);
    transition: box-shadow var(--duration-fast, 120ms) ease,
                border-color var(--duration-fast, 120ms) ease;
}

.animated-color-chip input[type="color"]:hover,
.animated-color-chip input[type="color"]:focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--chip-color) 70%, var(--lux-line, var(--border-color)));
    box-shadow:
        inset 0 0 0 1px color-mix(in srgb, #ffffff 22%, transparent),
        0 0 0 3px color-mix(in srgb, var(--chip-color) 28%, transparent);
}

/* WebKit/Blink swatch internals */
.animated-color-chip input[type="color"]::-webkit-color-swatch-wrapper {
    padding: 0;
    border: 0;
}
.animated-color-chip input[type="color"]::-webkit-color-swatch {
    border: 0;
    border-radius: 7px;
}
/* Firefox */
.animated-color-chip input[type="color"]::-moz-color-swatch {
    border: 0;
    border-radius: 7px;
}

.animated-color-remove {
    position: absolute;
    top: -6px;
    right: -6px;
    width: 16px;
    height: 16px;
    padding: 0;
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: 50%;
    background: var(--lux-bg-1, var(--card-bg));
    color: var(--text-muted, #9aa3ad);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transform: scale(0.7);
    transition:
        opacity var(--duration-fast, 120ms) ease,
        transform var(--duration-fast, 120ms) ease,
        color var(--duration-fast, 120ms) ease,
        background var(--duration-fast, 120ms) ease,
        border-color var(--duration-fast, 120ms) ease;
    pointer-events: none;
}

.animated-color-chip:hover .animated-color-remove,
.animated-color-chip:focus-within .animated-color-remove,
.animated-color-remove:focus-visible {
    opacity: 1;
    transform: scale(1);
    pointer-events: auto;
}

.animated-color-remove:hover,
.animated-color-remove:focus-visible {
    color: #ffffff;
    background: var(--danger-color, #f44336);
    border-color: var(--danger-color, #f44336);
    outline: none;
}

.animated-color-remove .icon {
    width: 10px;
    height: 10px;
    stroke-width: 2.4;
}

.animated-color-add {
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px dashed color-mix(in srgb, var(--lux-line, var(--border-color)) 80%, transparent);
    border-radius: 8px;
    background: transparent;
    color: var(--text-muted, #9aa3ad);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition:
        border-color var(--duration-fast, 120ms) ease,
        color var(--duration-fast, 120ms) ease,
        background var(--duration-fast, 120ms) ease,
        transform var(--duration-fast, 120ms) ease;
}

.animated-color-add:hover,
.animated-color-add:focus-visible {
    border-style: solid;
    border-color: var(--primary-color);
    color: var(--primary-color);
    background: color-mix(in srgb, var(--primary-color) 10%, transparent);
    outline: none;
    transform: translateY(-1px);
}

.animated-color-add-glyph {
    font-size: 1.15rem;
    font-weight: 500;
    line-height: 1;
    letter-spacing: 0;
}

/* ── Notification per-app overrides (unified color + sound) ──── */

#notification-app-overrides-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 4px;
}

.notif-override-row {
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 10px;
    background: var(--bg-secondary, var(--bg-color));
}

.notif-override-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
}

.notif-override-label {
    font-weight: 600;
    font-size: 0.85rem;
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--text-secondary);
}

.notif-override-label .icon {
    width: 16px;
    height: 16px;
    opacity: 0.7;
}

.btn-remove-override {
    background: none;
    border: none;
    color: var(--danger-color, #dc3545);
    cursor: pointer;
    padding: 2px 6px;
    opacity: 0.7;
    transition: opacity 0.15s;
}

.btn-remove-override:hover {
    opacity: 1;
}

.btn-remove-override .icon {
    width: 16px;
    height: 16px;
}

.notif-override-fields {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.notif-override-app-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.notif-override-app-row .notif-override-name {
    flex: 1;
    min-width: 0;
}

.notif-override-app-row .notif-override-color {
    width: 26px;
    height: 26px;
    border: 1px solid var(--border-color);
    border-radius: 4px;
    padding: 1px;
    cursor: pointer;
    background: transparent;
    flex-shrink: 0;
}

.notif-override-sound-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    align-items: center;
}

.notif-override-sound-row .notif-override-sound,
.notif-override-sound-row .entity-select-trigger {
    min-width: 0;
    width: 100%;
}

.notif-override-sound-row .notif-override-volume {
    width: 100%;
}


/* ── Notification history list ─────────────────────────────────── */

.notif-history-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0.6rem;
    border-bottom: 1px solid var(--border-color);
    font-size: 0.82rem;
}

.notif-history-row:last-child {
    border-bottom: none;
}

.notif-history-app {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}

.notif-history-time {
    color: var(--text-muted);
    white-space: nowrap;
    font-size: 0.78rem;
    flex-shrink: 0;
}

.notif-history-badges {
    display: flex;
    gap: 3px;
    flex-shrink: 0;
}

.notif-history-badge {
    display: inline-block;
    min-width: 18px;
    padding: 0 4px;
    border-radius: 10px;
    font-size: 0.72rem;
    font-weight: 600;
    text-align: center;
    line-height: 18px;
}

.notif-history-badge--fired {
    background: var(--primary-color);
    color: #fff;
}

.notif-history-badge--filtered {
    background: var(--border-color);
    color: var(--text-muted);
}

.notif-history-empty {
    padding: 1rem;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* ── Composite layer editor ────────────────────────────────────────
   Mixer-strip channel rack: each layer reads as a numbered strip with
   a violet rail + blend chip. Header collapses/expands the body via
   the .composite-layer-expanded class on the item; class names are
   preserved so composite.ts wiring (toggle, drag, sync) is untouched. */

#composite-layers-list {
    --cl-ch: var(--ch-violet, #8b7eff);
    counter-reset: cl-slot;
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 8px;
}

.composite-layer-item {
    --cl-ch: var(--ch-violet, #8b7eff);
    counter-increment: cl-slot;
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0;
    padding: 0;
    border: 1px solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--cl-ch) 4%, var(--lux-bg-2, var(--bg-secondary))) 0%,
            color-mix(in srgb, var(--lux-bg-1, var(--card-bg)) 70%, transparent) 100%);
    overflow: hidden;
    transition:
        border-color 0.15s ease,
        box-shadow 0.15s ease;
}
.composite-layer-item:hover {
    border-color: color-mix(in srgb, var(--cl-ch) 50%, var(--lux-line, var(--border-color)));
    box-shadow:
        inset 2px 0 0 color-mix(in srgb, var(--cl-ch) 80%, transparent),
        0 1px 0 color-mix(in srgb, var(--cl-ch) 12%, transparent);
}
.composite-layer-expanded {
    border-color: color-mix(in srgb, var(--cl-ch) 55%, var(--lux-line, var(--border-color)));
    box-shadow:
        inset 2px 0 0 var(--cl-ch),
        0 0 0 1px color-mix(in srgb, var(--cl-ch) 18%, transparent),
        0 4px 14px color-mix(in srgb, var(--cl-ch) 12%, transparent);
}

.composite-layer-header {
    display: grid;
    grid-template-columns: 28px 18px 18px 1fr auto auto;
    grid-auto-flow: dense;  /* DOM order is drag→chevron, but visual order is chevron→drag — let the grid backfill the earlier column. Without `dense`, the chevron skips to row 2 and drags every other item with it. */
    align-items: center;
    gap: 8px;
    padding: 7px 8px 7px 6px;
    cursor: pointer;
    user-select: none;
}
.composite-layer-header::before {
    content: counter(cl-slot, decimal-leading-zero);
    grid-column: 1;
    justify-self: center;
    font-family: var(--font-mono);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    color: color-mix(in srgb, var(--cl-ch) 75%, var(--lux-ink-dim, var(--text-secondary)));
    opacity: 0.85;
}

.composite-layer-expand-btn {
    grid-column: 2;
    justify-self: center;
    font-size: 0.55rem;
    color: color-mix(in srgb, var(--cl-ch) 60%, var(--lux-ink-dim, var(--text-secondary)));
    transition: transform 0.18s ease, color 0.15s ease;
    width: 14px;
    text-align: center;
    line-height: 1;
}
.composite-layer-item:hover .composite-layer-expand-btn {
    color: var(--cl-ch);
}
.composite-layer-expanded .composite-layer-expand-btn {
    transform: rotate(90deg);
    color: var(--cl-ch);
}

.composite-layer-summary {
    grid-column: 4;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    overflow: hidden;
}

.composite-layer-summary-name {
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--lux-ink, var(--text-color));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.25;
}

.composite-layer-summary-blend {
    font-family: var(--font-mono);
    font-size: 0.6rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: color-mix(in srgb, var(--cl-ch) 75%, var(--lux-ink-dim, var(--text-secondary)));
    background: color-mix(in srgb, var(--cl-ch) 8%, transparent);
    padding: 1px 6px;
    border: 1px solid color-mix(in srgb, var(--cl-ch) 28%, transparent);
    border-radius: 2px;
    line-height: 1.3;
    white-space: nowrap;
    flex-shrink: 0;
}

.composite-layer-body-wrapper {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.22s ease;
}

.composite-layer-expanded .composite-layer-body-wrapper {
    grid-template-rows: 1fr;
}

.composite-layer-body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 0 10px 0 36px;  /* indent under index/chevron rail */
    overflow: hidden;
    min-height: 0;
    transition: padding 0.22s ease;
    font-size: 0.85rem;
    border-top: 1px solid transparent;
}

.composite-layer-expanded .composite-layer-body {
    padding: 8px 10px 10px 36px;
    border-top-color: color-mix(in srgb, var(--cl-ch) 22%, var(--lux-line, var(--border-color)));
}

.composite-layer-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.composite-layer-source {
    flex: 1;
    min-width: 0;
}

.composite-layer-brightness-label,
.composite-layer-opacity-label {
    flex-shrink: 0;
    width: 96px;
    font-family: var(--font-mono);
    font-size: 0.62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: color-mix(in srgb, var(--cl-ch) 60%, var(--lux-ink-dim, var(--text-secondary)));
    white-space: nowrap;
}

.composite-layer-brightness,
.composite-layer-cspt {
    flex: 1;
    min-width: 0;
}

.composite-layer-blend {
    width: 110px;
    flex-shrink: 0;
}

.composite-layer-opacity-container,
.composite-layer-brightness-container {
    flex: 1;
    min-width: 60px;
}

.composite-layer-toggle {
    grid-column: 5;
    flex-shrink: 0;
}

.composite-layer-remove-btn {
    grid-column: 6;
    background: none;
    border: 1px solid transparent;
    color: var(--lux-ink-dim, var(--text-secondary));
    cursor: pointer;
    width: 26px;
    height: 26px;
    border-radius: 5px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0.7;
    transition:
        opacity 0.15s ease,
        color 0.15s ease,
        background 0.15s ease,
        border-color 0.15s ease;
}

.composite-layer-remove-btn .icon {
    width: 14px;
    height: 14px;
}

.composite-layer-remove-btn:hover,
.composite-layer-remove-btn:focus-visible {
    opacity: 1;
    color: var(--ch-coral, var(--danger-color, #ff5e5e));
    background: color-mix(in srgb, var(--ch-coral, var(--danger-color, #ff5e5e)) 10%, transparent);
    border-color: color-mix(in srgb, var(--ch-coral, var(--danger-color, #ff5e5e)) 35%, transparent);
    outline: none;
}

/* Override the flex from .composite-layer-row — use grid so each
   cluster (toggle / fields / reverse) lives in its own column and
   can't bleed into its neighbour. minmax(0, 1fr) lets the middle
   column shrink under tight widths instead of pushing reverse over
   the END input. */
.composite-layer-range-row {
    display: grid;
    grid-template-columns: 96px minmax(0, 1fr) auto;
    column-gap: 10px;
    row-gap: 6px;
    align-items: center;
}

.composite-layer-range-toggle-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-mono);
    font-size: 0.62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: color-mix(in srgb, var(--cl-ch) 60%, var(--lux-ink-dim, var(--text-secondary)));
    cursor: pointer;
    white-space: nowrap;
}

.composite-layer-range-fields {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.composite-layer-range-fields label {
    font-family: var(--font-mono);
    font-size: 0.6rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--lux-ink-dim, var(--text-secondary));
    flex-shrink: 0;
}

.composite-layer-range-fields input[type="number"] {
    width: 64px;
    flex-shrink: 0;
}

.composite-layer-range-disabled {
    opacity: 0.4;
    pointer-events: none;
}

.composite-layer-reverse-label {
    display: flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: 0.62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: color-mix(in srgb, var(--cl-ch) 60%, var(--lux-ink-dim, var(--text-secondary)));
    cursor: pointer;
}

/* ── Composite layer drag-to-reorder ── */

.composite-layer-drag-handle {
    grid-column: 3;
    cursor: grab;
    opacity: 0;
    color: color-mix(in srgb, var(--cl-ch) 70%, var(--lux-ink-dim, var(--text-secondary)));
    font-size: 0.85rem;
    line-height: 1;
    padding: 2px 4px;
    border-radius: 3px;
    transition: opacity 0.18s ease, color 0.15s ease, background 0.15s ease;
    user-select: none;
    touch-action: none;
    flex-shrink: 0;
}

.composite-layer-item:hover .composite-layer-drag-handle {
    opacity: 0.55;
}

.composite-layer-drag-handle:hover {
    opacity: 1 !important;
    color: var(--cl-ch);
    background: color-mix(in srgb, var(--cl-ch) 14%, transparent);
}

/* "+ Add Layer" slot — full-width dashed violet channel, mirrors the
   scene-target add slot in components.css for vocabulary consistency. */
.composite-add-layer-slot {
    --cl-ch: var(--ch-violet, #8b7eff);
    margin-top: 2px;
    width: 100%;
    padding: 9px 12px;
    background:
        repeating-linear-gradient(135deg,
            color-mix(in srgb, var(--cl-ch) 5%, transparent) 0 6px,
            transparent 6px 12px);
    border: 1px dashed color-mix(in srgb, var(--cl-ch) 50%, var(--lux-line, var(--border-color)));
    border-radius: var(--lux-r-md, 6px);
    color: color-mix(in srgb, var(--cl-ch) 80%, var(--lux-ink, var(--text-color)));
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    transition:
        background 0.15s ease,
        border-color 0.15s ease,
        color 0.15s ease,
        transform 0.15s ease;
}
.composite-add-layer-slot::before {
    content: '+';
    font-family: var(--font-mono);
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1;
}
.composite-add-layer-slot:hover {
    background:
        repeating-linear-gradient(135deg,
            color-mix(in srgb, var(--cl-ch) 12%, transparent) 0 6px,
            transparent 6px 12px);
    border-color: color-mix(in srgb, var(--cl-ch) 75%, transparent);
    color: var(--cl-ch);
}
.composite-add-layer-slot:active {
    transform: translateY(1px);
}

/* ── Weather source location row ── */

.weather-location-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.weather-location-field {
    display: flex;
    align-items: center;
    gap: 4px;
}

.weather-location-field label {
    font-size: 0.85rem;
    color: var(--text-secondary);
    flex-shrink: 0;
}

.weather-location-field input[type="number"] {
    width: 100px;
}

.composite-layer-drag-handle:active {
    cursor: grabbing;
}

.composite-layer-drag-clone {
    position: fixed;
    z-index: var(--z-modal-top);
    pointer-events: none;
    opacity: 0.95;
    transform: scale(1.015);
    border-color: color-mix(in srgb, var(--ch-violet, #8b7eff) 60%, var(--lux-line, var(--border-color))) !important;
    box-shadow:
        inset 2px 0 0 var(--ch-violet, #8b7eff),
        0 14px 40px color-mix(in srgb, var(--ch-violet, #8b7eff) 22%, rgba(0, 0, 0, 0.45));
    will-change: top;
}

.composite-layer-drag-placeholder {
    border: 1px dashed color-mix(in srgb, var(--ch-violet, #8b7eff) 60%, var(--lux-line, var(--border-color)));
    border-radius: var(--lux-r-md, 6px);
    background:
        repeating-linear-gradient(135deg,
            color-mix(in srgb, var(--ch-violet, #8b7eff) 8%, transparent) 0 6px,
            transparent 6px 12px);
    min-height: 42px;
    transition: height 0.15s ease;
}

body.composite-layer-dragging .composite-layer-item {
    transition: none !important;
}

body.composite-layer-dragging .composite-layer-drag-handle {
    opacity: 0 !important;
}

/* ── File drop zone ── */
.file-dropzone {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 28px 20px;
    border: 2px dashed var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-color);
    cursor: pointer;
    transition: border-color var(--duration-normal) ease,
                background var(--duration-normal) ease,
                box-shadow var(--duration-normal) ease;
    user-select: none;
    outline: none;
}

.file-dropzone:hover {
    border-color: var(--primary-color);
    background: color-mix(in srgb, var(--primary-color) 5%, var(--bg-color));
}

.file-dropzone:focus-visible {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.15);
}

.file-dropzone.dragover {
    border-color: var(--primary-color);
    border-style: solid;
    background: color-mix(in srgb, var(--primary-color) 10%, var(--bg-color));
    box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.15),
                inset 0 0 20px rgba(76, 175, 80, 0.06);
}

.file-dropzone.has-file {
    border-style: solid;
    border-color: var(--primary-color);
    padding: 16px 20px;
}

.file-dropzone-icon {
    color: var(--text-muted);
    transition: color var(--duration-normal) ease, transform var(--duration-normal) var(--ease-spring);
}

.file-dropzone:hover .file-dropzone-icon,
.file-dropzone.dragover .file-dropzone-icon {
    color: var(--primary-color);
    transform: translateY(-2px);
}

.file-dropzone.has-file .file-dropzone-icon {
    color: var(--primary-color);
}

.file-dropzone-text {
    text-align: center;
}

.file-dropzone-label {
    font-size: 0.9rem;
    color: var(--text-muted);
    transition: color var(--duration-normal) ease;
}

.file-dropzone:hover .file-dropzone-label {
    color: var(--text-secondary);
}

.file-dropzone-info {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border-radius: var(--radius-sm);
    background: var(--bg-secondary);
    width: 100%;
    max-width: 100%;
    overflow: hidden;
}

.file-dropzone-filename {
    flex: 1;
    font-size: 0.88rem;
    font-weight: var(--weight-medium);
    color: var(--text-color);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.file-dropzone-filesize {
    font-size: 0.8rem;
    color: var(--text-muted);
    white-space: nowrap;
    font-family: var(--font-mono);
}

.file-dropzone-remove {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    font-size: 1.1rem;
    cursor: pointer;
    transition: background var(--duration-fast) ease, color var(--duration-fast) ease;
    line-height: 1;
    padding: 0;
}

.file-dropzone-remove:hover {
    background: var(--danger-color);
    color: white;
}

/* Inline code + copyable snippet used by the setup-required modal */
.code-snippet-wrapper {
    position: relative;
    margin: 6px 0;
}

.code-snippet {
    display: block;
    margin: 0;
    padding: 10px 44px 10px 12px;
    background: rgba(0, 0, 0, 0.35);
    border: 1px solid var(--border-color, rgba(255, 255, 255, 0.1));
    border-radius: 6px;
    font-family: var(--font-mono, 'Consolas', 'Courier New', monospace);
    font-size: 0.85em;
    line-height: 1.45;
    color: var(--text-color, #e0e0e0);
    white-space: pre-wrap;
    word-break: break-word;
    overflow-x: auto;
}

.code-snippet code {
    font-family: inherit;
    background: none;
    padding: 0;
    color: inherit;
}

.code-snippet-wrapper .copy-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    padding: 4px 6px;
    line-height: 1;
}

/* ── Device Settings: rack-panel sections ──────────────────────────
   The General Settings modal groups its many conditional fields into
   four logical sections (Identity / Connection / Hardware / Behavior),
   each with its own channel-color silkscreen accent. Sections that end
   up with no visible form-groups get the `[data-ds-empty="true"]`
   attribute from devices.ts and collapse out of the layout entirely. */

#device-settings-modal .modal-content {
    max-width: 620px;
}

.ds-section {
    --ds-ch: var(--ch-signal, var(--primary-color));
    position: relative;
    margin: 0 0 14px;
    padding: 0 14px 4px;
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--ds-ch) 4%, var(--lux-bg-2, var(--bg-secondary))) 0%,
            color-mix(in srgb, var(--lux-bg-1, var(--card-bg)) 60%, transparent) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.025),
        0 1px 0 rgba(0, 0, 0, 0.18);
}

.ds-section[data-ch="signal"] { --ds-ch: var(--ch-signal, var(--primary-color)); }
.ds-section[data-ch="cyan"]   { --ds-ch: var(--ch-cyan, var(--info-color)); }
.ds-section[data-ch="amber"]  { --ds-ch: var(--ch-amber, var(--warning-color)); }
.ds-section[data-ch="violet"] { --ds-ch: var(--ch-violet, #8b7eff); }
.ds-section[data-ch="coral"]  { --ds-ch: var(--ch-coral, var(--danger-color)); }
.ds-section[data-ch="magenta"]{ --ds-ch: var(--ch-magenta, #ff4ade); }

/* A faint left edge stripe in the channel color — reads like a panel
   accent on a piece of rack equipment. */
.ds-section::before {
    content: '';
    position: absolute;
    left: 0; top: 4px; bottom: 4px;
    width: 2px;
    border-radius: 2px;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--ds-ch) 70%, transparent) 0%,
        color-mix(in srgb, var(--ds-ch) 0%, transparent) 100%);
    opacity: 0.65;
    pointer-events: none;
}

.ds-section-header {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 -4px 6px;
    padding: 8px 4px 4px;
    line-height: 1;
}

.ds-section-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ds-ch);
    box-shadow:
        0 0 7px color-mix(in srgb, var(--ds-ch) 65%, transparent),
        0 0 0 1px color-mix(in srgb, var(--ds-ch) 30%, transparent);
    flex-shrink: 0;
}

.ds-section-title {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--lux-ink, var(--text-color));
    opacity: 0.85;
}

.ds-section-index {
    margin-left: auto;
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: 0.62rem;
    font-weight: 500;
    color: var(--lux-ink-mute, var(--text-muted));
    letter-spacing: 0.12em;
    opacity: 0.55;
    font-variant-numeric: tabular-nums;
}

.ds-section-body > .form-group:last-child {
    margin-bottom: 8px;
}

/* When devices.ts marks a section as empty, fully remove it from layout
   so the modal doesn't show a barren header band. */
.ds-section[data-ds-empty="true"] {
    display: none;
}

/* Identity section gets the signal-green accent and a slightly more
   prominent input — it's the one field everyone sets. */
#device-settings-modal .ds-section[data-ds-key="identity"] {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--ds-ch) 8%, var(--lux-bg-2, var(--bg-secondary))) 0%,
        color-mix(in srgb, var(--ds-ch) 1%, transparent) 100%);
    border-color: color-mix(in srgb, var(--ds-ch) 22%, var(--lux-line, var(--border-color)));
}

#device-settings-modal .ds-name-group input#settings-device-name {
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    padding: 10px 12px;
}

/* Two-column row for naturally-paired numeric fields (DMX Universe +
   Start Channel). When one of the pair is hidden, the other expands to
   fill — `display:none` form-groups simply collapse out of the grid. */
.ds-pair-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    align-items: start;
}

.ds-pair-row > .form-group {
    margin-bottom: 15px;
    min-width: 0;
}

@media (max-width: 480px) {
    .ds-pair-row {
        grid-template-columns: 1fr;
        gap: 0;
    }
}

/* Toggle row: text on the left, action (button or switch) anchored right,
   wrapped in a recessed sub-panel that reads like a discrete hardware
   switch on the panel face. Used by Lifecycle / Backup / Notifications /
   Updates and the device-settings Auto-Restore row. The selector must
   match a bare `.ds-toggle-row` so the global Settings modal — which
   does NOT pair it with `.form-group` — still gets the grid layout. */
.ds-toggle-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 14px;
    align-items: center;
    padding: 12px 14px;
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--lux-line, var(--border-color)) 80%, transparent);
    border-radius: var(--lux-r-md, 6px);
    background: color-mix(in srgb, var(--lux-bg-1, var(--card-bg)) 55%, transparent);
    margin-bottom: 10px;
}
.ds-toggle-row:last-child {
    margin-bottom: 0;
}

.ds-toggle-row .ds-toggle-text {
    min-width: 0;
}

.ds-toggle-row .label-row {
    margin-bottom: 0;
}

.ds-toggle-row .label-row label {
    margin-bottom: 0;
    font-weight: 600;
    color: var(--lux-ink, var(--text-color));
}

.ds-toggle-row .input-hint {
    margin: 4px 0 0;
    font-size: 0.78rem;
    line-height: 1.35;
}

.ds-toggle-row .settings-toggle {
    margin-top: 0;
    flex-shrink: 0;
}

@media (prefers-reduced-motion: no-preference) {
    .ds-section {
        animation: dsSectionIn 0.35s cubic-bezier(0.16, 1, 0.3, 1) both;
    }
    .ds-section[data-ds-key="identity"]     { animation-delay: 0.02s; }
    .ds-section[data-ds-key="connection"]   { animation-delay: 0.06s; }
    .ds-section[data-ds-key="hardware"]     { animation-delay: 0.10s; }
    .ds-section[data-ds-key="behavior"]     { animation-delay: 0.14s; }
    .ds-section[data-ds-key="targets"]      { animation-delay: 0.06s; }
    .ds-section[data-ds-key="triggers"]     { animation-delay: 0.06s; }
    .ds-section[data-ds-key="action"]       { animation-delay: 0.10s; }
    .ds-section[data-ds-key="deactivation"] { animation-delay: 0.14s; }
    .ds-section[data-ds-key="provider"]     { animation-delay: 0.06s; }
    .ds-section[data-ds-key="refresh"]      { animation-delay: 0.10s; }
    .ds-section[data-ds-key="filters"]      { animation-delay: 0.10s; }
    .ds-section[data-ds-key="routing"]      { animation-delay: 0.06s; }
    .ds-section[data-ds-key="output"]       { animation-delay: 0.10s; }
    .ds-section[data-ds-key="filtering"]    { animation-delay: 0.14s; }
    .ds-section[data-ds-key="broker"]       { animation-delay: 0.06s; }
    .ds-section[data-ds-key="protocol"]     { animation-delay: 0.10s; }
    .ds-section[data-ds-key="adapter"]      { animation-delay: 0.06s; }
    .ds-section[data-ds-key="mappings"]     { animation-delay: 0.10s; }
    .ds-section[data-ds-key="diagnostics"]  { animation-delay: 0.14s; }
    .ds-section[data-ds-key="source"]       { animation-delay: 0.06s; }
    .ds-section[data-ds-key="engine"]       { animation-delay: 0.06s; }
    .ds-section[data-ds-key="timing"]       { animation-delay: 0.06s; }
    .ds-section[data-ds-key="gradient"]     { animation-delay: 0.06s; }
    .ds-section[data-ds-key="layout"]       { animation-delay: 0.06s; }
    .ds-section[data-ds-key="strip"]        { animation-delay: 0.10s; }
    .ds-section[data-ds-key="type"]         { animation-delay: 0.06s; }
    .ds-section[data-ds-key="notes"]        { animation-delay: 0.10s; }
    .ds-section[data-ds-key="file"]         { animation-delay: 0.06s; }
    .ds-section[data-ds-key="auth"]         { animation-delay: 0.02s; }
    .ds-section[data-ds-key="configure"]    { animation-delay: 0.02s; }
    .ds-section[data-ds-key="restart"]      { animation-delay: 0.06s; }
    .ds-section[data-ds-key="loopback"]     { animation-delay: 0.10s; }
    .ds-section[data-ds-key="test-setup"]   { animation-delay: 0.02s; }
    .ds-section[data-ds-key="offsets"]      { animation-delay: 0.10s; }
    .ds-section[data-ds-key="line-properties"] { animation-delay: 0.06s; }
    .ds-section[data-ds-key="test"]         { animation-delay: 0.02s; }
    .ds-section[data-ds-key="preview"]      { animation-delay: 0.02s; }
    .ds-section[data-ds-key="controls"]     { animation-delay: 0.06s; }
    .ds-section[data-ds-key="history"]      { animation-delay: 0.02s; }
}

@keyframes dsSectionIn {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ── Settings modal: rail + rack-panel layout ──────────────────────
   The redesigned settings modal replaces the old icon-only top tab strip
   with a left rail (icon + label) and wraps each tab body in a stack of
   .ds-section panels. The rail and the existing tab-button machinery in
   settings.ts share the same data-settings-tab attribute, so
   switchSettingsTab() needs no behavioral changes. */

/* Top-anchor the settings modal so switching tabs (which changes content
   height) doesn't re-center the dialog and shift the header up/down.
   Why: vertical re-centering on tab change is jarring; the header staying
   put is preferred even if the dialog is no longer optically centered. */
#settings-modal {
    align-items: flex-start;
    padding-top: clamp(40px, 8vh, 80px);
}

#settings-modal .modal-content {
    max-width: 760px;
    overflow: hidden;
    max-height: calc(100vh - clamp(40px, 8vh, 80px) - 40px);
}

/* ── Buttons inside the settings modal follow the rack-panel mockup
   (mixed-case body font, auto width, tighter padding) instead of the
   project's default uppercase monospace house style. Scoped here so
   other modals continue to use the house style. */
#settings-modal .btn {
    flex: 0 0 auto;
    min-width: auto;
    padding: 8px 14px;
    font-family: var(--font-body, inherit);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: none;
    text-decoration: none;
}
/* Plain `.btn` (no .btn-primary / -danger / -secondary / -ghost / -icon
   modifier) needs an explicit silhouette so an `<a class="btn">` renders
   as a real button instead of a default link. Used by the About panel's
   GitHub / Donate action row, matching the mockup's bare-`.btn` look. */
#settings-modal .btn:not([class*="btn-"]) {
    background: var(--lux-bg-1, var(--card-bg));
    border-color: var(--lux-line-bold, var(--border-color));
    color: var(--lux-ink, var(--text-color));
}
#settings-modal .btn:not([class*="btn-"]):hover {
    border-color: var(--ch-amber, var(--warning-color));
    color: var(--lux-ink, var(--text-color));
    transform: translateY(-1px);
}
#settings-modal .btn:not([class*="btn-"]) .icon {
    color: var(--lux-ink-dim, var(--text-secondary));
}
#settings-modal .btn:not([class*="btn-"]):hover .icon {
    color: var(--ch-amber, var(--warning-color));
}
#settings-modal .btn-sm {
    padding: 5px 9px;
    font-size: 0.72rem;
}
/* Buttons inside a toggle-row anchor to the right of a title+sub block.
   Giving them a shared min-width keeps paired actions (Download / Restore,
   Open viewer / Restart, …) optically aligned across stacked rows even
   when their labels differ in length. */
#settings-modal .ds-toggle-row .btn {
    min-width: 120px;
}

/* ── About panel: stretch the .ds-section to fill the available height
   and center the hero (mark · name · version · tagline · links · license)
   inside it. The settings-body becomes a column flex container so the
   active About panel can flex-grow; other panels keep their natural
   content-height behaviour because they don't carry `flex: 1`. */
#settings-modal .settings-body {
    display: flex;
    flex-direction: column;
}
#settings-panel-about.active {
    flex: 1;
    display: flex;
    flex-direction: column;
}
#settings-panel-about > #about-panel-content {
    flex: 1;
    display: flex;
    flex-direction: column;
}
#settings-panel-about .ds-section {
    flex: 1;
    display: flex;
    flex-direction: column;
    margin-bottom: 0;
}
#settings-panel-about .ds-section-body {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px 0;
}
#settings-panel-about .about-hero {
    width: 100%;
}
/* `.inline-row` buttons that should fill the row keep their inline
   `style="flex:1"`. Anywhere else, an inline-row primary button stretches
   while the secondary stays auto — matches the mockup's
   "Save schedule" + "Backup now" composition. */
#settings-modal .inline-row > .btn[style*="flex:1"] {
    flex: 1 1 auto;
}

/* The classic modal-body padding is dropped here — the rail divides the
   content area horizontally and the rail/body each handle their own
   padding. */
#settings-modal .modal-body {
    padding: 0;
}

.settings-layout {
    display: flex;
    min-height: 0;
    flex: 1 1 auto;
    overflow: hidden;
}

.settings-rail {
    flex: 0 0 184px;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--lux-bg-2, var(--bg-secondary)) 60%, transparent),
        transparent);
    border-right: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    padding: 16px 0 16px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    overflow-y: auto;
    scrollbar-gutter: stable;
}

.settings-rail-group {
    padding: 8px 16px 4px;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--lux-ink-faint, var(--text-muted));
    display: flex;
    align-items: center;
    gap: 6px;
}
.settings-rail-group::before {
    content: '';
    width: 6px;
    height: 1px;
    background: var(--lux-line-bold, var(--border-color));
}
.settings-rail-group:not(:first-child) {
    margin-top: 6px;
}

.settings-rail-btn {
    --rail-ch: var(--ch-amber, var(--warning-color));
    background: none;
    border: none;
    cursor: pointer;
    width: 100%;
    padding: 9px 16px 9px 18px;
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--lux-ink-dim, var(--text-secondary));
    font: inherit;
    font-size: 0.85rem;
    font-weight: 500;
    text-align: left;
    border-left: 2px solid transparent;
    transition: color var(--duration-normal, 0.25s) var(--ease-out, ease),
                background var(--duration-normal, 0.25s) var(--ease-out, ease),
                border-color var(--duration-normal, 0.25s) var(--ease-out, ease);
    position: relative;
}
.settings-rail-btn[data-rail-ch="signal"]  { --rail-ch: var(--ch-signal, var(--primary-color)); }
.settings-rail-btn[data-rail-ch="cyan"]    { --rail-ch: var(--ch-cyan, var(--info-color)); }
.settings-rail-btn[data-rail-ch="amber"]   { --rail-ch: var(--ch-amber, var(--warning-color)); }
.settings-rail-btn[data-rail-ch="violet"]  { --rail-ch: var(--ch-violet, #8b7eff); }
.settings-rail-btn[data-rail-ch="magenta"] { --rail-ch: var(--ch-magenta, #ff4ade); }
.settings-rail-btn[data-rail-ch="coral"]   { --rail-ch: var(--ch-coral, var(--danger-color)); }

.settings-rail-btn .icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}
.settings-rail-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.settings-rail-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: transparent;
    transition: all var(--duration-normal, 0.25s) var(--ease-out, ease);
    flex-shrink: 0;
}
.settings-rail-btn:hover {
    color: var(--lux-ink, var(--text-color));
    background: color-mix(in srgb, var(--rail-ch) 6%, transparent);
}
.settings-rail-btn.active {
    color: var(--lux-ink, var(--text-color));
    background: color-mix(in srgb, var(--rail-ch) 10%, transparent);
    border-left-color: var(--rail-ch);
    font-weight: 600;
}
.settings-rail-btn.active .icon {
    color: var(--rail-ch);
    filter: drop-shadow(0 0 6px color-mix(in srgb, var(--rail-ch) 50%, transparent));
}
.settings-rail-btn.active .settings-rail-dot {
    background: var(--rail-ch);
    box-shadow: 0 0 6px color-mix(in srgb, var(--rail-ch) 70%, transparent);
}
.settings-rail-btn:focus-visible {
    outline: 2px solid var(--rail-ch);
    outline-offset: -2px;
}

.settings-rail-badge {
    margin-left: auto;
    font-size: 0.6rem;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--ch-coral, var(--danger-color)) 80%, transparent);
    color: #fff;
    letter-spacing: 0.04em;
    flex-shrink: 0;
}

.settings-rail-footer {
    margin-top: auto;
    padding: 12px 16px 0;
    border-top: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    font-family: var(--font-mono, monospace);
    font-size: 0.62rem;
    letter-spacing: 0.08em;
    color: var(--lux-ink-faint, var(--text-muted));
}
.settings-rail-footer:empty {
    display: none;
}

/* Body */
.settings-body {
    flex: 1 1 auto;
    overflow-y: auto;
    scrollbar-gutter: stable;
    padding: 18px 22px 22px;
    min-width: 0;
}

/* The old top-strip tab bar is no longer rendered (the rail replaces it),
   but keep the rules intact in case of cached templates. The rail is the
   live UI surface for tab switching. */
#settings-modal .settings-tab-bar { display: none; }

/* Section meta pill (e.g. "RUNNING" / "DESTRUCTIVE" / "GRANTED" badges
   that sit between the title and the index in a .ds-section header). */
.ds-section-meta {
    margin-left: 8px;
    font-family: var(--font-mono, monospace);
    font-size: 0.62rem;
    font-weight: 600;
    color: var(--lux-ink-mute, var(--text-muted));
    letter-spacing: 0.1em;
    padding: 2px 6px;
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ds-ch, var(--primary-color)) 30%, transparent);
    border-radius: 3px;
    background: color-mix(in srgb, var(--ds-ch, var(--primary-color)) 8%, transparent);
}
.ds-section-meta[hidden] { display: none; }

/* Toggle-row title/sub used by the new rack-panel rows
   (Lifecycle/Backup/Notifications). The container .ds-toggle-row is
   already styled — these refine its content slots. */
.ds-toggle-row .ds-toggle-text {
    min-width: 0;
}
.ds-toggle-row .ds-toggle-title {
    font-weight: 600;
    color: var(--lux-ink, var(--text-color));
    font-size: 0.85rem;
}
.ds-toggle-row .ds-toggle-sub {
    margin-top: 3px;
    font-size: 0.74rem;
    line-height: 1.4;
    color: var(--lux-ink-mute, var(--text-muted));
}

/* Danger variant — coral border + slightly recessed surface */
.ds-toggle-row.ds-toggle-row--danger {
    border-color: color-mix(in srgb, var(--ch-coral, var(--danger-color)) 28%, var(--lux-line, var(--border-color)));
}

/* Inline action row (Save + Backup-now etc.) */
.inline-row {
    display: flex;
    gap: 8px;
    align-items: center;
}
.inline-row > input,
.inline-row > select {
    flex: 1;
    min-width: 0;
}
.inline-row--actions {
    margin-top: 6px;
}

/* ── API key list (read-only rows in General → API section) ── */
.api-key-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 4px;
}
.api-key-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 10px;
    align-items: center;
    padding: 7px 10px;
    background: var(--lux-bg-1, var(--card-bg));
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 4px);
    font-size: 0.78rem;
}
.api-key-row .api-key-name {
    font-family: var(--font-mono, monospace);
    font-weight: 600;
    color: var(--lux-ink, var(--text-color));
}
.api-key-row .api-key-mask {
    font-family: var(--font-mono, monospace);
    color: var(--lux-ink-mute, var(--text-muted));
    letter-spacing: 0.06em;
    font-size: 0.74rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.api-key-row .api-key-tag {
    font-size: 0.62rem;
    font-weight: 700;
    padding: 2px 7px;
    border-radius: 3px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    background: color-mix(in srgb, var(--ch-amber, var(--warning-color)) 18%, transparent);
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ch-amber, var(--warning-color)) 35%, transparent);
    color: var(--ch-amber, var(--warning-color));
}
.api-key-empty-note {
    font-size: 0.76rem;
    color: var(--lux-ink-mute, var(--text-muted));
    padding: 12px;
    text-align: center;
    background: color-mix(in srgb, var(--ch-amber, var(--warning-color)) 4%, var(--lux-bg-1, var(--card-bg)));
    border: var(--lux-hairline, 1px) dashed var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 4px);
}

/* ── Notifications matrix (rows = events, cols = channels) ── */
.notif-matrix {
    display: grid;
    grid-template-columns: minmax(0, 1fr) repeat(4, 60px);
    gap: 0;
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-md, 6px);
    overflow: hidden;
    background: var(--lux-bg-1, var(--card-bg));
}
.notif-matrix-cell {
    border-bottom: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    padding: 10px 10px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.notif-matrix-cell:nth-last-child(-n+5) {
    border-bottom: none;
}
.notif-matrix-head {
    padding: 8px 10px;
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--lux-ink-mute, var(--text-muted));
    background: color-mix(in srgb, var(--ch-violet, #8b7eff) 6%, var(--lux-bg-2, var(--bg-secondary)));
}
.notif-matrix-head:first-child {
    justify-content: flex-start;
}
.notif-matrix-row-label {
    justify-content: flex-start;
    gap: 8px;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--lux-ink, var(--text-color));
    text-align: left;
}
.notif-matrix-row-label .icon {
    width: 14px;
    height: 14px;
    color: var(--ch-violet, #8b7eff);
    flex-shrink: 0;
}
.notif-matrix-opt {
    border-left: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    cursor: pointer;
    transition: background var(--duration-fast, 0.15s) var(--ease-out, ease);
}
.notif-matrix-opt .notif-matrix-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1.5px solid var(--lux-line-bold, var(--border-color));
    background: transparent;
    transition: all var(--duration-fast, 0.15s) var(--ease-out, ease);
}
.notif-matrix-opt:hover .notif-matrix-dot {
    border-color: var(--ch-violet, #8b7eff);
    transform: scale(1.15);
}
.notif-matrix-opt.selected {
    background: color-mix(in srgb, var(--ch-violet, #8b7eff) 14%, transparent);
}
.notif-matrix-opt.selected .notif-matrix-dot {
    background: var(--ch-violet, #8b7eff);
    border-color: var(--ch-violet, #8b7eff);
    box-shadow: 0 0 8px color-mix(in srgb, var(--ch-violet, #8b7eff) 60%, transparent);
}
.notif-matrix-opt:focus-visible {
    outline: 2px solid var(--ch-violet, #8b7eff);
    outline-offset: -2px;
}

/* ── Status card (Updates tab) ── */
.status-card {
    --status-ch: var(--ch-signal, var(--primary-color));
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 14px;
    align-items: center;
    padding: 12px 14px;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--status-ch) 8%, var(--lux-bg-2, var(--bg-secondary))) 0%,
        var(--lux-bg-1, var(--card-bg)) 100%);
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--status-ch) 30%, var(--lux-line, var(--border-color)));
    border-radius: var(--lux-r-md, 6px);
    margin-bottom: 10px;
}
.status-card[data-state="available"] { --status-ch: var(--ch-amber, var(--warning-color)); }
.status-card[data-state="error"]     { --status-ch: var(--ch-coral, var(--danger-color)); }
.status-card[data-state="updated"],
.status-card[data-state="checking"]  { --status-ch: var(--ch-signal, var(--primary-color)); }

.status-card-icon {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--status-ch) 16%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--status-ch);
    flex-shrink: 0;
}
.status-card-icon .icon {
    width: 20px;
    height: 20px;
}
.status-card-text {
    min-width: 0;
}
.status-card-main {
    font-family: var(--font-display, var(--font-body));
    font-size: 1rem;
    font-weight: 700;
    color: var(--lux-ink, var(--text-color));
    letter-spacing: 0.005em;
    line-height: 1.2;
}
.status-card-sub {
    font-size: 0.72rem;
    color: var(--lux-ink-mute, var(--text-muted));
    font-family: var(--font-mono, monospace);
    letter-spacing: 0.04em;
    margin-top: 4px;
    line-height: 1.5;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.status-card-sub strong {
    color: var(--lux-ink, var(--text-color));
    font-weight: 600;
}
/* Each "Current version / Install type / Last check" pair on its own line. */
.status-card-line {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: baseline;
    min-width: 0;
}
.status-card-line:empty {
    display: none;
}
/* Legacy inline separator from the old single-line layout. */
.status-card-sep {
    display: none;
}
.status-card-actions {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex-shrink: 0;
}

/* Update progress bar */
.update-progress {
    margin-bottom: 10px;
    height: 4px;
    background: var(--lux-line, var(--border-color));
    border-radius: 2px;
    overflow: hidden;
}
.update-progress > #update-progress-bar {
    width: 0;
    height: 100%;
    background: linear-gradient(90deg, var(--ch-signal, var(--primary-color)), var(--ch-amber, var(--warning-color)));
    transition: width 0.3s ease;
}

/* ── Backup list (saved backup files) ── */
.backup-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 200px;
    overflow-y: auto;
    margin-top: 6px;
}
.backup-list:empty::after {
    content: attr(data-empty);
    display: block;
    text-align: center;
    padding: 14px;
    font-size: 0.78rem;
    color: var(--lux-ink-mute, var(--text-muted));
    background: var(--lux-bg-1, var(--card-bg));
    border: var(--lux-hairline, 1px) dashed var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 4px);
}
.backup-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) repeat(3, auto);
    gap: 6px;
    align-items: center;
    padding: 8px 10px;
    background: var(--lux-bg-1, var(--card-bg));
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 4px);
    transition: border-color var(--duration-fast, 0.15s) var(--ease-out, ease);
}
.backup-row:hover {
    border-color: var(--ch-amber, var(--warning-color));
}
.backup-row .backup-name {
    font-family: var(--font-mono, monospace);
    font-size: 0.74rem;
    color: var(--lux-ink, var(--text-color));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.backup-row .backup-meta {
    font-size: 0.7rem;
    color: var(--lux-ink-mute, var(--text-muted));
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}
.backup-row .icon-btn {
    width: 26px;
    height: 26px;
    background: transparent;
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: 4px;
    color: var(--lux-ink-dim, var(--text-secondary));
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all var(--duration-fast, 0.15s) var(--ease-out, ease);
}
.backup-row .icon-btn:hover {
    color: var(--lux-ink, var(--text-color));
    border-color: var(--ch-amber, var(--warning-color));
}
.backup-row .icon-btn .icon {
    width: 13px;
    height: 13px;
}
.backup-row .icon-btn.danger:hover {
    color: var(--ch-coral, var(--danger-color));
    border-color: var(--ch-coral, var(--danger-color));
}

/* ── Settings switch (custom toggle, replaces plain checkbox) ── */
.settings-switch {
    --switch-ch: var(--ch-signal, var(--primary-color));
    position: relative;
    display: inline-block;
    width: 38px;
    height: 22px;
    flex-shrink: 0;
    cursor: pointer;
}
.settings-switch input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
    z-index: 1;
}
.settings-switch-track {
    position: absolute;
    inset: 0;
    background: var(--lux-bg-3, var(--bg-secondary));
    border-radius: 999px;
    border: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    transition: all var(--duration-normal, 0.25s) var(--ease-out, ease);
}
.settings-switch-track::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--lux-ink-dim, var(--text-secondary));
    transition: all var(--duration-normal, 0.25s) var(--ease-out, ease);
}
.settings-switch input:checked ~ .settings-switch-track {
    background: color-mix(in srgb, var(--switch-ch) 80%, transparent);
    border-color: var(--switch-ch);
}
.settings-switch input:checked ~ .settings-switch-track::after {
    left: 18px;
    background: #fff;
}
.settings-switch input:focus-visible ~ .settings-switch-track {
    outline: 2px solid var(--switch-ch);
    outline-offset: 2px;
}

/* About hero (used by renderAboutPanel) */
.about-hero {
    text-align: center;
    padding: 22px 16px 18px;
}
.about-hero .about-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 54px;
    height: 54px;
    border-radius: 14px;
    background: linear-gradient(135deg, var(--ch-amber, var(--warning-color)), var(--ch-coral, var(--danger-color)));
    color: #000;
    font-family: var(--font-display, sans-serif);
    font-size: 1.7rem;
    font-weight: 900;
    box-shadow: 0 8px 24px color-mix(in srgb, var(--ch-amber, var(--warning-color)) 40%, transparent);
    margin-bottom: 10px;
}
.about-hero .about-name {
    font-family: var(--font-display, var(--font-body));
    font-size: 1.5rem;
    font-weight: 800;
    color: var(--lux-ink, var(--text-color));
    margin-bottom: 2px;
    letter-spacing: 0.005em;
}
.about-hero .about-version {
    display: inline-block;
    margin-top: 4px;
    padding: 3px 11px;
    border-radius: 999px;
    font-family: var(--font-mono, monospace);
    font-size: 0.72rem;
    font-weight: 600;
    background: color-mix(in srgb, var(--ch-amber, var(--warning-color)) 12%, transparent);
    color: var(--ch-amber, var(--warning-color));
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ch-amber, var(--warning-color)) 30%, transparent);
}
.about-hero .about-tag {
    margin-top: 10px;
    font-size: 0.78rem;
    color: var(--lux-ink-dim, var(--text-secondary));
}
.about-hero .about-author {
    margin-top: 10px;
    font-size: 0.78rem;
    color: var(--lux-ink-dim, var(--text-secondary));
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: center;
}
.about-hero .about-author strong {
    color: var(--lux-ink, var(--text-color));
    font-weight: 700;
}
.about-hero .about-author a {
    color: var(--primary-text-color);
    text-decoration: none;
    transition: opacity 0.2s;
}
.about-hero .about-author a:hover {
    opacity: 0.8;
    text-decoration: underline;
}
.about-hero .about-author-sep {
    opacity: 0.5;
}
.about-hero .about-links {
    display: flex;
    gap: 6px;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 14px;
}
.about-hero .about-license {
    margin-top: 14px;
    font-size: 0.7rem;
    color: var(--lux-ink-faint, var(--text-muted));
    opacity: 0.7;
    letter-spacing: 0.04em;
}

/* ── Per-section save bar ──────────────────────────────────
   Appears under a dirty field; warns about unsaved changes and offers
   inline Save / Revert. Toggled via the [hidden] attribute by settings.ts. */
.save-bar {
    margin: 6px 0 4px;
    padding: 9px 12px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    background: color-mix(in srgb, var(--ch-amber, var(--warning-color)) 10%, var(--lux-bg-1, var(--card-bg)));
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ch-amber, var(--warning-color)) 36%, transparent);
    border-left: 3px solid var(--ch-amber, var(--warning-color));
    border-radius: var(--lux-r-sm, 4px);
    animation: saveBarSlide var(--duration-normal, 0.25s) var(--ease-out, ease);
}
.save-bar[hidden] { display: none; }
@keyframes saveBarSlide {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}
.save-bar-msg {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.78rem;
    font-weight: 500;
    color: var(--lux-ink, var(--text-color));
    min-width: 0;
}
.save-bar-msg::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ch-amber, var(--warning-color));
    box-shadow: 0 0 8px var(--ch-amber, var(--warning-color));
    animation: saveBarPulse 1.6s ease-in-out infinite;
    flex-shrink: 0;
}
.save-bar-msg strong {
    color: var(--lux-ink, var(--text-color));
    font-weight: 600;
}
@keyframes saveBarPulse {
    0%, 100% { opacity: 0.6; }
    50%      { opacity: 1; }
}
.save-bar-actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}

/* ── Responsive collapse: rail to icon-only at narrow widths ── */
@media (max-width: 600px) {
    #settings-modal .modal-content {
        max-width: 100%;
    }
    .settings-rail {
        flex-basis: 56px;
    }
    .settings-rail-btn {
        padding: 11px 0;
        justify-content: center;
        gap: 0;
    }
    .settings-rail-btn .settings-rail-label,
    .settings-rail-btn .settings-rail-dot {
        display: none;
    }
    .settings-rail-group { display: none; }
    .settings-rail-footer { display: none; }
    .ds-pair-row { grid-template-columns: 1fr; gap: 0; }
    .notif-matrix { grid-template-columns: minmax(0, 1fr) repeat(4, 50px); }
    .status-card { grid-template-columns: auto 1fr; }
    .status-card-actions { grid-column: 1 / -1; flex-direction: row; }
    .status-card-actions .btn { flex: 1; }
}

/* ===================================================================
   Icon picker modal (#icon-picker-modal)
   See: features/icon-picker.ts and modals/icon-picker.html
   =================================================================== */
#icon-picker-modal .modal-content {
    --modal-ch: var(--ch-cyan, var(--primary-color));
    max-width: 720px;
    width: 100%;
}

.icon-picker-head {
    display: flex !important;
    align-items: center;
    gap: 14px;
    padding: 18px 22px 14px !important;
}

.icon-picker-preview-wrap {
    flex: 0 0 56px;
}
.icon-picker-preview {
    --plate-size: 56px;
    width: 56px;
    height: 56px;
    cursor: default !important;
    --ch: var(--ch-cyan, var(--primary-color));
}
.icon-picker-preview svg {
    width: 30px;
    height: 30px;
}
.icon-picker-preview.is-empty {
    border-style: dashed !important;
    background: transparent !important;
    color: var(--lux-ink-mute, var(--text-secondary)) !important;
}
.icon-picker-preview.is-inherited svg {
    opacity: 0.7;
}
.icon-picker-sub.is-inherited {
    color: var(--ch-cyan, var(--primary-color));
    font-style: italic;
}
.icon-picker-sub.is-inherited::before {
    content: '↳';
    margin-right: 4px;
    font-style: normal;
    opacity: 0.85;
}

.icon-picker-meta { flex: 1; min-width: 0; }
.icon-picker-eyebrow {
    font-family: var(--font-mono, monospace);
    font-size: 0.58rem;
    font-weight: 600;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--ch-cyan, var(--primary-color));
    margin-bottom: 4px;
}
.icon-picker-title {
    font-family: var(--font-display, inherit);
    font-size: 1.4rem !important;
    font-weight: 800 !important;
    letter-spacing: -0.005em;
    margin: 0;
    color: var(--lux-ink, var(--text-color)) !important;
}
.icon-picker-sub {
    font-family: var(--font-mono, monospace);
    font-size: 0.66rem;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: 0.06em;
    margin-top: 3px;
}
.icon-picker-sub strong {
    color: var(--lux-ink, var(--text-color));
    font-weight: 700;
}

.icon-picker-body {
    padding: 0 !important;
    background: var(--lux-bg-1, var(--card-bg));
}

.icon-picker-toolbar {
    display: flex;
    gap: 10px;
    padding: 12px 22px;
    background: var(--lux-bg-0, var(--bg-color));
    border-bottom: 1px solid var(--lux-line, var(--border-color));
    align-items: center;
}
.icon-picker-search-wrap {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: var(--lux-bg-1, var(--card-bg));
    border: 1px solid var(--lux-line-bold, var(--border-color));
    border-radius: var(--lux-r-sm, var(--radius-sm));
}
.icon-picker-search-wrap:focus-within {
    border-color: color-mix(in srgb, var(--ch-cyan) 50%, var(--lux-line-bold));
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ch-cyan) 15%, transparent);
}
.icon-picker-search-icon { color: var(--lux-ink-mute, var(--text-secondary)); flex-shrink: 0; }
.icon-picker-search-wrap input {
    flex: 1;
    background: none;
    border: none;
    outline: none;
    font-family: var(--font-mono, monospace);
    font-size: 0.78rem;
    letter-spacing: 0.04em;
    color: var(--lux-ink, var(--text-color));
}
.icon-picker-search-wrap input::placeholder {
    color: var(--lux-ink-mute, var(--text-secondary));
    text-transform: uppercase;
    letter-spacing: 0.16em;
    font-size: 0.66rem;
}

.icon-picker-color-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: var(--lux-bg-1, var(--card-bg));
    border: 1px solid var(--lux-line-bold, var(--border-color));
    border-radius: var(--lux-r-sm, var(--radius-sm));
    cursor: pointer;
    font-family: var(--font-mono, monospace);
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--lux-ink-dim, var(--text-color));
    transition: color 0.15s, background 0.15s;
}
.icon-picker-color-toggle:hover { color: var(--lux-ink, var(--text-color)); }
.icon-picker-swatch {
    width: 14px;
    height: 14px;
    border-radius: 2px;
    background: var(--ch-cyan, var(--primary-color));
    border: 1px solid var(--ch-cyan, var(--primary-color));
}

.icon-picker-tabs {
    display: flex;
    gap: 0;
    padding: 0 22px;
    background: var(--lux-bg-0, var(--bg-color));
    border-bottom: 1px solid var(--lux-line, var(--border-color));
    overflow-x: auto;
}
.icon-picker-tab {
    appearance: none;
    background: none;
    border: none;
    padding: 11px 16px;
    font-family: var(--font-mono, monospace);
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    cursor: pointer;
    border-bottom: 2px solid transparent;
    transition: color 0.15s, border-color 0.15s;
    display: flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}
.icon-picker-tab .count {
    font-size: 0.55rem;
    color: var(--lux-ink-faint, var(--text-muted));
    letter-spacing: 0.05em;
    background: var(--lux-bg-2, var(--card-bg));
    padding: 1px 5px;
    border-radius: 99px;
}
.icon-picker-tab:hover { color: var(--lux-ink-dim, var(--text-color)); }
.icon-picker-tab.is-active {
    color: var(--ch-cyan, var(--primary-color));
    border-bottom-color: var(--ch-cyan, var(--primary-color));
}
.icon-picker-tab.is-active .count {
    background: color-mix(in srgb, var(--ch-cyan) 14%, transparent);
    color: var(--ch-cyan, var(--primary-color));
}

.icon-picker-recent {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 10px 22px;
    border-bottom: 1px solid var(--lux-line, var(--border-color));
    background: var(--lux-bg-0, var(--bg-color));
}
.icon-picker-recent__label {
    font-family: var(--font-mono, monospace);
    font-size: 0.58rem;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    flex-shrink: 0;
}
.icon-picker-recent__strip {
    display: flex;
    gap: 6px;
    flex: 1;
    overflow-x: auto;
}
.icon-picker-recent .icon-tile { width: 30px; height: 30px; }
.icon-picker-recent .icon-tile svg { width: 16px; height: 16px; }

.icon-picker-grid-wrap {
    padding: 16px 22px 14px;
    max-height: 380px;
    overflow-y: auto;
    background: var(--lux-bg-1, var(--card-bg));
}
.icon-picker-cat {
    font-family: var(--font-mono, monospace);
    font-size: 0.58rem;
    font-weight: 600;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    margin: 14px 0 10px;
    display: flex;
    align-items: center;
    gap: 10px;
}
.icon-picker-cat:first-child { margin-top: 0; }
.icon-picker-cat::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--lux-line, var(--border-color));
}

.icon-picker-grid {
    display: grid;
    grid-template-columns: repeat(8, minmax(0, 1fr));
    gap: 6px;
}

.icon-tile {
    --ch: var(--ch-cyan, var(--primary-color));
    appearance: none;
    border: 1px solid var(--lux-line, var(--border-color));
    width: 100%;
    aspect-ratio: 1;
    background: var(--lux-bg-0, var(--bg-color));
    border-radius: 3px;
    color: var(--lux-ink-dim, var(--text-color));
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: color 0.15s, background 0.15s, border-color 0.15s, box-shadow 0.15s;
    position: relative;
    padding: 0;
}
.icon-tile svg {
    width: 20px;
    height: 20px;
    stroke: currentColor;
    stroke-width: 1.6;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.icon-tile:hover {
    color: var(--ch);
    border-color: color-mix(in srgb, var(--ch) 50%, var(--lux-line));
    background: color-mix(in srgb, var(--ch) 8%, var(--lux-bg-0));
    box-shadow: 0 0 12px color-mix(in srgb, var(--ch) 22%, transparent);
}
.icon-tile.is-selected {
    color: var(--ch);
    border-color: var(--ch);
    background: color-mix(in srgb, var(--ch) 16%, var(--lux-bg-0));
    box-shadow:
        0 0 16px color-mix(in srgb, var(--ch) 35%, transparent),
        inset 0 0 0 1px color-mix(in srgb, var(--ch) 35%, transparent);
}
.icon-tile.is-selected::after {
    content: '';
    position: absolute;
    top: 3px;
    right: 3px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ch);
    box-shadow: 0 0 6px var(--ch);
}

.icon-picker-empty {
    padding: 28px 0;
    text-align: center;
    font-family: var(--font-mono, monospace);
    font-size: 0.72rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
}

.icon-picker-foot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 22px !important;
    background: var(--lux-bg-0, var(--bg-color));
    border-top: 1px solid var(--lux-line, var(--border-color));
}
.icon-picker-hint {
    font-family: var(--font-mono, monospace);
    font-size: 0.6rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    margin-right: auto;
}
.icon-picker-foot .btn { flex: 0 0 auto; min-width: 0; }
.icon-picker-btn-remove {
    color: var(--ch-coral, var(--danger-color)) !important;
    border-color: color-mix(in srgb, var(--ch-coral) 40%, var(--lux-line-bold)) !important;
}
.icon-picker-btn-remove:hover:not(:disabled) {
    background: color-mix(in srgb, var(--ch-coral) 12%, transparent) !important;
}

@media (max-width: 600px) {
    #icon-picker-modal .modal-content { max-width: 96%; }
    .icon-picker-head { flex-wrap: wrap; }
    .icon-picker-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
    .icon-picker-toolbar { flex-direction: column; align-items: stretch; }
}

