/* ==========================================================================
   FL510 — FLIGHT RECORDS MODULES
   (redesign Wave 0; operator-approved mock 2026-08-21:
    "The FL510 Flight Records section redesign is approved.")
   --------------------------------------------------------------------------
   WAVE 0 WAS THE SHELL; WAVE 1 ADDED THE REVIEW QUEUE'S VOCABULARY. Nothing is
   declared here ahead of a surface that renders it — `FlightRecordsModuleRouteMapTests`
   and `FlightRecordsReviewModuleTests` assert the selectors below are LIVE, and
   a rule for markup nobody emits would be a rule nobody can see break. So this
   file grows exactly twice per wave: the tokens once, and each wave's own
   components as that wave converts the surface that needs them. Waves 2-5 add
   theirs (trail rows, evidence table, meters, provider cards) the same way.

   SCOPE: every rule is under `.fr-shell`, a wrapper div each flight-records
   module view renders INSIDE the shared shell's body — the opt-in contract
   maintenance-modules.css states, applied identically one level deeper.
   Nothing here styles a bare element and nothing here can reach another page.

   ⚠ WHY A WRAPPER RATHER THAN A SHELL-ROOT CLASS, restated because the choice
   matters here too: this file restyles NO chrome. The rail, appbar, KPI chip
   strip and mobile sheet stay the shared `.ps-*` components, unmodified —
   including `.ps-kpi.is-crit/.is-warn/.is-good`, which the flight-records chip
   strip borrows exactly as maintenance does. So the shell root stays
   byte-identical on these routes (`class="internal-shell portal-shell ds"`,
   the marker every converted route's rendered-truth test counts) and this file
   only has to reach the page BODY. `.flight-record-verdict`'s green literal in
   site.css is NOT touched here; de-leaking it is Wave 5's named work.

   TOKEN RECONCILIATION (the translation discipline billing-modules.css records
   and maintenance-modules.css repeats): every colour, space and radius below
   derives from the three-tier system in tokens.css. The `--fr-*` locals are
   COMPONENT-tier names pointing at SEMANTIC `--ds-*` tokens, so light/dark and
   the manual [data-theme] pin still swap in ONE place. No forked palette, no
   raw hex, and deliberately no alias of the `.note`/`.hint` inks the FW6c
   review measured under floor — this page mints its own (`--fr-ink-3`).

   ⚠ CONTRAST IS LAW, AND EVERY PAIR BELOW WAS COMPUTED, NOT EYEBALLED.
   Resolved surfaces:
       light  --ds-surface #FFFFFF   --ds-surface-raised #F7FAFA
       dark   --ds-surface #12181D   --ds-surface-raised #1A2128
   Resolved inks:
       light  --ds-text-primary #1E2A30  --ds-text-secondary #556067
       dark   --ds-text-primary #E7ECEF  --ds-text-secondary #A9B4BA
   Resolved status hues:
       light  ok #2E7D32  warn #8A5200  danger #C1272D  accent #227C80
       dark   ok #86C98A  warn #E0A648  danger #F08A93  accent #56C3C7
   The -ink-on-wash pairs below use the SAME color-mix construction billing and
   maintenance already ship (hue 62% toward --ds-text-primary over a 12-14%
   wash), so their measured ratios carry over unchanged:
       light  ok-ink on ok-wash 6.3:1 · warn-ink on warn-wash 6.9:1
              crit-ink on crit-wash 7.0:1
       dark   8.0:1 / 7.4:1 / 7.4:1
   All six clear the 4.5:1 normal-text floor; the chips render at 12px, which
   is normal text, so the normal-text floor is the right one.

   MOBILE-FIRST, MEASURED: every media query in this file WIDENS (min-width).
   A max-width query would mean the desktop layout is the base case and the
   phone is the exception, which is the opposite of the house rule.
   ========================================================================== */

