/* ══════════════════════════════════════════════════════
   Home page: instrument panel and chart grid.

   The CSP carries no 'unsafe-inline' in style-src, so page styles live in a
   file rather than a <style> block, and nothing uses a style="" attribute.
   ══════════════════════════════════════════════════════ */

/* ── Pack tabs ────────────────────────────────────────────────────────
   The pack is what this page is about, so it is the first thing on it
   rather than a control tucked into the header. Same tab as the plant
   page's Day/Month/Year strip: accent underline, no radius.

   It scrolls sideways rather than wrapping. A wrapped strip changes the
   page height as packs come and go, which moves everything below it.
   ── */
.pack-tabs {
    display: flex;
    gap: 0;
    margin-bottom: var(--space-8);
    border-bottom: 1px solid var(--color-border-strong);
    overflow-x: auto;
    scrollbar-width: thin;
}
.pack-tab {
    padding: 10px 22px; min-height: 44px;
    font-family: var(--font-display);
    font-size: 0.85em; font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--color-text-muted);
    background: none; border: none;
    border-bottom: 3px solid transparent;
    margin-bottom: -1px;
    cursor: pointer; white-space: nowrap;
    transition: color 0.15s ease-out, border-color 0.15s ease-out, scale 0.15s ease-out;
}
.pack-tab:hover { color: var(--color-accent); }
.pack-tab[aria-selected="true"] {
    color: var(--color-accent);
    border-bottom-color: var(--color-accent);
}
.pack-tab:active { scale: 0.96; }

/* ── Pack overview ────────────────────────────────────────────────────
   Live measurements and battery state are two views of the same pack. The
   shared card keeps their relationship visible and collapses as one unit.
   ── */
.overview-tabs {
    display: flex;
    gap: var(--space-5);
    min-width: 0;
    overflow-x: auto;
}
.overview-tab {
    min-height: 44px;
    padding: 6px 0;
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text-secondary);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    white-space: nowrap;
    transition: color 0.15s ease-out, border-color 0.15s ease-out;
}
.overview-tab:hover { color: var(--color-primary-light); }
.overview-tab[aria-selected="true"] {
    color: var(--color-primary);
    border-bottom-color: var(--color-accent);
}
.overview-header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-inline-start: auto;
}
#protection-pill {
    color: var(--color-primary-dark);
    border-color: var(--mk-accent);
}
/* "Protection state unavailable" is the absence of a state, not a state. As a
   bordered chip it outweighed the freshness pill beside it, so the eye landed
   on the one fact that carries no information. Reported protections keep the
   chip; not knowing is stated quietly. */
#protection-pill.is-neutral {
    padding: 0;
    background: none;
    border-color: transparent;
    color: var(--color-text-secondary);
    text-transform: none;
    letter-spacing: 0.01em;
    font-family: var(--font-family);
    font-size: 0.78rem;
    font-weight: 400;
}
.overview-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 44px;
    padding: 6px var(--space-3);
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--color-primary);
    background: none;
    border: 1px solid var(--color-border-strong);
    border-radius: 6px;
    cursor: pointer;
    touch-action: manipulation;
}
.overview-toggle:hover { color: var(--color-accent); border-color: var(--color-accent); }
.overview-toggle svg {
    width: 16px;
    height: 16px;
    transition: transform 0.15s ease-out;
}
.overview-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

.reading-times {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-4);
    margin-top: var(--space-1);
    font-size: 0.74rem;
    color: var(--color-text-secondary);
}
.reading-stamp {
    color: var(--color-text-primary);
    font-variant-numeric: tabular-nums;
}

