/* History section (design 2026-07-30). Only tokens the Onda sheet already defines — no hardcoded palette,
   so light and dark follow data-bs-theme like the rest of the design system, and no new token is introduced.
   The pill toggles reuse .niol-tab from app.css: no parallel "chip" component is defined here. */

/* Two groups: the filters that narrow the read on the left, the pills that pick what is shown on the right.
   flex-START, not flex-end: every control here now carries its label above, so it is the FIRST row that must
   line up. Aligning the bottoms instead let the tallest control place all the others — which is how picking
   the "custom" period, whose two date fields grow the period picker downward, used to shove the pills. */
.niol-history__bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--niol-space-3);
    align-items: flex-start;
    margin-block: var(--niol-space-4);
}

.niol-history__filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--niol-space-3);
    align-items: flex-start;
}

/* margin-inline-start: auto pins the group to the right edge, and lets it drop to its own line when the bar
   runs out of room — the same mechanism .niol-history__export uses on the tab row above. */
.niol-history__pills {
    margin-inline-start: auto;
    display: flex;
    flex-direction: column;
    gap: var(--niol-space-2);
    align-items: flex-start;
}

/* Label ABOVE the select, like the period picker and the pill group beside it — .label is inline-block, so
   left alone it sits on the select's own line and this control alone starts a row higher than the others.
   The same space-2 all three use between their label and their control is what puts the three labels on one
   line and the three controls on the next. */
.niol-source-picker {
    display: flex;
    flex-direction: column;
    gap: var(--niol-space-2);
    align-items: flex-start;
}

.niol-history__pill-row { display: flex; flex-wrap: wrap; gap: var(--niol-space-2); }

/* The table scrolls inside its own box: a wide register must never make the page scroll sideways.
   container-type is not styling: it is what gives the expanded detail below a length equal to the VISIBLE
   width (100cqw) rather than to the table's — the only measure CSS has of a scroll box's viewport. */
.niol-aligned {
    overflow-x: auto;
    border: 1px solid var(--niol-border);
    border-radius: var(--niol-radius);
    container-type: inline-size;
}

.niol-aligned__table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.875rem;
}

/* Sticky header: scrolling a long register must not cost you the column names. */
.niol-aligned__table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--niol-panel-2);
    text-align: left;
    padding: var(--niol-space-2) var(--niol-space-3);
    white-space: nowrap;
}

.niol-aligned__table td {
    padding: var(--niol-space-2) var(--niol-space-3);
    border-top: 1px solid var(--niol-border);
    white-space: nowrap;
}

/* z-index is load-bearing, not decoration: Bootstrap's reboot gives <sup> position:relative, so the change
   pills are POSITIONED elements too and would otherwise paint over this column as the grid scrolls under it. */
.niol-aligned__instant { position: sticky; left: 0; z-index: 2; background: var(--niol-panel); }

/* The corner cell is sticky on both axes, so it has to outrank the header row AND the instant column. */
.niol-aligned__table thead th.niol-aligned__instant { z-index: 3; background: var(--niol-panel-2); }

.niol-aligned__unit { margin-inline-start: var(--niol-space-1); opacity: 0.6; font-size: 0.75rem; }

/* The row toggle is a bare affordance: the chevron is the button, nothing else. */
.niol-aligned__toggle {
    background: transparent;
    border: 0;
    padding: 0;
    margin-inline-end: var(--niol-space-2);
    color: var(--niol-text-muted);
    cursor: pointer;
}

.niol-aligned__toggle:hover { color: var(--niol-accent); }

/* The change marker: readable, not shouting — it is a hint that the row is worth expanding. */
.niol-aligned__changes {
    margin-inline-start: 0.25em;
    padding: 0 0.35em;
    border-radius: 999px;
    background: var(--niol-accent-soft);
    color: var(--niol-accent);
    font-size: 0.7rem;
}

.niol-aligned__empty { opacity: 0.4; }

/* A missing poll and a resync are the two rows that say something no value says. */
.niol-aligned__row--missing td { background: var(--niol-warning-soft); font-style: italic; }
/* An INSET SHADOW, not a border: a border on one row's cell widens that column for the whole table —
   border-collapse shares the column width — which shifted the grid and left a white notch in the header. */
.niol-aligned__row--resync .niol-aligned__instant { box-shadow: inset 3px 0 0 var(--niol-warning); }
.niol-aligned__row--open { background: var(--niol-panel-2); }

.niol-aligned__detail td { white-space: normal; background: var(--niol-panel-2); padding: 0; }