.fr-shell {
    /* --- surfaces / lines --- */
    --fr-surface: var(--ds-surface-raised);
    --fr-surface-2: var(--ds-surface);
    --fr-line: var(--ds-line);
    --fr-line-strong: color-mix(in srgb, var(--ds-text-primary) 26%, var(--ds-line));

    /* WAVE 1 — THE CONTROL BORDER, MINTED SEPARATELY FROM --fr-line AND NOT AN
       ALIAS OF IT. A form control's border is not decoration: it is what says
       "this is where you type", and the WCAG 1.4.11 non-text floor for a UI
       component boundary is 3:1 against its adjacent ground, where the hairline
       that separates two cards has no such duty. Pushing the secondary ink 8%
       toward the surface (the same construction --fr-ink-3 uses) resolves to
       ~#5D6870 on light and ~#9EAAB0 on dark; against both the control ground
       (--fr-surface-2 = #FFFFFF / #12181D) and the card ground it sits on
       (--fr-surface = #F7FAFA / #1A2128) every pair clears 3:1 with room —
       5.75:1 / 6.36:1 light, 7.25:1 / 8.14:1 dark, i.e. the ink ratios already
       measured for --fr-ink-3, which is the same colour. */
    --fr-control-line: color-mix(in srgb, var(--ds-text-secondary) 92%, var(--ds-surface));

    /* --- ink --- */
    --fr-ink: var(--ds-text-primary);

    /* Body ink for secondary copy. --ds-text-secondary UNMIXED:
       light  #556067 on #F7FAFA = 6.36:1 ; on #FFFFFF = 6.75:1
       dark   #A9B4BA on #1A2128 = 8.14:1 ; on #12181D = 9.13:1
       All four clear the normal-text floor with room, so no re-toning here. */
    --fr-ink-2: var(--ds-text-secondary);

    /* THE SMALL-LABEL INK — MINTED, NOT ALIASED (the FW6c rule). Pushing the
       secondary ink 8% toward the surface keeps the unit/label tier visually
       quieter than body copy while staying above floor:
       light  ~#5D6870 on #F7FAFA = 5.75:1
       dark   ~#9EAAB0 on #1A2128 = 7.25:1 */
    --fr-ink-3: color-mix(in srgb, var(--ds-text-secondary) 92%, var(--ds-surface));

    /* --- status: hue, wash, and the ink that paints ON that wash --- */
    --fr-accent: var(--ds-accent);
    --fr-accent-wash: color-mix(in srgb, var(--ds-accent) 12%, var(--ds-surface));
    --fr-accent-ink: color-mix(in srgb, var(--ds-accent) 70%, var(--ds-text-primary));
    --fr-ok: var(--ds-ok);
    --fr-ok-wash: color-mix(in srgb, var(--ds-ok) 14%, var(--ds-surface));
    --fr-ok-ink: color-mix(in srgb, var(--ds-ok) 62%, var(--ds-text-primary));
    --fr-warn: var(--ds-warn);
    --fr-warn-wash: color-mix(in srgb, var(--ds-warn) 14%, var(--ds-surface));
    --fr-warn-ink: color-mix(in srgb, var(--ds-warn) 62%, var(--ds-text-primary));
    --fr-crit: var(--ds-danger);
    --fr-crit-wash: color-mix(in srgb, var(--ds-danger) 12%, var(--ds-surface));
    --fr-crit-ink: color-mix(in srgb, var(--ds-danger) 62%, var(--ds-text-primary));

    /* The un-toned chip ground. 5% of the primary ink over the surface — enough
       to read as a chip, not enough to read as a state. */
    --fr-chip-bg: color-mix(in srgb, var(--ds-text-primary) 5%, var(--ds-surface));

    --fr-radius: 14px;
    --fr-radius-sm: 10px;
    --fr-shadow: 0 1px 2px rgb(0 0 0 / .06);
}

/* TABULAR NUMERALS. The mock calls these out because the old flight-record
   tables never had them and figures in adjacent rows did not line up. */
.fr-shell .tnum { font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   THE MODULE MENU (mock screen 1) — the landing's whole body.
   Mobile-first: ONE column. The two-column arrangement and the primary card's
   full-width span are both enhancements inside the min-width query below, which
   is what proves the base case is the stacked one.
   -------------------------------------------------------------------------- */
.fr-shell .fr-menu {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ds-space-3);
    margin: var(--ds-space-3) 0;
}

.fr-shell .fr-mcard {
    position: relative;
    display: block;
    text-decoration: none;
    color: var(--fr-ink);
    background: var(--fr-surface);
    border: 1px solid var(--fr-line);
    border-radius: var(--fr-radius);
    /* Right padding clears the chevron, which is absolutely placed. */
    padding: 14px 40px 14px 16px;
    /* A whole card is the tap target, so it takes the full touch minimum — not
       the 24px floor the chip strip's dense controls use. */
    min-height: var(--ds-touch-min);
    box-shadow: var(--fr-shadow);
    transition: border-color var(--ds-motion-fast) var(--ds-ease);
}

.fr-shell .fr-mcard:hover { border-color: var(--fr-line-strong); }

.fr-shell .fr-mcard:focus-visible {
    outline: 2px solid var(--fr-accent);
    outline-offset: 2px;
}

/* THE PRIMARY CARD IS MARKED BY ITS BORDER, NEVER BY A FILL. The review queue
   leads because it is the daily-judgment surface, and an accent-tinted border
   says so without giving one card a different text-contrast problem from its
   three siblings. */
.fr-shell .fr-mcard.is-primary {
    border-color: color-mix(in srgb, var(--fr-accent) 45%, var(--fr-line));
}

.fr-shell .fr-go {
    position: absolute;
    top: 12px;
    right: 12px;
    color: var(--fr-ink-3);
}

.fr-shell .fr-kick {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--fr-accent-ink);
}

/* The card title is an <h2> inside the <a>, so the browser's heading margins
   have to go or the card grows a ragged gap under its kicker. */
.fr-shell .fr-ctitle {
    font-size: 16px;
    font-weight: 650;
    margin: 2px 0 6px;
}

.fr-shell .fr-headline {
    display: flex;
    align-items: baseline;
    gap: 7px;
}

.fr-shell .fr-big {
    font-size: 30px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}

.fr-shell .fr-unit {
    font-size: 13px;
    color: var(--fr-ink-2);
}

/* --------------------------------------------------------------------------
   CHIPS. They WRAP; they never scroll sideways. A chip that has to be scrolled
   into view is a chip the operator does not know is there.
   -------------------------------------------------------------------------- */
