/* ── Dashboard ── */

.dashboard-section {
    margin-bottom: 16px;
}

.dashboard-section-header {
    font-family: var(--font-mono, monospace);
    font-size: 0.82rem;
    font-weight: 700;
    margin-bottom: 16px;
    color: var(--lux-ink-dim, var(--text-secondary));
    display: flex;
    align-items: center;
    gap: 12px;
    text-transform: uppercase;
    letter-spacing: 0.25em;
    user-select: none;
    padding-bottom: 10px;
    border-bottom: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    position: relative;
}

.dashboard-section-header::before {
    content: '';
    position: absolute;
    left: 0; bottom: -1px;
    width: 40px;
    height: 1px;
    background: var(--ch-signal, var(--primary-color));
    box-shadow: 0 0 6px color-mix(in srgb, var(--ch-signal, var(--primary-color)) 50%, transparent);
}
.dashboard-section-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    flex: 1;
    min-width: 0;
}

.dashboard-section-chevron {
    font-size: 0.6rem;
    color: var(--text-secondary);
    width: 10px;
    display: inline-block;
    transition: transform 0.2s ease;
}

.dashboard-section-count {
    background: var(--lux-bg-3, var(--border-color));
    color: var(--lux-ink-dim, var(--text-secondary));
    font-family: var(--font-mono, monospace);
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: 2px;
    padding: 2px 7px;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    font-variant-numeric: tabular-nums;
    line-height: 1.3;
    min-width: 22px;
    text-align: center;
}


.dashboard-subsection {
    margin-bottom: 10px;
    padding-left: 16px;
}

.dashboard-subsection .dashboard-section-content {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(var(--card-grid-min, 380px), 100%), 1fr));
    gap: var(--card-grid-gap, 14px);
}

.dashboard-subsection .dashboard-section-content .dashboard-target {
    margin-bottom: 0;
    min-width: 0;
}
.dashboard-subsection .dashboard-section-header {
    font-size: 0.72rem;
}

.dashboard-stop-all {
    margin-left: auto;
    padding: 2px 8px;
    font-size: 0.7rem;
    white-space: nowrap;
    flex: 0 0 auto;
}

.dashboard-poll-wrap {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 3px;
}

.dashboard-poll-slider {
    width: 48px;
    height: 12px;
    accent-color: var(--primary-color);
    cursor: pointer;
}

.dashboard-poll-value {
    font-size: 0.6rem;
    color: var(--text-secondary);
    min-width: 18px;
}

.dashboard-target {
    --ch: var(--ch-signal, var(--primary-color));
    position: relative;
    overflow: hidden;
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: center;
    gap: 12px;
    padding: 10px 14px 10px 18px;
    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-md, 6px);
    margin-bottom: 4px;
    transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}

/* Full module layout — activated when the row contains the rich mod-head
   markup emitted by renderDashboardTarget for LED/HA targets. Integration
   and sync-clock "autostart" rows keep the compact grid layout above. */
.dashboard-target:has(.mod-head) {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 16px 18px 14px 22px;
    margin-bottom: 0;
    align-items: stretch;
}

/* Channel stripe on left edge */
.dashboard-target::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--ch);
    box-shadow: 0 0 8px color-mix(in srgb, var(--ch) 40%, transparent);
    opacity: 0.6;
    transition: opacity 0.2s ease, box-shadow 0.2s ease, width 0.2s ease;
}

/* Corner bracket top-right — silkscreened panel cue on idle modules only
   (compact autostart/integration rows don't have space for it). Swapped
   for a signal-flow line when the module is running (see below). */
.dashboard-target:has(.mod-head)::after {
    content: '';
    position: absolute;
    top: 8px; right: 8px;
    width: 12px; height: 12px;
    border-top: 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));
    pointer-events: none;
    opacity: 0.7;
}

.dashboard-target:hover {
    box-shadow: var(--lux-shadow-rack, 0 2px 8px var(--shadow-color));
    border-color: var(--lux-line-bold, var(--border-color));
    transform: translateY(-1px);
}

.dashboard-target:hover::before {
    opacity: 1;
    box-shadow: 0 0 14px color-mix(in srgb, var(--ch) 70%, transparent);
}

.dashboard-card-link:hover {
    border-color: color-mix(in srgb, var(--ch) 40%, var(--lux-line, var(--border-color)));
    box-shadow: 0 6px 20px var(--shadow-color);
}

/* Running modules: stripe widens + glows, corner bracket swaps for
   signal-flow strip along the bottom. */
.dashboard-target.is-running {
    border-color: color-mix(in srgb, var(--ch) 32%, var(--lux-line, var(--border-color)));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--ch) 18%, transparent),
                0 6px 20px rgba(0, 0, 0, 0.25);
}

.dashboard-target.is-running::before {
    opacity: 1;
    width: 4px;
    box-shadow:
        0 0 14px color-mix(in srgb, var(--ch) 70%, transparent),
        0 0 4px color-mix(in srgb, var(--ch) 90%, transparent);
}

.dashboard-target:has(.mod-head).is-running::after {
    top: auto; right: auto;
    left: 4px; bottom: 0;
    width: calc(100% - 4px);
    height: 2px;
    border: none;
    opacity: 0.7;
    background: linear-gradient(90deg,
        transparent 0%,
        color-mix(in srgb, var(--ch) 85%, transparent) 50%,
        transparent 100%);
    background-size: 30% 100%;
    background-repeat: no-repeat;
    animation: signalFlow 2.4s linear infinite;
}