/* The detail belongs to the ROW, not to the grid: scrolling the columns sideways must not carry it off screen.
   Its cell spans the whole table, so the cell itself cannot stick (a sticky box has nowhere to shift inside a
   containing block it fills). The inner box can: pinned at the scroll box's left edge and exactly as wide as
   what is visible, it holds still while the columns move under it. Padding lives here, not on the cell, so
   100cqw is the whole budget. */
.niol-aligned__detail-inner {
    position: sticky;
    left: 0;
    width: 100cqw;
    padding: var(--niol-space-2) var(--niol-space-3);
}

/* A COLUMN, so the explicit range appears UNDER the presets instead of beside them: the range block is the
   one thing here that changes the control's height, and growing downward is the only way it can do that
   without moving the controls next to it in the bar. Deliberately not "row + wrap", which would put the
   dates beside the presets on a wide viewport and under them on a narrow one — the same selection laid out
   two different ways. */
.niol-period { display: flex; flex-direction: column; gap: var(--niol-space-2); align-items: flex-start; }
.niol-period__row { display: flex; flex-wrap: wrap; gap: var(--niol-space-2); align-items: center; }
.niol-period__presets { display: flex; flex-wrap: wrap; gap: var(--niol-space-2); }
.niol-period__retention { color: var(--niol-text-muted); font-size: var(--niol-fs-label); }
.niol-period__clamped { color: var(--niol-warning); font-size: var(--niol-fs-label); }

.niol-series-picker { position: relative; }
.niol-series-picker__panel {
    position: absolute;
    /* Above the table's whole sticky stack (1 header, 2 instant column, 3 corner), not equal to its top layer:
       the bar precedes the table in the DOM, so a TIE paints the panel under the corner cell. Well below the
       backdrop (150) — an offcanvas or a dialog must still cover this. */
    z-index: 10;
    min-width: 16rem;
    max-height: 20rem;
    overflow-y: auto;
    padding: var(--niol-space-2);
    background: var(--niol-panel);
    border: 1px solid var(--niol-border);
    border-radius: var(--niol-radius);
    box-shadow: var(--niol-shadow);
}
.niol-series-picker__row { display: flex; gap: var(--niol-space-2); align-items: center; padding: 0.2rem 0; }
.niol-series-picker__class { margin-inline-start: auto; color: var(--niol-text-subtle); font-size: var(--niol-fs-label); }

.niol-events__bar { display: flex; flex-wrap: wrap; gap: var(--niol-space-2); align-items: center; margin-block-end: var(--niol-space-3); }
.niol-events__summary { display: flex; flex-wrap: wrap; gap: var(--niol-space-3); list-style: none; padding: 0; }
.niol-events__list { margin: 0; padding-inline-start: var(--niol-space-4); }
.niol-events__row { display: flex; gap: var(--niol-space-3); align-items: baseline; }
.niol-events__t { color: var(--niol-text-muted); }
.niol-events__more { color: var(--niol-text-muted); font-size: var(--niol-fs-label); }

.niol-interval__head { color: var(--niol-text-muted); font-size: var(--niol-fs-label); }

.niol-extraction__row { padding-inline-start: calc(var(--tree-depth, 0) * var(--niol-space-3)); }
.niol-extraction__key { font-weight: 600; margin-inline-end: var(--niol-space-2); }
.niol-extraction__null { color: var(--niol-text-subtle); }

.niol-history__pager { display: flex; gap: var(--niol-space-3); align-items: center; justify-content: center; margin-block-start: var(--niol-space-4); }

/* ---------------------------------------------------------------- strips (step 2) */

.niol-strips__panel { margin-block: var(--niol-space-4); }

/* position: relative anchors the one crosshair over the whole stack. */
.niol-strips {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--niol-space-3);
    margin-block-start: var(--niol-space-3);
}

.niol-strip__head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--niol-space-2);
    align-items: baseline;
    font-size: var(--niol-fs-label);
}

.niol-strip__label { font-weight: 600; }
.niol-strip__unit { color: var(--niol-text-muted); }

/* The readout is written by strip-stack.js; it keeps its line so the layout never jumps on hover. */
.niol-strip__readout { margin-inline-start: auto; min-height: 1em; color: var(--niol-accent); }

/* "Approximate" is a statement about the data, not a fault: warning-coloured, not alarm-coloured. */
.niol-strip__coarse { color: var(--niol-warning); font-size: var(--niol-fs-label); }

.niol-strip__none { color: var(--niol-text-subtle); font-size: var(--niol-fs-label); margin: 0; }