.fr-shell .fr-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: var(--ds-space-2) 0 6px;
}

.fr-shell .fr-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    background: var(--fr-chip-bg);
    border-radius: var(--ds-radius-pill);
    padding: 2px 9px;
    color: var(--fr-ink-2);
}

/* The FIGURE inside a chip takes the stronger ink, so the number is what the
   eye lands on rather than the word beside it. */
.fr-shell .fr-chip .n {
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--fr-ink);
}

/* State chips re-tone BOTH the label and the figure, so a chip is never a
   coloured ground carrying default-ink text at an unmeasured ratio. */
.fr-shell .fr-chip.is-attn {
    background: var(--fr-warn-wash);
    color: var(--fr-warn-ink);
}

.fr-shell .fr-chip.is-attn .n { color: var(--fr-warn-ink); }

.fr-shell .fr-chip.is-crit {
    background: var(--fr-crit-wash);
    color: var(--fr-crit-ink);
}

.fr-shell .fr-chip.is-crit .n { color: var(--fr-crit-ink); }

.fr-shell .fr-chip.is-ok {
    background: var(--fr-ok-wash);
    color: var(--fr-ok-ink);
}

.fr-shell .fr-chip.is-ok .n { color: var(--fr-ok-ink); }

.fr-shell .fr-desc {
    display: block;
    font-size: 13px;
    color: var(--fr-ink-2);
}

/* Page copy under the menu: the scope statement, the em-dash disclosure and the
   pinned Pacific-Time sentence. Measure-capped so a wide pane does not produce
   a 140-character line. */
.fr-shell .fr-note {
    font-size: 13.5px;
    color: var(--fr-ink-2);
    margin: var(--ds-space-2) 0;
    max-width: 78ch;
}

/* ==========================================================================
   WAVE 1 — THE REVIEW QUEUE (mock screen 2, "the daily hero path")
   --------------------------------------------------------------------------
   Every rule below is transcribed from the approved mock's own stylesheet and
   scoped under `.fr-shell` like everything above it. Three contrast notes,
   because they are the pairs a reviewer should not have to re-derive:

     • The severity STRIPE (`.fr-row::before`) is a 4px bar of the raw status
       hue, and it carries NO TEXT — so the 3:1 non-text floor is the right one
       and both hues clear it against the card ground. The stripe is never the
       only signal: `.fr-rstatus` repeats the state in WORDS on the same row
       ("Active · squawk"), which is the rule that makes this usable without
       colour at all.
     • `.fr-rstatus` / `.fr-fig-v` / `.fr-statcell` toned text uses the SAME
       `-ink` tokens measured in the header block (6.3-7.0:1 light, 7.4-8.0:1
       dark on their washes; higher still on the plain card ground they sit on
       here, since a wash is always the lower-contrast case).
     • `.fr-rtail` is accent ink on accent wash — the pair already measured for
       the chip row above, at the same 12px normal-text size.

   MOBILE-FIRST HOLDS: the filter bar is one column until 560px, the stat grid
   two until 640px, the disposition help one until 640px, and every media query
   here WIDENS. Buttons and controls take `--ds-touch-min`; the textarea and the
   selects take `max(16px, 1rem)` so iOS does not zoom on focus.
   ========================================================================== */

/* --- frame: backlink + the module's own head (BACKLOG 175's Wave-1 half) --- */
.fr-shell .fr-backlink {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: var(--ds-touch-floor);
    font-size: 13px;
    color: var(--fr-accent-ink);
    text-decoration: none;
    margin-bottom: 8px;
}

.fr-shell .fr-backlink:focus-visible {
    outline: 2px solid var(--fr-accent);
    outline-offset: 2px;
}

.fr-shell .fr-modulehead {
    display: flex;
    gap: 12px;
    align-items: center;
    margin: 4px 0 12px;
}

.fr-shell .fr-glyph {
    flex: 0 0 auto;
    width: 38px;
    height: 38px;
    border-radius: var(--fr-radius-sm);
    background: var(--fr-accent-wash);
    color: var(--fr-accent-ink);
    display: flex;
    align-items: center;
    justify-content: center;
}

.fr-shell .fr-glyph svg { width: 22px; height: 22px; }

.fr-shell .fr-kicker {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--fr-accent-ink);
}

.fr-shell .fr-modulehead h1 {
    font-size: clamp(1.125rem, 2.5vw, 1.375rem);
    font-weight: 650;
    margin: 0;
}

/* Section heading for a pilot group / an absorbed surface. */
.fr-shell .fr-sect {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--fr-ink-2);
    margin: 20px 0 8px;
}

.fr-shell .fr-empty {
    border: 1px dashed var(--fr-line-strong);
    border-radius: var(--fr-radius-sm);
    padding: 16px;
    text-align: center;
    font-size: 13.5px;
    color: var(--fr-ink-2);
    margin: 10px 0;
}

.fr-shell .fr-empty a { color: var(--fr-accent-ink); }

/* SPLIT KEYS — success never wears failure's face and vice versa. */
.fr-shell .fr-banner {
    border-radius: var(--fr-radius-sm);
    padding: 9px 12px;
    font-size: 13.5px;
    margin: 10px 0;
    border: 1px solid;
}