/* Dashboard-target channel mapping — targets default to signal green
   (tracks the accent picker), sync clocks to violet. Integrations use
   the default stripe so they match the overall accent; the health-dot
   inside the card already carries the connection state. */
.dashboard-target[data-target-id]   { --ch: var(--ch-signal, var(--primary-color)); }
.dashboard-target[data-sync-clock-id]  { --ch: var(--ch-violet, #8b7eff); }

/* ── Module head: ID badge + name + meta · LED cluster ── */
.mod-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.mod-id {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    flex: 1;
}

.mod-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    align-self: flex-start;
    font-family: var(--font-mono, monospace);
    font-size: 0.55rem;
    font-weight: 600;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--ch);
    padding: 2px 6px;
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ch) 35%, var(--lux-line, var(--border-color)));
    border-radius: 3px;
    background: color-mix(in srgb, var(--ch) 8%, transparent);
    line-height: 1.4;
    white-space: nowrap;
}

.mod-name {
    font-family: var(--font-body, inherit);
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--lux-ink, var(--text-color));
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mod-name > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.mod-meta {
    font-family: var(--font-mono, monospace);
    font-size: 0.66rem;
    letter-spacing: 0.06em;
    color: var(--lux-ink-mute, var(--text-secondary));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Device URL hyperlink inside the meta line.
   Picks up the card's channel accent (--ch) so it ties into the card's
   color identity instead of using the generic browser-blue link style. */
.mod-meta__link {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    color: var(--ch, var(--primary-text-color));
    text-decoration: none;
    border-bottom: 1px dotted color-mix(in srgb, var(--ch, var(--primary-color)) 55%, transparent);
    padding-bottom: 1px;
    transition: color 0.15s ease, border-color 0.15s ease, text-shadow 0.15s ease;
}

.mod-meta__link:hover,
.mod-meta__link:focus-visible {
    color: var(--ch, var(--primary-color));
    border-bottom-style: solid;
    border-bottom-color: currentColor;
    text-shadow: 0 0 8px color-mix(in srgb, var(--ch, var(--primary-color)) 35%, transparent);
    outline: none;
}

.mod-meta__link .icon {
    width: 0.95em;
    height: 0.95em;
    transform: translateY(0.12em);
    opacity: 0.7;
    transition: opacity 0.15s ease;
}

.mod-meta__link:hover .icon,
.mod-meta__link:focus-visible .icon {
    opacity: 1;
}

.mod-leds {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 5px 7px;
    background: var(--lux-bg-0, var(--bg-color));
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    flex-shrink: 0;
}

/* ── Custom card icon plate ──────────────────────────────────────
   A 44x44 instrument-panel face plate at the leading edge of the
   head row. Channel-tinted; clickable to open the icon picker.
   Renders only when ModHeadOpts.iconHtml is supplied.

   The plate sits at the top-left of the head row at its own fixed
   size. We deliberately do NOT set align-items:stretch on the head —
   that would force sibling slots (LED bezel, kebab) to inherit the
   plate's height. Instead each slot keeps its natural compact size.
*/

.mod-icon {
    --plate-size: 44px;
    flex: 0 0 var(--plate-size);
    width: var(--plate-size);
    height: var(--plate-size);
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    margin: 0;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--ch) 10%, var(--lux-bg-0, var(--bg-color))) 0%,
        var(--lux-bg-0, var(--bg-color)) 100%);
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ch) 28%, var(--lux-line, var(--border-color)));
    border-radius: var(--lux-r-sm, 3px);
    color: var(--ch);
    cursor: default;
    transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
    box-shadow:
        inset 0 1px 0 color-mix(in srgb, var(--ch) 14%, transparent),
        inset 0 -8px 14px color-mix(in srgb, var(--ch) 6%, transparent);
    overflow: hidden;
    isolation: isolate;
    font: inherit;
    line-height: 0;
}
button.mod-icon { cursor: pointer; }

.mod-icon::before {
    content: '';
    position: absolute;
    top: 3px;
    right: 3px;
    width: 6px;
    height: 6px;
    border-top: 1px solid color-mix(in srgb, var(--ch) 55%, var(--lux-line, var(--border-color)));
    border-right: 1px solid color-mix(in srgb, var(--ch) 55%, var(--lux-line, var(--border-color)));
    opacity: 0.7;
    pointer-events: none;
}
.mod-icon::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: repeating-linear-gradient(180deg,
        rgba(255, 255, 255, 0.02) 0 1px,
        transparent 1px 3px);
    mix-blend-mode: overlay;
    opacity: 0.45;
}

.mod-icon svg {
    width: 24px;
    height: 24px;
    stroke: currentColor;
    fill: none;
    z-index: 1;
    transition: transform 0.25s ease;
    filter: drop-shadow(0 0 5px color-mix(in srgb, var(--ch) 30%, transparent));
}

button.mod-icon:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--ch) 60%, var(--lux-line, var(--border-color)));
    box-shadow:
        inset 0 1px 0 color-mix(in srgb, var(--ch) 24%, transparent),
        inset 0 -10px 18px color-mix(in srgb, var(--ch) 10%, transparent),
        0 0 0 3px color-mix(in srgb, var(--ch) 18%, transparent),
        0 4px 12px color-mix(in srgb, var(--ch) 22%, transparent);
}
button.mod-icon:hover svg { transform: scale(1.06); }
button.mod-icon:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ch) 60%, transparent);
}

/* Empty / placeholder plate — kept visible so the slot is discoverable.
   Styled as a dashed outline with a quiet "+" glyph; tints to --ch on
   hover so the user sees it light up just like a populated plate. */