.metric {
    padding: var(--space-3) var(--space-5);
    border-inline-start: 1px solid var(--color-border);
    min-width: 0;
}
.metric:first-child { border-inline-start: none; padding-inline-start: 0; }
.metric-label {
    margin-bottom: var(--space-1);
    font-family: var(--font-display);
    font-size: 0.66rem; font-weight: 600;
    letter-spacing: 0.09em; text-transform: uppercase;
    color: var(--color-text-secondary);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The four readings are the reason the page exists. They carry the largest
   size on it, which is also what makes the labels above them safe to keep
   small. */
.metric-value {
    font-size: 1.9rem; font-weight: 500;
    line-height: 1.2;
    color: var(--color-text-primary);
    letter-spacing: -0.02em;
}
.metric-unit {
    font-size: 0.55em; font-weight: 500;
    color: var(--color-text-secondary);
    margin-inline-start: 3px;
}
/* A measurement the pack never sent is dashed out, not zeroed: a missing
   value and a value of zero are different facts. */
.metric-value.is-absent { color: var(--color-text-muted); }

/* ── Battery state ─────────────────────────────────────────────────────
   Secondary operational facts are grouped apart from the four live safety
   measurements. The diagnostic identifiers sit below them under their own
   heading, as readable at a glance as the state values above.
   ── */
.battery-state-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(135px, 1fr));
    gap: var(--space-5);
}
.state-value-group { min-width: 0; }
.state-label {
    font-family: var(--font-display);
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--color-text-secondary);
}
.state-value {
    margin-top: var(--space-1);
    font-family: var(--font-mono);
    font-size: 1rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-primary);
    overflow-wrap: anywhere;
}
/* The charge track is the visualisation; its reading belongs over the middle
   of it, not tucked against one end. */
.state-value-group--lead {
    text-align: center;
}
.state-value-group--lead .state-value {
    font-family: var(--font-body);
    font-size: 1.55rem;
    line-height: 1.1;
}
.state-value.is-absent { color: var(--color-text-muted); }

/* The pack's thermal profile. The band is drawn between sensors; the ticks
   below mark where a sensor actually is, so the reader can tell the two apart. */
.thermal {
    margin-top: var(--space-6);
}
.thermal__ribbon {
    position: relative;
    height: 26px;
    margin-top: var(--space-2);
    background: var(--color-border);
}
/* The hottest probe, marked on the band itself: the point of a profile is
   where the heat is, and on a wide pack the labels cannot say it. */
.thermal__peak {
    position: absolute;
    inset-block: -3px;
    width: 2px;
    margin-inline-start: -1px;
    background: var(--color-text-primary);
}
/* Ticks sit at the probe positions rather than in flex cells, so a label and
   the colour it describes stay on the same vertical line. */
.thermal__values {
    position: relative;
    height: 1.1rem;
    margin-top: var(--space-2);
}
.thermal__values span {
    position: absolute;
    transform: translateX(-50%);
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--color-text-secondary);
}
.thermal__values span.is-first { transform: none; }
.thermal__values span.is-last { transform: translateX(-100%); }
.thermal__values span.is-first::before { left: 0; }
.thermal__values span.is-last::before { left: 100%; }
.thermal__values span::before {
    content: "";
    position: absolute;
    top: calc(var(--space-2) * -1);
    left: 50%;
    width: 1px;
    height: var(--space-2);
    background: var(--color-border-strong);
}
.thermal__ends {
    display: flex;
    justify-content: space-between;
    font-size: 0.68rem;
    color: var(--color-text-secondary);
}
.thermal__caption {
    margin-top: var(--space-2);
    font-size: 0.72rem;
    color: var(--color-text-secondary);
    text-wrap: pretty;
}

/* Pack voltage, drawn against the pack's own measured range. The arc is the
   donut primitive's geometry opened out to 180 degrees: it carries the same
   sweep, and it is half the height, which is what a 308px panel can spare. */
.voltage-gauge {
    margin-top: var(--space-6);
}
.voltage-gauge__dial-wrap {
    position: relative;
    max-width: 200px;
    margin-inline: auto;
}
.voltage-gauge__dial {
    display: block;
    width: 100%;
}
.voltage-gauge__base {
    fill: none;
    stroke: var(--color-border);
    stroke-width: 9;
    stroke-linecap: round;
}
.voltage-gauge__fill {
    fill: none;
    stroke: var(--color-accent);
    stroke-width: 9;
    stroke-linecap: round;
    transition: stroke-dashoffset 0.9s cubic-bezier(0.22, 1, 0.36, 1) 0.15s;
}
/* Inside the dial's hollow, where an instrument puts its reading. */
.voltage-gauge__read {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    display: grid;
    justify-items: center;
    gap: 1px;
    text-align: center;
}
.voltage-gauge__read .state-value {
    margin-top: 0;
    font-family: var(--font-body);
    font-size: 1.55rem;
    line-height: 1.1;
}
/* Aligned to the arc ends, not the box: the numbers label the dial. */
.voltage-gauge__ends {
    display: flex;
    justify-content: space-between;
    max-width: 200px;
    margin: var(--space-2) auto 0;
    padding-inline: 4%;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-secondary);
}
.protection-detail {
    margin-top: var(--space-5);
    font-size: 0.82rem;
    color: var(--mk-accent);
    overflow-wrap: anywhere;
}
.protection-detail[hidden] { display: none; }
.telemetry-details { margin-top: var(--space-5); }
.telemetry-details h3 {
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-text-secondary);
    margin: 0;
}
.telemetry-detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--space-4) var(--space-6);
    margin: var(--space-4) 0 0;
}
.telemetry-detail-grid > div { min-width: 0; }
.telemetry-detail-grid dd.is-absent { color: var(--color-text-muted); }
.telemetry-detail-grid dt {
    font-family: var(--font-display);
    font-size: 0.64rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-text-secondary);
}
.telemetry-detail-grid dd {
    margin: var(--space-1) 0 0;
    font-family: var(--font-mono);
    font-size: 0.76rem;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-primary);
    overflow-wrap: anywhere;
}