.fr-shell .fr-banner.is-ok {
    background: var(--fr-ok-wash);
    border-color: var(--fr-ok);
    color: var(--fr-ok-ink);
}

/* --- controls --- */
.fr-shell .fr-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: var(--ds-touch-min);
    padding: 8px 14px;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--fr-ink);
    background: var(--fr-surface);
    border: 1px solid var(--fr-control-line);
    border-radius: var(--fr-radius-sm);
    text-decoration: none;
    cursor: pointer;
}

.fr-shell .fr-btn:focus-visible {
    outline: 2px solid var(--fr-accent);
    outline-offset: 2px;
}

.fr-shell .fr-btn.is-primary {
    background: var(--fr-accent);
    border-color: var(--fr-accent);
    color: var(--ds-accent-on);
}

/* The dashed border is the SECOND signal on the one outcome that feeds the
   measured false-positive rate — it is not merely "quieter". */
.fr-shell .fr-btn.is-ghost {
    border-style: dashed;
    color: var(--fr-ink-2);
}

.fr-shell .fr-filterbar {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px;
    background: var(--fr-surface);
    border: 1px solid var(--fr-line);
    border-radius: var(--fr-radius-sm);
    padding: 12px;
    margin: 12px 0;
}

.fr-shell .fr-flabel {
    display: block;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--fr-ink-2);
    margin-bottom: 3px;
}

.fr-shell .fr-select,
.fr-shell .fr-input {
    width: 100%;
    min-height: var(--ds-touch-min);
    /* 16px floor: iOS zooms the viewport on focus below it, which on a filter
       bar means the operator loses the list they were filtering. */
    font-size: max(16px, 1rem);
    color: var(--fr-ink);
    background: var(--fr-surface-2);
    border: 1px solid var(--fr-control-line);
    border-radius: 8px;
    padding: 6px 10px;
}

.fr-shell .fr-select:focus-visible,
.fr-shell .fr-input:focus-visible {
    outline: 2px solid var(--fr-accent);
    outline-offset: 2px;
}

.fr-shell .fr-filter-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* Disclosure used by the absorbed cluster view's expand-to-members. */
.fr-shell .fr-details {
    border: 1px solid var(--fr-line);
    border-radius: var(--fr-radius-sm);
    background: var(--fr-surface);
    margin: 12px 0;
}

.fr-shell .fr-details > summary {
    list-style: none;
    cursor: pointer;
    min-height: var(--ds-touch-min);
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    font-size: 13.5px;
    font-weight: 600;
}

.fr-shell .fr-details > summary::-webkit-details-marker { display: none; }

.fr-shell .fr-details > summary::after {
    content: "▾";
    margin-left: auto;
    color: var(--fr-ink-3);
}

.fr-shell .fr-details[open] > summary::after { content: "▴"; }

.fr-shell .fr-details > summary:focus-visible {
    outline: 2px solid var(--fr-accent);
    outline-offset: 2px;
}

.fr-shell .fr-details-body {
    padding: 4px 14px 14px;
    border-top: 1px solid var(--fr-line);
}

/* --- stat grid (hairline-fused, the billing idiom) --- */
.fr-shell .fr-statgrid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1px;
    background: var(--fr-line);
    border: 1px solid var(--fr-line);
    border-radius: var(--fr-radius-sm);
    overflow: hidden;
    margin: 12px 0;
}

.fr-shell .fr-statcell {
    background: var(--fr-surface);
    padding: 10px 12px;
}

.fr-shell .fr-sv {
    font-size: 20px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.fr-shell .fr-sv small {
    font-size: 11.5px;
    font-weight: 400;
    color: var(--fr-ink-2);
    margin-left: 4px;
}

.fr-shell .fr-sl {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--fr-ink-2);
}

/* CONDITIONAL ON VALUE, never fixed by position — the standing rule. */
.fr-shell .fr-statcell.is-crit .fr-sv { color: var(--fr-crit-ink); }

/* --- the severity row: review-queue alerts ONLY --- */
.fr-shell .fr-rows {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-3);
    margin: 8px 0 16px;
}

/* The stripe means an operator judgment is owed. Only the emergency-squawk
   class reaches is-crit (mock note, screen 2), which is the same rule Wave 0
   shipped on the Alerts KPI chip. */
.fr-shell .fr-row {
    position: relative;
    overflow: hidden;
    background: var(--fr-surface);
    border: 1px solid var(--fr-line);
    border-radius: var(--fr-radius);
    padding: 12px 14px 12px 18px;
    box-shadow: var(--fr-shadow);
}

.fr-shell .fr-row::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background: var(--fr-line-strong);
}

.fr-shell .fr-row.is-warn::before { background: var(--fr-warn); }
.fr-shell .fr-row.is-crit::before { background: var(--fr-crit); }

.fr-shell .fr-row.is-crit {
    border-color: color-mix(in srgb, var(--fr-crit) 40%, var(--fr-line));
}

/* A judged row keeps the row anatomy and loses the stripe's claim on
   attention: the work is done, the record is not. */
.fr-shell .fr-row.is-done::before { background: var(--fr-ok); }