.mod-icon.is-empty {
    background: transparent;
    border-style: dashed;
    border-color: var(--lux-line-bold, var(--border-color));
    color: var(--lux-ink-mute, var(--text-secondary));
    box-shadow: none;
}
.mod-icon.is-empty::before,
.mod-icon.is-empty::after { display: none; }
.mod-icon.is-empty svg {
    width: 18px;
    height: 18px;
    filter: none;
    opacity: 0.7;
}
button.mod-icon.is-empty:hover {
    transform: none;
    border-color: color-mix(in srgb, var(--ch) 60%, var(--lux-line-bold, var(--border-color)));
    color: var(--ch);
    background: color-mix(in srgb, var(--ch) 5%, transparent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ch) 14%, transparent);
}
button.mod-icon.is-empty:hover svg { transform: none; opacity: 1; }
.is-running .mod-icon.is-empty,
.card-running .mod-icon.is-empty { animation: none; }

/* Running cards: the plate breathes with the live indicator. */
.is-running .mod-icon,
.card-running .mod-icon {
    animation: modIconPulse 2.6s ease-in-out infinite;
}
@keyframes modIconPulse {
    0%, 100% {
        box-shadow:
            inset 0 1px 0 color-mix(in srgb, var(--ch) 14%, transparent),
            inset 0 -8px 14px color-mix(in srgb, var(--ch) 6%, transparent);
    }
    50% {
        box-shadow:
            inset 0 1px 0 color-mix(in srgb, var(--ch) 22%, transparent),
            inset 0 -8px 18px color-mix(in srgb, var(--ch) 12%, transparent),
            0 0 14px color-mix(in srgb, var(--ch) 28%, transparent);
    }
}

.mod-leds .led {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--lux-ink-faint, var(--text-muted));
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5);
    transition: background 0.2s, box-shadow 0.2s;
}
.mod-leds .led.on {
    background: var(--ch);
    box-shadow: 0 0 6px color-mix(in srgb, var(--ch) 80%, transparent);
}
.mod-leds .led.blink { animation: ledBlink 1.2s ease-in-out infinite; }
.mod-leds .led.blink:nth-child(2) { animation-delay: 0.2s; }
.mod-leds .led.blink:nth-child(3) { animation-delay: 0.4s; }

@keyframes ledBlink {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.28; }
}

/* ── Metric grid: FPS · Uptime · Errors ── */
.mod-metrics {
    display: grid;
    grid-template-columns: 1.2fr 1fr 1fr;
    gap: 0;
    background: var(--lux-bg-0, var(--bg-color));
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    overflow: hidden;
}

.mod-metric {
    padding: 9px 12px 10px;
    border-right: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    position: relative;
}
.mod-metric:last-child { border-right: none; }

.mod-metric .k {
    font-family: var(--font-mono, monospace);
    font-size: 0.55rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

/* Label-row icon sizing — the status glyph (clock/check/warning) sits
   next to the mono caps label, not the big value. Tiny + muted so it
   reads as an accent, not a competing element. */
.mod-metric .k > .icon,
.mod-metric .k > svg {
    width: 10px;
    height: 10px;
    flex-shrink: 0;
    opacity: 0.85;
}

/* Errors cell: the label icon shifts to coral when there are errors
   (matching the big-value tint). */
.mod-metric.has-errors .k,
.mod-metric.has-errors .k > .icon,
.mod-metric.has-errors .k > svg {
    color: var(--ch-coral, var(--danger-color));
    opacity: 1;
}

.mod-metric .v {
    font-family: var(--font-display, 'Big Shoulders Display', 'Orbitron', sans-serif);
    font-size: 2rem;
    font-weight: 800;
    line-height: 1;
    color: var(--lux-ink, var(--text-color));
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.mod-metric .v.signal {
    color: var(--ch);
}

/* Errors cell — coral tint when > 0 so non-zero counts draw the eye
   without needing an inline glyph that'd eat horizontal space. */
.mod-metric .v.has-errors {
    color: var(--ch-coral, var(--danger-color));
}

.mod-metric .v small {
    font-family: var(--font-mono, monospace);
    font-size: 0.65rem;
    font-weight: 500;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: 0.08em;
    margin-left: 3px;
}

/* Text-stack variant — used for short identifier values that don't render
   well in the heavy display font (e.g. SK6812 + RGBW). The primary line
   sits in the same slot as `.v`, and an optional `.v-sub` element below
   carries a secondary line in the small mono caps style. */
.mod-metric--text-stack .v {
    font-family: var(--font-mono, monospace);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    line-height: 1.15;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    display: flex;
    flex-direction: column;
    gap: 4px;
    align-items: flex-start;
}
.mod-metric--text-stack .v-sub {
    font-family: var(--font-mono, monospace);
    font-size: 0.55rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    opacity: 0.85;
}

.mod-metric .v .dashboard-fps-target {
    font-family: var(--font-mono, monospace);
    font-size: 0.6rem;
    color: var(--lux-ink-mute, var(--text-secondary));
    opacity: 0.6;
    margin-left: 3px;
}
.mod-metric .v .dashboard-fps-avg {
    display: block;
    font-family: var(--font-mono, monospace);
    font-size: 0.55rem;
    font-weight: 500;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: 0.06em;
    opacity: 0.7;
    margin-top: 2px;
    line-height: 1;
}

.mod-metric-spark {
    width: 100%;
    height: 20px;
    margin-top: 3px;
    display: block;
}

.mod-metric-spark-canvas {
    width: 100% !important;
    height: 20px !important;
    display: block;
}

/* ── Module foot: patch indicator + action buttons ── */
.mod-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    padding-top: 2px;
}

.mod-patch {
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-mono, monospace);
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    margin-right: auto;
    min-width: 0;
}