/* ── Chart grid ───────────────────────────────────────────────────────
   Two columns, read left to right in order of importance. The two charts
   about cells span the full row: one carries a line per cell and the other
   a bar per cell, and neither survives being squeezed into half a row.
   ── */
.chart-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5);
}
.chart-grid > .card-modern { min-width: 0; }
.chart-grid > .chart-wide { grid-column: 1 / -1; }

/* Tabs inside a card header, switching which view of the cells the card's
   title refers to. Same accent underline as the pack strip, at the smaller
   weight a secondary control earns: this changes one card, not the page. */
.chart-tabs { display: flex; gap: var(--space-4); }
.chart-tab {
    padding: 4px 0; min-height: 36px;
    font-family: var(--font-display);
    font-size: 0.78rem; font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--color-text-muted);
    background: none; border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer; white-space: nowrap;
    transition: color 0.15s ease-out, border-color 0.15s ease-out;
}
.chart-tab:hover { color: var(--color-accent); }
.chart-tab[aria-selected="true"] {
    color: var(--color-accent);
    border-bottom-color: var(--color-accent);
}

.chart-zoom-controls {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    margin-inline-start: auto;
}
.chart-zoom-controls[hidden] { display: none; }
.chart-zoom-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    min-height: 40px;
    padding: 0 var(--space-2);
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    line-height: 1;
    /* Secondary, not muted: these are words, so they hold 4.5:1 at rest. The
       weight comes off the border, not off the label. */
    color: var(--color-text-secondary);
    background: none;
    /* Transparent, not absent: the box still reserves its 40px target and
       returns on hover and focus. Six chart cards carry this trio, and
       eighteen outlined boxes outweighed the six charts they belong to. */
    border: 1px solid transparent;
    border-radius: 6px;
    cursor: pointer;
    touch-action: manipulation;
    transition: color 0.15s ease-out, border-color 0.15s ease-out, background-color 0.15s ease-out;
}
.chart-zoom-btn--reset {
    width: auto;
    font-size: 0.72rem;
}
.chart-zoom-btn--touch {
    display: none;
    width: auto;
    font-size: 0.72rem;
}
.chart-zoom-btn--touch[aria-pressed="true"] {
    color: var(--color-primary);
    border-color: var(--color-primary-light);
    background: var(--color-primary-subtle);
}
/* The card owns its controls: hovering anywhere on it brings the outlines
   back, so they are found without hunting for an invisible target. Ordered
   ahead of the button's own hover so pointing at one still reads as accent. */
.chart-grid > .card-modern:hover .chart-zoom-btn:not(:disabled),
.chart-grid > .card-modern:focus-within .chart-zoom-btn:not(:disabled) {
    color: var(--color-text-secondary);
    border-color: var(--color-border-strong);
}
.chart-zoom-btn:hover:not(:disabled) {
    color: var(--color-accent);
    border-color: var(--color-accent);
    background: var(--color-accent-subtle);
}
.chart-zoom-btn:active:not(:disabled) { scale: 0.96; }
.chart-zoom-btn:disabled { opacity: 0.45; cursor: not-allowed; }
/* Six filled header bands down the page gave every chart the same weight as
   the live reading above them. The hairline still separates title from plot;
   the one filled band left on the page belongs to the pack overview. */
.chart-grid .card-modern__header {
    flex-wrap: wrap;
    background: none;
}