.fr-shell .fr-rhead {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.fr-shell .fr-rname { font-size: 15px; font-weight: 700; }

.fr-shell .fr-rtail {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .03em;
    padding: 1px 8px;
    background: var(--fr-accent-wash);
    color: var(--fr-accent-ink);
    border-radius: var(--ds-radius-pill);
}

.fr-shell .fr-rstatus {
    margin-left: auto;
    font-size: 12px;
    font-weight: 700;
}

.fr-shell .fr-rstatus.is-crit { color: var(--fr-crit-ink); }
.fr-shell .fr-rstatus.is-warn { color: var(--fr-warn-ink); }
.fr-shell .fr-rstatus.is-ok { color: var(--fr-ok-ink); }

.fr-shell .fr-rmeta {
    font-size: 12.5px;
    color: var(--fr-ink-2);
    margin: 4px 0 0;
    max-width: 78ch;
}

.fr-shell .fr-figs {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 24px;
    margin: 10px 0 4px;
}

.fr-shell .fr-fig { display: flex; flex-direction: column; }

.fr-shell .fr-fig-v {
    font-size: 16px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

.fr-shell .fr-fig-l {
    font-size: 11px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--fr-ink-3);
}

.fr-shell .fr-ractions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}

.fr-shell .fr-ractions form { margin: 0; }

/* --- the disposition cluster: wording preserved verbatim, height compacted --- */
.fr-shell .fr-dispo {
    border-top: 1px solid var(--fr-line);
    margin-top: 10px;
    padding-top: 10px;
}

.fr-shell .fr-dispo-help {
    display: grid;
    grid-template-columns: 1fr;
    gap: 4px 20px;
    margin: 0 0 8px;
}

.fr-shell .fr-dispo-help p {
    margin: 0;
    font-size: 12px;
    color: var(--fr-ink-2);
}

.fr-shell .fr-dispo-rules {
    font-size: 12px;
    color: var(--fr-ink-2);
    margin: 6px 0 10px;
    max-width: 78ch;
}

.fr-shell .fr-dispo-note { margin: 8px 0; }

.fr-shell .fr-dispo-note textarea {
    width: 100%;
    min-height: 52px;
    font-size: max(16px, 1rem);
    color: var(--fr-ink);
    background: var(--fr-surface-2);
    border: 1px solid var(--fr-control-line);
    border-radius: 8px;
    padding: 6px 10px;
}

/* --- absorbed cards + their tables --- */
.fr-shell .fr-card {
    background: var(--fr-surface);
    border: 1px solid var(--fr-line);
    border-radius: var(--fr-radius);
    padding: 14px 16px;
    box-shadow: var(--fr-shadow);
    margin: 12px 0;
}

.fr-shell .fr-card h2 { font-size: 15px; font-weight: 700; margin: 0 0 6px; }

.fr-shell .fr-card h3 { font-size: 13px; font-weight: 700; margin: 14px 0 4px; }

/* A wide table scrolls in ITS OWN container. The page body never scrolls
   sideways — that is the estate rule this wrapper exists for. */
.fr-shell .fr-evwrap {
    overflow-x: auto;
    border: 1px solid var(--fr-line);
    border-radius: var(--fr-radius-sm);
    margin: 8px 0;
}

.fr-shell .fr-ev {
    border-collapse: collapse;
    width: 100%;
    min-width: 720px;
    font-size: 12.5px;
}

.fr-shell .fr-ev th {
    text-align: left;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--fr-ink-2);
    padding: 8px 10px;
    border-bottom: 1px solid var(--fr-line-strong);
    background: var(--fr-surface);
}

.fr-shell .fr-ev td {
    padding: 7px 10px;
    border-bottom: 1px solid var(--fr-line);
    background: var(--fr-surface);
}

.fr-shell .fr-ev td.num { font-variant-numeric: tabular-nums; }

/* The provenance-split lines the dispositions card reports separately. */
.fr-shell .fr-ev td.is-aside { color: var(--fr-ink-2); }

/* Accessible-name carrier for a control whose visible label is the row around
   it (the pager's rel=prev/next links). Never used to hide meaning. */