.mod-patch .patch-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--lux-bg-0, var(--bg-color));
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--ch) 55%, var(--lux-line-bold, var(--border-color)));
    flex-shrink: 0;
    position: relative;
}
.mod-patch .patch-dot.is-live::after {
    content: '';
    position: absolute;
    inset: 1px;
    border-radius: 50%;
    background: var(--ch);
    box-shadow: 0 0 6px var(--ch);
    animation: pulse 2s ease-in-out infinite;
}

.mod-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    font-family: var(--font-mono, monospace);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 7px 14px;
    min-width: 0;
    flex: 0 0 auto;
    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));
    cursor: pointer;
    transition: all 0.15s ease;
}
.mod-btn:hover {
    color: var(--lux-ink, var(--text-color));
    border-color: color-mix(in srgb, var(--ch) 40%, var(--lux-line-bold, var(--border-color)));
    background: var(--lux-bg-3, var(--border-color));
}
.mod-btn.mod-btn-go {
    background: var(--ch);
    color: var(--lux-bg-0, var(--primary-contrast));
    border-color: var(--ch);
    box-shadow: 0 0 14px color-mix(in srgb, var(--ch) 35%, transparent);
}
.mod-btn.mod-btn-go:hover {
    filter: brightness(1.1);
    color: var(--lux-bg-0, var(--primary-contrast));
}
.mod-btn.mod-btn-stop {
    color: var(--ch-coral, var(--danger-color));
    border-color: color-mix(in srgb, var(--ch-coral, var(--danger-color)) 40%, transparent);
}
.mod-btn.mod-btn-stop:hover {
    background: color-mix(in srgb, var(--ch-coral, var(--danger-color)) 12%, transparent);
    color: var(--ch-coral, var(--danger-color));
}
.mod-btn .icon {
    width: 12px;
    height: 12px;
}

.dashboard-target-info {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    overflow: hidden;
}

.dashboard-target-icon {
    font-size: 1rem;
    flex-shrink: 0;
    color: var(--primary-text-color);
}

.dashboard-target-info > div {
    min-width: 0;
    overflow: hidden;
}

.dashboard-target-name {
    font-size: 0.88rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: flex;
    align-items: center;
    gap: 4px;
    color: var(--lux-ink, var(--text-color));
}

.dashboard-target-name-text {
    overflow: hidden;
    text-overflow: ellipsis;
}

.dashboard-card-link {
    cursor: pointer;
}

.dashboard-target-name .health-dot {
    margin-right: 0;
    flex-shrink: 0;
}

.dashboard-target-subtitle {
    font-family: var(--font-mono, monospace);
    font-size: 0.64rem;
    letter-spacing: 0.05em;
    color: var(--lux-ink-mute, var(--text-secondary));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-top: 2px;
}

.dashboard-target-metrics {
    display: grid;
    grid-template-columns: auto 72px 36px;
    gap: 8px;
    align-items: center;
}

.dashboard-metric {
    text-align: center;
    overflow: hidden;
}

.dashboard-metric-value {
    font-family: var(--font-mono, monospace);
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--ch, var(--primary-text-color));
    line-height: 1.2;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
}

.dashboard-metric-label {
    font-family: var(--font-mono, monospace);
    font-size: 0.55rem;
    color: var(--lux-ink-mute, var(--text-secondary));
    text-transform: uppercase;
    letter-spacing: 0.15em;
}

.dashboard-fps-metric {
    display: flex;
    align-items: center;
    gap: 6px;
    overflow: hidden;
}

.dashboard-fps-sparkline {
    position: relative;
    width: 100px;
    height: 36px;
}

.dashboard-fps-label {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 44px;
    flex-shrink: 0;
    line-height: 1.1;
}

.dashboard-fps-target {
    font-weight: 400;
    opacity: 0.5;
    font-size: 0.75rem;
}

.dashboard-fps-avg {
    display: block;
    font-size: 0.6rem;
    font-weight: 400;
    opacity: 0.45;
    line-height: 1.1;
    color: var(--primary-color);
}

.dashboard-target-actions {
    display: flex;
    align-items: center;
    gap: 4px;
}

.dashboard-action-btn {
    background: none;
    border: none;
    width: 28px;
    height: 28px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border-radius: 4px;
    transition: color 0.2s, background 0.2s;
}

.dashboard-action-btn.start {
    color: var(--primary-color);
}

.dashboard-action-btn.start:hover {
    background: color-mix(in srgb, var(--primary-color) 12%, transparent);
}