@media (pointer: coarse) {
    .chart-zoom-btn--touch { display: inline-flex; }
}

.chart-body { padding: var(--space-4) var(--space-5) var(--space-5); }
/* Explicit height: Chart.js sizes to its container, and a container sized
   by the canvas is a feedback loop that grows on every resize. */
.chart-canvas-wrap { position: relative; width: 100%; height: 260px; }
.chart-canvas-wrap > canvas { max-width: 100%; }
.chart-wide .chart-canvas-wrap { height: 300px; }

/* ── Cell grid ────────────────────────────────────────────────────────
   The cells in rack order, which is the one view that answers "which one
   do I go and look at". Colour is the scan and the printed millivolts are
   the confirmation, so neither has to be read through the other.

   Deviation is tinted against a fixed 20 mV reference rather than against
   the pack's own worst cell. Normalising to the worst cell makes every
   pack look equally bad, and the first thing this has to say is whether
   this one is.
   ── */
.cell-matrix-wrap { position: relative; min-height: 300px; }
.cell-matrix {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1px;
    background: var(--color-border);
    border: 1px solid var(--color-border);
    max-width: 560px;
    margin: 0 auto;
}
.cell-tile {
    background: var(--color-surface);
    padding: var(--space-3) var(--space-4);
    min-width: 0;
}
.cell-tile.is-worst { box-shadow: inset 0 0 0 2px var(--color-warning); }
/* The tint says which cells to look at; the weight says it again, because a
   grid that encodes anything in colour alone excludes the readers who need it
   most. */
.cell-tile.is-adrift .cell-tile-d {
    font-weight: 600;
    color: var(--color-text-primary);
}
.cell-tile-n {
    font-family: var(--font-display);
    font-size: 0.62rem; font-weight: 600;
    letter-spacing: 0.09em; text-transform: uppercase;
    color: var(--color-text-secondary);
}
.cell-tile-v {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 1.02rem; font-weight: 500;
    color: var(--color-text-primary);
    line-height: 1.35;
}
.cell-tile-d {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.72rem;
    color: var(--color-text-secondary);
}

/* Overlay states share the canvas footprint so the card never changes
   height between loading, empty, and drawn. */