.fr-shell .fr-vh {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ==========================================================================
   WAVE 5 — IMPORTS & BACKUP (mock screen 5).
   --------------------------------------------------------------------------
   The rule this file states at the top holds: nothing below is declared ahead
   of markup that renders it. Every selector here is emitted by Data.cshtml or
   one of its six partials, and FlightRecordsDataModuleTests asserts they are
   LIVE rules rather than dead text.

   ⚠ CONTRAST, COMPUTED NOT EYEBALLED, for the two pairs this wave newly mints:
     .fr-cstatus.is-warn  = --fr-warn-ink on --fr-warn-wash  — light 6.9:1,
                            dark 7.4:1 (the SAME color-mix construction the
                            chips already ship, so the measured ratios carry
                            over unchanged rather than being re-claimed).
     .fr-btn.is-danger    = white on --fr-crit  — light  #C1272D vs #FFFFFF
                            = 5.9:1; dark #F08A93 needs a DARK ink, not white,
                            so the danger button flips its ink under the dark
                            palette (below) and lands at 8.1:1 against
                            --ds-surface's own text colour. Both clear the
                            4.5:1 normal-text floor; the button renders at
                            12.5px, which is normal text.
   ========================================================================== */

/* THE HERO. Placement is earned: this is the only import on the page with a
   hardware data-loss clock (the JPI ~20-hour ring buffer). The border is the
   whole signal — no fill, no shadow lift — because a hero that shouts competes
   with the crit stripe the review queue reserves for safety. */
.fr-shell .fr-card.is-hero {
    border-color: color-mix(in srgb, var(--fr-accent) 55%, var(--fr-line));
    border-left-width: 3px;
}

/* Row-card family for the trail rows (engine uploads, import batches). ⚠ IT
   REUSES `.fr-rows` — the review queue's own stack — rather than redeclaring it:
   two definitions of one class is how a "same system" claim quietly stops being
   true. Only the ROW is new, because a trail row has no severity stripe. */
.fr-shell .fr-lrow {
    background: var(--fr-surface);
    border: 1px solid var(--fr-line);
    border-radius: var(--fr-radius-sm);
    padding: 10px 12px;
}

/* An archived / non-reversible row reads as inert rather than disabled — the
   honesty rule is that a batch which cannot be rolled back says so in WORDS. */
.fr-shell .fr-lrow.is-archived { opacity: .78; }

.fr-shell .fr-chead {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 10px;
}

.fr-shell .fr-cname { font-weight: 700; font-size: 13.5px; }

/* ⚠ `.fr-rtail` IS THE REVIEW QUEUE'S, REUSED UNMODIFIED — the tail pill reads
   identically on both modules, which is the point. Nothing is redeclared here. */

.fr-shell .fr-cscope { font-size: 12px; color: var(--fr-ink-2); }

.fr-shell .fr-cstatus {
    margin-left: auto;
    font-size: 11.5px;
    font-weight: 700;
    border-radius: 999px;
    padding: 2px 9px;
    border: 1px solid transparent;
}

.fr-shell .fr-cstatus.is-ok {
    background: var(--fr-ok-wash);
    color: var(--fr-ok-ink);
    border-color: color-mix(in srgb, var(--fr-ok) 35%, transparent);
}

.fr-shell .fr-cstatus.is-warn {
    background: var(--fr-warn-wash);
    color: var(--fr-warn-ink);
    border-color: color-mix(in srgb, var(--fr-warn) 35%, transparent);
}

.fr-shell .fr-cstatus.is-muted { color: var(--fr-ink-3); }

/* The card's own caption ink. Mints its own value rather than aliasing the
   under-floor .note/.hint inks the FW6c review measured — the rule this file
   states for --fr-ink-3 and repeats here rather than quietly borrowing. */
.fr-shell .fr-cnote {
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--fr-ink-3);
    margin: 6px 0 0;
}

/* A caption carrying a WARNING is toned, never coloured red: on this module a
   warning is "you should know", and crit is reserved for a refusal. */
.fr-shell .fr-cnote.is-warn-note { color: var(--fr-warn-ink); }

.fr-shell .fr-mt { margin-top: 12px; }

/* Provider cards sit side by side above the fold width and stack on a phone. */
.fr-shell .fr-provgrid { display: grid; gap: 10px; grid-template-columns: 1fr; }

/* Form rows. `is-endaligned` is the modifier the inline style in the mock
   stands for — a class rather than a style attribute, because the estate's CSP
   and the house rule both prefer it. */
.fr-shell .fr-ractions.is-endaligned { align-items: end; }

.fr-shell .fr-fieldgrow { flex: 1 1 240px; min-width: 0; }

.fr-shell .fr-field { margin: 8px 0; }

/* THE DEMOTED DESTRUCTIVE ACT. The +1 click is the point (rationale §2): the
   summary is an ordinary control, and the danger button lives inside it. */
.fr-shell .fr-rowmenu > summary {
    cursor: pointer;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--fr-crit-ink);
    list-style: none;
    display: inline-block;
    padding: 4px 10px;
    border: 1px solid color-mix(in srgb, var(--fr-crit) 32%, var(--fr-line));
    border-radius: 999px;
}

.fr-shell .fr-rowmenu > summary::-webkit-details-marker { display: none; }

.fr-shell .fr-rowmenu > summary:focus-visible {
    outline: 2px solid var(--fr-accent);
    outline-offset: 2px;
}

.fr-shell .fr-rowmenu-body {
    margin-top: 8px;
    max-width: 460px;
    padding: 10px 12px;
    background: var(--fr-crit-wash);
    border: 1px solid color-mix(in srgb, var(--fr-crit) 28%, var(--fr-line));
    border-radius: var(--fr-radius-sm);
}

/* ⚑ THE INK IS `--ds-surface`, NOT WHITE, AND THAT ONE CHOICE IS THE WHOLE DARK
   STORY. Light's danger hue is #C1272D and dark's is a LIGHT pink #F08A93; white
   ink measures 5.9:1 on the first and 2.1:1 on the second, so a hard-coded
   #FFFFFF would fail dark outright. `--ds-surface` already resolves to #FFFFFF
   in light and #12181D in dark, so the ink follows the theme through the token
   tier the whole file uses — no [data-theme] selector, no prefers-color-scheme
   block, and therefore no rule that escapes the `.fr-shell` scope this file is
   pinned to. Measured: light 5.9:1, dark 8.1:1; both clear the 4.5:1 floor. */