.dashboard-action-btn.stop {
    color: var(--warning-color, #ffc107);
}

.dashboard-action-btn.stop:hover {
    background: rgba(255, 193, 7, 0.12);
}

.dashboard-autostart-btn {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 0.8rem;
    width: 24px;
    height: 24px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border-radius: 4px;
    transition: color 0.2s, background 0.2s;
}

.dashboard-autostart-btn:hover {
    color: var(--warning-color, #ffc107);
    background: rgba(255, 193, 7, 0.1);
}

.dashboard-autostart-btn.active {
    color: var(--warning-color, #ffc107);
}

.dashboard-status-dot {
    font-size: 1rem;
    line-height: 1;
}

.dashboard-status-dot.active {
    color: var(--primary-color);
    animation: pulse 2s infinite;
}

.dashboard-no-targets {
    text-align: center;
    padding: 32px 16px;
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.dashboard-badge-stopped {
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 0.7rem;
    font-weight: 600;
    background: var(--border-color);
    color: var(--text-secondary);
    flex-shrink: 0;
}

.dashboard-badge-active {
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 0.7rem;
    font-weight: 600;
    background: var(--primary-color);
    color: var(--primary-contrast);
    flex-shrink: 0;
}

/* Automation cards use the autostart grid now; no special width cap. */
.dashboard-automation .dashboard-target-metrics {
    min-width: 48px;
}

/* ── Integrations / autostart grid — tuned for the new module cards ── */
.dashboard-integrations-grid,
.dashboard-autostart-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(var(--card-grid-min-narrow, 320px), 100%), 1fr));
    gap: var(--card-grid-gap-narrow, 12px);
}

/* Legacy row-style overrides kept for any card that still lacks .mod-head */
.dashboard-autostart:not(:has(.mod-head)) {
    grid-template-columns: 1fr auto;
    margin-bottom: 0;
}

.dashboard-autostart:not(:has(.mod-head)) .dashboard-target-info > div {
    min-width: 0;
}

/* Compact autostart module — has .mod-head but no metric grid */
.dashboard-autostart:has(.mod-head) {
    gap: 10px;
    padding-top: 14px;
    padding-bottom: 12px;
}

@media (max-width: 768px) {
    .dashboard-target {
        grid-template-columns: 1fr auto;
        gap: 6px;
    }

    .dashboard-target-metrics {
        display: none;
    }
}

/* ===== PERFORMANCE CHARTS ===== */

/* ── Perf strip — equal-width cells sharing one rack-module shell,
       divided by hairlines rather than separate cards. Mirrors the
       mockup hero. Max 4 columns even on widescreen so each cell
       stays substantial; wraps to 2 rows when the full 7 cells are
       present. ── */
.perf-charts-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0;
    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-md, 6px);
    overflow: hidden;
    position: relative;
}

@media (max-width: 1100px) {
    .perf-charts-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}
@media (max-width: 760px) {
    .perf-charts-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}
@media (max-width: 480px) {
    .perf-charts-grid {
        grid-template-columns: 1fr;
    }
}

/* ── Per-metric accent colors ── */
.perf-chart-card {
    --perf-accent: var(--ch-signal, var(--primary-color));
    --perf-accent-glow: color-mix(in srgb, var(--perf-accent) 18%, transparent);
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0;
    min-width: 0;
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: background var(--duration-normal) ease;
}

/* Hairline divider between cells (except the first) */
.perf-chart-card + .perf-chart-card {
    border-left: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
}

/* Top-edge channel accent per cell — marks the metric's identity without
   needing an explicit left stripe that'd clash with the divider. */
.perf-chart-card::before {
    content: '';
    position: absolute;
    left: 0; right: 0; top: 0;
    height: 2px;
    background: var(--perf-accent);
    box-shadow: 0 0 10px color-mix(in srgb, var(--perf-accent) 50%, transparent);
    opacity: 0.85;
    z-index: 2;
}

/* Corner bracket — keep in top-right but smaller and subtler now that it's
   on a shared surface. Hidden when the card is in hint mode (see below)
   or has an APP tag occupying that slot. */
.perf-chart-card::after {
    content: '';
    position: absolute;
    top: 10px; right: 10px;
    width: 10px; height: 10px;
    border-top: 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;
}

.perf-chart-card:hover {
    background: color-mix(in srgb, var(--perf-accent) 4%, transparent);
}