/* The state band: 40 viewBox units tall, stretched to the container's width like the line chart. */
.niol-band { position: relative; }
.niol-band__svg { display: block; width: 100%; height: 2.5rem; }
.niol-band__rect--neutral { fill: var(--niol-panel-2); stroke: var(--niol-border); }

.niol-band__labels { position: absolute; inset: 0; pointer-events: none; }

.niol-band__label {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    padding-inline: 0.25rem;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 0.7rem;
}

.niol-band__empty { color: var(--niol-text-subtle); font-size: var(--niol-fs-label); margin: 0; }

/* Hidden until a pointer enters the stack, then moved by JS only — the circuit sees no pointer event. */
.niol-strips__crosshair {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--niol-accent);
    opacity: 0;
    pointer-events: none;
}

.niol-strips.is-hovering .niol-strips__crosshair { opacity: 0.7; }

/* The row the crosshair is over: the same instant, in the table. */
.niol-aligned__row.is-crosshair { background: var(--niol-accent-soft); }

/* The min/max wick, behind the average line: same accent, quieter. */
.niol-chart__wick { stroke: var(--niol-accent); stroke-width: 1; opacity: 0.35; }

@media (max-width: 640px) {
    /* The instant column stops being sticky on a narrow viewport: it would eat half the width. */
    .niol-aligned__instant { position: static; }
}

/* Band zones sit behind the series: a wash, not a fill — the line must stay the thing you read. */
.niol-chart__zone { opacity: .14; }

/* ---------------------------------------------------------------- KPI tab */

.niol-kpi-group { margin-block: 1.25rem; }
.niol-kpi-group__head { display: flex; align-items: center; gap: .5rem; margin-bottom: .35rem; }
.niol-kpi-group__grid { font-size: .8rem; opacity: .75; }

.niol-kpi-cell { display: inline-flex; align-items: baseline; gap: .35rem; }
/* Absent and gap must not read alike: one is "outside this KPI's history", the other "measured, empty". */
.niol-kpi-cell--absent { display: block; width: 100%; opacity: .25; background: repeating-linear-gradient(
    135deg, transparent 0 4px, currentColor 4px 5px); height: 1em; }
.niol-kpi-cell--gap { opacity: .5; }
.niol-kpi-cell__band { border-radius: .5rem; padding: 0 .4rem; font-size: .72rem; }
.niol-kpi-cell__partial { font-size: .62rem; opacity: .7; }

/* ---------------------------------------------------------------- extractions tab */

/* Room between the tab pills above and the first request row (design feedback pt.1) — same scale as the
   other tabs' top-of-content gap (.niol-history__bar, .niol-strips__panel), not an ad-hoc pixel value. */
.niol-export { margin-block-start: var(--niol-space-4); }

/* Badge + running pulse + mode/format, on one row (design feedback pt.4: the request-level progress cue). */
.niol-export__status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--niol-space-2); }

/* The files of an open request: a full-width third child of the list row, like the purge panel. */
.niol-export__files {
    flex: 1 1 100%;
    display: flex;
    flex-direction: column;
    gap: var(--niol-space-2);
    padding-block-start: var(--niol-space-3);
    border-block-start: 1px solid var(--niol-border);
}

/* Two lines (name, then details) plus the action pinned to the end — wraps to its own line on narrow
   viewports, margin-inline-start: auto keeps it at the right edge either way (design feedback pt.5). */
.niol-export__file { display: flex; flex-wrap: wrap; align-items: center; gap: var(--niol-space-2) var(--niol-space-3); }

/* ---------------------------------------------------------------- tab row */

/* The tab row carries the tabs on the left and the export action on the right. The action is a sibling of
   the tablist, never a child: inside it, a screen reader announces it as a fourth tab. */
.niol-history__tabrow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--niol-space-2);
}

.niol-history__export { margin-inline-start: auto; }

.niol-export__file-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }

.niol-export__file-action { flex: none; margin-inline-start: auto; }

/* A finished export and a failed one must not read alike at a glance. */
.niol-badge--ok { border-color: transparent; background: var(--niol-ok-soft); color: var(--niol-ok); }
.niol-badge--danger { border-color: transparent; background: var(--niol-alarm-soft); color: var(--niol-alarm); }

/* The explicit range, shown only when the custom preset is active. Wraps on a narrow viewport rather than
   overflowing the period bar. */
.niol-period__range {
    display: flex;
    flex-wrap: wrap;
    gap: var(--niol-space-2);
    align-items: flex-end;
}

.niol-period__range-field {
    display: flex;
    flex-direction: column;
    gap: var(--niol-space-1);
    font-size: .8125rem;
}