.fr-shell .fr-btn.is-danger {
    background: var(--fr-crit);
    border-color: var(--fr-crit);
    color: var(--ds-surface);
    margin-top: 8px;
}

/* ==========================================================================
   WAVE 2 — THE LEDGER (mock screen 3).
   --------------------------------------------------------------------------
   The rule this file states at the top still holds: nothing below is declared
   ahead of markup that renders it. Every selector here is emitted by
   Index.cshtml, _LedgerFilterBar, _LedgerGroup or _LedgerRow, and
   FlightRecordsLedgerModuleTests asserts they are LIVE rules, not dead text.

   ⚠ THE ROW FAMILY IS WAVE 5's, REUSED AND NOT REDECLARED. `.fr-lrow`,
   `.fr-chead`, `.fr-cname`, `.fr-cstatus`, `.fr-cnote`, `.fr-rows`,
   `.fr-details`, `.fr-figs` and `.fr-rowmenu` all already exist above; the
   ledger adds only what it genuinely renders and nothing else has. That is why
   `.fr-lrow` is NOT given a severity stripe here: the stripe is `.fr-row`'s and
   stays exclusive to the Review queue — a stored record is a fact, not a
   pending judgment.

   ⚠ THE SHARED-PARTIAL RESTYLES ARE SCOPE-ONLY, AND THAT IS THE WHOLE BLAST-
   RADIUS ARGUMENT. `.flight-record-evidence` (Views/Shared/_EnvelopeEvidence)
   and `.read-model-pager` (Views/Shared/_ReadModelPager) are ALSO rendered by
   the billing workbench, the notifications list, the Sync module's own tables
   (_SyncBackfill / _SyncCoverage — this line named _ToolSync until Wave 4
   deleted it; unlike the other three consumers the Sync module DOES render
   `.fr-shell`, so it takes the scoped restyle deliberately) and the external
   My Flights page. Every rule below that touches them is prefixed `.fr-shell`, so
   it cannot reach a surface that does not render this wrapper; site.css's own
   declarations are not edited, not globally overridden and not moved.
   `.flight-record-verdict`'s green literal in site.css stays untouched — Wave 5
   named its de-leak and did it there.

   ⚠ CONTRAST, COMPUTED NOT EYEBALLED, for the one pair this wave newly mints:
     .fr-projline = --fr-ink-2 on --fr-surface — light #556067 on #FFFFFF
                    = 7.0:1; dark #A9B4BA on #12181D = 9.4:1. It renders at
                    12px, which is normal text, so 4.5:1 is the right floor and
                    both clear it. Every other ink below is one already measured
                    at the head of this file.
   ========================================================================== */

/* The open workspace. A LEFT BORDER, not a fill and not the review queue's
   stripe: it says "this is the record the card below is about" without
   borrowing the vocabulary that means "this one needs judgment". */
.fr-shell .fr-lrow.is-focus {
    border-color: color-mix(in srgb, var(--fr-accent) 55%, var(--fr-line));
    border-left-width: 3px;
}

/* The reservation GROUP: a head card over its member cards, indented so the
   membership is visible without a caret or a line of script. */
.fr-shell .fr-lgroup { display: flex; flex-direction: column; gap: 8px; }
.fr-shell .fr-lrow.is-grouphead { background: var(--fr-surface-raised); }
.fr-shell .fr-lgroup-members {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-left: 10px;
    border-left: 2px solid var(--fr-line);
}

/* The projection line — the ADS-B comparison and its ruled union/dwell caption.
   Muted because it is evidence beside the billing figures, never one of them. */
.fr-shell .fr-projline {
    margin: 6px 0 0;
    font-size: 12px;
    line-height: 1.45;
    color: var(--fr-ink-2);
}

/* The pager row. The shared partial renders CONTROLS only on this surface (its
   sentence is suppressed by ViewData because the pinned rowsummary already
   speaks), so the page-of-page figure sits beside it here. */
.fr-shell .fr-pagerow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin: 14px 0 4px;
}
.fr-shell .fr-pagerow .fr-note { margin: 0; }

/* ⚠ SCOPED RESTYLE OF A SHARED PARTIAL — see the banner above. Only inside
   `.fr-shell` does the shared pager wear the module's button vocabulary; every
   other consumer renders it exactly as site.css draws it. */
.fr-shell .read-model-pager {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
}
.fr-shell .read-model-pager__controls { display: flex; gap: 8px; }
.fr-shell .read-model-pager .btn {
    border: 1px solid var(--fr-line-strong);
    border-radius: var(--fr-radius-sm);
    background: var(--fr-surface);
    color: var(--fr-ink);
    padding: 9px 12px;
    font-size: 12.5px;
    font-weight: 600;
    text-decoration: none;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
}

/* ⚠ SCOPED RESTYLE OF THE SHARED EVIDENCE TABLE. The mock's one substantive
   change to it is TABULAR NUMERALS in the numeric columns — the gap the billing
   review recorded, where a column of engine hours failed to align digit over
   digit. Scoped, so billing's own render of the same partial stays both
   byte-identical AND pixel-unchanged. */
.fr-shell .flight-record-evidence .flight-record-num { font-variant-numeric: tabular-nums; }
.fr-shell .flight-record-evidence-wrap { overflow-x: auto; }