.perf-chart-card[data-metric="cpu"] {
    --perf-accent: var(--ch-coral, #FF6B6B);
}

.perf-chart-card[data-metric="ram"] {
    --perf-accent: var(--ch-violet, #A855F7);
}

.perf-chart-card[data-metric="gpu"] {
    --perf-accent: var(--ch-signal, #10B981);
}

.perf-chart-card[data-metric="temp"] {
    --perf-accent: var(--ch-amber, #FFB800);
}

/* ── Header (mono label + color picker) at the top of each cell ── */
.perf-chart-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 18px 6px;
    position: relative;
    z-index: 2;
}

.perf-chart-label {
    font-family: var(--font-mono, monospace);
    font-size: 0.58rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.25em;
    color: var(--lux-ink-mute, var(--text-secondary));
    display: flex;
    align-items: center;
    gap: 8px;
}

/* No pre-dot now — the top accent bar and the value color already carry
   the channel identity. Keeps the label tidy. */

.perf-chart-label .color-picker-swatch {
    width: 12px;
    height: 12px;
    vertical-align: middle;
}

/* ── Body: value block on top, sparkline inline below ── */
.perf-chart-body {
    position: relative;
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
}

.perf-chart-value-block {
    position: relative;
    z-index: 2;
    padding: 2px 18px 4px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    line-height: 1;
}

/* Big numeric readout in the display font — instrument-style.
   Solid fill, no glow — glow is reserved for the sparkline stroke which
   already renders a soft bloom for the "lit panel" feel.
   Font size uses clamp() so the widest cells (RAM "18.9/31.8 GB",
   GPU "50% · 37°C") shrink gracefully in narrow layouts while still
   reading as the hero element of each cell. */
.perf-chart-value {
    font-family: var(--font-display, 'Big Shoulders Display', sans-serif);
    font-size: clamp(1.8rem, 2.8vw, 2.8rem);
    font-weight: 800;
    color: var(--lux-ink, var(--text-color));
    line-height: 0.95;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: nowrap;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: clip;
}

/* APP load tag pinned to the true top-right corner of the perf card,
   overlapping where the idle corner bracket would be. Only visible in
   'both' mode (hidden by JS when a metric has no app variant or mode
   is single). */
.perf-chart-app {
    position: absolute;
    top: 10px;
    right: 12px;
    z-index: 3;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-mono, monospace);
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--perf-accent);
    background: color-mix(in srgb, var(--perf-accent) 12%, transparent);
    border: var(--lux-hairline, 1px) solid color-mix(in srgb, var(--perf-accent) 40%, transparent);
    padding: 3px 8px;
    border-radius: 3px;
    letter-spacing: 0.04em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    line-height: 1.1;
}

/* Hide the pill when there's nothing to show (host-only metrics, or a
   mode/state that has no app variant). Avoids a ghost bordered box in
   the top-right corner. */
.perf-chart-app:empty { display: none; }

/* ── Spark hover tooltip (single floating element, reused across all
   cards; positioned via JS; inline layout reads like an instrument
   readout). ── */
.perf-chart-tooltip {
    position: fixed;
    display: none;
    z-index: var(--z-toast, 3500);
    background: var(--lux-bg-1, var(--card-bg));
    border: var(--lux-hairline, 1px) solid var(--lux-line-bold, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.02),
        0 8px 24px rgba(0, 0, 0, 0.4);
    padding: 8px 10px 6px;
    pointer-events: none;
    font-family: var(--font-mono, monospace);
    font-size: 0.72rem;
    color: var(--lux-ink, var(--text-color));
    letter-spacing: 0.02em;
    line-height: 1.3;
    min-width: 110px;
}

.perf-chart-tooltip .perf-tip-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.perf-chart-tooltip .perf-tip-dot {
    width: 8px;
    height: 8px;
    border-radius: 2px;
    flex-shrink: 0;
    box-shadow: 0 0 4px currentColor;
}
.perf-chart-tooltip .perf-tip-dot-app {
    background: transparent;
    border: var(--lux-hairline, 1px) solid currentColor;
    box-shadow: none;
}
.perf-chart-tooltip .perf-tip-k {
    color: var(--lux-ink-mute, var(--text-secondary));
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    margin-right: auto;
}
.perf-chart-tooltip .perf-tip-v {
    color: var(--lux-ink, var(--text-color));
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}
.perf-chart-tooltip .perf-tip-app .perf-tip-v {
    color: var(--lux-ink-dim, var(--text-secondary));
    font-weight: 500;
}
.perf-chart-tooltip .perf-tip-age {
    margin-top: 4px;
    padding-top: 4px;
    border-top: var(--lux-hairline, 1px) dashed var(--lux-line, var(--border-color));
    font-size: 0.6rem;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: 0.14em;
    text-transform: uppercase;
    text-align: right;
}

/* Vertical marker line over the spark at cursor x. */
.perf-chart-tooltip-marker {
    position: fixed;
    display: none;
    width: 1px;
    pointer-events: none;
    background: var(--marker-color, var(--ch-signal, var(--primary-color)));
    opacity: 0.55;
    z-index: calc(var(--z-toast, 3500) - 1);
    box-shadow: 0 0 6px var(--marker-color, var(--ch-signal, var(--primary-color)));
}

/* Hide the idle corner bracket on perf cards — the APP tag now
   owns that slot in 'both' mode. */
.perf-chart-card::after {
    display: none;
}

.perf-chart-app .perf-chart-app-k {
    font-size: 0.55rem;
    font-weight: 600;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--perf-accent) 80%, var(--lux-ink-mute, #888));
    opacity: 0.85;
}

/* "Install LibreHardwareMonitor" explainer shown in the Temperature card
   on Windows when no CPU die sensor is reachable. Replaces the big number
   with wrapped, readable secondary text so users understand why the card
   is empty and how to enable it. */
.perf-chart-card-hint .perf-chart-value {
    font-family: var(--font-body, system-ui, sans-serif);
    font-size: 0.78rem;
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: 0;
    color: var(--lux-ink-mute, var(--text-secondary));
    white-space: normal;
    flex-wrap: nowrap;
    text-transform: none;
}

.perf-chart-hint {
    display: inline-block;
    max-width: 100%;
    opacity: 0.9;
}

/* CPU / GPU model name — silkscreened micro-type under the big value */
.perf-chart-subtitle {
    font-family: var(--font-mono, monospace);
    font-size: 0.55rem;
    letter-spacing: 0.08em;
    color: var(--lux-ink-mute, var(--text-secondary));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
    margin-top: 2px;
}

/* Sparkline sits inline below the value block, flush with the cell
   bottom. `margin-top: auto` pushes it to the bottom so the spark
   baseline aligns across cells regardless of subtitle presence —
   cells with CPU/GPU model names, FPS min/max etc. no longer have a
   higher spark than cells without a subtitle.
   Pointer events stay enabled so hover tooltips work; the SVG itself
   is non-interactive via `perf-chart-svg` below. */
.perf-chart-spark {
    position: relative;
    margin-top: auto;
    height: 42px;
    padding: 0 18px 14px;
    cursor: crosshair;
    filter: drop-shadow(0 0 5px color-mix(in srgb, var(--perf-accent) 45%, transparent));
    /* Clip the scroll-out animation: when a new sample arrives the SVG
       is snap-translated +1 step right then eased back to 0, so the
       previous sample's frame remains visually anchored while old
       samples slide off the left. Without overflow:hidden the temporary
       overshoot would peek into the padding. */
    overflow: hidden;
}

.perf-chart-spark .perf-chart-svg {
    pointer-events: none;
}

.perf-chart-spark .perf-chart-svg {
    width: 100%;
    height: 100%;
    display: block;
    /* Promote to its own compositor layer so the scroll animation runs
       on the GPU — the path strings underneath don't repaint, only the
       layer transform updates per frame. */
    will-change: transform;
}

/* Honor the global animations preference. "reduced" keeps the scroll
   but cuts duration so motion is brief; "off" pins the SVG so each
   tick is a hard cut. */
[data-layout-anim="off"] .perf-chart-spark .perf-chart-svg {
    transition: none !important;
    transform: none !important;
}

.perf-chart-unavailable {
    text-align: center;
    padding: 20px 0;
    color: var(--lux-ink-mute, var(--text-secondary));
    font-family: var(--font-mono, monospace);
    font-size: 0.7rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
}

/* ── Active Patches cell — first in the perf strip. Shows channel count
   and a short list of running targets with their live FPS. ── */
.perf-patches-cell {
    --perf-accent: var(--ch-signal, var(--primary-color));
    position: relative;
    isolation: isolate;
    /* Soft radial glow anchored to the bottom-right corner of the cell
       itself — marks this as the "live" channel bank. Percent-based so
       it always lands in the corner regardless of cell height/width. */
    background:
        radial-gradient(
            circle at 95% 105%,
            color-mix(in srgb, var(--perf-accent) 32%, transparent) 0%,
            color-mix(in srgb, var(--perf-accent) 14%, transparent) 18%,
            color-mix(in srgb, var(--perf-accent) 4%, transparent) 38%,
            transparent 55%);
}

.perf-patches-cell .perf-chart-value-block,
.perf-patches-cell .perf-patches-list,
.perf-patches-cell .perf-chart-header {
    position: relative;
    z-index: 1;
}

.perf-patches-cell .perf-chart-value {
    color: var(--lux-ink, var(--text-color));
}

/* Total count is dramatically smaller than the running count so the eye
   lands on the big live number first, with "/12" as muted context. */
.perf-patches-cell .perf-patches-sep,
.perf-patches-cell .perf-patches-total {
    color: var(--lux-ink-mute, var(--text-secondary));
    font-family: var(--font-mono, monospace);
    font-weight: 500;
    font-size: 0.38em;
    letter-spacing: 0.04em;
    align-self: center;
    margin-left: -2px;
}
.perf-patches-cell .perf-patches-sep {
    opacity: 0.6;
    margin-right: 1px;
}

.perf-patches-list {
    padding: 6px 18px 14px;
    display: flex;
    flex-direction: column;
    gap: 5px;
    font-family: var(--font-mono, monospace);
    font-size: 0.72rem;
    min-height: 42px;
}

.perf-patches-row {
    display: grid;
    grid-template-columns: 4px 1fr auto;
    gap: 10px;
    align-items: center;
    line-height: 1.2;
    min-width: 0;
}

.perf-patches-stripe {
    width: 4px;
    height: 14px;
    border-radius: 2px;
    background: var(--ch-signal, var(--primary-color));
    box-shadow: 0 0 6px currentColor;
    flex-shrink: 0;
}

.perf-patches-name {
    color: var(--lux-ink, var(--text-color));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.perf-patches-fps {
    color: var(--ch-signal, var(--primary-color));
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    letter-spacing: 0.02em;
}

.perf-patches-more {
    font-size: 0.62rem;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: 0.12em;
    text-transform: uppercase;
    padding-top: 2px;
}

/* Patches cell has no sparkline, so it doesn't need the bottom spark slot
   — the list owns the rest of the cell height. */
.perf-patches-cell .perf-chart-spark { display: none; }

/* Errors cell — value is muted at 0 (healthy state, no alarm) and
   shifts to the cell's coral accent the moment the rate or cumulative
   count goes non-zero. The accent stripe + value tint give a passive
   "is anything wrong?" indicator without flashing or animation. */
.perf-errors-cell .perf-chart-value {
    color: var(--lux-ink-mute, var(--text-secondary));
    opacity: 0.65;
}
.perf-errors-cell.has-errors .perf-chart-value {
    color: var(--perf-accent, var(--ch-coral, var(--danger-color)));
    opacity: 1;
}
.perf-errors-cell.has-errors .perf-chart-subtitle {
    color: var(--perf-accent, var(--ch-coral, var(--danger-color)));
    opacity: 0.85;
}

/* Empty-state hint shown when no patches are running. A pulsing accent
   dot keeps the card visually alive even when idle, and the small caps
   text reads as a status line ("Ready to launch") rather than a stale
   empty list. */
.perf-patches-empty {
    display: flex;
    align-items: center;
    gap: 8px;
    padding-top: 4px;
    font-family: var(--font-mono, monospace);
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
    opacity: 0.85;
}
.perf-patches-empty-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--perf-accent, var(--ch-magenta, var(--primary-color)));
    box-shadow: 0 0 6px currentColor;
    color: var(--perf-accent, var(--ch-magenta, var(--primary-color)));
    flex-shrink: 0;
    animation: perfPatchesIdlePulse 2.4s ease-in-out infinite;
}
.perf-patches-empty-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