.chart-canvas-wrap > .chart-overlay,
.cell-matrix-wrap > .chart-overlay {
    position: absolute; inset: 0;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 8px;
    background: rgba(255,255,255,0.72);
}
.chart-overlay[hidden] { display: none; }
.chart-overlay svg { width: 30px; height: 30px; color: var(--color-border-strong); }
.chart-overlay-text { font-size: 0.82em; color: var(--color-text-secondary); }
.chart-spinner {
    width: 26px; height: 26px;
    border: 2px solid var(--color-border);
    border-top-color: var(--color-accent);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

/* Field and endpoint names quoted inline, in the empty state's instructions. */
.field-name { font-family: var(--font-mono); font-size: 0.82em; }

/* ── Skeleton sizing for the first paint ── */
.metric-value.skeleton { display: inline-block; min-width: 110px; height: 1.9rem; }
.reading-stamp.skeleton { display: inline-block; min-width: 150px; height: 0.9em; }

/* ── Section tabs ─────────────────────────────────────────────────────
   Graphs and Rules, one level below the pack strip and reading lighter
   than it: this switches what you are looking at within a rack, not which
   rack you are looking at.
   ── */
.section-tabs {
    display: flex;
    gap: var(--space-6);
    margin: var(--space-5) 0;
    border-bottom: 1px solid var(--color-border);
}
.section-tab {
    display: inline-flex; align-items: center; gap: var(--space-2);
    padding: 6px 0; min-height: 40px;
    font-family: var(--font-display);
    font-size: 0.82rem; font-weight: 600;
    color: var(--color-text-muted);
    background: none; border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    cursor: pointer;
    transition: color 0.15s ease-out, border-color 0.15s ease-out;
}
.section-tab:hover { color: var(--color-accent); }
.section-tab[aria-selected="true"] {
    color: var(--color-accent);
    border-bottom-color: var(--color-accent);
}
/* The count is open incidents. Losing evidence must not make it decrease. */
.section-count {
    font-family: var(--font-mono);
    font-size: 0.68rem; font-weight: 600;
    padding: 1px 6px;
    color: var(--color-error);
    border: 1px solid var(--color-error);
}
.section-pane[hidden] { display: none; }
.section-pane > .card-modern + .card-modern { margin-top: var(--space-5); }

/* ── Rule rows ────────────────────────────────────────────────────────
   One row per rule: what it is called, what it asks, what it concluded,
   and when it last said so. The condition is printed in the same words
   the editor uses, so the list and the form cannot drift apart.
   ── */
.rule {
    border-top: 1px solid var(--color-border);
}
.rule:first-child { border-top: none; }
.rule.is-disabled { opacity: 0.55; }
.rule-main {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 2fr) auto;
    gap: var(--space-3) var(--space-5);
    align-items: center;
    padding: var(--space-4) var(--space-5);
}
.rule-name {
    font-family: var(--font-display);
    font-weight: 600; font-size: 0.88rem;
    color: var(--color-text-primary);
    overflow-wrap: anywhere;
}
.rule-scope {
    display: inline-block;
    margin-top: 3px;
    font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--color-text-secondary);
}
.rule-condition {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    color: var(--color-text-secondary);
    overflow-wrap: anywhere;
}
.rule-status-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    min-height: 44px;
    padding: var(--space-3) var(--space-5);
    border-top: 1px solid var(--color-border);
}
.rule-state {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    min-width: 0;
    font-size: 0.78rem;
    color: var(--color-text-secondary);
}
.rule-evidence {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--color-text-primary);
    overflow-wrap: anywhere;
}
.rule-evidence-time {
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.rule-state-meta { color: var(--color-text-muted); }
.rule-actions { display: flex; align-items: center; gap: var(--space-3); }
.rule-timeline-toggle {
    min-height: 44px;
    padding: 0 var(--space-3);
    border: 1px solid var(--color-border-strong);
    background: transparent;
    color: var(--color-primary);
    font-family: var(--font-display);
    font-size: 0.74rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition-property: color, border-color, background-color, scale;
    transition-duration: 0.15s;
    transition-timing-function: ease;
}
.rule-timeline-toggle:hover { background: var(--color-primary-subtle); }
.rule-timeline-toggle:active { scale: 0.96; }
.rule-timeline {
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--color-border);
    background: var(--color-bg);
    overflow-x: auto;
}
.rule-timeline[hidden] { display: none; }
.rule-timeline-track {
    display: flex;
    align-items: flex-start;
    min-width: min-content;
}
.rule-transition {
    --transition-accent: var(--color-primary-light);
    --transition-subtle: var(--color-primary-subtle);
    position: relative;
    flex: 0 0 210px;
    padding: var(--space-5) var(--space-4) 0 0;
}
.rule-transition:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 5px;
    inset-inline-start: 13px;
    inset-inline-end: 0;
    height: 2px;
    background: var(--color-border-strong);
}
.rule-transition-dot {
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    z-index: 1;
    width: 13px;
    height: 13px;
    border: 2px solid var(--transition-accent);
    border-radius: 50%;
    background: var(--transition-subtle);
}
.rule-transition.is-clear { --transition-accent: var(--color-accent); --transition-subtle: var(--color-accent-subtle); }
.rule-transition.is-breach_pending,
.rule-transition.is-recovery_pending { --transition-accent: var(--color-warning); --transition-subtle: var(--color-warning-subtle); }
.rule-transition.is-in_breach { --transition-accent: var(--color-error); --transition-subtle: var(--color-error-subtle); }
.rule-transition.is-unknown { --transition-accent: var(--color-info); --transition-subtle: var(--color-info-subtle); }
.rule-transition-label {
    font-family: var(--font-display);
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--color-text-primary);
}
.rule-transition-time,
.rule-transition-path,
.rule-transition-evidence,
.rule-transition-evidence-time,
.rule-transition-incident,
.rule-timeline-empty,
.rule-timeline-error {
    margin-top: 2px;
    font-size: 0.72rem;
    color: var(--color-text-secondary);
}
.rule-transition-time,
.rule-transition-evidence,
.rule-transition-evidence-time { font-variant-numeric: tabular-nums; }
.rule-transition-evidence { margin-top: var(--space-1); color: var(--color-text-primary); }
.rule-transition-evidence-time { color: var(--color-text-muted); }
.rule-transition-incident.is-open { color: var(--color-error); }
.rule-transition-incident.is-closed { color: var(--color-accent); }
.rule-timeline-error { color: var(--color-error); }