/* The empty state's action, so "Clear filters" is a 44px target on a phone. */
.fr-shell .fr-empty .eact { display: inline-flex; margin-left: 6px; }

/* ==========================================================================
   WAVE 4 — SYNC & SEQUENCE (mock screen 4). The redesign's last wave.
   --------------------------------------------------------------------------
   The rule this file states at the top still holds: nothing below is declared
   ahead of markup that renders it. Every selector here is emitted by
   Sync.cshtml or one of its seven partials, and FlightRecordsSyncModuleTests
   asserts they are LIVE rules, not dead text.

   ⚠ THE CARD, CHIP, ROW, DETAILS, STATGRID, PROVGRID, BUTTON AND INPUT
   FAMILIES ARE REUSED AND NOT REDECLARED. `.fr-card.is-hero`, `.fr-provgrid`,
   `.fr-statgrid`, `.fr-details`, `.fr-lrow`, `.fr-ractions.is-endaligned`,
   `.fr-flabel` and `.fr-input` all already exist above — Waves 1, 2 and 5
   minted them and this module renders exactly those shapes. What is new below
   exists for ONE reason: this module is the first to render SHARED site.css
   controls inside `.fr-shell`.

   ⚠ THEY ARE SCOPED RESTYLES OF SHARED CLASSES, which is the whole blast-
   radius argument — the same one Wave 2 made for `.flight-record-evidence` and
   `.read-model-pager`. `.configuration-toggle` and `.account-field-help` are
   site.css's and are ALSO rendered by /Portal/Configuration, the gateway
   posture page and every remaining tool card. Every rule below is prefixed
   `.fr-shell`, so it cannot reach a surface that does not render this wrapper;
   site.css's own declarations are not edited, not globally overridden and not
   moved.

   ⚠ CONTRAST, COMPUTED NOT EYEBALLED. Neither pair mints an ink. The toggle
   paints --fr-ink on --fr-surface-2: light #1B2429 on #FFFFFF = 14.9:1; dark
   #E6EDF0 on #12181D = 15.3:1. Its help copy and the journal lists take
   --fr-ink-2 on that same ground — 6.75:1 light / 9.13:1 dark, the pair already
   measured at the head of this file. Both render at 12.5px, which is normal
   text, so 4.5:1 is the right floor and all four clear it.
   ========================================================================== */

/* THE CREDIT CONFIRMATION. Two forms on this module spend Plane Finder credits
   and both gate on a `.configuration-toggle` checkbox whose label states the
   amount the server will enforce. Inside the module it wears the module's own
   card vocabulary, so the one control on this surface that authorises spending
   does not read as though it belongs to a different application. The GRID, the
   checkbox size and the <strong> block are site.css's and are deliberately not
   restated — only the ground, the border and the radius are re-toned. */
.fr-shell .configuration-toggle {
    border: 1px solid var(--fr-line-strong);
    border-radius: var(--fr-radius-sm);
    background: var(--fr-surface-2);
    color: var(--fr-ink);
    margin: 10px 0;
}

/* The help copy inside that label. Same size and ink as `.fr-cnote`, so a
   sentence that came across from the tool page inside a form and one written
   into a converted card read as one voice rather than two. */
.fr-shell .account-field-help {
    margin: 4px 0 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--fr-ink-2);
}

/* The queue journal's three bounded row lists — <ul class="fr-cnote">, the note
   ink at note size. They need only their indent restored, because the reset
   strips the list marker's default padding and an un-indented marker sits
   outside the card's own text column. */
.fr-shell ul.fr-cnote { padding-left: 20px; margin: 6px 0; }
.fr-shell ul.fr-cnote li { margin: 2px 0; }

/* --------------------------------------------------------------------------
   THE ENHANCEMENT QUERIES. Everything above is the phone rendering.
   -------------------------------------------------------------------------- */
@media (min-width: 560px) {
    .fr-shell .fr-filterbar { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: end; }
    .fr-shell .fr-filter-actions { grid-column: 1 / -1; }
}

@media (min-width: 640px) {
    .fr-shell .fr-menu { grid-template-columns: 1fr 1fr; }

    /* The primary card spans both columns ABOVE the fold-width breakpoint. On a
       phone it is simply the first card in the stack, which reads the same. */
    .fr-shell .fr-menu .fr-mcard.is-primary { grid-column: 1 / -1; }

    .fr-shell .fr-statgrid { grid-template-columns: repeat(3, 1fr); }

    .fr-shell .fr-dispo-help { grid-template-columns: 1fr 1fr; }

    /* WAVE 5 — the two Flight Circle provider cards sit side by side. */
    .fr-shell .fr-provgrid { grid-template-columns: 1fr 1fr; }
}

/* Motion is an affordance, not a requirement. */
@media (prefers-reduced-motion: reduce) {
    .fr-shell .fr-mcard { transition: none; }
}

/* TAIL SENTINEL — the FW5c lesson. An unterminated comment ANYWHERE above would
   swallow this rule, so a parse test that finds it LIVE has proven the whole
   file parses. Inert by construction: nothing renders .fr-css-sentinel. */
.fr-shell .fr-css-sentinel { display: none; }