@keyframes perfPatchesIdlePulse {
    0%, 100% { opacity: 0.45; transform: scale(1); }
    50%      { opacity: 1;    transform: scale(1.15); }
}

/* Honor the global "reduced/off" animations preference set on the
   dashboard root — the pulse vanishes when the user wants stillness. */
[data-layout-anim="off"] .perf-patches-empty-dot,
[data-layout-anim="reduced"] .perf-patches-empty-dot {
    animation: none;
    opacity: 0.7;
}

/* ── Devices cell — online/total count + dot strip per device ── */
.perf-devices-cell {
    --perf-accent: var(--ch-signal, var(--primary-color));
}

.perf-devices-cell .perf-chart-value {
    color: var(--lux-ink, var(--text-color));
}

.perf-devices-cell .perf-chart-subtitle {
    font-family: var(--font-mono, monospace);
    font-size: 0.58rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--lux-ink-mute, var(--text-secondary));
}

.perf-devices-dots {
    padding: 8px 18px 14px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-height: 32px;
}

.perf-devices-dot {
    width: 10px;
    height: 10px;
    border-radius: 2px;
    background: var(--lux-ink-faint, var(--text-muted));
    flex-shrink: 0;
    position: relative;
    transition: background 0.2s, box-shadow 0.2s;
}