/* A switch, because enabling a rule is a state and not an errand. */
.switch {
    position: relative;
    width: 38px; height: 20px;
    padding: 0;
    background: var(--color-border-strong);
    border: none; border-radius: 10px;
    cursor: pointer;
    transition: background-color 0.2s ease;
}
.switch::after {
    content: "";
    position: absolute; top: 2px; inset-inline-start: 2px;
    width: 16px; height: 16px;
    background: #fff; border-radius: 50%;
    transition: translate 0.2s ease;
}
.switch[aria-pressed="true"] { background: var(--color-accent); }
.switch[aria-pressed="true"]::after { translate: 18px 0; }
[dir="rtl"] .switch[aria-pressed="true"]::after { translate: -18px 0; }
.icon-btn {
    padding: 4px 8px; min-height: 32px;
    font-size: 0.74rem;
    color: var(--color-text-secondary);
    background: none;
    border: 1px solid var(--color-border);
    cursor: pointer;
}
.icon-btn:hover { color: var(--color-primary); border-color: var(--color-border-strong); }
.icon-btn.is-danger:hover { color: var(--color-error); border-color: var(--color-error); }

/* ── Rule editor ──────────────────────────────────────────────────────
   The condition is laid out as the sentence it is. A column of labelled
   inputs has to be reassembled in the head before anyone can tell whether
   it says what they meant.
   ── */
.text-input {
    padding: 7px 10px; min-height: 36px;
    font-family: var(--font-body);
    font-size: 0.85rem;
    color: var(--color-text-primary);
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
}
.text-input:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px var(--color-accent-subtle);
}
.text-input.num { width: 84px; font-family: var(--font-mono); }

.field-block { display: block; margin-bottom: var(--space-5); }
.field-block > span {
    display: block; margin-bottom: 6px;
    font-family: var(--font-display);
    font-size: 0.68rem; font-weight: 600;
    letter-spacing: 0.09em; text-transform: uppercase;
    color: var(--color-text-secondary);
}
.field-block .text-input { width: 100%; }

.sentence {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: var(--space-2) var(--space-3);
    margin-bottom: var(--space-4);
}
.sentence[hidden] { display: none; }
.sentence select {
    padding: 6px 10px; min-height: 36px;
    font-family: var(--font-body); font-size: 0.85rem;
    color: var(--color-text-primary);
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
}
.sentence-kw {
    font-family: var(--font-mono);
    font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em;
    color: var(--color-text-muted);
}
.sentence-unit { font-size: 0.82rem; color: var(--color-text-secondary); }

.modal-backdrop {
    position: fixed; inset: 0; z-index: 60;
    display: flex; align-items: center; justify-content: center;
    padding: var(--space-5);
    background: rgba(19,59,107,0.35);
}
.modal-backdrop[hidden] { display: none; }
.modal {
    width: 100%; max-width: 620px;
    max-height: 90vh; overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--color-surface);
    border: none;
    box-shadow:
        0 0 0 1px oklch(0 0 0 / 0.06),
        0 24px 64px -16px rgba(19,59,107,0.35);
}
.modal-head {
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--color-border);
}
.modal-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1rem; font-weight: 600;
    color: var(--color-primary);
}
.modal-body { padding: var(--space-5); }
.modal-foot {
    display: flex; justify-content: flex-end; gap: var(--space-3);
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--color-border);
}
.modal-note { margin: 0; font-size: 0.8rem; color: var(--color-error); }
.modal-note[hidden] { display: none; }

@media (max-width: 720px) {
    .rule-main { grid-template-columns: 1fr; }
    .rule-status-row { align-items: flex-start; }
}
@media (max-width: 620px) {
    .cell-matrix { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
    .chart-grid { grid-template-columns: 1fr; }
    .chart-grid > .chart-wide { grid-column: auto; }
    .metric { padding: var(--space-3) var(--space-4); }
    .metric:first-child { padding-inline-start: var(--space-4); }
    .metric:nth-child(odd) { border-inline-start: none; padding-inline-start: 0; }
    .metric:nth-child(n + 3) { border-top: 1px solid var(--color-border); }
}
@media (max-width: 480px) {
    .overview-tabs { flex: 1 1 100%; }
    .overview-header-actions { flex: 1 1 100%; }
    .overview-toggle { margin-inline-start: auto; }
}