.perf-devices-dot.is-online {
    background: var(--ch-signal, var(--primary-color));
    box-shadow: 0 0 6px color-mix(in srgb, var(--ch-signal, var(--primary-color)) 60%, transparent);
}

.perf-devices-dot.is-offline {
    background: var(--ch-coral, var(--danger-color));
    box-shadow: 0 0 6px color-mix(in srgb, var(--ch-coral, var(--danger-color)) 50%, transparent);
}

.perf-devices-more {
    font-family: var(--font-mono, monospace);
    font-size: 0.62rem;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: 0.08em;
    margin-left: 2px;
}

.perf-devices-cell .perf-chart-spark { display: none; }

/* ── Total FPS cell — unit suffix styling (fps text after the number) ── */
.perf-chart-card[data-metric="fps"] .perf-chart-value {
    color: var(--perf-accent);
}

.perf-chart-card .perf-fps-unit {
    font-family: var(--font-mono, monospace);
    font-size: 0.3em;
    font-weight: 500;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: 0.2em;
    text-transform: uppercase;
    margin-left: 6px;
    align-self: center;
}
/* Errors cell — when the rate is non-zero, the unit takes the same coral
   tint as the value so they read as a single composite reading. */
.perf-errors-cell.has-errors .perf-fps-unit {
    color: var(--perf-accent, var(--ch-coral, var(--danger-color)));
    opacity: 0.85;
}

/* Target-FPS ceiling suffix — "/ 120" next to the big live number, sized
   down + muted so the live value remains the primary reading. Matches
   the "/ 12" style from the Active Patches cell. */
.perf-chart-card[data-metric="fps"] .perf-fps-ceiling {
    font-family: var(--font-mono, monospace);
    font-size: 0.38em;
    font-weight: 500;
    color: var(--lux-ink-mute, var(--text-secondary));
    letter-spacing: 0.04em;
    margin-left: 4px;
    align-self: center;
}

/* Hint mode — the card is revealed with an explanatory message instead
   of a live metric (e.g. Windows without LibreHardwareMonitor for CPU
   temp). Neutralizes the big display font + hides the sparkline so the
   explainer text reads as plain body copy. */
.perf-chart-card-hint .perf-chart-value {
    font-size: 0;                 /* kill inherited 3.2rem */
    text-shadow: none;
    line-height: normal;
    letter-spacing: 0;
    display: block;
    color: inherit;
}

.perf-chart-card-hint .perf-chart-spark,
.perf-chart-card-hint .perf-chart-subtitle,
.perf-chart-card-hint .perf-chart-body::after {
    display: none;
}

.perf-chart-card-hint .perf-chart-body {
    min-height: 0;
    padding-bottom: 14px;
}

.perf-chart-hint {
    font-family: var(--font-body, inherit);
    font-size: 0.78rem;
    font-weight: 400;
    line-height: 1.45;
    color: var(--lux-ink-dim, var(--text-secondary));
    letter-spacing: 0;
    text-transform: none;
    display: block;
    white-space: normal;
    max-width: 42ch;
}

.perf-chart-unavailable {
    text-align: center;
    padding: 20px 0;
    color: var(--text-secondary);
    font-size: 0.8rem;
}

/* ── Mode toggle ── */
.perf-mode-toggle {
    display: inline-flex;
    gap: 0;
    margin-left: auto;
    border: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
    border-radius: var(--lux-r-sm, 3px);
    overflow: hidden;
    background: var(--lux-bg-0, var(--bg-secondary));
}

.perf-mode-btn {
    background: transparent;
    border: none;
    color: var(--lux-ink-mute, var(--text-secondary));
    font-family: var(--font-mono, inherit);
    font-size: 0.6rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    padding: 4px 10px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, box-shadow 0.15s;
}

.perf-mode-btn:not(:last-child) {
    border-right: var(--lux-hairline, 1px) solid var(--lux-line, var(--border-color));
}

.perf-mode-btn:hover {
    color: var(--lux-ink, var(--text-color));
    background: var(--lux-bg-2, var(--hover-bg));
}

.perf-mode-btn.active {
    background: var(--ch-signal, var(--primary-color));
    color: var(--lux-bg-0, #fff);
    box-shadow: inset 0 0 8px color-mix(in srgb, var(--ch-signal, var(--primary-color)) 60%, transparent);
}
