:root {
    /* `only light` (not plain `light`) is what actually opts the page out
       of Android Chrome's auto-dark ("Force dark") engine — plain `light`
       stopped being honoured, which is why the app was being force-darkened
       into the muddy mixed rendering on Android. The designed dark theme
       lives under html[data-theme="dark"] below. */
    color-scheme: only light;
    /* JAGS aviation palette over the Achromatic Precision layout — navy
       primary, slate secondary, cool blue-tinted surfaces. Layout structure
       (radii, tracking, shadows, spacing) stays from the design system. */
    --bg: #F7F9FC;
    --card: #FFFFFF;
    /* Alias used by several pages as var(--card-bg, #fff). It was never
       defined, so the #fff fallback ALWAYS fired — defining it here makes
       those pages theme-correct in one place. */
    --card-bg: var(--card);
    /* RGB triplet for frosted-glass chrome (topbar, bottom nav, sheets,
       sticky action bars) — used as rgba(var(--glass-rgb), <alpha>) so each
       surface keeps its tuned alpha while the tint follows the theme. */
    --glass-rgb: 255, 255, 255;
    --surface: #FFFFFF;
    --surface-low: #F7F9FC;
    --surface-high: #FFFFFF;
    --surface-container: #EEF1F7;
    /* Three aliases that inline page stylesheets already reach for but which
       had never been DEFINED anywhere — so each silently took its fallback,
       and every fallback was a fixed colour that could only ever suit ONE
       theme. Aliasing a custom property to another resolves against the
       cascade at USE time, so one declaration here follows both themes; do
       not "helpfully" duplicate these into the dark block.

       --surface-2      fell back to `transparent`, which let the columns
                        scrolling under a position:sticky frozen cell show
                        straight through it on row hover, and to a hard-coded
                        #f5f7fb pill that stayed light in dark mode.
       --warn-ink       fell back to #8a6d1f, a dark yellow with no dark-mode
                        value at all.
       --text-on-primary fell back to #fff. --primary is #171756 in light but
                        #9DB0F0 in dark, so that painted white on pale blue —
                        about 1.8:1 — on the active view toggle. */
    --surface-2: var(--surface-container);
    --warn-ink: var(--status-warning-ink);
    --text-on-primary: var(--text-inverse);
    /* --ink: reservation_flight_schedule.php reads it in three places with no
       fallback, and the only definition was public_html/companion/style.css —
       a standalone mini-app's :root that the main layout never loads. Those
       declarations computed to `inherit`. The audit's scanner missed it
       because it counted a definition in ANY file. Aliased to the body ink. */
    --ink: var(--text);
    /* --warn: same story. A risk-assessment border and an hour-estimate bar
       fill read it with light-only literal fallbacks (#B6883A, #C09A3D) —
       dim ochre on a dark card. The only definition was the companion
       stylesheet. --warning carries a value for both themes. */
    --warn: var(--warning);
    --surface-container-high: #E6EAF3;
    --surface-container-highest: #DDE3EE;
    --inverse-surface: #1B1F2E;
    --inverse-on-surface: #F2F4FA;
    /* Primary ink is a deep brand navy (not near-black): headings, body and
       table text all read as part of the JAGS identity. 14.9:1 on --card. */
    --text: #10173B;
    --text-strong: #0A102C;
    --muted: #5E6472;
    --muted-strong: #4B5061;
    --primary: #171756;
    --primary-hover: #0B0B2F;
    --secondary: #274270;
    --secondary-hover: #1B345B;
    --link: #274270;
    --border: #E2E6EE;
    --border-strong: #C7D1E2;
    --outline: #7E7576;
    --success: #4A6733;
    --info: #5A79A5;
    --danger: #B83235;
    --warning: #B6883A;
    /* Airy ambient shadows kept from the design system — long blur, low
       opacity, navy-tinted so the lift reads as part of the brand. */
    --shadow-xs: 0 1px 1px rgba(14, 14, 18, 0.025);
    --shadow-sm: 0 1px 2px rgba(14, 14, 18, 0.035);
    --shadow-md: 0 8px 24px rgba(14, 14, 18, 0.05);
    --shadow-lg: 0 30px 60px rgba(11, 11, 47, 0.08), 0 2px 4px rgba(14, 14, 18, 0.03);
    /* 0.70 alpha measures 4.31:1 on --card; the old 0.22 was 1.31:1, i.e. a
       focus ring keyboard users could not actually see. WCAG 2.4.11 needs 3:1. */
    --ring-focus: 0 0 0 3px rgba(39, 66, 112, 0.70);
    --radius: 12px;
    --radius-sm: 8px;
    --radius-md: var(--radius);
    --radius-lg: 16px;
    --grad-jags: linear-gradient(135deg, #171756 0%, #274270 60%, #5A79A5 100%);
    --grad-soft: linear-gradient(180deg, #F7F9FC 0%, #FFFFFF 100%);

    /* ------------------------------------------------------------------
       Aliases — names that read closer to brand language. Each maps to
       an existing token so adopting the alias does not change a colour.
       Use these in NEW code so future palette tweaks happen in one place.
       ------------------------------------------------------------------ */
    --jags-blue:        #171756;  /* same as --primary */
    --jags-blue-deep:   #0B0B2F;  /* same as --primary-hover */
    --jags-blue-soft:   #5A79A5;  /* same as --info */
    --jags-navy:        #274270;  /* same as --secondary */
    --jags-surface:     #FFFFFF;
    --jags-surface-low: #F7F9FC;
    --jags-success:     #4A6733;  /* same as --success */
    --jags-warning:     #B6883A;  /* same as --warning */
    --jags-danger:      #B83235;  /* same as --danger */

    /* ------------------------------------------------------------------
       Dark sidebar — premium executive shell (2026-05-22 MVP UI pass).
       The authenticated app sits on a white/soft canvas with a deep navy
       rail, matching the reference's "elegant dark sidebar" while staying
       on the JAGS navy/indigo brand. Single source of truth so the desktop
       rail and the mobile slide-in drawer never drift. The brand logo keeps
       a LIGHT lockup panel (--sidebar-brand-bg): the logo asset is locked
       and must not be recoloured, so it reads cleanly on its own white card.
       --sidebar-accent is a lighter periwinkle tint of --jags-blue-soft
       (#5A79A5) so the active marker reads as an accent against the navy.
       Display/TV boards (layout_display_open) and auth pages
       (layout_blank_open) never use the app shell, so these never reach
       them. Tune the whole rail from here. ------------------------------ */
    --sidebar-bg:        #0E1230;  /* deep brand navy-indigo (rail base) */
    --sidebar-bg-2:      #161C40;  /* lifted top of the rail gradient */
    --sidebar-text:      #EAEDF7;  /* primary nav label */
    --sidebar-muted:     #98A1C6;  /* section labels, idle icons, account sub */
    --sidebar-border:    rgba(255, 255, 255, 0.08);
    --sidebar-hover-bg:  rgba(255, 255, 255, 0.06);
    --sidebar-active-bg: rgba(255, 255, 255, 0.11);
    --sidebar-accent:    #8AA3D6;  /* active rail/marker — light tint of blue-soft */
    --sidebar-brand-bg:  #FFFFFF;  /* light lockup panel for the locked logo */
    --grad-sidebar:      linear-gradient(180deg, #161C40 0%, #0E1230 62%, #0B0E26 100%);

    /* ------------------------------------------------------------------
       Typography — Inter when available, system stack everywhere else.
       Sizes follow a relaxed 1.18 scale tuned for dense aviation tables
       without compressing report headings. Mono is used for hours / regs.
       ------------------------------------------------------------------ */
    --font-sans:    Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Segoe UI", sans-serif;
    --font-display: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", sans-serif;
    --font-mono:    ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

    --text-xs:   12px;
    --text-sm:   13px;
    --text-base: 14px;
    --text-lg:   16px;
    --text-xl:   20px;
    --text-2xl:  24px;
    --text-3xl:  32px;

    /* Tracking: tighter on display/headings, slight negative on body for the
       "locked-in" editorial feel. Uppercase labels keep wider spacing. */
    --tracking-tight:  -0.02em;
    --tracking-normal: -0.006em;
    --tracking-wide:   0.05em;

    --line-tight:   1.2;
    --line-normal:  1.5;
    --line-relaxed: 1.65;

    /* Motion system — tokens used across buttons, cards, tables, nav, modal.
       Apple-style decelerated easings. Calm, not flashy. */
    --motion-fast: 140ms;
    --motion-med:  220ms;
    --motion-slow: 380ms;
    --ease-premium: cubic-bezier(0.2, 0.8, 0.2, 1);
    --ease-soft:    cubic-bezier(0.22, 0.61, 0.36, 1);
    --ease-out:     cubic-bezier(0.4, 0, 0.2, 1);

    /* ------------------------------------------------------------------
       Mobile fixed bottom-nav geometry — single source of truth.
       .mobile-bottom-nav is position:fixed at the viewport bottom on
       phones (<=900px). Every surface that must sit clear of it — page
       content, sticky action bars, toasts, the docked walkthrough card —
       derives its offset from these tokens instead of repeating magic
       numbers, so the bar's reserved space is tuned in ONE place.

       --safe-area-bottom carries an explicit 0px fallback. Without it, a
       calc()/max() that references env(safe-area-inset-bottom) becomes
       INVALID on in-app browsers / older WebViews that don't implement
       safe-area insets (WhatsApp Business, some Chrome Custom Tabs, older
       Android System WebView). An invalid clearance declaration is
       dropped, the reserved space collapses to the base .content padding,
       and the fixed bar then overlaps the last cards / footer / buttons —
       exactly the reported overlap. The fallback keeps the calc() valid
       everywhere so the clearance always applies.

       --mobile-bottom-nav-height is the bar's intrinsic height with no
       inset (icon + label + paddings + hairline ≈ 61px, rounded up to
       64px for a small cushion). Footprint = height + device safe area
       (the space the bar actually occupies); clearance = footprint +
       comfortable breathing room so the final content never meets the
       bar. Sticky action bars sit on the footprint; page content reserves
       the full clearance. Desktop (>900px) never consumes these. */
    --mobile-bottom-nav-height: 64px;
    --safe-area-bottom: env(safe-area-inset-bottom, 0px);
    --mobile-bottom-nav-footprint: calc(var(--mobile-bottom-nav-height) + var(--safe-area-bottom));
    --mobile-bottom-nav-clearance: calc(var(--mobile-bottom-nav-footprint) + 22px);

    /* ------------------------------------------------------------------
       SEMANTIC TOKENS (2026-08 application design system).
       One vocabulary for every shared component: surfaces, ink tiers,
       separators, accent, status pairs (strong + soft tint), depth, radii
       and an 8-point spacing scale. Each maps onto the palette above so
       the theme is tuned in one place; the dark block re-derives the same
       names. New/updated components should reach for THESE first.
       ------------------------------------------------------------------ */
    --surface-page:      var(--bg);
    --surface-primary:   var(--card);
    --surface-secondary: var(--surface-container);
    --surface-elevated:  var(--surface-high);
    --surface-selected:  rgba(39, 66, 112, 0.08);
    --text-primary:      var(--text);
    --text-secondary:    var(--muted);
    --text-tertiary:     #6B7287;  /* was #8A91A6 = 3.14:1 on --card / 2.98:1 on --bg;
                                      now 4.79:1 and 4.54:1 — it clears AA on BOTH grounds. */
    --text-inverse:      #FFFFFF;
    --separator:         var(--border);
    --border-subtle:     rgba(23, 23, 86, 0.08);
    --focus-ring:        var(--ring-focus);
    --accent:            var(--secondary);
    --accent-hover:      var(--secondary-hover);
    --accent-soft:       rgba(90, 121, 165, 0.14);
    --status-success:      var(--success);
    --status-success-soft: rgba(74, 103, 51, 0.12);
    --status-warning:      var(--warning);
    --status-warning-soft: rgba(182, 136, 58, 0.16);
    --status-danger:       var(--danger);
    --status-danger-soft:  rgba(184, 50, 53, 0.10);
    --status-info:         var(--info);
    --status-info-soft:    rgba(90, 121, 165, 0.14);
    /* Ink for text sitting ON a soft status surface (--status-*-soft, or a
       raw rgba tint of the same hue). The soft background re-tints itself
       per theme; the ink never could, which is why status chips, alerts and
       the reservation vocabulary all read as dark-on-dark in dark mode.
       These values ARE the literals that were previously hardcoded, so light
       mode is unchanged; the dark block below supplies the counterparts. */
    --status-success-ink: #3B5326;
    --status-warning-ink: #7C5A1F;
    --status-danger-ink:  #8E2226;
    --status-info-ink:    #244A78;
    --status-neutral-ink: var(--muted-strong);
    --shadow-card:     0 1px 2px rgba(11, 11, 47, 0.04), 0 10px 30px rgba(11, 11, 47, 0.06);
    --shadow-elevated: var(--shadow-md);
    --radius-control: 12px;
    --radius-card:    16px;
    --radius-panel:   20px;
    --radius-round:   999px;
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-8: 32px;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Light is the default scheme; `only light` hard-opts-out of browser
   force-darkening (see :root note). The designed dark theme is activated by
   stamping data-theme="dark" on <html> — server-side from the jags_theme
   cookie, or by the head bootstrap when the preference is System and the
   device is dark. Display boards (TV wallboards) keep their own separate
   dark scheme via layout_display_open() and never load this stylesheet. */
html { color-scheme: only light; background: var(--bg); }
body {
    font-family: var(--font-sans);
    background: var(--bg);
    color: var(--text);
    font-size: var(--text-base);
    line-height: var(--line-normal);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    font-feature-settings: "ss01", "cv11"; /* Inter stylistic alternates when present */
}
/* ======================================================================
   DESIGNED DARK THEME — activated by html[data-theme="dark"].
   Aviation navy/charcoal, layered surfaces, not pure black. All text/token
   pairings meet WCAG AA on their surfaces (ratios noted). The navy hero
   gradient keeps the exact JAGS identity; interactive --primary shifts to
   a periwinkle-indigo of the same family for dark-surface contrast.
   Never applied to display boards (separate shell) or print (guard below).
   ====================================================================== */
html[data-theme="dark"] {
    color-scheme: dark; /* native dark form controls, pickers, keyboard */

    /* Surfaces — layered, calm */
    --bg:                        #0E1220;
    --card:                      #171C2B;
    --surface:                   #171C2B;
    --surface-low:               #10141F;
    --surface-high:              #1B2133;
    --surface-container:         #1E2438;
    --surface-container-high:    #232A40;
    --surface-container-highest: #29314A;
    --inverse-surface:           #E6E9F2;
    --inverse-on-surface:        #171C2B;

    /* Text — 13.9:1 on card / 15.3:1 on bg; muted 7.3:1 on card */
    --text:         #E6E9F2;
    --text-strong:  #F5F7FB;
    --muted:        #A2AAC0;
    --muted-strong: #BAC1D4;

    /* Brand / interactive — JAGS navy family, dark-adjusted (8.0:1 on card) */
    --primary:        #9DB0F0;
    --primary-hover:  #B4C3F5;
    --secondary:      #93A6DE;
    --secondary-hover:#A9B8E8;
    --link:           #9DB0F0;

    /* Borders */
    --border:        #2C3346;
    --border-strong: #3C4560;

    /* Status — all >= 4.5:1 as text on --card */
    --success: #7FB069;
    --info:    #7CA5D8;
    --danger:  #E0797B;
    --warning: #E0B25C;

    /* Elevation — darker shadows; surface layering does the separating */
    --shadow-xs: 0 1px 1px rgba(0,0,0,0.30);
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.40);
    --shadow-md: 0 8px 24px rgba(0,0,0,0.45);
    --shadow-lg: 0 24px 60px rgba(0,0,0,0.55), 0 2px 4px rgba(0,0,0,0.40);
    /* 2.69:1 at 0.45 — below the 3:1 floor. 0.75 measures 5.09:1. */
    --ring-focus: 0 0 0 3px rgba(157,176,240,0.75);

    /* Hero keeps the JAGS navy identity; soft gradient goes dark */
    --grad-jags: linear-gradient(135deg, #171756 0%, #274270 55%, #3D5A8A 100%);
    --grad-soft: linear-gradient(180deg, #10141F 0%, #171C2B 100%);

    /* Brand-language aliases — same dark-adjusted family as --primary etc.
       These are used as TEXT/accent colours; the one brand FILL that must
       stay navy (bottom-nav Guide button) is pinned separately below. */
    --jags-blue:        #9DB0F0;
    --jags-blue-deep:   #B4C3F5;
    --jags-blue-soft:   #7CA5D8;
    --jags-navy:        #93A6DE;
    --jags-surface:     #171C2B;
    --jags-surface-low: #10141F;
    --jags-success:     #7FB069;
    --jags-warning:     #E0B25C;
    --jags-danger:      #E0797B;

    /* The sidebar rail is already deep navy in light mode — unchanged.
       Its brand lockup chip softens from pure white to a soft-white so the
       locked dark-navy logo artwork stays crisp without a glaring slab. */
    --sidebar-brand-bg: #F4F6FC;
    /* In dark mode the navy rail (#0E1230) sits on a near-identical page
       canvas (#0E1220) — about 1.06:1 — so the shell had almost no visible
       content boundary. Lift the shared border token rather than patching
       the rail: every surface drawn with it (rail edge, panel edge, Quick
       Access, the Customize card) gains the same separation at once. */
    --sidebar-border: rgba(255, 255, 255, 0.16);

    /* Frosted chrome tint (see :root note) */
    --glass-rgb: 23, 28, 43;

    /* Semantic tokens — dark derivations of the same vocabulary. Tokens
       that alias other tokens (--surface-page, --text-primary, --accent…)
       follow automatically; only the literal values need restating. */
    --surface-selected:  rgba(157, 176, 240, 0.12);
    --text-tertiary:     #7C86A0;
    --text-inverse:      #0B0E1A;
    --border-subtle:     rgba(255, 255, 255, 0.07);
    --accent-soft:       rgba(147, 166, 222, 0.16);
    --status-success-soft: rgba(127, 176, 105, 0.16);
    --status-warning-soft: rgba(224, 178, 92, 0.18);
    --status-danger-soft:  rgba(224, 121, 123, 0.16);
    --status-info-soft:    rgba(124, 165, 216, 0.16);
    /* Dark counterparts. Same values the .badge-* dark overrides already use,
       so a chip and a badge of the same status are the same colour. */
    --status-success-ink: #A9D392;
    --status-warning-ink: #E6C078;
    --status-danger-ink:  #EDA0A2;
    --status-info-ink:    #A6C4E6;
    --status-neutral-ink: var(--muted-strong);
    --shadow-card:     0 1px 2px rgba(0, 0, 0, 0.35), 0 10px 30px rgba(0, 0, 0, 0.40);
}

/* --- Dark component rules tokens alone can't express ------------------- */

/* Primary/danger buttons: dark theme is tonal — light fill + dark ink
   (white-on-periwinkle would fail contrast). 9.1:1 both states. */
html[data-theme="dark"] .btn-primary,
html[data-theme="dark"] .btn-primary:hover { color: #0B0E1A; }
html[data-theme="dark"] .btn-danger { color: #1A0B0B; }
html[data-theme="dark"] .btn-danger:hover { background: #E89294; color: #1A0B0B; }
html[data-theme="dark"] .btn-ghost:hover { background: rgba(157,176,240,0.10); }

/* Badge soft-tints: light theme uses dark ink on pale tints — flip to
   light ink on dark tints. */
html[data-theme="dark"] .badge-success { background: rgba(127,176,105,0.18); color: #A9D392; }
html[data-theme="dark"] .badge-warn    { background: rgba(224,178,92,0.20);  color: #E6C078; }
html[data-theme="dark"] .badge-danger  { background: rgba(224,121,123,0.18); color: #EDA0A2; }
html[data-theme="dark"] .badge-info    { background: rgba(124,165,216,0.18); color: #A6C4E6; }
html[data-theme="dark"] .badge-neutral { background: rgba(162,170,192,0.16); color: var(--muted); }

/* Toast variants: gradients ended in #fff — end them in the card surface. */
html[data-theme="dark"] .jags-toast.success { background: linear-gradient(180deg, rgba(127,176,105,0.08), var(--card)); }
html[data-theme="dark"] .jags-toast.warn    { background: linear-gradient(180deg, rgba(224,178,92,0.10),  var(--card)); }
html[data-theme="dark"] .jags-toast.danger  { background: linear-gradient(180deg, rgba(224,121,123,0.08), var(--card)); }
html[data-theme="dark"] .jags-toast.info    { background: linear-gradient(180deg, rgba(124,165,216,0.09), var(--card)); }
html[data-theme="dark"] .jags-toast.warn .toast-icon   { color: var(--warning); }
html[data-theme="dark"] .jags-toast.danger .toast-icon { color: var(--danger); }

/* Tables: headers/zebra/hover were hard-coded near-whites. */
html[data-theme="dark"] table.tbl th { background: linear-gradient(180deg, #1E2438 0%, #171C2B 100%); }
html[data-theme="dark"] table.tbl tr:hover td { background: var(--surface-high); }
html[data-theme="dark"] table.tbl-sticky-first tbody tr:hover td:first-child,
html[data-theme="dark"] table.tbl-sticky-first tbody tr:nth-child(even) td:first-child { background: var(--surface-container); }
html[data-theme="dark"] table.dr th { background: linear-gradient(180deg, #232A40 0%, #1E2438 100%); color: var(--muted-strong); }
html[data-theme="dark"] table.dr tbody td.reg-cell { background: var(--surface-low); }
html[data-theme="dark"] .cell-list li { background: rgba(255,255,255,0.04); }
html[data-theme="dark"] .legend { background: var(--surface-low); }

/* Compliance/report cell states: light-tint + dark ink flipped for dark. */
html[data-theme="dark"] .cell-warn        { background: rgba(124,165,216,0.18) !important; color: #A6C4E6; }
html[data-theme="dark"] .cell-green       { background: rgba(127,176,105,0.16) !important; color: #A9D392; }
html[data-theme="dark"] .cell-major       { background: rgba(224,178,92,0.16)  !important; color: #E6C078; }
html[data-theme="dark"] .cell-outstanding { background: rgba(224,121,123,0.14) !important; color: #EDA0A2; }
html[data-theme="dark"] .cell-coa-soon    { background: rgba(127,176,105,0.20) !important; color: #A9D392; }
html[data-theme="dark"] .cell-cmr-soon    { background: rgba(186,140,220,0.18) !important; color: #CDA9E0; }
html[data-theme="dark"] .cell-expired     { background: rgba(224,121,123,0.22) !important; color: #EDA0A2; }
html[data-theme="dark"] .dr-kw-critical { color: #EDA0A2; }
html[data-theme="dark"] .dr-kw-warn     { color: #E6C078; }
html[data-theme="dark"] .dr-kw-info     { color: #A6C4E6; }

/* Form controls: hard-coded #FFF fills go to a recessed input surface. */
html[data-theme="dark"] .field input[type=text], html[data-theme="dark"] .field input[type=email],
html[data-theme="dark"] .field input[type=password], html[data-theme="dark"] .field input[type=date],
html[data-theme="dark"] .field input[type=time], html[data-theme="dark"] .field input[type=number],
html[data-theme="dark"] .field input[type=search], html[data-theme="dark"] .field input[type=tel],
html[data-theme="dark"] .field input[type=url], html[data-theme="dark"] .field input[type=datetime-local],
html[data-theme="dark"] .field select, html[data-theme="dark"] .field textarea,
html[data-theme="dark"] .time24-input { background: var(--surface-low); }

/* Chrome autofill paints its own light fill — repaint via inset shadow
   (background-color is ignored on :-webkit-autofill). */
html[data-theme="dark"] input:-webkit-autofill,
html[data-theme="dark"] input:-webkit-autofill:hover,
html[data-theme="dark"] input:-webkit-autofill:focus,
html[data-theme="dark"] textarea:-webkit-autofill,
html[data-theme="dark"] select:-webkit-autofill {
    -webkit-text-fill-color: var(--text);
    -webkit-box-shadow: 0 0 0 1000px var(--surface-low) inset;
    box-shadow: 0 0 0 1000px var(--surface-low) inset;
    caret-color: var(--text);
}

/* Walkthrough / tour card: light glass panel goes to dark glass so its
   token-coloured text stays readable. */
html[data-theme="dark"] .jags-tour-card {
    background: linear-gradient(180deg, rgba(30,36,56,0.96) 0%, rgba(23,28,43,0.94) 100%);
    border-color: rgba(157,176,240,0.18);
    box-shadow:
      0 1px 0 rgba(255,255,255,0.06) inset,
      0 0 0 1px rgba(0,0,0,0.40),
      0 28px 60px -12px rgba(0,0,0,0.60),
      0 8px 18px -8px rgba(0,0,0,0.40);
}

/* Bottom-nav Guide button: keep the brand-navy FILL (white glyph needs the
   navy, not the periwinkle text alias); ring matches the dark chrome. */
html[data-theme="dark"] .mobile-bottom-nav .mobile-nav-primary .jags-icon-wrap {
    background: #171756;
    border-color: rgba(23, 28, 43, 0.96);
}

/* Horizontal table scrollbars: navy-on-light thumb is invisible on dark. */
html[data-theme="dark"] .table-wrap { scrollbar-color: rgba(157,176,240,0.35) transparent; }
html[data-theme="dark"] .table-wrap::-webkit-scrollbar-thumb { background: rgba(157,176,240,0.30); }
html[data-theme="dark"] .table-wrap::-webkit-scrollbar-thumb:hover { background: rgba(157,176,240,0.50); }

/* ---------------------------------------------------------------------
   Contrast repairs (2026-09-06). Two shipped failure modes, both fixed
   here rather than in the base rules so LIGHT mode is untouched:

   a) Status inks pinned to a light-mode literal instead of a token. They
      read 1.4-3.0:1 on the dark card, i.e. invisible. Each is restated
      with the dark ink its own family already uses.
   b) White ink over a --primary/--secondary/--danger FILL. Those tokens
      invert to light periwinkle/rose tints in this theme, so white lands
      at 2.1-2.9:1. The dark theme is tonal — light fill, dark ink — which
      is the decision .btn-primary/.btn-danger above already made; these
      selectors simply never followed it. Darkening the fills instead was
      rejected: --secondary is also a TEXT colour here (.btn-ghost, links),
      so the token cannot move, and a dark-filled secondary button would be
      the only inverted control in a tonal set.
   --------------------------------------------------------------------- */

/* (a) Status / emphasis inks. "Scheduled" and the prominent type pill keep
   their light-theme relationship to Customer Confirmed — a DEEPER green
   than --status-success-ink — by taking --success. */
html[data-theme="dark"] .rsv-status-scheduled          { color: var(--success); }
html[data-theme="dark"] .rsv-acft-type-pill-prominent  { color: var(--success); }
html[data-theme="dark"] .rsv-aa-pill-warn              { color: var(--status-warning-ink); }
html[data-theme="dark"] .av2-feature.success .feat-val { color: var(--status-success-ink); }
html[data-theme="dark"] .fs-mobile-handoff strong      { color: var(--status-success-ink); }
html[data-theme="dark"] table.ops-board.ops-mobile-schedule td:nth-child(6) { color: var(--primary); }

/* (b) White ink over an inverted brand fill — same treatment as .btn-primary. */
html[data-theme="dark"] .skip-to-content,
html[data-theme="dark"] .btn-secondary,
html[data-theme="dark"] .btn-secondary:hover,
html[data-theme="dark"] .rsv-chip-active,
html[data-theme="dark"] .rsv-chip-active:hover,
html[data-theme="dark"] .ops-board-toolbar .ops-board-tabs a.active,
html[data-theme="dark"] .time24-chip-on,
html[data-theme="dark"] .time24-chip-accent,
html[data-theme="dark"] .auth-portal-pill:hover,
html[data-theme="dark"] .filter-chips .filter-chip .x:hover,
html[data-theme="dark"] .topbar-bell-badge,
html[data-theme="dark"] .jags-pwa-auth-banner__icon,
html[data-theme="dark"] .jags-pwa-auth-banner__btn,
html[data-theme="dark"] .jags-pwa-install-card__icon,
html[data-theme="dark"] .jags-pwa-install-card__btn,
html[data-theme="dark"] .jags-pwa-modal-dialog__logo,
html[data-theme="dark"] .jags-pwa-modal-dialog__close,
html[data-theme="dark"] .qa-card.qa-card-primary .qa-icon,
html[data-theme="dark"] .qa-card.qa-card-primary:hover .qa-icon { color: var(--text-inverse); }
/* The bell badge's white halo ring belongs to the light chrome. */
html[data-theme="dark"] .topbar-bell-badge { box-shadow: 0 0 0 2px var(--card); }

/* (c) A light slab that survived into the dark theme. The ops board header
   follows table.tbl th / table.dr th onto a layered dark surface. */
html[data-theme="dark"] table.ops-board thead th { background: var(--surface-container); }

/* (d) The sidebar brand lockup keeps a LIGHT panel in this theme on purpose
   (--sidebar-brand-bg, so the locked dark-navy logo artwork stays crisp).
   Its subtitle must therefore keep the LIGHT muted ink instead of following
   --muted, which inverts to a pale grey and vanishes on that panel. */
html[data-theme="dark"] .sidebar-brand .brand-sub { color: #5E6472; }

/* Print stays a light paper document no matter the app theme. Resetting
   `body` alone is not enough: every retint above is more specific than body,
   so it would follow the ink onto white paper. The (a) inks are the ones that
   matter — they are LIGHT tints for a dark card and land at 1.7-2.5:1 on
   paper. Each is restated with its own light-theme literal, using the
   !important pattern `table.ops-board thead th` already uses below.
   The (b) selectors need nothing: --text-inverse is #0B0E1A in this theme, so
   they print as near-black ink; (c) is already covered by that thead rule and
   (d) is #5E6472 in both themes. */
@media print {
    html[data-theme="dark"] { color-scheme: light; }
    html[data-theme="dark"] body { background: #fff; color: #111; }

    html[data-theme="dark"] .rsv-status-scheduled,
    html[data-theme="dark"] .rsv-acft-type-pill-prominent          { color: #294019 !important; }
    html[data-theme="dark"] .rsv-aa-pill-warn                      { color: #7B5318 !important; }
    html[data-theme="dark"] .av2-feature.success .feat-val         { color: #2C4A1B !important; }
    html[data-theme="dark"] .fs-mobile-handoff strong              { color: #1F7A4D !important; }
    html[data-theme="dark"] table.ops-board.ops-mobile-schedule td:nth-child(6) { color: #183B63 !important; }
}
/* Baseline heading rhythm — page-level pages can still override per card. */
h1, h2, h3, h4 {
    font-family: var(--font-display);
    color: var(--text-strong);
    line-height: var(--line-tight);
    letter-spacing: var(--tracking-tight);
    margin: 0;
    font-weight: 600;
}
h1 { font-size: var(--text-2xl); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }
h4 { font-size: var(--text-base); font-weight: 600; }
p  { margin: 0 0 12px; }
a  { color: var(--link); text-decoration: none; }
a:hover { color: var(--primary); }
hr { border: none; border-top: 1px solid var(--border); margin: 24px 0; }
.muted        { color: var(--muted); }
.muted-strong { color: var(--muted-strong); }
.small        { font-size: var(--text-sm); }
.xs           { font-size: var(--text-xs); }
.mono         { font-family: var(--font-mono); }
.eyebrow {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--muted);
    font-weight: 600;
}

/* App shell */
.app-shell { min-height: 100vh; display: grid; grid-template-columns: 248px minmax(0, 1fr); }
.sidebar {
    /* Deep navy executive rail (2026-05-22 MVP UI pass) — premium dark
       sidebar over the white app canvas, on the JAGS navy/indigo brand.
       Tuned from the --sidebar-* tokens in :root so desktop + mobile drawer
       stay in lockstep. */
    background: var(--grad-sidebar);
    color: var(--sidebar-text);
    border-right: 1px solid var(--sidebar-border);
    padding: 20px 16px 24px;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,0.18) transparent;
}
.sidebar::-webkit-scrollbar { width: 6px; }
.sidebar::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.16); border-radius: 6px; }
.sidebar::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.28); }
.sidebar-brand {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    margin-bottom: 24px;
    padding: 10px;
    /* Light lockup panel — the logo asset is locked and may not be
       recoloured, so it keeps its own white card to stay crisp on the
       dark rail. */
    background: var(--sidebar-brand-bg);
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: var(--radius);
    box-shadow: 0 6px 18px rgba(5, 7, 22, 0.35);
}
.sidebar-brand img { width: 100%; height: auto; max-height: 56px; object-fit: contain; background: var(--sidebar-brand-bg); display: block; }
/* Animated brand mark (plays once per session, then rests on its final
   frame). The video is inert chrome: no pointer events, fixed 16:9 box so
   nothing shifts while it loads. Falls back to the static <img> above. */
.jags-brand-motion { display: block; width: 100%; }
.jags-brand-motion video {
    display: block; width: 100%; aspect-ratio: 16 / 9;
    /* Matches the static <img> chip directly above, NOT a theme surface.
       The logo artwork is dark navy, and object-fit:contain letterboxes a
       16:9 box around it — with --card here, dark mode painted those bars
       navy and the lockup read as two black slabs flanking the logo. */
    object-fit: contain; background: var(--sidebar-brand-bg);
    pointer-events: none; border-radius: 6px;
}
/* In the sidebar chip the mark keeps the compact lockup height the static
   logo had (max-height 56-64px), instead of a full-width 16:9 block that
   dominates the mobile drawer. Fixed height = still no layout shift. */
.sidebar-brand .jags-brand-motion video {
    aspect-ratio: auto; height: 64px; max-height: 64px;
}
.jags-brand-motion.jags-brand-motion-failed video { display: none; }
.jags-brand-motion .jags-brand-motion-fallback:not([hidden]) { display: block; }
.jags-brand-motion .jags-brand-motion-fallback[hidden] { display: none; }
.sidebar-brand .brand-sub { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.1em; text-align: center; padding-bottom: 2px; }
.sidebar-section {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--sidebar-muted);
    margin: 20px 10px 10px;
    font-weight: 600;
}
.sidebar nav a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 11px;
    border-radius: var(--radius-sm);
    color: var(--sidebar-text);
    font-weight: 500;
    font-size: var(--text-base);
    letter-spacing: -0.005em;
    margin-bottom: 2px;
    transition:
        background var(--motion-fast) var(--ease-out),
        color      var(--motion-fast) var(--ease-out),
        box-shadow var(--motion-fast) var(--ease-out),
        transform  var(--motion-fast) var(--ease-out);
    position: relative;
}
.sidebar nav a:hover { background: var(--sidebar-hover-bg); color: #fff; }
.sidebar nav a:hover .nav-icon { color: #fff; opacity: 1; }
.sidebar nav a.active {
    /* Selected nav — a frosted raised pill with a bright accent marker so
       the active destination reads clearly against the dark navy rail. */
    background: var(--sidebar-active-bg);
    color: #fff;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
}
.sidebar nav a.active .nav-icon { color: #fff; opacity: 1; }
.sidebar nav a.active::before {
    content: "";
    /* Pulled out to the panel's own edge. The -16px offset was tuned for the
       old 248px sidebar's 16px gutter; the panel's nav has 8px padding, so
       -16px painted the marker 8px INSIDE the 56px icon rail. */
    position: absolute; left: calc(-1 * var(--nav-list-gutter, 16px)); top: 8px; bottom: 8px;
    width: 3px; border-radius: 0 3px 3px 0;
    background: var(--sidebar-accent);
    opacity: 0.95;
}
.nav-icon {
    width: 18px; height: 18px;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--sidebar-muted);
    opacity: 0.92;
    transition: color var(--motion-fast) var(--ease-out), opacity var(--motion-fast) var(--ease-out);
    flex: 0 0 18px;
}
.nav-icon svg { width: 18px; height: 18px; display: block; }
.nav-icon .jags-icon-glyph { font-size: 14px; line-height: 1; }

/* ---------- Workspace panel page list ----------
   Every nav item carries a canonical 'group' (nav_workspace_group_for_item),
   so layout_header wraps each workspace's pages in a .nav-group. The rail
   decides which one is .is-current; the list itself is always flat. */
.sidebar nav.nav-grouped { display: flex; flex-direction: column; }
.sidebar nav.nav-grouped .nav-group { display: flex; flex-direction: column; gap: 1px; }
.nav-utilities { padding: 8px; position: relative; }
.nav-search-trigger, .nav-rail-toggle, .nav-settings-toggle, .nav-settings-reset {
    appearance: none; border: 1px solid var(--sidebar-border); color: var(--sidebar-text);
    background: rgba(255,255,255,.045); font: inherit; cursor: pointer;
}
.nav-search-trigger:hover, .nav-rail-toggle:hover, .nav-settings-toggle:hover { background: var(--sidebar-hover-bg); color:#fff; }
.nav-shortcut { margin-left:auto; color:var(--sidebar-muted); font: 600 10px/1 var(--font-mono); }
.nav-settings-toggle { width:100%; min-height:36px; border-radius:8px; display:flex; align-items:center; justify-content:center; gap:7px; font-size:12px; }
.nav-settings {
    margin-top:8px; padding:12px; border:1px solid var(--sidebar-border); border-radius:10px;
    background:#111735; box-shadow:0 14px 30px rgba(0,0,0,.28);
}
.nav-settings-title { color:#fff; font-weight:700; font-size:13px; }
.nav-settings p { margin:5px 0 10px; color:var(--sidebar-muted); font-size:11px; line-height:1.45; }
.nav-settings-groups { display:grid; gap:3px; }
.nav-settings-option { display:flex; align-items:center; gap:8px; min-height:32px; color:var(--sidebar-text); font-size:12px; }
.nav-settings-option input { width:16px; height:16px; accent-color:var(--sidebar-accent); }
.nav-settings-reset { width:100%; min-height:34px; margin-top:9px; border-radius:8px; font-size:12px; }
.nav-quick-access { margin:0 8px 8px; padding:8px; border:1px solid var(--sidebar-border); border-radius:10px; }
.nav-quick-access[hidden] { display:none; }
.nav-quick-title { color:var(--sidebar-muted); font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.08em; padding:0 4px 5px; }
.nav-quick-links { display:grid; gap:2px; }
.nav-quick-links a { margin:0 !important; min-height:36px !important; padding:7px 8px !important; }

/* The pin star overlays the row's right edge instead of taking a grid
   column, so the 204px panel spends its width on labels, not on a control
   that is invisible until hover. */
.nav-item-row { position:relative; }
.nav-item-row > a { min-width:0; padding-right:26px; }
.nav-pin {
    position:absolute; top:50%; right:5px; transform:translateY(-50%);
    width:24px; height:24px; padding:0; border:0; border-radius:6px;
    background:transparent; color:var(--sidebar-muted); cursor:pointer; opacity:0;
    line-height:1; font-size:13px;
}
.nav-item-row:hover .nav-pin, .nav-pin:focus-visible, .nav-pin.is-pinned { opacity:1; }
.nav-pin.is-pinned { color:#F4C96A; }
.nav-pin:hover { background:var(--sidebar-hover-bg); }

/* ================================================================
   WORKSPACE RAIL + CONTEXTUAL PANEL (2026-09-09)
   Replaces the department accordion as the desktop navigation model.
   Layer A (.ws-rail) answers "where can I go?"; Layer B (.ws-panel)
   answers "what can I do here?". Exactly one .nav-workspace carries
   .is-current, so the panel is always a flat list with no expanders.
   ================================================================ */
.ws-rail-tip { display:none; }
.ws-rail-btn {
    appearance:none; border:0; background:transparent; color:var(--sidebar-muted);
    font:inherit; cursor:pointer; width:100%;
    display:flex; align-items:center; gap:10px;
    min-height:40px; padding:8px 10px; border-radius:8px;
    text-align:left; position:relative;
}
.ws-rail-icon { display:inline-flex; width:22px; height:22px; flex:0 0 22px; }
.ws-rail-icon .jags-icon { width:22px; height:22px; }
.ws-rail-text { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:13px; }
.ws-rail-btn:hover { background:var(--sidebar-hover-bg); color:#fff; }
.ws-rail-btn.is-current { background:var(--sidebar-active-bg); color:#fff; }
.ws-rail-btn.is-hidden { display:none; }
.ws-rail-btn:focus-visible, .nav-rail-toggle:focus-visible, .nav-search-trigger:focus-visible {
    outline:2px solid var(--sidebar-accent); outline-offset:2px;
}
.ws-panel-head { padding:14px 12px 8px; }
.ws-panel-title {
    color:#fff; font-size:11px; font-weight:700;
    text-transform:uppercase; letter-spacing:.09em;
}
.ws-panel-sub { color:var(--sidebar-muted); font-size:11px; line-height:1.4; margin-top:3px; }
.nav-workspace.is-hidden { display:none; }

@media (min-width:901px) {
    /* Rail 68 + panel 224 = 292px docked, 68px on the rail alone.
       The panel is DOCKED on every desktop width (owner decision 2026-09-10).
       It used to dock only at >=1536px, chosen so the Operations board kept its
       ~1254px; the effect was that most windows showed an icon-only rail and
       had to click to read a workspace's pages. Labels visible by default won
       that trade. The cost is real and accepted: the content column gives up
       292px rather than 68px, so the widest boards reach their .table-wrap
       horizontal scroll sooner. Collapse is one click away when that width is
       wanted back, and the choice persists per browser. */
    .app-shell { grid-template-columns:292px minmax(0,1fr); }
    .sidebar {
        padding:0; overflow:hidden;
        display:grid; grid-template-columns:68px minmax(0,1fr);
    }
    /* Sized for the WORST case: 14 workspaces (the whole $groupOrder, which
       is what an Admin sees) plus brand, Search and Collapse, all reachable
       at 1366x768 without scrolling. The widening grew the buttons sideways,
       not taller, so the vertical budget holds: brand 48+8, 14x40 with 2px
       gaps, and a 40px Search + 40px Collapse under a hairline = 760px of 768.
       It is TIGHT — adding a 15th workspace, or a taller button, overflows and
       the short-viewport rule below takes over. Overflow stays visible so the icon
       tooltips can escape the 68px column; the short-viewport rule
       below trades tooltips for reachable controls when it truly cannot fit. */
    .ws-rail {
        grid-column:1; min-width:0;
        display:flex; flex-direction:column; align-items:center; gap:2px;
        padding:8px; overflow:visible;
        /* The rail reads as its own column, not as a strip that happens to be
           darker. A hairline alone was doing all the work at 56px; at 68px it
           gets a slightly deeper ground and a crisper edge so the eye lands on
           one boundary instead of hunting for it. */
        background:rgba(0,0,0,.16);
        border-right:1px solid var(--sidebar-border);
    }
    .ws-panel {
        grid-column:2; min-width:0;
        display:flex; flex-direction:column;
        overflow-y:auto;
        transition:opacity var(--motion-fast,160ms) var(--ease-out,ease);
    }
    .ws-panel > nav { flex:1 1 auto; padding:0 8px; --nav-list-gutter:8px; }
    .ws-panel > .sidebar-section { padding-left:16px; margin-top:4px; }
    .ws-panel > .sidebar-account { margin:0 8px 12px; }

    /* Brand: a restrained mark at the head of the rail, not a billboard. */
    /* The mark here is the square APPLICATION icon, not the wide lockup: the
       lockup is 2.2:1 and its "member of" line is illegible at this size. The
       icon is a finished object with its own ground and border, so the chip
       gets no panel, no border and no shadow of its own — that would be a card
       inside a card. */
    .ws-rail > .sidebar-brand {
        width:48px; height:48px; min-height:48px; padding:0; margin-bottom:8px;
        border:0; background:none; box-shadow:none; border-radius:10px;
        overflow:hidden; flex:0 0 auto;
    }
    .ws-rail > .sidebar-brand .sidebar-brand-mark {
        width:48px; height:48px; max-height:none; display:block; border-radius:12px;
    }
    .ws-rail > .sidebar-brand .brand-sub { display:none; }
    .ws-rail-nav { display:flex; flex-direction:column; gap:1px; width:100%; align-items:center; }
    .ws-rail-foot {
        margin-top:auto; padding-top:6px; display:flex; flex-direction:column;
        gap:3px; width:100%; align-items:center; flex:0 0 auto;
    }

    /* Rail buttons collapse to icon squares; the label becomes a tooltip. */
    .ws-rail-btn, .ws-rail-foot .nav-search-trigger, .ws-rail-foot .nav-rail-toggle {
        width:52px; min-width:52px; height:40px; min-height:40px; padding:0;
        flex:0 0 auto; justify-content:center; gap:0; border-radius:12px;
    }
    .ws-rail .ws-rail-text, .ws-rail .nav-label, .ws-rail .nav-shortcut { display:none; }
    .ws-rail-btn.is-current::before {
        content:""; position:absolute; left:-8px; top:50%; transform:translateY(-50%);
        width:3px; height:26px; border-radius:0 3px 3px 0; background:var(--sidebar-accent);
    }
    /* A separator above Search/Collapse so the utilities read as a foot rather
       than as two more workspaces. */
    .ws-rail-foot { border-top:1px solid var(--sidebar-border); }
    .ws-rail-tip {
        display:block; position:absolute; left:calc(100% + 10px); top:50%;
        transform:translateY(-50%);
        padding:5px 9px; border-radius:7px; white-space:nowrap;
        background:#111735; color:#fff; font-size:12px; font-weight:600;
        border:1px solid rgba(255,255,255,.12);
        box-shadow:0 10px 24px rgba(0,0,0,.34);
        opacity:0; pointer-events:none; z-index:9400;
        transition:opacity var(--motion-fast,160ms) var(--ease-out,ease);
    }
    .ws-rail-btn:hover .ws-rail-tip, .ws-rail-btn:focus-visible .ws-rail-tip,
    .nav-search-trigger:hover .ws-rail-tip, .nav-search-trigger:focus-visible .ws-rail-tip,
    .nav-rail-toggle:hover .ws-rail-tip, .nav-rail-toggle:focus-visible .ws-rail-tip { opacity:1; }

    /* Exactly one workspace in the panel — this is what retires the
       accordion. No expander, no second nesting level. */
    .ws-panel .nav-workspace { display:none; border:0; }
    .ws-panel .nav-workspace.is-current { display:block; }
    .ws-panel .nav-workspace.is-current.is-hidden { display:block; }

    /* ---- Compact mode: rail only, panel opens as a click-pinned flyout.
       Click, never hover: the panel cannot vanish because the pointer
       drifted, and it survives until Escape / another icon / outside. ---- */
    html.jags-nav-rail .app-shell { grid-template-columns:68px minmax(0,1fr); }
    /* .sidebar is position:sticky, so it forms its own stacking context: the
       flyout's z-index is scoped INSIDE it and would otherwise paint under
       .main, which follows in DOM order. Lift the whole context instead. */
    html.jags-nav-rail .sidebar { grid-template-columns:68px; overflow:visible; z-index:9300; }
    html.jags-nav-rail .ws-rail { overflow:visible; border-right:0; }
    html.jags-nav-rail .ws-panel {
        position:fixed; left:68px; top:0; bottom:0; width:224px; z-index:9300;
        background:var(--grad-sidebar);
        border-right:1px solid var(--sidebar-border);
        box-shadow:0 22px 54px rgba(0,0,0,.40);
        opacity:0; visibility:hidden;
        transform:translateX(-8px);
        transition:opacity 180ms var(--ease-out,ease), transform 180ms var(--ease-out,ease), visibility 0s linear 180ms;
    }
    html.jags-nav-rail.jags-ws-flyout-open .ws-panel {
        opacity:1; visibility:visible; transform:translateX(0);
        transition-delay:0s;
    }
    /* With the panel open the workspace names are on screen; a hover label
       over them is noise. §27: no tooltip when the text is already visible. */
    html.jags-ws-flyout-open .ws-rail-tip { display:none; }
    html.jags-nav-rail .nav-rail-toggle .nav-icon { transform:rotate(180deg); }
}

/* ---- Mobile / tablet drawer: the SAME one-workspace-at-a-time model, so
   the phone sheet has no accordion either. The rail becomes a horizontal
   scroller of workspace chips above the flat page list. ---- */
@media (max-width:900px) {
    .ws-rail { display:flex; flex-direction:column; }
    .ws-rail > .sidebar-brand { order:1; }
    .ws-rail-nav {
        order:2; display:flex; gap:6px; overflow-x:auto; overflow-y:hidden;
        padding:10px 2px 4px; margin:0 -4px;
        scrollbar-width:none; -webkit-overflow-scrolling:touch;
    }
    .ws-rail-nav::-webkit-scrollbar { height:0; }
    .ws-rail-btn {
        width:auto; flex:0 0 auto; min-height:40px; padding:8px 12px;
        border-radius:999px; border:1px solid var(--sidebar-border);
    }
    .ws-rail-btn.is-current { border-color:var(--sidebar-accent); }
    .ws-rail-foot { order:3; }
    .ws-rail-foot .nav-search-trigger {
        width:100%; min-height:44px; padding:9px 12px; border-radius:12px;
        display:flex; align-items:center; gap:9px; text-align:left;
    }
    /* Compact mode is a desktop idea — the phone sheet is always expanded. */
    .ws-rail-foot .nav-rail-toggle { display:none; }
    .ws-panel .nav-workspace { display:none; }
    .ws-panel .nav-workspace.is-current { display:block; }
    .ws-panel-head { padding:10px 4px 2px; }
}

/* The rail needs 760px for 14 workspaces. Below ~800px of viewport height it
   can run out of room (browser zoom, a short laptop window) — and the previous
   740px threshold left 741-759px clipping the Collapse button with no fallback.
   Scrolling clips the tooltips at the 68px column, which is the right trade:
   an unreachable Collapse button is a defect, a missing hover label is not.
   The buttons keep their title text either way. */
@media (min-width:901px) and (max-height:800px) {
    .ws-rail { overflow-y:auto; overflow-x:hidden; }
    .ws-rail::-webkit-scrollbar { width:0; }
}

/* ----------------------------------------------------------------
   PINNING — connecting the press to the thing that appears.
   ----------------------------------------------------------------
   You press a star in the middle of a list and a row materialises ABOVE
   it, in a different part of the panel, with nothing joining the two.
   Two small acknowledgements close that gap: the star confirms the press
   landed, and the row it created arrives rather than pops.

   Only on PIN. Unpinning is a removal, and a pleased little pulse for
   taking something away is dishonest feedback. */
.nav-pin.is-pinning { animation: jags-pin-pop 300ms var(--ease-premium, cubic-bezier(0.2, 0.8, 0.2, 1)); }
@keyframes jags-pin-pop {
    40% { transform: translateY(-50%) scale(1.35); }
    to  { transform: translateY(-50%) scale(1); }
}

.nav-quick-links a.is-arriving {
    animation: jags-quick-in var(--motion-med, 220ms)
               var(--ease-premium, cubic-bezier(0.2, 0.8, 0.2, 1)) both;
}
@keyframes jags-quick-in {
    from { opacity: 0; transform: translateX(-8px); }
}

/* The first pin is the moment Quick Access exists at all. */
.nav-quick-access.is-revealing {
    animation: jags-quick-reveal var(--motion-med, 220ms)
               var(--ease-premium, cubic-bezier(0.2, 0.8, 0.2, 1)) both;
}
@keyframes jags-quick-reveal {
    from { opacity: 0; transform: translateY(-6px); }
}

/* ----------------------------------------------------------------
   SWITCHING WORKSPACE — the rail's answer arriving.
   ----------------------------------------------------------------
   Pressing a rail icon replaces the panel's whole page list at once.
   Without a cue the panel just becomes different text and the icon you
   pressed is never connected to what changed. The list arrives FROM the
   rail — a short slide along the same axis the rail sits on — so the
   press and the result read as one movement.

   A list appearing as a list earns a stagger; a scrolled section does
   not. The delay is CAPPED at six rows (~90ms). Beyond that a stagger
   stops explaining anything and starts making people wait, and
   Administration has nineteen rows.

   Transform and opacity only, and only on the rows of the ONE visible
   workspace — the other thirteen sections are display:none and cost
   nothing. Applied by class on a real change, never on first paint. */
.ws-panel.is-entering .nav-workspace.is-current .nav-item-row {
    animation: jags-ws-row-in var(--motion-med, 220ms)
               var(--ease-premium, cubic-bezier(0.2, 0.8, 0.2, 1)) both;
}
.ws-panel.is-entering .nav-workspace.is-current .nav-item-row:nth-child(1) { animation-delay: 0ms; }
.ws-panel.is-entering .nav-workspace.is-current .nav-item-row:nth-child(2) { animation-delay: 18ms; }
.ws-panel.is-entering .nav-workspace.is-current .nav-item-row:nth-child(3) { animation-delay: 36ms; }
.ws-panel.is-entering .nav-workspace.is-current .nav-item-row:nth-child(4) { animation-delay: 54ms; }
.ws-panel.is-entering .nav-workspace.is-current .nav-item-row:nth-child(5) { animation-delay: 72ms; }
/* Everything from the sixth row on shares the cap — no growing wait. */
.ws-panel.is-entering .nav-workspace.is-current .nav-item-row:nth-child(n+6) { animation-delay: 90ms; }

/* The heading changes too, and it changes FIRST — it is the label for
   everything below it. */
.ws-panel.is-entering .ws-panel-head {
    animation: jags-ws-head-in var(--motion-fast, 140ms)
               var(--ease-premium, cubic-bezier(0.2, 0.8, 0.2, 1)) both;
}

@keyframes jags-ws-row-in {
    from { opacity: 0; transform: translateX(-10px); }
}
@keyframes jags-ws-head-in {
    from { opacity: 0; }
}

/* ================================================================
   COLLAPSING THE PANEL — the one authored moment in the shell.
   ================================================================
   Layer B (what can I do here) folding back into Layer A (where can I
   go) is the spatial relationship this navigation is built on, and the
   only reversible layout change the user performs deliberately. It is
   worth explaining; nothing else in the shell is.

   It is driven by a View Transition, not by transitioning
   grid-template-columns: that would reflow the whole page every frame,
   and on the Operations board that is precisely the cost we refuse to
   pay. The browser takes ONE snapshot and interpolates on the
   compositor, so the price is flat whatever the page is showing.

   Three elements are named, and each name earns itself:
     .ws-rail   — anchored. Naming it lifts it OUT of the root snapshot
                  so the icons never cross-fade against themselves,
                  which is where "ghosting" comes from. It does not move,
                  and it should not appear to.
     .ws-panel  — the thing actually leaving and arriving. It gets the
                  authored slide.
     .main      — named so the content box is INTERPOLATED (a real
                  resize on the compositor) rather than cross-faded
                  between two differently-sized textures.
   Names are applied only while the transition runs — see
   jags-nav-anim in layout.php — because view-transition-name creates a
   stacking context, and .ws-panel is position:fixed in rail mode.

   Exit is faster than entrance: leaving should feel decisive, arriving
   should feel settled. */
html.jags-nav-anim .ws-rail  { view-transition-name: jags-rail; }
html.jags-nav-anim .ws-panel { view-transition-name: jags-panel; }
html.jags-nav-anim .main     { view-transition-name: jags-main; }

::view-transition-group(jags-main),
::view-transition-group(jags-panel) {
    animation-duration: var(--motion-slow, 380ms);
    animation-timing-function: var(--ease-premium, cubic-bezier(0.2, 0.8, 0.2, 1));
}
/* The content box resizes; its pixels must not cross-fade through the
   change or the table appears to double. Hold the new frame and let the
   GROUP do the moving. */
::view-transition-old(jags-main) { animation: none; opacity: 0; }
::view-transition-new(jags-main) { animation: none; opacity: 1; }

::view-transition-old(jags-panel) {
    animation: jags-panel-leave var(--motion-med, 220ms)
               var(--ease-premium, cubic-bezier(0.2, 0.8, 0.2, 1)) both;
}
::view-transition-new(jags-panel) {
    animation: jags-panel-arrive var(--motion-slow, 380ms)
               var(--ease-premium, cubic-bezier(0.2, 0.8, 0.2, 1)) both;
}
@keyframes jags-panel-leave {
    to { opacity: 0; transform: translateX(-16px); }
}
@keyframes jags-panel-arrive {
    from { opacity: 0; transform: translateX(-16px); }
}

/* The rail is the fixed point of the whole move. */
::view-transition-group(jags-rail) { animation-duration: 0s; }

@media (prefers-reduced-motion:reduce) {
    .ws-panel, .ws-rail-tip, .app-shell, .sidebar { transition-duration:.01ms !important; }
    /* Belt and braces: the script already declines to add .is-entering, but the
       stylesheet must not need the script to be correct. */
    .ws-panel.is-entering .nav-workspace.is-current .nav-item-row,
    .ws-panel.is-entering .ws-panel-head,
    .nav-pin.is-pinning,
    .nav-quick-links a.is-arriving,
    .nav-quick-access.is-revealing { animation: none !important; }
}
/* ---------- End admin grouped workspace navigation ---------- */
.sidebar-account {
    margin-top: 12px;
    padding: 10px 11px;
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid var(--sidebar-border);
    display: flex; align-items: center; gap: 10px;
}
.sidebar-account .who { min-width: 0; flex: 1; line-height: 1.2; }
.sidebar-account .who .name {
    font-weight: 600; font-size: var(--text-sm);
    color: var(--sidebar-text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sidebar-account .who .role {
    font-size: var(--text-xs); color: var(--sidebar-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sidebar-account form { margin: 0; }
.sidebar-account .btn-icon {
    width: 28px; height: 28px;
    padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 8px;
    border: 1px solid transparent;
    background: transparent;
    color: var(--sidebar-muted);
    cursor: pointer;
    transition: background var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out);
}
.sidebar-account .btn-icon:hover { background: rgba(184,50,53,0.22); color: #F4A8AA; }
.sidebar-account .btn-icon:focus-visible {
    outline: none;
    box-shadow: var(--ring-focus);
}

.main { display: flex; flex-direction: column; min-width: 0; }
.topbar {
    background: rgba(var(--glass-rgb), 0.78);
    backdrop-filter: saturate(160%) blur(12px);
    -webkit-backdrop-filter: saturate(160%) blur(12px);
    border-bottom: 1px solid var(--border);
    padding: 14px 28px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: sticky;
    top: 0;
    z-index: 10;
}
.topbar h1 {
    margin: 0;
    font-size: var(--text-2xl);
    letter-spacing: var(--tracking-tight);
    font-weight: 700;
    color: var(--text-strong);
    line-height: 1.1;
}
.topbar-leading { display: flex; align-items: center; gap: 14px; min-width: 0; }
/* Role eyebrow + date — the quiet context lines around the page title.
   Visible at every size (the premium mobile layer re-tunes them <=900px)
   so the title block reads: eyebrow / strong title / subdued date. */
.mobile-page-context,
.mobile-page-meta { display: block; }
.mobile-page-context {
    color: var(--text-secondary);
    font-size: 12.5px;
    font-weight: 650;
    line-height: 1.2;
}
.mobile-page-meta {
    margin-top: 3px;
    color: var(--text-tertiary);
    font-size: 13px;
    line-height: 1.25;
}
/* Topbar search pill — visible affordance for the ⌘K command palette
   (the reference's "beautiful search bar"). Reuses the existing palette;
   no second search system. Full pill on wide desktop, icon-only on narrow
   desktop, hidden on phones (drawer/bottom-nav own navigation there). */
.topbar-search {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-left: 8px;
    padding: 7px 10px 7px 12px;
    min-width: 210px;
    max-width: 320px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--surface-low);
    color: var(--muted);
    font-size: var(--text-sm);
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    text-align: left;
    line-height: 1;
    transition:
        background var(--motion-fast) var(--ease-out),
        border-color var(--motion-fast) var(--ease-out),
        box-shadow var(--motion-fast) var(--ease-out);
}
.topbar-search:hover { background: var(--card); border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.topbar-search:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.topbar-search-icon { display: inline-flex; align-items: center; color: var(--muted); flex: 0 0 auto; }
.topbar-search-text { flex: 1 1 auto; color: var(--muted); }
.topbar-search-kbd {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--muted-strong);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 3px 6px;
    line-height: 1;
}
/* Narrow desktop / tablet — collapse to a 36px circle that matches the
   bell / refresh controls so the topbar never crowds the page title. */
@media (max-width: 1180px) {
    .topbar-search {
        min-width: 0; max-width: none;
        width: 36px; height: 36px;
        padding: 0; gap: 0;
        justify-content: center;
        background: rgba(90,121,165,0.08);
    }
    .topbar-search-text, .topbar-search-kbd { display: none; }
}
@media (max-width: 900px) { .topbar-search { display: none; } }
.topbar-user { display: flex; align-items: center; gap: 12px; font-size: var(--text-sm); }
.topbar-user .who { line-height: 1.15; text-align: right; }
.topbar-user .who .name { font-weight: 600; color: var(--text-strong); }
.topbar-user .who .role { font-size: var(--text-xs); color: var(--muted); margin-top: 1px; letter-spacing: 0.01em; }

/* Notification bell — sits between Walkthrough and the user avatar. Quiet
   when there is nothing new (just the icon) and grows a small red badge with
   the unread count when there is. Clicking opens the notifications page. */
.topbar-bell {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    border-radius: 999px;
    color: var(--text-strong);
    background: rgba(90,121,165,0.08);
    border: 1px solid var(--border);
    text-decoration: none;
    transition: background var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out);
}
.topbar-bell:hover  { background: rgba(90,121,165,0.18); color: var(--primary); }
.topbar-bell:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.topbar-bell-icon { display: inline-flex; align-items: center; justify-content: center; }
.topbar-bell-badge {
    position: absolute;
    top: -4px; right: -4px;
    min-width: 18px; height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--danger);
    color: #fff;
    font-size: 10.5px; font-weight: 700;
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: 0 0 0 2px rgba(255,255,255,0.95);
    line-height: 1;
}
@media (max-width: 700px) {
    .topbar-bell { width: 32px; height: 32px; }
}

/* Discreet topbar refresh control — sits between Walkthrough and the
   bell. Clicking forces a fresh GET reload of the current URL so the
   user can pull updated data without using the browser refresh button
   (which can resubmit POSTs). Spinner state matches the existing
   submit-loading spinner so the page feels consistent. The "Last
   refreshed HH:MM" timestamp is exposed as a tooltip; no extra layout
   shift on the page. */
.topbar-refresh {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    padding: 0;
    border-radius: 999px;
    color: var(--text-strong);
    background: rgba(90,121,165,0.08);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: background var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out);
}
.topbar-refresh:hover { background: rgba(90,121,165,0.18); color: var(--primary); }
.topbar-refresh:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.topbar-refresh .topbar-refresh-icon { display: inline-flex; align-items: center; justify-content: center; }
.topbar-refresh.is-refreshing { pointer-events: none; opacity: 0.65; cursor: wait; }
.topbar-refresh.is-refreshing .topbar-refresh-icon { animation: jagsSpin 700ms linear infinite; }
@media (prefers-reduced-motion: reduce) {
    .topbar-refresh.is-refreshing .topbar-refresh-icon { animation: none; }
}
@media (max-width: 700px) {
    .topbar-refresh { width: 32px; height: 32px; }
}

/* ---------------------------------------------------------------
   Inline SVG icons + avatars.
   --------------------------------------------------------------- */
.jags-icon { display: inline-block; vertical-align: middle; flex: 0 0 auto; }
.jags-icon-glyph { display: inline-block; line-height: 1; }
.jags-icon-missing { display: inline-block; width: 18px; height: 18px; }
.btn .jags-icon { width: 16px; height: 16px; }
.btn-sm .jags-icon { width: 14px; height: 14px; }

.jags-avatar {
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px;
    background: var(--grad-jags);
    color: #fff;
    font-weight: 600;
    letter-spacing: 0.02em;
    box-shadow: var(--shadow-sm);
    line-height: 1;
    flex-shrink: 0;
    overflow: hidden;
    user-select: none;
}
.jags-avatar-sm { width: 28px; height: 28px; font-size: 11px; }
.jags-avatar-md { width: 36px; height: 36px; font-size: 13px; }
.jags-avatar-lg { width: 56px; height: 56px; font-size: 18px; }
.jags-avatar-initials { display: block; }
.jags-avatar-glyph { color: #fff; opacity: 0.85; }
.jags-avatar-empty { background: linear-gradient(180deg, #5A79A5, #274270); }

/* Role-tinted thin ring around the avatar — purely decorative. */
.jags-avatar-ring { box-shadow: var(--shadow-sm), 0 0 0 2px rgba(255,255,255,0.85), 0 0 0 3.5px rgba(94,100,114,0.30); }
.jags-avatar-ring-admin       { box-shadow: var(--shadow-sm), 0 0 0 2px rgba(255,255,255,0.92), 0 0 0 3.5px rgba(184,50,53,0.55); }
.jags-avatar-ring-tr          { box-shadow: var(--shadow-sm), 0 0 0 2px rgba(255,255,255,0.92), 0 0 0 3.5px rgba(90,121,165,0.55); }
.jags-avatar-ring-operations  { box-shadow: var(--shadow-sm), 0 0 0 2px rgba(255,255,255,0.92), 0 0 0 3.5px rgba(216,181,109,0.65); }
.jags-avatar-ring-maintenance { box-shadow: var(--shadow-sm), 0 0 0 2px rgba(255,255,255,0.92), 0 0 0 3.5px rgba(216,181,109,0.65); }
.jags-avatar-ring-pilot       { box-shadow: var(--shadow-sm), 0 0 0 2px rgba(255,255,255,0.92), 0 0 0 3.5px rgba(74,103,51,0.55); }
.jags-avatar-ring-viewer      { box-shadow: var(--shadow-sm), 0 0 0 2px rgba(255,255,255,0.92), 0 0 0 3.5px rgba(94,100,114,0.40); }

/* Legacy .avatar — keep so any pre-existing markup outside layout.php
   still renders. New code should use user_avatar(). */
.avatar {
    width: 36px; height: 36px; border-radius: 999px;
    background: var(--grad-jags);
    color: #fff; font-weight: 600; font-size: 13px;
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: var(--shadow-sm);
}
.content { padding: 28px; }

/* Page entrance — every navigation fades content in with a 6px settle.
   Suppressed in print and under prefers-reduced-motion (see below). */
.main > .content {
    animation: jagsPageIn var(--motion-med) var(--ease-premium) both;
}
@keyframes jagsPageIn {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Cards */
.card {
    background: var(--surface-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
    padding: 22px;
    transition:
        box-shadow var(--motion-med) var(--ease-soft),
        border-color var(--motion-med) var(--ease-soft);
}
.card + .card { margin-top: 18px; }
/* Hero card — Apple-style premium dark panel. Top hairline highlight,
   ambient corner glow, refined typography hierarchy. Used by any page
   that wants a brand moment at the top of its content. */
.card-hero {
    /* Theme-stable ink for anything sitting on the gradient: the hero stays navy in
       both themes, so --text-inverse (which retints) is wrong here. */
    --hero-ink: #FFFFFF;
    --hero-on-ink: #171756;
    position: relative;
    overflow: hidden;
    background: var(--grad-jags);
    color: #fff;
    border: none;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: 28px 32px;
}
.card-hero::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 1px;
    background: linear-gradient(90deg,
        rgba(255,255,255,0) 0%,
        rgba(255,255,255,0.18) 30%,
        rgba(255,255,255,0.22) 50%,
        rgba(255,255,255,0.18) 70%,
        rgba(255,255,255,0) 100%);
    pointer-events: none;
    z-index: 1;
}
.card-hero::after {
    content: "";
    position: absolute;
    top: -120px; right: -120px;
    width: 380px; height: 380px;
    background: radial-gradient(circle, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 65%);
    pointer-events: none;
    z-index: 0;
}
.card-hero > * { position: relative; z-index: 2; }
.card-hero h1, .card-hero h2, .card-hero h3, .card-hero h4 {
    margin: 0 0 6px;
    letter-spacing: -0.03em;
    color: #fff;
    font-weight: 700;
}
.card-hero p { margin: 0; opacity: 0.85; color: #fff; }

.section-title {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
    margin: 0 0 14px;
}
.section-title h2 {
    margin: 0;
    font-size: var(--text-lg);
    letter-spacing: -0.02em;
    font-weight: 650;
    color: var(--text-strong);
}
.section-title .muted { font-size: var(--text-sm); }
.card-hero h2 {
    font-size: var(--text-3xl);
    letter-spacing: -0.04em;
    font-weight: 700;
    line-height: 1.1;
    color: #fff;
}
.card-hero p { font-size: var(--text-base); line-height: var(--line-relaxed); }

/* ----------------------------------------------------------------------
   Reusable polished primitives — work on any page.

   .hero-eyebrow      — small uppercase label inside dark hero cards
   .metadata-chips    — inline metadata row with thin vertical dividers
   .metadata-chips .chip
   .feature-value     — large lead number on a tinted band inside a card
   .row-list          — Apple Settings-style key/value list with dividers
   .modern-card-head  — card header with icon chip + title + corner meta
   ---------------------------------------------------------------------- */
.hero-eyebrow {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(255,255,255,0.62);
    margin: 0 0 6px;
}
/* Light-surface variant of metadata-chips for use outside hero cards */


.row-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.row-list li {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 14px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
    min-width: 0;
}
.row-list li:last-child { border-bottom: none; padding-bottom: 0; }
.row-list .k {
    font-size: 13px;
    color: var(--muted);
    font-weight: 500;
    flex-shrink: 0;
}
.row-list .v {
    font-size: 14px;
    color: var(--text-strong);
    font-weight: 600;
    text-align: right;
    min-width: 0;
    word-break: break-word;
}
.row-list .v.mono {
    font-family: var(--font-mono);
    font-feature-settings: 'tnum' 1, 'lnum' 1;
}
.row-list .v .sub {
    display: block;
    font-size: 11.5px;
    color: var(--muted);
    font-weight: 500;
    margin-top: 2px;
}

/* Countdown chip — semantic-coloured pill for date countdowns, etc. */

/* Card section title — drop-in replacement for the inline-styled
   `<h3 style="margin:0 0 10px; font-size:15px;">` pattern used inside
   .card blocks. Slightly tighter than .section-title h2. */
.card-section-title {
    margin: 0 0 12px;
    font-size: 15px;
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--text-strong);
}

/* ====================================================================
   Skip-to-content — first focusable element on the page. Hidden until
   focused so keyboard users can jump straight past the chrome.
   ==================================================================== */
.skip-to-content {
    position: fixed;
    top: -100px; left: 16px;
    z-index: 99999;
    background: var(--primary);
    color: #fff;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    box-shadow: var(--shadow-md);
    transition: top var(--motion-fast) var(--ease-out);
}
.skip-to-content:focus,
.skip-to-content:focus-visible {
    top: 16px;
    outline: none;
    box-shadow: 0 0 0 3px rgba(90,121,165,0.45), var(--shadow-md);
}

/* ====================================================================
   Toast notifications — replace the top-of-page flash strip with a
   slide-in stack in the bottom-right corner. Stacks up to 5 visible
   toasts; older ones auto-dismiss after 5s.
   ==================================================================== */
.jags-toast-region {
    position: fixed;
    bottom: 24px; right: 24px;
    z-index: 9500;
    display: flex; flex-direction: column-reverse;
    gap: 10px;
    pointer-events: none;
    max-width: min(420px, calc(100vw - 32px));
}
.jags-toast {
    pointer-events: auto;
    display: flex; align-items: flex-start; gap: 10px;
    padding: 12px 14px;
    border-radius: var(--radius);
    background: var(--card);
    border: 1px solid var(--border);
    box-shadow: 0 12px 32px rgba(11,11,47,0.18), 0 2px 6px rgba(11,11,47,0.06);
    font-size: 13.5px;
    line-height: 1.45;
    color: var(--text);
    animation: jagsToastIn 220ms var(--ease-premium);
    will-change: transform, opacity;
}
.jags-toast.is-leaving { animation: jagsToastOut 180ms var(--ease-out) forwards; }
.jags-toast .toast-icon {
    flex: 0 0 18px;
    width: 18px; height: 18px;
    display: inline-flex; align-items: center; justify-content: center;
    margin-top: 1px;
    color: var(--secondary);
}
.jags-toast .toast-body { flex: 1 1 auto; min-width: 0; word-break: break-word; }
.jags-toast .toast-close {
    flex: 0 0 auto;
    background: transparent; border: none;
    width: 24px; height: 24px;
    border-radius: 999px;
    color: var(--muted);
    font-size: 16px; line-height: 1;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0;
    transition: background var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out);
}
.jags-toast .toast-close:hover { background: rgba(94,100,114,0.12); color: var(--text); }
.jags-toast .toast-close:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.jags-toast.success { border-color: rgba(74,103,51,0.36); background: linear-gradient(180deg, rgba(74,103,51,0.04), #fff); }
.jags-toast.success .toast-icon { color: var(--success); }
.jags-toast.warn    { border-color: rgba(216,181,109,0.50); background: linear-gradient(180deg, rgba(216,181,109,0.06), #fff); }
.jags-toast.warn    .toast-icon { color: #B6883A; }
.jags-toast.danger  { border-color: rgba(184,50,53,0.40); background: linear-gradient(180deg, rgba(184,50,53,0.04), #fff); }
.jags-toast.danger  .toast-icon { color: #B83235; }
.jags-toast.info    { border-color: rgba(90,121,165,0.36); background: linear-gradient(180deg, rgba(90,121,165,0.05), #fff); }
.jags-toast.info    .toast-icon { color: var(--info); }
@keyframes jagsToastIn  { from { opacity: 0; transform: translateY(12px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } }
@keyframes jagsToastOut { to { opacity: 0; transform: translateY(8px) scale(0.98); } }
@media (max-width: 700px) {
    .jags-toast-region { left: 12px; right: 12px; bottom: var(--mobile-bottom-nav-clearance); max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
    .jags-toast { animation: none !important; }
}
@media print {
    .jags-toast-region,
    .user-menu-popover,
    .bell-popover,
    .bell-wrap,
    .user-menu,
    .cmdk-modal,
    .skip-to-content { display: none !important; }
    .jags-flash-region { display: none !important; }
    /* Re-show flash messages on print via the noscript fallback. */

    /* ----------------------------------------------------------------
       Operational-document print overflow safety (2026-05-30 polish
       sprint). Long unbroken tokens — route strings, registration/code
       cells, consignor/consignee names, and free-text remarks/notes —
       must wrap to the page instead of clipping off the right edge of
       dispatch packs, radio logs, the Daily Report, and W&B records.
       `overflow-wrap: anywhere` only breaks a word when it would
       otherwise overflow its box, so normal prose, headings, and short
       codes are visually unchanged. Print-only: screen layout untouched.
       ---------------------------------------------------------------- */
    td, th { overflow-wrap: anywhere; }
    .pre-wrap, [style*="pre-wrap"] { overflow-wrap: anywhere; }

    /* ----------------------------------------------------------------
       Wide horizontal-scroll boards must collapse to fit the page on
       print instead of clipping at the scroll container's right edge.
       The Compliance whiteboard table is laid out at min-width:1100px
       inside an overflow-x:auto wrapper for the screen — neither survives
       an A4/Letter page. Unlock both for print only; the cell wrapping
       rule above keeps the content legible. Pilot Compliance already
       ships its own print parity, so it is intentionally not touched.
       ---------------------------------------------------------------- */
    .cb-board-scroll { overflow-x: visible !important; }
    .cb-board { min-width: 0 !important; }
}

/* ====================================================================
   User-menu dropdown — replaces the static .topbar-user block. Click
   the avatar/name to open a popover with profile/settings/logout.
   ==================================================================== */
.user-menu-button {
    display: flex; align-items: center; gap: 12px;
    padding: 4px 6px 4px 10px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--text-sm);
    color: var(--text-strong);
    transition: background var(--motion-fast) var(--ease-out), border-color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out);
}
.user-menu-button .who { line-height: 1.15; text-align: right; }
.user-menu-button .who .name { font-weight: 600; color: var(--text-strong); }
.user-menu-button .who .role { font-size: var(--text-xs); color: var(--muted); margin-top: 1px; letter-spacing: 0.01em; }
.user-menu-button:hover { background: rgba(90,121,165,0.06); border-color: var(--border); }
.user-menu-button:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.user-menu-button[aria-expanded="true"] { background: rgba(90,121,165,0.10); border-color: var(--border-strong); }

.user-menu {
    position: relative;
}
.user-menu-popover {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    min-width: 240px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 16px 40px rgba(11,11,47,0.16), 0 2px 6px rgba(11,11,47,0.06);
    padding: 6px;
    display: none;
    z-index: 100;
    animation: jagsPopoverIn 160ms var(--ease-out);
}
.user-menu-popover.is-open { display: block; }
.user-menu-popover .menu-head {
    padding: 10px 12px 8px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 6px;
}
.user-menu-popover .menu-head .name { font-weight: 600; color: var(--text-strong); font-size: 13.5px; line-height: 1.25; }
.user-menu-popover .menu-head .email { font-size: 12px; color: var(--muted); margin-top: 2px; word-break: break-all; }
.user-menu-popover .menu-item {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    color: var(--text);
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    background: transparent;
    border: none;
    width: 100%;
    text-align: left;
    font-family: inherit;
    line-height: 1.3;
}
.user-menu-popover .menu-item:hover { background: rgba(90,121,165,0.08); color: var(--primary); }
.user-menu-popover .menu-item:focus-visible { outline: none; background: rgba(90,121,165,0.12); box-shadow: 0 0 0 2px var(--secondary) inset; }
.user-menu-popover .menu-item .ico {
    width: 18px; height: 18px;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--muted);
    flex: 0 0 18px;
}
.user-menu-popover .menu-divider { height: 1px; background: var(--border); margin: 6px 4px; }
.user-menu-popover form { margin: 0; }
.user-menu-popover .menu-item.danger { color: var(--status-danger-ink); }
.user-menu-popover .menu-item.danger:hover { background: rgba(184,50,53,0.08); }
@keyframes jagsPopoverIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }

/* ====================================================================
   Bell popover — recent notifications inline.
   ==================================================================== */
.bell-popover {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: min(380px, calc(100vw - 32px));
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 16px 40px rgba(11,11,47,0.16), 0 2px 6px rgba(11,11,47,0.06);
    display: none;
    z-index: 100;
    animation: jagsPopoverIn 160ms var(--ease-out);
    overflow: hidden;
}
.bell-popover.is-open { display: block; }
.bell-wrap { position: relative; display: inline-block; }
.bell-popover .bell-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px;
    padding: 12px 14px 10px;
    border-bottom: 1px solid var(--border);
}
.bell-popover .bell-head .ttl { font-weight: 700; font-size: 14px; color: var(--text-strong); }
.bell-popover .bell-head .count { font-size: 11px; color: var(--muted); }
.bell-popover .bell-list {
    list-style: none; margin: 0; padding: 0;
    max-height: 360px; overflow-y: auto;
}
.bell-popover .bell-list li {
    border-bottom: 1px solid var(--border);
}
.bell-popover .bell-list li:last-child { border-bottom: none; }
.bell-popover .bell-list a {
    display: block;
    padding: 10px 14px;
    text-decoration: none;
    color: var(--text);
    transition: background var(--motion-fast) var(--ease-out);
}
.topbar-bell { min-width:44px;min-height:44px; }
.bell-popover .bell-list a { min-height:52px; }
.bell-popover .bell-foot form { margin:0; }
.bell-mark-all { border:0;background:transparent;color:var(--secondary);font:inherit;font-size:12.5px;font-weight:600;cursor:pointer;padding:8px; }
.bell-mark-all:hover,.bell-mark-all:focus-visible { text-decoration:underline; }
.bell-popover .bell-list a:hover { background: rgba(90,121,165,0.06); }
.bell-popover .bell-list a:focus-visible { outline: none; background: rgba(90,121,165,0.12); }
.bell-popover .bell-list .ttl-line {
    font-weight: 600;
    font-size: 13px;
    color: var(--text-strong);
    line-height: 1.35;
    word-break: break-word;
}
.bell-popover .bell-list .meta-line {
    font-size: 11.5px;
    color: var(--muted);
    margin-top: 2px;
}
.bell-popover .bell-list li.unread .ttl-line::before {
    content: "";
    display: inline-block;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--info);
    margin-right: 6px;
    vertical-align: middle;
}
.bell-popover .bell-empty {
    padding: 28px 18px;
    text-align: center;
    color: var(--muted);
    font-size: 13px;
}
.bell-popover .bell-empty svg { color: var(--border-strong); margin-bottom: 6px; }
.bell-popover .bell-foot {
    border-top: 1px solid var(--border);
    padding: 8px 14px;
    display: flex; align-items: center; justify-content: space-between;
}
.bell-popover .bell-foot a { font-size: 12.5px; font-weight: 600; }

/* ====================================================================
   Missing Risk Assessment departure escalation — authenticated bell and
   Notification Centre only. Ordinary notification rules remain unchanged.
   ==================================================================== */
.bell-popover .bell-list li.bell-item--departure-escalation {
    border-left: 4px solid var(--danger);
    background: color-mix(in srgb, var(--danger) 7%, var(--card));
}
.bell-popover .bell-list li.bell-item--departure-escalation a {
    padding-left: 12px;
    overflow-wrap: anywhere;
}
.bell-escalation-heading {
    display: flex;
    align-items: center;
    gap: 7px;
    color: var(--danger);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: .055em;
    line-height: 1.25;
}
.bell-escalation-shield {
    display: inline-flex;
    flex: 0 0 auto;
}
.bell-escalation-statement {
    margin-top: 5px;
    color: var(--text-strong);
    font-size: 12.5px;
    font-weight: 650;
    line-height: 1.4;
    overflow-wrap: anywhere;
}
.notif-item--departure-escalation {
    margin: 10px 0;
    border: 2px solid color-mix(in srgb, var(--danger) 65%, var(--border));
    border-left-width: 6px;
    border-radius: 12px;
    background: color-mix(in srgb, var(--danger) 6%, var(--card));
    overflow: hidden;
}
.notif-item--departure-escalation:last-child { border-bottom: 2px solid color-mix(in srgb, var(--danger) 65%, var(--border)); }
.notif-item--departure-escalation .notif-escalation-link {
    grid-template-columns: 42px minmax(0, 1fr) max-content;
    gap: 14px;
    align-items: start;
    padding: 16px;
}
.notif-item--departure-escalation .notif-escalation-shield {
    width: 42px;
    height: 42px;
    color: var(--danger);
    background: color-mix(in srgb, var(--danger) 13%, var(--card));
}
.notif-item--departure-escalation .notif-escalation-body,
.notif-item--departure-escalation .notif-escalation-statement,
.notif-item--departure-escalation .notif-escalation-detail {
    min-width: 0;
    overflow-wrap: anywhere;
}
.notif-escalation-heading {
    display: flex;
    align-items: center;
    gap: 7px;
    color: var(--danger);
    font-size: 12px;
    font-weight: 850;
    letter-spacing: .065em;
    line-height: 1.3;
}
.notif-escalation-statement {
    margin-top: 7px;
    color: var(--text-strong);
    font-size: 14px;
    font-weight: 700;
    line-height: 1.45;
}
.notif-escalation-details {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 5px 16px;
    margin-top: 11px;
}
.notif-escalation-detail {
    color: var(--muted-strong);
    font-size: 12.5px;
    line-height: 1.4;
}
.notif-escalation-status {
    color: var(--danger);
    font-weight: 800;
}
.notif-escalation-action {
    align-self: center;
    color: var(--danger);
    font-size: 12.5px;
    font-weight: 750;
    white-space: nowrap;
}
@media (max-width: 700px) {
    .notif-item--departure-escalation .notif-escalation-link {
        grid-template-columns: 36px minmax(0, 1fr);
        gap: 10px;
        padding: 14px;
    }
    .notif-item--departure-escalation .notif-escalation-shield {
        width: 36px;
        height: 36px;
    }
    .notif-item--departure-escalation .notif-escalation-details {
        grid-template-columns: minmax(0, 1fr);
    }
    .notif-item--departure-escalation .notif-escalation-action {
        grid-column: 2;
        justify-self: start;
        white-space: normal;
    }
}

/* ====================================================================
   Cmd-K quick switcher — modal with search + categorised results.
   ==================================================================== */
.cmdk-modal {
    position: fixed;
    inset: 0;
    z-index: 9300;
    display: none;
    align-items: flex-start;
    justify-content: center;
    padding-top: clamp(60px, 12vh, 140px);
    padding-left: 16px; padding-right: 16px;
}
.cmdk-modal.is-open { display: flex; }
.cmdk-modal[hidden] {
    display: none !important;
    pointer-events: none !important;
}
.cmdk-backdrop {
    position: absolute; inset: 0;
    background: rgba(11,11,47,0.45);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    animation: jagsTourFade 180ms ease-out;
}
.cmdk-panel {
    position: relative;
    width: min(640px, 100%);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: 0 24px 60px rgba(11,11,47,0.30), 0 4px 12px rgba(11,11,47,0.12);
    overflow: hidden;
    animation: jagsTourPop 200ms var(--ease-premium);
    display: flex; flex-direction: column;
    max-height: min(560px, calc(100vh - 120px));
}
.cmdk-input-wrap {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
    background: var(--surface);
}
.cmdk-input-wrap svg { color: var(--muted); flex-shrink: 0; }
.cmdk-input {
    flex: 1 1 auto;
    border: none;
    background: transparent;
    font-size: 15px;
    color: var(--text);
    font-family: inherit;
    outline: none;
    line-height: 1.4;
}
.cmdk-input::placeholder { color: var(--muted); }
.cmdk-hint {
    font-size: 11px;
    color: var(--muted);
    background: rgba(90,121,165,0.08);
    border: 1px solid var(--border);
    padding: 2px 6px;
    border-radius: 4px;
    font-family: var(--font-mono);
    flex-shrink: 0;
}
.cmdk-results { flex: 1 1 auto; overflow-y: auto; padding: 6px 8px 10px; }
.cmdk-section-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.10em;
    text-transform: uppercase;
    color: var(--muted);
    padding: 10px 10px 4px;
}
.cmdk-item {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    color: var(--text);
    text-decoration: none;
    cursor: pointer;
    border: 1px solid transparent;
    background: transparent;
    width: 100%; text-align: left;
    font-family: inherit;
    line-height: 1.3;
    font-size: 14px;
}
.cmdk-item .ico {
    width: 22px; height: 22px;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--muted);
    flex: 0 0 22px;
}
.cmdk-item .label { font-weight: 500; color: var(--text-strong); flex: 1 1 auto; min-width: 0; word-break: break-word; }
.cmdk-item .sub   { font-size: 12px; color: var(--muted); flex-shrink: 0; }
.cmdk-item.is-active,
.cmdk-item:hover {
    background: rgba(90,121,165,0.08);
    border-color: var(--border);
}
.cmdk-empty {
    padding: 32px 18px;
    text-align: center;
    color: var(--muted);
    font-size: 13.5px;
}
.cmdk-foot {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap;
    padding: 8px 14px;
    border-top: 1px solid var(--border);
    background: var(--surface);
    font-size: 11.5px;
    color: var(--muted);
}
.cmdk-foot kbd {
    background: rgba(94,100,114,0.10);
    border: 1px solid var(--border);
    padding: 1px 6px;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 10.5px;
}
@media (prefers-reduced-motion: reduce) {
    .cmdk-backdrop, .cmdk-panel, .user-menu-popover, .bell-popover, .jags-toast {
        animation: none !important;
    }
}

/* ====================================================================
   Breadcrumbs — used on detail pages (aircraft-view, defect-view, etc.)
   ==================================================================== */
.breadcrumbs {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 6px;
    list-style: none;
    margin: 0 0 16px;
    padding: 0;
    font-size: 13px;
    color: var(--muted);
    line-height: 1.4;
}
.breadcrumbs li { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.breadcrumbs li + li::before {
    content: "›";
    color: var(--border-strong);
    font-size: 14px;
    line-height: 1;
}
.breadcrumbs a {
    color: var(--secondary);
    text-decoration: none;
    font-weight: 500;
    border-radius: 4px;
    padding: 2px 4px;
    transition: background var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out);
}
.breadcrumbs a:hover { color: var(--primary); background: rgba(90,121,165,0.08); }
.breadcrumbs li.current { color: var(--text-strong); font-weight: 600; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media print { .breadcrumbs { display: none; } }

/* ====================================================================
   Empty state — used inside .card or stand-alone for "no items yet"
   states. Icon block + title + description + optional CTA.
   ==================================================================== */
.empty-state {
    display: flex; flex-direction: column; align-items: center;
    text-align: center;
    padding: 42px 24px;
    color: var(--muted);
    font-size: 13.5px;
    line-height: 1.55;
}
.empty-state .empty-icon {
    width: 56px; height: 56px;
    border-radius: 16px;
    background: linear-gradient(180deg, rgba(39,66,112,0.08), rgba(39,66,112,0.03));
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--secondary);
    margin-bottom: 14px;
}
.empty-state .empty-icon svg { width: 28px; height: 28px; opacity: 0.85; }
.empty-state h3 {
    margin: 0 0 6px;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--text-strong);
}
.empty-state p {
    margin: 0 0 16px;
    max-width: 360px;
    color: var(--muted);
}
.empty-state .empty-actions {
    display: flex; gap: 8px; flex-wrap: wrap; justify-content: center;
}
.empty-state.compact { padding: 26px 16px; }

/* ====================================================================
   Filter chip row — for active filters above lists.
   ==================================================================== */
.filter-chips {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 14px;
    font-size: 12.5px;
}
.filter-chips .lbl {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
    font-weight: 700;
    margin-right: 4px;
}
.filter-chips .filter-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 6px 4px 10px;
    border-radius: 999px;
    background: rgba(90,121,165,0.10);
    border: 1px solid rgba(90,121,165,0.22);
    color: var(--secondary);
    font-weight: 600;
    line-height: 1.3;
}
.filter-chips .filter-chip .x {
    width: 18px; height: 18px;
    border-radius: 999px;
    background: rgba(90,121,165,0.16);
    border: none;
    color: var(--secondary);
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 13px; line-height: 1;
    padding: 0;
    text-decoration: none;
    transition: background var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out);
}
.filter-chips .filter-chip .x:hover { background: var(--secondary); color: #fff; }
.filter-chips .clear-all {
    font-size: 12px;
    font-weight: 600;
    color: var(--muted);
    text-decoration: underline;
}
.filter-chips .clear-all:hover { color: var(--primary); }

/* ====================================================================
   List search — input inside a page-header that filters table rows.
   ==================================================================== */
.list-search {
    display: inline-flex; align-items: center; gap: 8px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 6px 12px 6px 14px;
    width: 240px;
    transition: border-color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out);
}
.list-search:focus-within { border-color: var(--secondary); box-shadow: var(--ring-focus); }
.list-search svg { color: var(--muted); flex-shrink: 0; }
.list-search input {
    border: none; background: transparent;
    flex: 1 1 auto;
    font-size: 13.5px;
    font-family: inherit;
    color: var(--text);
    outline: none;
    line-height: 1.4;
    min-width: 0;
}
.list-search input::placeholder { color: var(--muted); }
@media (max-width: 700px) {
    .list-search { width: 100%; }
}

/* ====================================================================
   Skeleton loaders — shimmer placeholders for lazy or pending content.
   ==================================================================== */
@keyframes jagsShimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* ====================================================================
   Density toggle — reads [data-density] on body. Cookie-backed.
   ==================================================================== */
body[data-density="compact"] .card { padding: 14px 16px; }
body[data-density="compact"] .card + .card { margin-top: 12px; }
body[data-density="compact"] .stat { padding: 14px 16px; }
body[data-density="compact"] .stat .value { font-size: 26px; }
body[data-density="compact"] .stats-grid { gap: 10px; margin-bottom: 14px; }
body[data-density="compact"] table.tbl th,
body[data-density="compact"] table.tbl td { padding: 8px 10px; }
body[data-density="compact"] .field { margin-bottom: 10px; }
body[data-density="compact"] .row-list li { padding: 7px 0; }
body[data-density="compact"] .kv .k,
body[data-density="compact"] .kv .v { padding: 7px 0; }

body[data-density="spacious"] .card { padding: 28px 30px; }
body[data-density="spacious"] .card + .card { margin-top: 24px; }
body[data-density="spacious"] .stats-grid { gap: 22px; margin-bottom: 28px; }
body[data-density="spacious"] .stat { padding: 22px 24px; }
body[data-density="spacious"] table.tbl th,
body[data-density="spacious"] table.tbl td { padding: 14px 16px; }
body[data-density="spacious"] .field { margin-bottom: 18px; }
body[data-density="spacious"] .row-list li { padding: 13px 0; }

/* ====================================================================
   Table polish — sticky first column, row-link hover lift, zebra.
   ==================================================================== */
table.tbl-sticky-first thead th:first-child,
table.tbl-sticky-first tbody td:first-child {
    position: sticky;
    left: 0;
    background: var(--card);
    z-index: 1;
    box-shadow: 1px 0 0 0 var(--border);
}
table.tbl-sticky-first thead th:first-child { background: var(--surface-low); z-index: 3; }
table.tbl-sticky-first tbody tr:hover td:first-child,
table.tbl-sticky-first tbody tr:nth-child(even) td:first-child { background: var(--surface-high); }

table.tbl tbody tr.row-link {
    cursor: pointer;
    transition:
        background var(--motion-fast) var(--ease-out),
        transform var(--motion-fast) var(--ease-out),
        box-shadow var(--motion-fast) var(--ease-out);
}
table.tbl tbody tr.row-link:hover td {
    background: rgba(90,121,165,0.07);
}
table.tbl tbody tr.row-link:focus-within td {
    background: rgba(90,121,165,0.10);
    box-shadow: inset 0 0 0 2px var(--secondary);
}

/* ====================================================================
   Pulse-critical — subtle pulse on grounded/expired badges that should
   draw the eye without being noisy.
   ==================================================================== */
@keyframes jagsPulseCritical {
    0%, 100% { box-shadow: 0 0 0 0 rgba(184,50,53,0.0); }
    50%      { box-shadow: 0 0 0 4px rgba(184,50,53,0.18); }
}

/* ====================================================================
   Tabular numbers — applied to all numeric columns and mono spans
   so figures line up vertically.
   ==================================================================== */
.mono, .cell-mono, .cell-num,
.tbl .cell-mono, .tbl .cell-num,
.stat .value, .feat-val, .av2-kpi .val, .row-list .v.mono,
.kv .v.mono, .dr-preview .v {
    font-feature-settings: 'tnum' 1, 'lnum' 1;
    font-variant-numeric: tabular-nums lining-nums;
}

/* Page header — reusable strip used at the top of many pages. Eyebrow,
   title, subtitle, and right-aligned action buttons. Apple-style: tight
   tracking, generous spacing, no card border. */
.page-header {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
    margin: 0 0 22px;
}
.page-header-text {
    min-width: 0;
    display: flex; flex-direction: column; gap: 2px;
}
.page-header-text .eyebrow {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.10em;
    color: var(--muted);
    font-weight: 700;
    margin-bottom: 2px;
}
.page-header-text h1,
.page-header-text h2 {
    margin: 0;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: -0.025em;
    line-height: 1.15;
    color: var(--text-strong);
}
.page-header-text p {
    margin: 4px 0 0;
    font-size: 14px;
    line-height: 1.45;
}
.page-header-actions {
    display: flex; gap: 10px; flex-wrap: wrap;
    align-items: center;
}
@media (max-width: 700px) {
    .page-header-text h1, .page-header-text h2 { font-size: 21px; }
    .page-header-actions .btn { flex: 1 1 auto; justify-content: center; }
}
/* Desktop heading dedupe (2026-08 redesign). The topbar title block —
   role eyebrow / strong h1 / subdued date — is the page's single
   typographic anchor at every size. The premium mobile layer has hidden
   the duplicated in-content .page-header headings <=900px since 2026-07;
   this extends the same proven treatment to desktop, so pages never show
   "Dashboard" twice. Page-authored meta (p) and actions keep rendering. */
@media (min-width: 901px) {
    .content > .page-header .page-header-text .eyebrow,
    .content > .page-header .page-header-text h1,
    .content > .page-header .page-header-text h2 { display: none; }
    .content > .page-header { margin-bottom: 16px; }
}

/* Stat tiles */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 22px;
}
.stat {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 20px;
    box-shadow: var(--shadow-sm);
    position: relative;
    overflow: hidden;
}
.stat .label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--muted); font-weight: 600; }
.stat .value { font-size: var(--text-3xl); font-weight: 700; letter-spacing: -0.04em; margin-top: 4px; line-height: 1.1; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.stat .delta { font-size: var(--text-xs); color: var(--muted); margin-top: 4px; }
.stat-warn .value { color: var(--warning); }
.stat-danger .value { color: var(--danger); }
.stat-success .value { color: var(--success); }
/* Interactive tiles — when a .stat or .card is itself a link (e.g. KPI tiles
   that drill into a filtered list), give it clear hover/focus feedback so it
   reads as clickable. Static (non-anchor) tiles are untouched. */
a.stat, a.card {
    color: inherit;
    text-decoration: none;
    cursor: pointer;
    transition:
        box-shadow var(--motion-med) var(--ease-soft),
        border-color var(--motion-med) var(--ease-soft),
        transform var(--motion-med) var(--ease-soft);
}
a.stat:hover, a.card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-1px); }
a.stat:active, a.card:active { transform: translateY(0); }
a.stat:focus-visible, a.card:focus-visible { outline: none; box-shadow: var(--ring-focus), var(--shadow-md); }
@media (prefers-reduced-motion: reduce) {
    a.stat, a.card { transition: box-shadow var(--motion-med) var(--ease-soft), border-color var(--motion-med) var(--ease-soft); }
    a.stat:hover, a.card:hover { transform: none; }
}

/* Buttons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 9px 16px;
    border-radius: var(--radius-control);
    font-weight: 600;
    font-size: var(--text-sm);
    letter-spacing: 0.005em;
    border: 1px solid transparent;
    cursor: pointer;
    transition:
        background var(--motion-fast) var(--ease-out),
        color      var(--motion-fast) var(--ease-out),
        transform  var(--motion-fast) var(--ease-out),
        box-shadow var(--motion-fast) var(--ease-out),
        border-color var(--motion-fast) var(--ease-out);
    text-decoration: none;
    line-height: 1;
    font-family: inherit;
}
.btn-primary {
    background: var(--primary);
    color: #fff;
}
/* Achromatic press feedback — subtle scale-down on click matches the
   "Vercel-inspired" interaction language without translating the lift. */
.btn-primary:hover { background: var(--primary-hover); color: #fff; box-shadow: var(--shadow-md); }
.btn-primary:active { transform: scale(0.98); }
.btn-secondary {
    background: var(--secondary);
    color: #fff;
}
.btn-secondary:hover { background: var(--secondary-hover); color: #fff; }
.btn-secondary:active { transform: scale(0.98); }
.btn-ghost {
    background: transparent;
    color: var(--secondary);
    border-color: var(--border);
}
.btn-ghost:hover { background: rgba(39,66,112,0.06); }
.btn-ghost:active { transform: scale(0.98); }
.btn-danger {
    background: var(--danger); color: #fff;
}
.btn-danger:hover { background: #8a1414; color: #fff; }
.btn-danger:active { transform: scale(0.98); }
.btn-sm, .btn-small { padding: 6px 11px; font-size: 13px; border-radius: 10px; }
.btn-block { width: 100%; justify-content: center; }
/* Tonal secondaries used by document/audit pages. Previously undefined
   (rendered as the bare .btn ghost-of-nothing) — given a real soft-tint
   treatment on the semantic tokens. */
.btn-light {
    background: var(--surface-secondary);
    color: var(--text-primary);
    border-color: var(--border-subtle);
}
.btn-light:hover { background: var(--surface-container-high); }
.btn-light:active { transform: scale(0.98); }
.btn-warn {
    background: var(--status-warning-soft);
    color: var(--status-warning-ink);
    border-color: transparent;
}
.btn-warn:hover { background: var(--status-warning); color: var(--text-inverse); }

/* Forms — mobile-first. Defaults are tuned for thumb-tap (44px+ targets,
   16px font to suppress iOS auto-zoom, generous spacing). Desktop scales
   down via @media (min-width: 700px) further down. */
.field { margin-bottom: 16px; }
.field label {
    display: block;
    font-weight: 600;
    font-size: 13px;
    color: var(--text-strong);
    margin-bottom: 6px;
    letter-spacing: 0.005em;
}
.field .hint { font-size: 12px; color: var(--muted); margin-top: 6px; line-height: 1.5; }
.field input[type=text], .field input[type=email], .field input[type=password],
.field input[type=date], .field input[type=time], .field input[type=number], .field input[type=search],
.field input[type=tel], .field input[type=url], .field input[type=datetime-local],
.field select, .field textarea {
    width: 100%;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--card);
    /* 16px on mobile suppresses iOS Safari's auto-zoom-on-focus; on desktop
       we drop back to 14.25px for a tighter feel (see media query below). */
    font-size: 16px;
    color: var(--text);
    font-family: inherit;
    line-height: 1.4;
    min-height: 44px;
    box-sizing: border-box;
    -webkit-appearance: none;
    appearance: none;
    transition:
        border-color var(--motion-fast) var(--ease-out),
        box-shadow   var(--motion-fast) var(--ease-out),
        background   var(--motion-fast) var(--ease-out),
        transform    var(--motion-fast) var(--ease-out);
}
/* Custom select chevron so the native control reads as styled rather than
   raw browser-default. Inline SVG keeps it asset-free. */
.field select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%235E6472' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px 16px;
    padding-right: 40px;
}
/* Placeholder ink is the muted token, not a literal: the literal read
   2.7:1 on the light card and 2.0:1 on the dark recessed input. opacity:1
   defeats Firefox's own placeholder fade. */
.field input::placeholder, .field textarea::placeholder { color: var(--muted); opacity: 1; }
.field input:focus, .field select:focus, .field textarea:focus {
    outline: none;
    border-color: var(--secondary);
    box-shadow: var(--ring-focus);
}
.field input:focus-visible:not([readonly]),
.field textarea:focus-visible:not([readonly]) {
    /* Tiny lift — almost imperceptible but feels responsive on touch. */
    transform: translateY(-1px);
}
.field textarea { min-height: 100px; resize: vertical; }
.field input[readonly], .field textarea[readonly] { background: var(--surface-low); cursor: default; }
.field input[disabled], .field textarea[disabled], .field select[disabled] {
    background: var(--surface-low); color: var(--muted); cursor: not-allowed;
}
/* Range inputs and checkboxes/radios shouldn't get the 44px min-height. */
.field input[type=checkbox], .field input[type=radio], .field input[type=range] {
    min-height: 0;
    -webkit-appearance: auto;
    appearance: auto;
    width: auto;
    padding: 0;
}
/* ------------------------------------------------------------------ */
/* Shared 24-hour time control (.time24) — replaces the native time    */
/* scroll-wheel everywhere in Flights / Reservations / Radio. Numeric  */
/* text field + an anchored popover of 30-minute quick chips. The      */
/* popover is position:fixed so it never widens dense tables.          */
/* ------------------------------------------------------------------ */
.time24 { position: relative; display: inline-block; }
.field .time24 { display: block; }
/* Explicit quick-times trigger (2026-09-10). The popover no longer opens when
   the field is focused, so this button is the affordance that replaces it.
   Absolutely positioned inside the already-relative .time24 wrapper, so adding
   it reflows nothing — only fields that render it get the matching padding.
   tabindex="-1" keeps it out of the tab order: keyboard users tab field to
   field and type, which is faster than any chip grid. */
.time24-quick {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: color var(--motion-fast) var(--ease-out),
                background-color var(--motion-fast) var(--ease-out);
}
.time24-quick svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.time24-quick:hover { color: var(--text); background: var(--surface-low); }
.time24-quick:focus-visible {
    outline: 2px solid var(--secondary);
    outline-offset: 1px;
    color: var(--text);
}
/* Only reserve the gutter where the button is actually rendered. */
.time24-has-quick .time24-input { padding-right: 42px; }
.time24-input {
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--card);
    font-size: 16px;
    color: var(--text);
    font-family: inherit;
    line-height: 1.4;
    min-height: 44px;
    box-sizing: border-box;
    -webkit-appearance: none;
    appearance: none;
    letter-spacing: 0.02em;
    transition: border-color var(--motion-fast) var(--ease-out),
                box-shadow var(--motion-fast) var(--ease-out);
}
.field .time24-input { width: 100%; }
.time24-input::placeholder { color: var(--muted); opacity: 1; letter-spacing: normal; }
.time24-input:focus {
    outline: none;
    border-color: var(--secondary);
    box-shadow: var(--ring-focus);
}
.time24-input.time24-input-invalid {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px rgba(184,50,53,0.16);
}
.time24-input[disabled] {
    background: var(--surface-low);
    color: var(--muted);
    cursor: not-allowed;
}
.time24-preview { display: block; margin-top: 5px; min-height: 1em; }
.rsv-time-invalid, .time24-invalid { color: var(--danger) !important; }

.time24-pop {
    position: fixed;
    z-index: 1200;
    width: 248px;
    max-width: calc(100vw - 16px);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 14px 38px rgba(6,6,11,0.18);
    padding: 10px;
    box-sizing: border-box;
}
.time24-pop-bar {
    display: flex;
    gap: 8px;
    margin-bottom: 8px;
}
.time24-pop-bar .time24-chip { flex: 1; }
.time24-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
    max-height: 232px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
.time24-chip {
    appearance: none;
    -webkit-appearance: none;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    padding: 10px 0;
    min-height: 40px;
    border-radius: 9px;
    cursor: pointer;
    text-align: center;
    transition: background var(--motion-fast) var(--ease-out),
                border-color var(--motion-fast) var(--ease-out);
}
.time24-chip:hover { background: var(--surface-low); border-color: var(--secondary); }
.time24-chip:active { transform: translateY(1px); }
.time24-chip-on {
    background: var(--secondary);
    border-color: var(--secondary);
    color: #FFF;
    font-weight: 600;
}
.time24-chip-accent {
    background: var(--secondary);
    border-color: var(--secondary);
    color: #FFF;
    font-weight: 600;
}
.time24-chip-ghost { color: var(--muted); }
@media (max-width: 560px) {
    .time24-pop { width: 268px; }
    .time24-chip { font-size: 15px; min-height: 44px; }
}

/* Inline checkbox/radio rows — checkbox + label on one line, generous touch. */
.field-check {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
    cursor: pointer;
    transition: border-color var(--motion-fast) var(--ease-out), background var(--motion-fast) var(--ease-out);
    min-height: 44px;
}
.field-check:hover { border-color: var(--border-strong); background: var(--surface-low); }
.field-check input[type=checkbox],
.field-check input[type=radio] {
    width: 18px; height: 18px; flex: 0 0 18px;
    accent-color: var(--secondary);
    margin: 0;
}
.field-check .label-text { flex: 1 1 auto; font-size: 14px; color: var(--text-strong); font-weight: 500; line-height: 1.4; }
/* Desktop tweaks — slightly tighter font/padding once we know the user is
   on a pointer device, but keep the touch-friendly defaults intact below
   that threshold. */
@media (min-width: 700px) {
    .field input[type=text], .field input[type=email], .field input[type=password],
    .field input[type=date], .field input[type=time], .field input[type=number], .field input[type=search],
    .field input[type=tel], .field input[type=url], .field input[type=datetime-local],
    .field select, .field textarea {
        font-size: 14.25px;
        padding: 10px 12px;
        min-height: 40px;
    }
    .field { margin-bottom: 14px; }
    .field label { font-size: var(--text-sm); }
}
/* Validation states — apply via .field.has-error / .field.has-success
   classes set server-side, or via :invalid styling on user-blurred inputs.
   Keep gentle so the form doesn't feel angry. */
.field .hint.error { color: var(--danger); }
/* Required indicator — pages can opt in by adding .required to the label. */
.field label.required::after {
    content: " *";
    color: var(--danger);
    font-weight: 700;
}
/* Form grid — mobile-first single column, expanding to 2-up at tablet
   and using auto-fit at desktop for forms that pack many fields. */
.form-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}
@media (min-width: 700px) {
    .form-grid { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
}
/* Span 2 columns inside a form-grid (on desktop). */

.form-actions {
    display: flex; gap: 10px; flex-wrap: wrap;
    margin-top: 18px;
}
.form-actions .btn { flex: 1 1 auto; justify-content: center; min-height: 44px; }
@media (min-width: 700px) {
    .form-actions .btn { flex: 0 0 auto; min-height: 0; }
}
/* Sticky form actions on long forms — wrap your action row in
   .form-actions.sticky to lock it to the bottom of the viewport. */
.form-actions.sticky {
    position: sticky;
    bottom: 0;
    margin: 16px -16px -16px;
    padding: 14px 16px max(14px, env(safe-area-inset-bottom, 0px));
    background: rgba(var(--glass-rgb), 0.96);
    backdrop-filter: blur(8px) saturate(160%);
    -webkit-backdrop-filter: blur(8px) saturate(160%);
    border-top: 1px solid var(--border);
    z-index: 5;
}
@media (min-width: 700px) {
    .form-actions.sticky { margin: 16px -22px -22px; padding: 14px 22px; }
}
/* On mobile, lift sticky-actions above the bottom-nav bar so the submit
   button is always reachable but never under the bottom-nav. */
@media (max-width: 900px) {
    .form-actions.sticky { bottom: calc(var(--mobile-bottom-nav-footprint) + 8px); border-radius: var(--radius); border: 1px solid var(--border); margin: 16px 0 0; box-shadow: var(--shadow-md); }
}
@media print {
    .form-actions.sticky { position: static; background: none; backdrop-filter: none; box-shadow: none; }
}

/* Form-card — wraps related .field blocks in a consistent surface so a
   long form reads as grouped sections. Combine with .form-section-head
   for an Apple-Settings-style segmented form. Cards stack vertically
   with consistent gaps. */

/* Floating-style label hint — small caps badge above a key field. */
.field-hint-pill {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--surface-low);
    border: 1px solid var(--border);
    color: var(--muted);
    font-size: 10.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-left: 6px;
    vertical-align: middle;
}

/* Form-section header — a.k.a. a fieldset divider inside a long form. */

/* Badges */
.badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.012em;
    line-height: 1.4;
    white-space: nowrap;
    border: 1px solid transparent;
}
.badge-success { background: var(--status-success-soft); color: var(--status-success-ink); }
.badge-warn    { background: var(--status-warning-soft); color: var(--status-warning-ink); }
.badge-danger  { background: var(--status-danger-soft); color: var(--status-danger-ink); }
.badge-info    { background: var(--status-info-soft); color: var(--status-info-ink); }
.badge-neutral { background: rgba(94, 100, 114, 0.12); color: var(--muted); }

/* ---------------------------------------------------------------
   Senior title badges (Accountable Manager, Chief Pilot, Chief
   Engineer, Safety Officer, Admin, System Admin).

   These chips display authority / responsibility next to the role
   badge. They never grant access — they're a visual cue only. Senior
   chips lean on a quiet amber/gold for "authority", admin chips
   borrow the danger tone to match the role badge, and non-senior
   titles fall through to the standard `badge-info` look.
   --------------------------------------------------------------- */
.jags-title-badges {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}
.jags-title-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.012em;
    line-height: 1.4;
    white-space: nowrap;
    border: 1px solid transparent;
    text-decoration: none;
}
.jags-title-badge-ico {
    display: inline-block;
    flex: 0 0 auto;
    vertical-align: middle;
}
.jags-title-badge-label { display: inline-block; }
.jags-title-badge-compact { padding: 3px 6px; }
.jags-title-badge-info {
    background: rgba(90, 121, 165, 0.14);
    color: var(--status-info-ink);
    border-color: rgba(90, 121, 165, 0.22);
}
.jags-title-badge-admin {
    background: rgba(184, 50, 53, 0.10);
    color: var(--status-danger-ink);
    border-color: rgba(184, 50, 53, 0.28);
}
.jags-title-badge-senior {
    background: rgba(182, 136, 58, 0.13);
    color: var(--status-warning-ink);
    border-color: rgba(182, 136, 58, 0.32);
}
.jags-title-badge-safety {
    background: rgba(216, 181, 109, 0.18);
    color: var(--status-warning-ink);
    border-color: rgba(216, 181, 109, 0.40);
}
a.jags-title-badge:hover { filter: brightness(0.97); }
a.jags-title-badge:focus-visible {
    outline: none;
    box-shadow: var(--ring-focus);
}
.jags-title-badge-more {
    font-size: var(--text-xs);
    padding: 3px 9px;
}

/* Visually-hidden helper for compact chips that keep the label
   accessible to screen readers without showing it on screen. */
.jags-visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Topbar / user-menu title chip — sits to the left of the avatar and
   is a quiet visual reinforcement of senior authority. Hidden on
   narrow widths so the topbar doesn't crowd. */
.user-menu-button .jags-title-badge,
.topbar .jags-title-badge {
    padding: 2px 8px;
    font-size: 11px;
}
@media (max-width: 900px) {
    .user-menu-button .jags-title-badge-label { display: none; }
    .user-menu-button .jags-title-badge { padding: 3px 6px; }
}
@media (max-width: 700px) {
    .topbar .user-menu-button .jags-title-badge { display: none; }
}

/* ----- Feature 09 — Daily Report verification / publish / amendment.
   Subtle 4px left-border accent on the status banner so the saved
   Daily Report makes its workflow state visible without painting a
   loud full-card background. The banner reuses the existing alert
   colours; this rule only adds the feature-specific accent. */
.dr-workflow-banner { border-left: 4px solid currentColor; }

/* Hero-friendly status badges — readable on the dark JAGS gradient hero.
   The standard badge variants above are designed for light surfaces and
   become unreadable on .card-hero. Use these inside hero cards instead. */
.hero-status-badge {
    display: inline-flex; align-items: center;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    border: 1px solid rgba(255, 255, 255, 0.22);
    background: rgba(255, 255, 255, 0.10);
    color: #fff;
    line-height: 1.4;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.hero-status-serviceable {
    background: rgba(122, 198, 96, 0.22);
    color: #DCF3CB;
    border-color: rgba(122, 198, 96, 0.55);
}
.hero-status-grounded {
    background: rgba(231, 95, 95, 0.25);
    color: #FFD3D3;
    border-color: rgba(231, 95, 95, 0.55);
}
.hero-status-maintenance,
.hero-status-inspection_required {
    background: rgba(216, 181, 109, 0.28);
    color: #FAE5B5;
    border-color: rgba(216, 181, 109, 0.55);
}
.hero-status-inactive {
    background: rgba(255, 255, 255, 0.10);
    color: rgba(255, 255, 255, 0.85);
    border-color: rgba(255, 255, 255, 0.25);
}

/* Hero-friendly warning chips — for the small contextual flags shown in the
   aircraft profile hero (insp due soon, CofA expired, etc.). */
.hero-warning-chip {
    display: inline-flex; align-items: center;
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.04em;
    background: rgba(255, 255, 255, 0.14);
    border: 1px solid rgba(255, 255, 255, 0.22);
    color: #fff;
}
.hero-warning-chip.success {
    background: rgba(122, 198, 96, 0.22);
    color: #DCF3CB;
    border-color: rgba(122, 198, 96, 0.50);
}
.hero-warning-chip.warn {
    background: rgba(216, 181, 109, 0.28);
    color: #FAE5B5;
    border-color: rgba(216, 181, 109, 0.50);
}
.hero-warning-chip.danger {
    background: rgba(231, 95, 95, 0.28);
    color: #FFD3D3;
    border-color: rgba(231, 95, 95, 0.50);
}
.hero-warning-chip.info {
    background: rgba(255, 255, 255, 0.18);
    color: #FFFFFF;
    border-color: rgba(255, 255, 255, 0.30);
}
.hero-warning-chip.neutral {
    background: rgba(255, 255, 255, 0.10);
    color: rgba(255, 255, 255, 0.85);
    border-color: rgba(255, 255, 255, 0.22);
}

/* Tables */
.table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--card);
    box-shadow: var(--shadow-sm);
    scrollbar-width: thin;
    scrollbar-color: rgba(39,66,112,0.30) transparent;
}
/* STICKY TABLE HEADERS ARE DELIBERATELY INERT. Do not "fix" this.
   ----------------------------------------------------------------
   `table.tbl th` and `table.ops-board thead th` declare position:sticky; top:0,
   and none of them sticks. The mechanism: .table-wrap sets overflow-x:auto,
   which makes overflow-y compute to auto, which makes the WRAPPER — not the
   page — the scroll container the header would stick inside. With no height cap
   that container never scrolls, so top:0 never engages.

   Making it work needs a max-height on .table-wrap, which turns every long
   table into a box that scrolls inside the page instead of scrolling with it.
   That shipped on 2026-09-10 and was reverted the same day by owner decision:
   Operations reads a long table by scrolling the page, and this refactor does
   not change a working habit to enable a feature nobody asked for.

   So the sticky declarations stay, doing nothing, and that is the intended
   state. tests/table_contract_test.php holds the decision so a later audit
   cannot quietly re-enable it. If it is ever wanted it needs an owner decision
   and a real Operations user in front of it — not a CSS fix. */
/* Scroll without chrome. .table-wrap is the CARD form — border, background,
   shadow — and wrapping a table that already sits inside a .card in one nests a
   card in a card. .table-scroll is the same overflow behaviour with none of the
   surface, for tables that already have a container around them. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
.table-scroll::-webkit-scrollbar { height: 8px; }
.table-scroll::-webkit-scrollbar-track { background: transparent; }

.table-wrap::-webkit-scrollbar { height: 8px; }
.table-wrap::-webkit-scrollbar-track { background: transparent; }
.table-wrap::-webkit-scrollbar-thumb { background: rgba(39,66,112,0.25); border-radius: 8px; }
.table-wrap::-webkit-scrollbar-thumb:hover { background: rgba(39,66,112,0.45); }

table.tbl { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
table.tbl th, table.tbl td {
    padding: 12px 14px;
    text-align: left;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
    line-height: 1.42;
}
table.tbl th {
    background: linear-gradient(180deg, #F8FAFD 0%, #F1F4FA 100%);
    font-weight: 600;
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--muted-strong);
    position: sticky; top: 0;
    white-space: nowrap;
    border-bottom: 1px solid var(--border);
}
table.tbl tr:last-child td { border-bottom: none; }
table.tbl tr:hover td { background: var(--surface-high); }

/* Denser variant for fleet-style tables that already pack a lot of columns. */
table.tbl-compact { font-size: 13px; }
table.tbl-compact th, table.tbl-compact td { padding: 9px 10px; }
table.tbl-compact th { font-size: 11px; }

/* Reusable cell helper classes — keep cells from blowing up rows. */
.tbl td.cell-mono   { font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace; white-space: nowrap; }
.tbl td.cell-num    { white-space: nowrap; text-align: right; }
.tbl td.cell-date   { white-space: nowrap; }
.tbl td.cell-narrow { width: 1%; white-space: nowrap; }
.tbl td.cell-actions {
    text-align: right;
    white-space: nowrap;
    width: 1%;
}
.tbl td.cell-actions .btn + .btn { margin-left: 4px; }
.tbl td.cell-remarks {
    max-width: 220px;
    color: var(--muted);
    font-size: 12.5px;
    line-height: 1.45;
}
.tbl td.cell-remarks .truncate {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: break-word;
}

/* Reusable date pill — replaces inline padding/radius styling on date spans. */
.date-chip {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 6px;
    white-space: nowrap;
    font-size: 12.5px;
    line-height: 1.5;
}
.date-chip.muted { color: var(--muted); }

/* Sub-line text under primary table cell content. */
.tbl .sub-line { font-size: 11.5px; color: var(--muted); margin-top: 2px; line-height: 1.35; }
.tbl .sub-line.tight { margin-top: 1px; }

/* Grounded indicator pip shown next to the registration. */
.reg-pip { display:inline-block; width:8px; height:8px; border-radius:50%; background:var(--danger); flex:0 0 8px; }

/* Daily report table */
.dr-wrap { background: var(--card); color: var(--text); border-radius: var(--radius); border: 1px solid var(--border); box-shadow: var(--shadow-md); overflow: hidden; }
.dr-header {
    background: var(--grad-jags);
    color: #fff;
    padding: 28px 32px;
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 16px;
}
.dr-header .title { display: flex; align-items: center; gap: 18px; }
.dr-header .title img { width: 84px; height: 84px; border-radius: 12px; background: #FFFFFF; padding: 8px; box-shadow: 0 6px 18px rgba(0,0,0,0.18); }
.dr-header h1 { margin: 0; font-size: 24px; letter-spacing: -0.03em; color: #fff; font-weight: 700; }
.dr-header .subtitle { opacity: 0.85; margin-top: 2px; font-size: 13px; }
.dr-header .meta { font-size: 14px; text-align: right; }
.dr-header .meta strong { display: block; font-size: 16px; }
.dr-toolbar { padding: 14px 24px; border-bottom: 1px solid var(--border); background: var(--surface-low); display: flex; gap: 12px; flex-wrap: wrap; align-items: center; justify-content: space-between; }

.dr-scroll { overflow-x: auto; }
table.dr {
    width: 100%; min-width: 1400px;
    border-collapse: collapse; font-size: 12.5px;
    background: var(--card); color: var(--text);
}
table.dr th, table.dr td {
    padding: 8px 10px;
    border: 1px solid var(--border);
    vertical-align: top;
    line-height: 1.35;
}
table.dr th {
    background: linear-gradient(180deg, var(--surface-container) 0%, var(--surface-container-high) 100%);
    text-transform: uppercase;
    font-size: 11px;
    letter-spacing: 0.04em;
    color: var(--muted-strong);
    text-align: center;
}
table.dr tbody td.reg-cell {
    background: var(--surface-low);
    font-weight: 600;
}
table.dr tbody td.reg-cell .reg { font-size: 14px; color: var(--primary); display: block; margin-bottom: 2px; }
table.dr tbody td.reg-cell .meta-line { font-size: 11px; color: var(--muted); font-weight: 500; }

.cell-list { list-style: none; margin: 0; padding: 0; }
.cell-list li { padding: 5px 8px; border-radius: 6px; margin-bottom: 4px; background: var(--surface-low); }
.cell-list li:last-child { margin-bottom: 0; }
.cell-tags { font-size: 10.5px; color: var(--muted); margin-top: 2px; }
.cell-line { padding: 3px 0; }
.hr-label { display: inline-block; min-width: 50px; font-size: 10px; text-transform: uppercase; color: var(--muted); letter-spacing: 0.05em; }

/* Cell color states */
.cell-warn      { background: rgba(90,121,165,0.16) !important; color: #1F3F73; font-weight: 600; }
.cell-green     { background: rgba(74,103,51,0.18) !important; color: #2C4A1B; font-weight: 600; }
.cell-major     { background: rgba(216,181,109,0.20) !important; color: var(--status-warning-ink); font-weight: 600; }
.cell-outstanding{ background: rgba(184,50,53,0.13) !important; color: var(--status-danger-ink); font-weight: 600; }
.cell-coa-soon  { background: rgba(80,180,90,0.20) !important; color: #245C28; font-weight: 600; }
.cell-cmr-soon  { background: rgba(155,90,200,0.18) !important; color: #5C2880; font-weight: 600; }
.cell-expired   { background: rgba(184,50,53,0.20) !important; color: var(--status-danger-ink); font-weight: 700; }

/* Daily Report — inline keyword emphasis applied by dr_snapshot_format_inline().
   Used inside snapshot rows where row_json colour classes are absent and to
   match the visual hierarchy of the paper Daily Report. Subtle: bold colour
   only, no background, so the cell-level tints stay readable. */
.dr-kw          { font-weight: 700; letter-spacing: 0.01em; }
.dr-kw-critical { color: var(--status-danger-ink); }
.dr-kw-warn     { color: var(--status-warning-ink); }
.dr-kw-info     { color: #1F3F73; }

/* Legend / key */
.legend { display: flex; flex-wrap: wrap; gap: 10px; padding: 12px 24px; background: var(--surface-low); border-top: 1px solid var(--border); }
.legend .swatch { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border-radius: 999px; font-size: 12px; }
.legend .dot { width: 12px; height: 12px; border-radius: 4px; display: inline-block; }

/* ----------------------------------------------------------------------
 * Daily Report scoped layout — keeps cells compact so Combined Board /
 * Compliance Board detail can never spill into the printed Daily Report.
 * Scoped to .daily-report-table so other tables (Compliance Board,
 * Aircraft profile) are unaffected.
 * -------------------------------------------------------------------- */
.daily-report-table { table-layout: fixed; width: 100%; }
.daily-report-table th,
.daily-report-table td {
    vertical-align: top;
    line-height: 1.25;
    overflow-wrap: break-word;
    word-break: normal;
}
.daily-report-table .dr-cell-list { margin: 0; padding: 0; list-style: none; }
.daily-report-table .dr-cell-list li {
    padding: 3px 6px;
    margin-bottom: 3px;
    border-radius: 5px;
    background: var(--surface-low);
    font-size: 11.5px;
    line-height: 1.25;
}
.daily-report-table .dr-cell-list li:last-child { margin-bottom: 0; }
.daily-report-table .dr-cell-list li strong { font-weight: 600; }
.daily-report-table .cell-tags { font-size: 10px; color: var(--muted); margin-top: 1px; }
.daily-report-table .cell-line { padding: 2px 0; font-size: 11.5px; line-height: 1.25; }

/* On screen, cap each list-type cell to a few visible lines so a single
 * row can never blow the table out vertically. Print restores full height
 * so the +N overflow note is hidden but every visible row still prints. */
.daily-report-table td .dr-cell-list,
.daily-report-table td .cell-list { max-height: 9em; overflow: hidden; }
.daily-report-table .daily-report-extra-note {
    font-size: 10.5px;
    margin-top: 2px;
    font-style: italic;
}

@media print {
    .daily-report-table { font-size: 9pt; }
    .daily-report-table td .dr-cell-list,
    .daily-report-table td .cell-list { max-height: none; overflow: visible; }
    .daily-report-table .daily-report-extra-note { display: none; }
}

/* Auth screens */
.auth-page {
    min-height: 100vh;
    display: grid;
    grid-template-columns: 1fr 1fr;
}
.auth-side {
    background: var(--grad-jags);
    color: #fff;
    padding: 52px 48px;
    display: flex; flex-direction: column; justify-content: space-between;
    position: relative; overflow: hidden;
}
.auth-side::before {
    content: ""; position: absolute; right: -120px; top: -120px;
    width: 400px; height: 400px; border-radius: 50%;
    background: radial-gradient(circle, rgba(255,255,255,0.18), transparent 65%);
}
.auth-side::after {
    content: ""; position: absolute; left: -100px; bottom: -100px;
    width: 350px; height: 350px; border-radius: 50%;
    background: radial-gradient(circle, rgba(255,255,255,0.10), transparent 65%);
}
.auth-side .brand { display: flex; flex-direction: column; gap: 10px; position: relative; z-index: 1; max-width: 220px; }
.auth-side .brand img { display: block; width: 100%; max-width: 200px; height: 120px; object-fit: contain; border-radius: 14px; background: #FFFFFF; padding: 14px; box-shadow: 0 8px 24px rgba(0,0,0,0.18); }
.auth-side .brand-sub { font-size: 11px; opacity: 0.75; text-transform: uppercase; letter-spacing: 0.12em; text-align: center; }
.auth-side .pitch h1 { font-size: 38px; letter-spacing: -0.04em; line-height: 1.1; margin: 0 0 14px; color: #fff; font-weight: 700; }
.auth-side .pitch p { font-size: 16px; opacity: 0.85; max-width: 380px; margin: 0; color: #fff; }
.auth-side .footnote { font-size: 12px; opacity: 0.7; position: relative; z-index: 1; }
.auth-form-wrap {
    display: flex; align-items: center; justify-content: center; padding: 40px;
    background: var(--bg);
}
.auth-card {
    width: 100%; max-width: 420px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 36px 32px;
    box-shadow: var(--shadow-lg);
}
.auth-card h2 { margin: 0 0 4px; font-size: 24px; letter-spacing: -0.01em; }
.auth-card .lede { color: var(--muted); margin: 0 0 22px; font-size: 14px; }

/* Department portal layer — branding chips, hero accents, chooser cards. */
.auth-eyebrow {
    display: inline-block;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    font-size: 11px;
    font-weight: 600;
    background: rgba(255,255,255,0.16);
    padding: 4px 10px;
    border-radius: 999px;
    margin-bottom: 14px;
    position: relative; z-index: 1;
}
.auth-portal-chip {
    display: inline-block;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    font-size: 11px;
    font-weight: 700;
    color: var(--secondary);
    background: rgba(39, 66, 112, 0.10);
    border: 1px solid rgba(39, 66, 112, 0.18);
    padding: 4px 10px;
    border-radius: 999px;
    margin-bottom: 12px;
}
/* Brand fallback — visible only when the <img> onerror fires. Keeps the
   auth side panel from ever showing an empty white rounded card. Renders a
   JAGS Aviation textmark via ::before / ::after so the fallback is a real
   brand mark, not a blank box, even on the rare hosts where neither the
   portal hero nor assets/jags-logo.png can be loaded. Layout uses padding +
   block pseudo-elements (not flex) so existing onerror handlers that set
   display:block continue to render correctly without per-page changes. */
.auth-side .brand-fallback {
    width: 100%; max-width: 200px;
    min-height: 120px;
    box-sizing: border-box;
    border-radius: 14px;
    background: var(--card);
    border: 1px solid rgba(255,255,255,0.18);
    box-shadow: 0 8px 24px rgba(0,0,0,0.18);
    padding: 30px 14px;
    text-align: center;
    color: var(--primary);
    font-family: var(--font-display);
    line-height: 1.05;
}
.auth-side .brand-fallback::before {
    content: "JAGS";
    display: block;
    font-size: 30px;
    font-weight: 800;
    letter-spacing: 0.04em;
    color: var(--primary);
}
.auth-side .brand-fallback::after {
    content: "AVIATION";
    display: block;
    margin-top: 6px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.32em;
    color: var(--secondary);
}
.auth-portal-switch {
    margin-top: 18px;
    text-align: center;
    font-size: 13px;
    color: var(--muted);
}
.auth-portal-switch a { font-weight: 600; }

/* Pills shown on the generic login screen — quick jump to a department. */
.auth-portal-grid {
    display: flex; flex-wrap: wrap; justify-content: center;
    gap: 6px; margin-top: 10px;
}
.auth-portal-pill {
    display: inline-block;
    padding: 6px 12px;
    font-size: 12.5px;
    font-weight: 600;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--card);
    color: var(--secondary);
    text-decoration: none;
    transition: transform .15s ease, box-shadow .15s ease, background .15s ease, border-color .15s ease;
}
.auth-portal-pill:hover {
    background: var(--secondary);
    color: #fff;
    border-color: var(--secondary);
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
}

/* Cards shown on the generic register screen — pick a department first. */
.auth-portal-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 10px;
    margin: 6px 0 18px;
}
.auth-portal-card {
    display: flex; flex-direction: column; gap: 4px;
    padding: 14px 16px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--card);
    color: var(--text-strong, #0E0E12);
    text-decoration: none;
    transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.auth-portal-card:hover {
    transform: translateY(-2px);
    border-color: var(--secondary);
    box-shadow: var(--shadow-md);
}
.auth-portal-card-label { font-weight: 700; font-size: 14px; color: var(--primary); }
.auth-portal-card-sub   { font-size: 12px; color: var(--muted); line-height: 1.45; }

/* Per-department hero tints — subtle accent bands layered above the gradient. */
.auth-page.auth-portal-tr          .auth-side { background: linear-gradient(135deg, #0F2A4F 0%, #274270 55%, #5A79A5 100%); }
.auth-page.auth-portal-operations  .auth-side { background: linear-gradient(135deg, #142A55 0%, #1F4D8F 60%, #4F86C5 100%); }
.auth-page.auth-portal-radio       .auth-side { background: linear-gradient(135deg, #1A2848 0%, #3D2E66 60%, #6F5BA5 100%); }
.auth-page.auth-portal-maintenance .auth-side { background: linear-gradient(135deg, #1F2A2E 0%, #2C5560 60%, #5C97A5 100%); }
.auth-page.auth-portal-pilot       .auth-side { background: linear-gradient(135deg, #112447 0%, #1F3F75 55%, #4670B0 100%); }
.auth-page.auth-portal-viewer      .auth-side { background: linear-gradient(135deg, #1B1F2A 0%, #3A3F55 60%, #6E7799 100%); }
.auth-page.auth-portal-admin       .auth-side { background: linear-gradient(135deg, #150F2E 0%, #2C1F55 60%, #5C4FA5 100%); }

/* Mobile hero — image hides on very small screens, copy stays. */
@media (max-width: 680px) {
    .auth-side {
        padding: 28px 22px;
        min-height: 220px;
    }
    .auth-side .brand img,
    .auth-side .brand-fallback { max-width: 140px; }
    .auth-side .pitch h1 { font-size: 24px; }
    .auth-side .pitch p  { font-size: 14px; }
    .auth-form-wrap { padding: 22px 16px; }
    .auth-card { padding: 24px 20px; border-radius: var(--radius); }
    .auth-portal-cards { grid-template-columns: 1fr; }
}
@media (max-width: 420px) {
    .auth-side .footnote { display: none; }
    .auth-side { padding: 22px 18px; min-height: 180px; }
    .auth-side .brand img,
    .auth-side .brand-fallback { max-width: 110px; }
}

/* Alerts / flash */
.alert {
    padding: 12px 14px;
    border-radius: var(--radius-sm);
    margin-bottom: 16px;
    font-size: var(--text-sm);
    line-height: var(--line-relaxed);
    border: 1px solid transparent;
    display: flex; align-items: flex-start; gap: 10px;
}
.alert > .jags-icon { margin-top: 2px; flex: 0 0 18px; }
.alert-info    { background: rgba(90,121,165,0.10); color: var(--status-info-ink); border-color: rgba(90,121,165,0.22); }
.alert-success { background: rgba(74,103,51,0.10);  color: var(--status-success-ink); border-color: rgba(74,103,51,0.22); }
.alert-warn    { background: rgba(216,181,109,0.16); color: var(--status-warning-ink); border-color: rgba(216,181,109,0.32); }
.alert-danger  { background: rgba(184,50,53,0.10);  color: var(--status-danger-ink); border-color: rgba(184,50,53,0.22); }

/* Aircraft status card */
.ac-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
.ac-card {
    background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
    padding: 18px; box-shadow: var(--shadow-sm); position: relative; overflow: hidden;
}
.ac-card .reg {
    font-size: 22px; font-weight: 700; letter-spacing: -0.02em;
    color: var(--primary); margin: 0 0 4px;
}
.ac-card .model { color: var(--muted); margin: 0 0 12px; font-size: 13px; }
.ac-card .meta-row { display: flex; justify-content: space-between; padding: 4px 0; font-size: 13px; }
.ac-card .meta-row .lbl { color: var(--muted); }
.ac-card .actions { display: flex; gap: 8px; margin-top: 14px; }

/* Profile readout — Apple Settings rhythm. Pairs of .k / .v render as
   rows with a thin divider between them. Default layout is two-column
   (label left, value right). When .kv is wrapped in a card it picks up
   tabular-nums + edge-to-edge dividers automatically. */
.kv {
    display: grid;
    grid-template-columns: minmax(120px, 200px) 1fr;
    gap: 0 18px;
    font-size: var(--text-base);
}
.kv .k {
    color: var(--muted);
    font-size: var(--text-sm);
    padding: 10px 0;
    border-top: 1px solid var(--border);
    align-self: center;
}
.kv .v {
    font-weight: 500;
    color: var(--text-strong);
    padding: 10px 0;
    border-top: 1px solid var(--border);
    align-self: center;
    word-break: break-word;
}
.kv > .k:first-of-type, .kv > .v:nth-of-type(1) { border-top: none; padding-top: 0; }
/* If .kv is the first thing inside a card, drop the lead spacing. */
.card > .kv:first-child > .k:first-of-type,
.card > .kv:first-child > .v:nth-of-type(1) { padding-top: 4px; }

/* Aircraft profile hero image — small framed rectangle that sits inside
   the dark .card-hero gradient on aircraft_view.php. Scoped to that one
   surface; do not reuse on lighter cards. */

/* ----------------------------------------------------------------------
   Aircraft view hero polish
   Layout, type and image-frame refinement for the aircraft profile hero.
   Every selector is scoped under .av-hero-card (added to the existing
   .card.card-hero on aircraft_view.php) or prefixed .av-, so nothing
   leaks to other pages. Print parity is preserved by the @media print
   rule at the end of this block. Reuses .hero-warning-chip and
   .hero-status-badge for chips and the serviceability badge unchanged.
   ---------------------------------------------------------------------- */

/* Title block typography */

/* Image frame: 16:10 aspect, layered radial stage, hairline border,
   inset corner vignette. Padding scales with viewport so the aircraft
   takes more of the frame on larger screens. Overrides the 16:9 /
   280px / glass treatment of the older .av-hero-img rules above for
   this region only. */
/* Fallback fills the content area inside the frame padding so the
   placeholder occupies the same space as a real image. Quiet aircraft
   glyph + label, no broken-image affordance. */

/* Actions column: badge above buttons, right-aligned, 12px gap. Buttons
   stack vertically on desktop with 8px between them. Button styles are
   not changed here; only the layout. */

/* Tablet: title and actions share the top row, image spans full width
   below. Reuses the project's existing 900px breakpoint. */

/* Mobile: full vertical stack. Title, then image, then actions (badge
   followed by buttons). Reuses the project's existing 700px breakpoint
   already in this file. */

/* Print parity: hide the image frame on print, mirroring the existing
   .av-hero-img rule above so the new class names are also hidden. */

/* ====================================================================
   Aircraft view — Apple-style hero + info cards (av2-).
   New design layer for /index.php?page=aircraft-view&id=...
   Scoped under .av2-* so it never bleeds to other pages. The legacy
   .av-hero-card rules above remain for any caller that still uses them.
   ==================================================================== */

/* ----- Hero ----- */
.av2-hero {
    position: relative;
    overflow: hidden;
    margin-bottom: 22px;
    padding: 36px 36px 28px;
    border-radius: var(--radius-lg);
    background: var(--grad-jags);
    color: #fff;
    border: none;
    box-shadow: 0 30px 60px rgba(11, 11, 47, 0.18), 0 1px 2px rgba(11, 11, 47, 0.08);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
    grid-template-areas:
        "head    image"
        "title   image"
        "tags    image"
        "kpis    kpis"
        "actions actions";
    column-gap: 36px;
    row-gap: 18px;
}
/* Soft top highlight — Apple's hairline at the top of dark cards. */
.av2-hero::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 1px;
    background: linear-gradient(90deg,
        rgba(255,255,255,0) 0%,
        rgba(255,255,255,0.18) 30%,
        rgba(255,255,255,0.22) 50%,
        rgba(255,255,255,0.18) 70%,
        rgba(255,255,255,0) 100%);
    pointer-events: none;
    z-index: 1;
}
/* Subtle ambient glow in the upper-right corner. */
.av2-hero::after {
    content: "";
    position: absolute;
    top: -120px; right: -120px;
    width: 380px; height: 380px;
    background: radial-gradient(circle, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0) 65%);
    pointer-events: none;
    z-index: 0;
}
.av2-hero > * { position: relative; z-index: 2; }
.av2-hero-head {
    grid-area: head;
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
}
.av2-hero-eyebrow {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(255,255,255,0.62);
}
.av2-hero-title { grid-area: title; min-width: 0; }
.av2-hero-reg {
    margin: 0;
    font-size: clamp(40px, 6vw, 64px);
    font-weight: 700;
    letter-spacing: -0.045em;
    line-height: 1;
    color: #fff;
    font-feature-settings: 'tnum' 1, 'lnum' 1, 'ss01' 1;
    overflow-wrap: break-word;
    word-break: break-word;
}
/* Tags: compact Apple-style metadata chips under the registration */
.av2-hero-tags {
    grid-area: tags;
    display: flex; flex-wrap: wrap; gap: 4px 8px;
    align-items: center;
}
.av2-tag {
    display: inline-flex; align-items: baseline; gap: 5px;
    padding: 0;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.005em;
    color: rgba(255,255,255,0.88);
    background: transparent;
    border: none;
    line-height: 1.4;
}
.av2-tag + .av2-tag {
    border-left: 1px solid rgba(255,255,255,0.20);
    padding-left: 8px;
}
.av2-tag .lbl {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.10em;
    color: rgba(255,255,255,0.50);
    font-weight: 600;
}
/* KPI strip — at-a-glance summary inside the hero */
.av2-hero-kpis {
    grid-area: kpis;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
    margin-top: 6px;
}
.av2-kpi {
    background: rgba(255,255,255,0.07);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px;
    padding: 12px 14px;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    min-width: 0;
}
.av2-kpi .lbl {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.10em;
    text-transform: uppercase;
    color: rgba(255,255,255,0.62);
    margin-bottom: 4px;
}
.av2-kpi .val {
    font-size: 18px;
    font-weight: 700;
    letter-spacing: -0.015em;
    color: #fff;
    font-feature-settings: 'tnum' 1, 'lnum' 1;
    line-height: 1.15;
    word-break: break-word;
}
.av2-kpi .sub {
    font-size: 11px;
    color: rgba(255,255,255,0.62);
    margin-top: 2px;
    font-weight: 500;
}
.av2-kpi.warn  { background: rgba(216,181,109,0.20); border-color: rgba(216,181,109,0.40); }
.av2-kpi.warn .val { color: #FAE5B5; }
.av2-kpi.danger{ background: rgba(231,95,95,0.22); border-color: rgba(231,95,95,0.45); }
.av2-kpi.danger .val { color: #FFD3D3; }
.av2-kpi.success { background: rgba(122,198,96,0.22); border-color: rgba(122,198,96,0.45); }
.av2-kpi.success .val { color: #DCF3CB; }
/* Image — clean white card so cutouts on white backgrounds blend
   naturally (Apple product-card treatment over a dark hero). Soft outer
   shadow lifts the card off the navy gradient. */
.av2-hero-image {
    grid-area: image;
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 10;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--card);
    border: 1px solid rgba(255,255,255,0.18);
    box-shadow:
        0 16px 40px rgba(0,0,0,0.22),
        0 2px 4px rgba(0,0,0,0.10);
    align-self: stretch;
}
.av2-hero-image > img {
    display: block;
    width: 100%; height: 100%;
    object-fit: contain;
    object-position: center;
    /* Tight zoom so the aircraft fills the white card with minimal margin.
       Tune down to 1.0 for tightly-cropped photos; current 1.15 reads well
       for typical white-background marketing cutouts. */
    transform: scale(1.15);
    transform-origin: center;
}
/* Fallback uses a gentle off-white tint and shows the airplane SVG plus
   helper copy. No hard contrast on the white card. */
.av2-hero-image .av2-hero-image-fallback {
    position: absolute; inset: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 8px;
    background: linear-gradient(180deg, #fbfcfe 0%, #eef1f7 100%);
    color: var(--muted);
}
.av2-hero-image .av2-hero-image-fallback svg {
    width: 56px; height: 56px;
    /* Decorative watermark only (1.22:1 by design). The adjacent span
       carries the same meaning as --muted text, so this glyph is exempt
       under WCAG 1.4.11; do not read it as an accessibility failure. */
    color: rgba(39,66,112,0.42);
}
.av2-hero-image .av2-hero-image-fallback span {
    font-size: 13px;
    font-weight: 500;
    color: var(--muted);
}
.av2-hero-image .av2-hero-image-fallback a {
    color: var(--secondary);
    text-decoration: underline;
    font-size: 12.5px;
    font-weight: 500;
}
/* Status badge — sits in the head row, presence pill */
.av2-status {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 6px 14px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #fff;
    background: rgba(255,255,255,0.10);
    border: 1px solid rgba(255,255,255,0.22);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}
.av2-status::before {
    content: "";
    width: 7px; height: 7px;
    border-radius: 50%;
    background: rgba(255,255,255,0.85);
    box-shadow: 0 0 0 3px rgba(255,255,255,0.18);
}
.av2-status.serviceable { background: rgba(122,198,96,0.22); border-color: rgba(122,198,96,0.55); color: #E2F4D6; }
.av2-status.serviceable::before { background: #B3E89A; box-shadow: 0 0 0 3px rgba(122,198,96,0.30); }
.av2-status.grounded { background: rgba(231,95,95,0.25); border-color: rgba(231,95,95,0.55); color: #FFE2E2; }
.av2-status.grounded::before { background: #F89A9A; box-shadow: 0 0 0 3px rgba(231,95,95,0.32); }
.av2-status.maintenance,
.av2-status.inspection_required { background: rgba(216,181,109,0.28); border-color: rgba(216,181,109,0.55); color: #FAE5B5; }
.av2-status.maintenance::before,
.av2-status.inspection_required::before { background: #E8C783; box-shadow: 0 0 0 3px rgba(216,181,109,0.32); }
/* Actions row */
.av2-hero-actions {
    grid-area: actions;
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 6px;
    padding-top: 18px;
    border-top: 1px solid rgba(255,255,255,0.12);
}
.av2-hero-actions .btn-primary {
    background: var(--card);
    color: var(--primary);
    border-color: #fff;
    font-weight: 700;
    box-shadow: 0 6px 18px rgba(0,0,0,0.18);
}
.av2-hero-actions .btn-primary:hover {
    background: rgba(255,255,255,0.92);
    color: var(--primary);
    box-shadow: 0 8px 22px rgba(0,0,0,0.22);
}
.av2-hero-actions .btn-ghost {
    background: rgba(255,255,255,0.10);
    color: #fff;
    border-color: rgba(255,255,255,0.22);
}
.av2-hero-actions .btn-ghost:hover {
    background: rgba(255,255,255,0.18);
    border-color: rgba(255,255,255,0.32);
    color: #fff;
}
/* Inactive overlay — Apple's frosted overlay treatment */
.av2-hero.is-inactive::before { background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.10) 50%, rgba(255,255,255,0) 100%); }
/* Tablet: image goes below the title block */
@media (max-width: 1100px) {
    .av2-hero {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "head"
            "title"
            "tags"
            "image"
            "kpis"
            "actions";
    }
    .av2-hero-image { aspect-ratio: 16 / 9; max-height: 320px; }
}
@media (max-width: 700px) {
    .av2-hero {
        padding: 24px 20px 20px;
        border-radius: var(--radius);
    }
    .av2-hero-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .av2-hero-actions .btn { flex: 1 1 140px; justify-content: center; }
    .av2-hero-reg { font-size: 36px; }
    .av2-hero-image { aspect-ratio: 4 / 3; max-height: 240px; }
}

/* ----- Info cards grid ----- */
.av2-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
    margin-bottom: 22px;
}
@media (max-width: 900px) {
    .av2-grid { grid-template-columns: minmax(0, 1fr); }
}
.av2-card {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0;
    box-shadow: var(--shadow-sm);
    transition:
        box-shadow var(--motion-med) var(--ease-soft),
        border-color var(--motion-med) var(--ease-soft);
    overflow: hidden;
    display: flex; flex-direction: column;
}
.av2-card:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--border-strong);
}
.av2-card-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    padding: 18px 22px 14px;
    border-bottom: 1px solid var(--border);
}
.av2-card-head .ttl {
    display: flex; align-items: center; gap: 10px;
    min-width: 0;
}
.av2-card-head .ttl-icon {
    width: 36px; height: 36px;
    border-radius: 10px;
    background: linear-gradient(180deg, rgba(39,66,112,0.10), rgba(39,66,112,0.04));
    color: var(--secondary);
    display: inline-flex; align-items: center; justify-content: center;
    flex: 0 0 36px;
}
.av2-card-head .ttl-icon svg { width: 18px; height: 18px; }
.av2-card-head h3 {
    margin: 0;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--text-strong);
}
.av2-card-head .meta {
    font-size: 12px;
    color: var(--muted);
    font-weight: 500;
    text-align: right;
    flex-shrink: 0;
}
/* Feature value — the lead number on each info card */
.av2-feature {
    padding: 18px 22px 14px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-low);
}
.av2-feature .feat-lbl {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
    font-weight: 600;
    margin-bottom: 4px;
}
.av2-feature .feat-val {
    font-size: 28px;
    font-weight: 700;
    letter-spacing: -0.025em;
    line-height: 1.05;
    color: var(--text-strong);
    font-feature-settings: 'tnum' 1, 'lnum' 1;
    word-break: break-word;
}
.av2-feature .feat-sub {
    font-size: 12.5px;
    color: var(--muted);
    margin-top: 4px;
    font-weight: 500;
}
.av2-feature.warn .feat-val   { color: var(--status-warning-ink); }
.av2-feature.warn             { background: rgba(216,181,109,0.10); }
.av2-feature.danger .feat-val { color: var(--status-danger-ink); }
.av2-feature.danger           { background: rgba(184,50,53,0.06); }
.av2-feature.success .feat-val{ color: #2C4A1B; }
.av2-feature.success          { background: rgba(74,103,51,0.08); }
/* Row list inside a card — Apple Settings rhythm */
.av2-rows {
    list-style: none;
    margin: 0;
    padding: 4px 22px 14px;
    flex: 1;
}
.av2-rows li {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 14px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
    min-width: 0;
}
.av2-rows li:last-child { border-bottom: none; }
.av2-rows .k {
    font-size: 13px;
    color: var(--muted);
    font-weight: 500;
    flex-shrink: 0;
}
.av2-rows .v {
    font-size: 14px;
    color: var(--text-strong);
    font-weight: 600;
    text-align: right;
    min-width: 0;
    word-break: break-word;
}
.av2-rows .v.mono { font-family: var(--font-mono); font-feature-settings: 'tnum' 1, 'lnum' 1; }
.av2-rows .v .sub {
    display: block;
    font-size: 11.5px;
    color: var(--muted);
    font-weight: 500;
    margin-top: 2px;
}
/* Countdown chip — for date rows where the urgency matters */
.av2-countdown {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.012em;
    line-height: 1.4;
}
.av2-countdown.success { background: rgba(74,103,51,0.12); color: var(--status-success-ink); }
.av2-countdown.info    { background: rgba(90,121,165,0.14); color: var(--status-info-ink); }
.av2-countdown.warn    { background: rgba(216,181,109,0.18); color: var(--status-warning-ink); }
.av2-countdown.danger  { background: rgba(184,50,53,0.14); color: var(--status-danger-ink); }
.av2-countdown.muted   { background: rgba(94,100,114,0.12); color: var(--muted); }

/* Aircraft images — hero card + gallery thumbs.
   Folder convention only; no DB. See assets/aircraft/<REG>/. */
.ac-images-hero {
    position: relative;
    overflow: hidden;
    border-radius: var(--radius);
    background: linear-gradient(180deg, #F8FAFD 0%, #F1F4FA 100%);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
    aspect-ratio: 16 / 9;
    display: block;
}
.ac-images-hero a, .ac-images-hero img { display: block; width: 100%; height: 100%; }
.ac-images-hero img { object-fit: cover; }
.ac-images-hero.empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center;
    color: var(--muted);
    aspect-ratio: auto;
    padding: 36px 24px;
}
.ac-images-hero.empty .placeholder-glyph {
    font-size: 38px; line-height: 1;
    color: var(--secondary);
    opacity: 0.55;
    margin-bottom: 10px;
}
.ac-images-hero.empty code {
    background: var(--card);
    border: 1px solid var(--border);
    color: var(--secondary);
    padding: 1px 6px; border-radius: 6px; font-size: 12.5px;
}
.ac-images-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
    margin-top: 12px;
}
.ac-images-gallery a {
    display: block;
    aspect-ratio: 4 / 3;
    border-radius: var(--radius-sm);
    overflow: hidden;
    border: 1px solid var(--border);
    background: var(--surface-low);
    box-shadow: var(--shadow-sm);
    transition: transform 140ms ease, box-shadow 140ms ease, border-color 140ms ease;
}
.ac-images-gallery a:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--secondary);
}
.ac-images-gallery img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}
@media (max-width: 700px) {
    .ac-images-hero { aspect-ratio: 4 / 3; }
    .ac-images-gallery { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px; }
}
@media print {
    .ac-images-hero, .ac-images-gallery { display: none !important; }
}

/* Tabs */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 18px; }
.tabs a { padding: 10px 14px; border-radius: 8px 8px 0 0; color: var(--muted); font-weight: 500; }
.tabs a.active { color: var(--primary); border-bottom: 2px solid var(--primary); }

/* ====================================================================
   Operations / Dispatch board — digital whiteboard
   Shared CSS for the schedule board (default) and table view fallback.
   Stays inside the existing card / btn / badge system so the rest of
   the portal continues to feel coherent.
   ==================================================================== */
.ops-board-wrap { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); overflow: hidden; }
.ops-board-toolbar {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 14px 18px; border-bottom: 1px solid var(--border);
    background: linear-gradient(180deg, var(--surface-primary), var(--surface-low));
    position: sticky; top: 0; z-index: 4;
}
.ops-board-toolbar .ops-board-date { font-weight: 700; letter-spacing: -0.02em; font-size: 17px; color: var(--primary); }
.ops-board-toolbar .ops-board-meta { color: var(--muted); font-size: 13px; }
.ops-board-toolbar .grow { flex: 1 1 auto; }
.ops-board-toolbar .ops-board-tabs { display: inline-flex; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; background: var(--card); }
.ops-board-toolbar .ops-board-tabs a { padding: 6px 12px; font-size: 12.5px; font-weight: 600; color: var(--muted); }
.ops-board-toolbar .ops-board-tabs a.active { background: var(--primary); color: #fff; }

.ops-board-scroll { overflow-x: auto; }
table.ops-board {
    width: 100%; border-collapse: separate; border-spacing: 0;
    font-size: 13.5px; min-width: 1180px;
}
table.ops-board thead th {
    position: sticky; top: 0; z-index: 2;
    background: #F1F4F9; color: var(--status-info-ink);
    font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
    padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
table.ops-board tbody td {
    padding: 12px;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}
table.ops-board tbody tr {
    background: var(--card);
    transition: background var(--motion-fast) var(--ease-out);
}
table.ops-board tbody tr:hover { background: #FAFBFD; }
table.ops-board tbody tr.ops-row-priority {
    background: linear-gradient(90deg, rgba(184,50,53,0.05) 0%, rgba(184,50,53,0.02) 30%, #fff 65%);
}
table.ops-board tbody tr.ops-row-priority td:first-child {
    box-shadow: inset 4px 0 0 0 #B83235;
}
table.ops-board tbody tr.ops-row-vip td:first-child   { box-shadow: inset 4px 0 0 0 #B83235; }
table.ops-board tbody tr.ops-row-gt td:first-child    { box-shadow: inset 4px 0 0 0 #C18931; }
table.ops-board tbody tr.ops-row-moh td:first-child,
table.ops-board tbody tr.ops-row-moe td:first-child   { box-shadow: inset 4px 0 0 0 #5A79A5; }

/* Departed / Arrived / Completed rows stay fully readable — these are
   operationally important and shouldn't look "cancelled". Subtle muted
   tone differentiates them from active flights; the status chip in the
   Remarks column carries the explicit Departed/Arrived/Completed label.
   The explicit text-decoration: none on every descendant is defence in
   depth — it overrides any stale cached rule or upstream selector that
   might try to strike through completed flights. */
table.ops-board tbody tr.ops-row-departed {
    /* --muted, not the #5E6472 literal this used to pin: that literal IS the
       light value of the token, so light is byte-identical and the dark theme
       finally lifts the departed row off the dark card. */
    color: var(--muted);
    background: repeating-linear-gradient(0deg, transparent 0, transparent 22px, rgba(94,100,114,0.05) 22px, rgba(94,100,114,0.05) 23px);
}
table.ops-board tbody tr.ops-row-departed,
table.ops-board tbody tr.ops-row-departed td,
table.ops-board tbody tr.ops-row-departed td *,
table.ops-board tbody tr.ops-row-arrived,
table.ops-board tbody tr.ops-row-arrived td,
table.ops-board tbody tr.ops-row-arrived td *,
table.ops-board tbody tr.ops-row-completed,
table.ops-board tbody tr.ops-row-completed td,
table.ops-board tbody tr.ops-row-completed td *,
table.ops-board tbody tr.ops-row-airborne,
table.ops-board tbody tr.ops-row-airborne td,
table.ops-board tbody tr.ops-row-airborne td *,
table.ops-board tbody tr.ops-row-processed,
table.ops-board tbody tr.ops-row-processed td,
table.ops-board tbody tr.ops-row-processed td * {
    text-decoration: none !important;
    text-decoration-line: none !important;
}
table.ops-board tbody tr.ops-row-departed .reg,
table.ops-board tbody tr.ops-row-departed .ops-cell-time {
    color: var(--muted);
}

/* Cancelled flights keep the strike — the flight is not happening, so
   the visual cue is meaningful. Archived rows fade but stay readable. */
table.ops-board tbody tr.ops-row-cancelled td { opacity: 0.5; text-decoration: line-through; text-decoration-color: rgba(184,50,53,0.55); }
table.ops-board tbody tr.ops-row-archived td  { opacity: 0.55; }

table.ops-board td.ops-cell-time { font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace; font-weight: 600; color: var(--primary); white-space: nowrap; }
table.ops-board td .reg { font-weight: 700; color: var(--primary); letter-spacing: 0.01em; }
table.ops-board td .sub { color: var(--muted); font-size: 12px; }
table.ops-board td .charter { font-weight: 600; }
table.ops-board td .followup { font-weight: 700; letter-spacing: 0.04em; color: var(--status-info-ink); }

/* A/C column — registration and model/type stack as one intentional, tight
   block. The registration must never break mid-token (e.g. 8R-KTB splitting
   at the hyphen into "8R-" / "KTB"). Scoped to .ops-aircraft so the shared
   .reg/.sub tone + the departed-row muting above still cascade through. */
table.ops-board td .ops-aircraft {
    display: flex; flex-direction: column; gap: 1px;
    line-height: 1.3; min-width: max-content;
}
table.ops-board td .ops-aircraft .ops-ac-reg {
    white-space: nowrap; word-break: keep-all; overflow-wrap: normal;
    font-variant-numeric: tabular-nums;
}
table.ops-board td .ops-aircraft .ops-ac-type {
    white-space: nowrap; word-break: keep-all;
    font-size: 11.5px; line-height: 1.25;
}

.ops-board-empty { padding: 36px; text-align: center; color: var(--muted); }
.ops-board-meta-row { padding: 10px 18px; border-top: 1px solid var(--border); background: var(--surface-high); color: var(--muted); font-size: 12.5px; display: flex; gap: 16px; flex-wrap: wrap; }


/* Sweep panel + bulk-add table */

.ops-metar-strip {
    display: flex; gap: 18px; flex-wrap: wrap;
    padding: 10px 18px; border-bottom: 1px solid var(--border);
    background: var(--card);
    font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace; font-size: 12px; color: var(--status-info-ink);
}
.ops-metar-strip .lbl { color: var(--muted); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; font-size: 10.5px; }

@media (max-width: 1100px) {
    table.ops-board { font-size: 12.75px; min-width: 1080px; }
    table.ops-board tbody td { padding: 10px; }
}
@media print {
    .ops-board-toolbar, .ops-board-meta-row, .ops-metar-strip { display: none !important; }
    .ops-board-wrap { box-shadow: none; border: none; }
    table.ops-board { min-width: 0; font-size: 9pt; }
    table.ops-board thead th { background: #E8ECF5 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    table.ops-board tbody tr.ops-row-priority { background: rgba(184,50,53,0.06) !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ====================================================================
   Operations mobile flight schedule — compact table-first board
   --------------------------------------------------------------------
   Phones retain the real schedule table rather than switching to card
   modules. Aircraft and route stay frozen on the left, while the row
   action remains available on the right; times, fuel, crew and remarks
   scroll naturally between them. Desktop and all print views keep the
   established board unchanged.
   ==================================================================== */
.ops-mobile-status { display: none; }
@media (max-width: 700px) {
    .ops-board-wrap {
        border-radius: 12px;
        box-shadow: 0 6px 18px rgba(18, 44, 78, 0.08);
    }
    .ops-board-scroll {
        overflow-x: auto;
        overscroll-behavior-x: contain;
        background: var(--surface-low);
    }
    table.ops-board.ops-mobile-schedule {
        width: max-content;
        min-width: 1020px;
        font-size: 12px;
        line-height: 1.25;
    }
    table.ops-board.ops-mobile-schedule thead th {
        padding: 8px 7px;
        font-size: 9.5px;
        letter-spacing: 0.055em;
        background: #EAF0F7;
    }
    table.ops-board.ops-mobile-schedule tbody td {
        padding: 8px 7px;
        vertical-align: middle;
        background: var(--card);
    }
    table.ops-board.ops-mobile-schedule tbody tr:nth-child(even) td {
        background: var(--surface-low);
    }
    table.ops-board.ops-mobile-schedule tbody tr.ops-row-editing td {
        background: #F3F8FF;
        border-bottom-color: rgba(36, 74, 120, 0.28);
    }
    /* The board date is already present in the compact toolbar. Flight
       follower, crew and charter remain available in the desktop board and
       mobile cards, but do not displace route and ETD in the first phone
       viewport. */
    table.ops-board.ops-mobile-schedule th:nth-child(1),
    table.ops-board.ops-mobile-schedule td:nth-child(1),
    table.ops-board.ops-mobile-schedule th:nth-child(3),
    table.ops-board.ops-mobile-schedule td:nth-child(3),
    table.ops-board.ops-mobile-schedule th:nth-child(4),
    table.ops-board.ops-mobile-schedule td:nth-child(4),
    table.ops-board.ops-mobile-schedule th:nth-child(5),
    table.ops-board.ops-mobile-schedule td:nth-child(5) {
        display: none;
    }
    /* Keep one compact identity column fixed; route is the first scrolling
       column so a 390px phone still has useful rail space. */
    table.ops-board.ops-mobile-schedule th:nth-child(2),
    table.ops-board.ops-mobile-schedule td:nth-child(2) {
        position: sticky;
        left: 0;
        z-index: 3;
        min-width: 88px;
        max-width: 88px;
        box-shadow: 2px 0 0 #DCE5F0, 5px 0 10px rgba(24, 52, 84, 0.06);
    }
    table.ops-board.ops-mobile-schedule th:nth-child(2) { z-index: 6; }
    table.ops-board.ops-mobile-schedule td:nth-child(6) {
        width: 150px;
        min-width: 150px;
        max-width: 150px;
        font-weight: 650;
        color: #183B63;
        white-space: normal;
        overflow-wrap: anywhere;
    }
    table.ops-board.ops-mobile-schedule th:nth-child(7),
    table.ops-board.ops-mobile-schedule td:nth-child(7) {
        min-width: 72px;
        font-weight: 750;
    }
    /* Fuel, crew, every movement time and the full remarks/status column
       stay in the native table; the dedicated action column is frozen so
       an Operations user never has to pan to begin a quick edit. */
    table.ops-board.ops-mobile-schedule th:nth-child(14),
    table.ops-board.ops-mobile-schedule td.ops-board-actions {
        position: sticky;
        right: 0;
        z-index: 4;
        min-width: 124px;
        max-width: 124px;
        padding: 6px;
        text-align: center !important;
        white-space: normal !important;
        box-shadow: -3px 0 10px rgba(24, 52, 84, 0.12);
    }
    /* The frozen identity and action columns stay fully opaque. opacity<1
       composites a cell's own background as well, so a cancelled or archived
       row let the scrolling columns show straight through the two cells that
       exist precisely so they never move. The strike-through and the fade on
       every other cell still carry the state.
       INSIDE this media query on purpose: the audit found the first version
       at top level, where it applied at every width — on desktop the two
       cells rendered at full opacity with a strike-through through them,
       because .ops-mobile-schedule is emitted regardless of viewport. */
    table.ops-board.ops-mobile-schedule tbody tr.ops-row-cancelled td:nth-child(2),
    table.ops-board.ops-mobile-schedule tbody tr.ops-row-archived  td:nth-child(2),
    table.ops-board.ops-mobile-schedule tbody tr.ops-row-cancelled td.ops-board-actions,
    table.ops-board.ops-mobile-schedule tbody tr.ops-row-archived  td.ops-board-actions { opacity: 1; }

    table.ops-board.ops-mobile-schedule th:nth-child(14) {
        z-index: 7;
        background: #EAF0F7;
    }
    table.ops-board.ops-mobile-schedule td.ops-board-actions .btn {
        display: inline-flex !important;
        width: calc(50% - 3px);
        min-height: 44px;
        margin: 2px 0;
        padding: 6px 3px;
        font-size: 11px;
        line-height: 1.1;
        white-space: normal;
        justify-content: center;
    }
    table.ops-board.ops-mobile-schedule td.ops-board-actions form {
        display: inline !important;
    }
    table.ops-board.ops-mobile-schedule td.ops-board-actions form .btn {
        width: calc(50% - 3px);
    }
    table.ops-board.ops-mobile-schedule .ops-inline-input,
    table.ops-board.ops-mobile-schedule .ops-inline-aircraft {
        min-height: 38px;
        font-size: 16px !important;
    }
    .ops-mobile-status {
        display: block;
        margin-top: 4px;
        white-space: nowrap;
    }
    .ops-mobile-status .badge {
        font-size: 9px;
        padding: 2px 5px;
    }
    .ops-board-meta-row {
        gap: 9px;
        padding: 9px 12px;
        font-size: 11.5px;
    }
    .ops-board-meta-row span { white-space: nowrap; }
}
@media print {
    .ops-mobile-status { display: none !important; }
}

/* Print */
@media print {
    body { background: #fff; font-size: 10pt; }
    .sidebar, .topbar, .dr-toolbar, .no-print { display: none !important; }
    .app-shell { grid-template-columns: minmax(0, 1fr); }
    .content { padding: 0; }
    .dr-wrap { box-shadow: none; border: none; border-radius: 0; }
    .dr-header { background: #171756 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    table.dr { font-size: 9pt; min-width: 0; }
    table.dr th { background: #E8ECF5 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    .cell-warn, .cell-green, .cell-major, .cell-outstanding,
    .cell-coa-soon, .cell-cmr-soon, .cell-expired {
        -webkit-print-color-adjust: exact !important;
        print-color-adjust: exact !important;
    }
    .dr-kw-critical { color: #8E2226 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    .dr-kw-warn     { color: #5C3F0E !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    .dr-kw-info     { color: #1F3F73 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    .legend { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    @page { size: A3 landscape; margin: 10mm; }
}

/* Responsive
   Tiered breakpoints:
   - >=1280px : default (desktop)
   - 1100px   : laptop  — slightly tighter sidebar + table
   - 900px    : tablet  — sidebar stacks above content; tables scroll inside their card
   - 700px    : mobile  — stat grid two-up, denser typography, topbar collapses */
@media (max-width: 1280px) {
    /* The shell width is NOT tapered any more. These 220/200px steps were
       written for the flat 248px sidebar; against the rail + panel they squeeze
       the panel below its labels (151px at 1200px, wrapping "Reservation
       Intake" onto two lines) while the rail keeps its fixed 68px. Width is
       recovered by collapsing to the rail, which is a user choice, not by
       silently shaving the labels. */
    .content { padding: 24px 22px; }
    table.tbl { font-size: 13.25px; }
    table.tbl th, table.tbl td { padding: 9px 11px; }
    .tbl td.cell-remarks { max-width: 200px; }
}
@media (max-width: 1100px) {
    .content { padding: 22px 20px; }
    .topbar { padding: 12px 22px; }
    table.tbl { font-size: 13px; }
    table.tbl th, table.tbl td { padding: 8px 10px; }
    table.tbl-compact th, table.tbl-compact td { padding: 7px 9px; }
    .tbl td.cell-remarks { max-width: 180px; font-size: 12px; }
    .tbl td.cell-actions .btn-sm { padding: 5px 9px; font-size: 12px; }
    .stats-grid { gap: 14px; }
    .stat .value { font-size: 26px; }
}
@media (max-width: 900px) {
    .app-shell { grid-template-columns: minmax(0, 1fr); }
    .sidebar {
        position: static;
        height: auto;
        border-right: none;
        border-bottom: 1px solid var(--border);
        padding: 14px 16px;
    }
    .sidebar-brand { padding: 6px; margin-bottom: 12px; }
    .sidebar-brand img { max-height: 56px; }
    .sidebar-section { margin: 12px 4px 6px; }
    /* The workspace RAIL is a horizontal chip scroller on small screens and
       must not be caught by this legacy two-column page grid (it wins on
       specificity and stacks the chips into a 574px-tall column). */
    .sidebar nav:not(.ws-rail-nav) {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
        gap: 4px;
    }
    .sidebar nav a { padding: 8px 11px; font-size: var(--text-sm); margin-bottom: 0; }
    .sidebar nav a.active::before { display: none; }
    .sidebar-account { margin-top: 10px; }
    .topbar h1 { font-size: 17px; }
    .content { padding: 18px 16px; }
    .auth-page { grid-template-columns: 1fr; }
    .auth-side { padding: 32px 28px; }
    .auth-side .pitch h1 { font-size: 28px; }
}
@media (max-width: 700px) {
    .topbar { padding: 10px 14px; }
    .topbar h1 { font-size: 16px; max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .topbar-user .who,
    .user-menu-button .who { display: none; }
    .user-menu-button { padding: 4px; border-radius: 999px; }
    .user-menu-popover { right: -4px; min-width: 220px; }
    .bell-popover { right: -4px; width: min(320px, calc(100vw - 24px)); }
    .stats-grid { grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 18px; }
    .stat { padding: 14px 16px; }
    .stat .value { font-size: 22px; }
    .stat .label { font-size: 11px; }
    .content { padding: 16px 12px; }
    .card { padding: 16px; }
    table.tbl { font-size: 12.75px; }
    table.tbl th, table.tbl td { padding: 7px 9px; }
    table.tbl th { font-size: 10.5px; letter-spacing: 0.04em; }
    .tbl td.cell-remarks { max-width: 140px; font-size: 11.75px; }
    .badge { font-size: 11px; padding: 2px 8px; }
    .date-chip { font-size: 11.5px; padding: 2px 7px; }
    .tbl td.cell-actions { padding-right: 8px; }
    .tbl td.cell-actions .btn-sm { padding: 5px 8px; font-size: 11.5px; }
    .form-grid { grid-template-columns: 1fr !important; gap: 10px; }
    .section-title { flex-wrap: wrap; gap: 4px; }
}

/* ====================================================
   Premium polish layer.
   Adds focus-visible rings, refined transitions, hover lift on
   *interactive* cards (a.card-glass, gallery thumbs), and the
   form-submit loading state. All sit on top of existing styles —
   nothing here removes prior behaviour.
   ==================================================== */

/* Smooth body-scroll on anchored navigation. */
html { scroll-behavior: smooth; }

/* Buttons — active press, focus ring, disabled, loading. */
.btn { transition:
    background var(--motion-fast) var(--ease-out),
    color      var(--motion-fast) var(--ease-out),
    transform  var(--motion-fast) var(--ease-out),
    box-shadow var(--motion-fast) var(--ease-out),
    border-color var(--motion-fast) var(--ease-out),
    opacity    var(--motion-fast) var(--ease-out);
}
.btn:active { transform: translateY(0) scale(0.985); transition-duration: 80ms; }
.btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(90, 121, 165, 0.45), var(--shadow-sm);
}
.btn-primary:focus-visible {
    box-shadow: 0 0 0 3px rgba(23, 23, 86, 0.42), var(--shadow-md);
}
.btn-danger:focus-visible {
    box-shadow: 0 0 0 3px rgba(184, 50, 53, 0.40), var(--shadow-md);
}
.btn:disabled, .btn[aria-disabled="true"] {
    opacity: 0.55;
    cursor: not-allowed;
    transform: none !important;
    box-shadow: none !important;
}

/* Submit-loading state — driven by jags_polish_script() in layout_footer.
   The button text is swapped to "Saving…" with a leading spinner; the
   button stays the same width as before (no jump). */
.btn.is-loading {
    pointer-events: none;
    cursor: wait;
    opacity: 0.92;
}
.jags-spinner {
    display: inline-block;
    width: 12px; height: 12px;
    margin: 0 6px -1px 0;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: jagsSpin 700ms linear infinite;
    vertical-align: middle;
    opacity: 0.75;
}
@keyframes jagsSpin { to { transform: rotate(360deg); } }

/* Form fields — refined transition timing. The :focus ring already exists
   above; here we just align timings to the motion tokens. */
.field input, .field select, .field textarea {
    transition:
        border-color var(--motion-fast) var(--ease-out),
        box-shadow   var(--motion-fast) var(--ease-out),
        background   var(--motion-fast) var(--ease-out);
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
    outline: none;
}

/* Sidebar nav — focus + smoother hover. Active state already uses the
   JAGS gradient; we just cushion the transition. */
.sidebar nav a {
    transition:
        background var(--motion-fast) var(--ease-out),
        color      var(--motion-fast) var(--ease-out),
        box-shadow var(--motion-fast) var(--ease-out),
        transform  var(--motion-fast) var(--ease-out);
}
.sidebar nav a:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(90, 121, 165, 0.45) inset;
}
.sidebar nav a.active { transform: translateZ(0); }

/* Topbar walkthrough launcher — lift + focus ring. Existing hover already
   nudges; we just give it a real focus state. */
#jags-tour-launcher:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(90, 121, 165, 0.45);
}

/* Stat cards — content tiles, NOT clickable. Subtle shadow grow on hover so
   they feel responsive without implying interactivity. No transform. */
.stat {
    transition:
        box-shadow   var(--motion-med) var(--ease-soft),
        border-color var(--motion-med) var(--ease-soft);
}
.stat:hover {
    box-shadow: var(--shadow-md);
    border-color: rgba(39, 66, 112, 0.16);
}

/* Glass quick-action cards — lift on hover when used as a link/button.
   Targets the a/button form so plain decorative .card-glass doesn't lift. */

/* Aircraft summary cards on dashboards (.ac-card) — soft hover. */
.ac-card { transition:
    box-shadow   var(--motion-med) var(--ease-soft),
    border-color var(--motion-med) var(--ease-soft),
    transform    var(--motion-med) var(--ease-soft);
}
.ac-card:hover {
    box-shadow: var(--shadow-md);
    border-color: rgba(39, 66, 112, 0.16);
    transform: translateY(-1px);
}

/* Table rows — smooth row-hover background fade (already triggered by
   tr:hover td above — this just transitions the change). */
table.tbl tbody td {
    transition: background var(--motion-fast) var(--ease-out);
}

/* Badges + date chips — gentle when state changes (e.g. JS toggles). */
.badge, .date-chip {
    transition:
        background var(--motion-fast) var(--ease-out),
        color      var(--motion-fast) var(--ease-out),
        box-shadow var(--motion-fast) var(--ease-out);
}

/* Aircraft images — load fade-in. Modern browsers also respect the
   loading="lazy" attribute on the gallery thumbs. */
.ac-images-hero img,
.ac-images-gallery img {
    opacity: 0;
    animation: jagsImgIn var(--motion-slow) var(--ease-soft) both;
}
@keyframes jagsImgIn { from { opacity: 0; } to { opacity: 1; } }

/* Walkthrough modal — already animated. Touch-up only: align buttons +
   progress fill to the motion tokens; existing keyframes stay unchanged. */
.jags-tour-card .btn { transition-duration: var(--motion-fast); }
.jags-tour-progress .fill { transition-duration: var(--motion-med); }

/* Generic link focus ring — applied to any unstyled <a> the user can tab to. */
a:focus-visible {
    outline: 2px solid rgba(90, 121, 165, 0.55);
    outline-offset: 2px;
    border-radius: 4px;
}
.btn:focus-visible, a.card-glass:focus-visible { outline: none; }

/* ====================================================
   Reduced-motion preference — respect the OS setting.
   ==================================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    .main > .content,
    .ac-images-hero img,
    .ac-images-gallery img {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
    .jags-tour-target { animation: none !important; }
    html { scroll-behavior: auto; }
}

/* ====================================================
   Print safety — disable polish animations + hover transforms in print.
   ==================================================== */
@media print {
    .main > .content { animation: none !important; }
    .ac-images-hero img, .ac-images-gallery img { animation: none !important; opacity: 1 !important; }
    .stat, a.card-glass, .ac-card, .btn { transition: none !important; transform: none !important; box-shadow: none !important; }
}

/* ====================================================
   Walkthrough / guided tour — overlay, card, target glow.
   All scoped under #jags-tour or .jags-tour-* so it can never bleed
   into the rest of the app.
   ==================================================== */
#jags-tour-launcher {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 7px 13px;
    border-radius: 999px;
    border: 1px solid rgba(39,66,112,0.18);
    background: linear-gradient(180deg, rgba(var(--glass-rgb),0.96) 0%, rgba(var(--glass-rgb),0.90) 100%);
    -webkit-backdrop-filter: saturate(140%) blur(8px);
    backdrop-filter: saturate(140%) blur(8px);
    color: var(--secondary);
    font-weight: 600; font-size: 12.5px; letter-spacing: 0.005em;
    cursor: pointer;
    box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset, 0 1px 2px rgba(11,11,47,0.04);
    transition: background 160ms var(--ease-out), transform 160ms var(--ease-out),
                box-shadow 160ms var(--ease-out), border-color 160ms var(--ease-out);
}
#jags-tour-launcher:hover {
    border-color: rgba(39,66,112,0.36);
    box-shadow: 0 1px 0 rgba(255,255,255,0.7) inset, 0 6px 16px rgba(11,11,47,0.08);
    transform: translateY(-1px);
}
#jags-tour-launcher .spark { color: var(--info); display: inline-flex; align-items: center; line-height: 1; }
#jags-tour-launcher .spark svg { width: 14px; height: 14px; display: block; }
@media (max-width: 700px) {
    #jags-tour-launcher .label { display: none; }
    #jags-tour-launcher { padding: 7px 9px; }
}

#jags-tour { position: fixed; inset: 0; z-index: 9000; }
#jags-tour[hidden] { display: none !important; }
.jags-tour-backdrop {
    position: absolute; inset: 0;
    background:
      radial-gradient(120% 80% at 50% 0%, rgba(11,11,47,0.42) 0%, rgba(11,11,47,0.62) 60%, rgba(11,11,47,0.74) 100%);
    backdrop-filter: blur(6px) saturate(120%);
    -webkit-backdrop-filter: blur(6px) saturate(120%);
    animation: jagsTourFade 220ms var(--ease-out);
}
@keyframes jagsTourFade { from { opacity: 0; } to { opacity: 1; } }
.jags-tour-card {
    position: absolute;
    z-index: 1;
    width: min(440px, calc(100vw - 32px));
    background: linear-gradient(180deg, rgba(var(--glass-rgb),0.94) 0%, rgba(var(--glass-rgb),0.88) 100%);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
    backdrop-filter: blur(20px) saturate(160%);
    border: 1px solid rgba(255,255,255,0.6);
    border-radius: 22px;
    box-shadow:
      0 1px 0 rgba(255,255,255,0.9) inset,
      0 0 0 1px rgba(39,66,112,0.06),
      0 28px 60px -12px rgba(11,11,47,0.34),
      0 8px 18px -8px rgba(11,11,47,0.16);
    overflow: hidden;
    animation: jagsTourPop 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
    /* Smooth re-centre when one step's body is taller than another's.
       Without this, the card would snap to its new top/left when text
       changes; with it, the card glides into place. */
    transition:
        top    220ms cubic-bezier(0.22, 1, 0.36, 1),
        left   220ms cubic-bezier(0.22, 1, 0.36, 1),
        width  220ms cubic-bezier(0.22, 1, 0.36, 1);
}
@media (prefers-reduced-motion: reduce) {
    .jags-tour-card { transition: none; animation: none; }
}
@keyframes jagsTourPop {
    from { opacity: 0; transform: translateY(10px) scale(0.985); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
.jags-tour-accent {
    height: 2px;
    background: linear-gradient(90deg,
        rgba(23,23,86,0)   0%,
        rgba(23,23,86,0.55) 18%,
        rgba(90,121,165,0.95) 50%,
        rgba(23,23,86,0.55) 82%,
        rgba(23,23,86,0)   100%);
    opacity: 0.85;
}
.jags-tour-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 20px 6px;
    gap: 12px;
}
.jags-tour-head .meta {
    display: flex; align-items: center; gap: 10px; min-width: 0;
}
.jags-tour-head .badge-step {
    display: inline-flex; align-items: center; gap: 5px;
    background: rgba(39,66,112,0.06);
    border: 1px solid rgba(39,66,112,0.10);
    color: var(--secondary);
    padding: 3px 9px 3px 8px; border-radius: 999px;
    font-size: 10.5px; font-weight: 700;
    letter-spacing: 0.06em; text-transform: uppercase;
}
.jags-tour-head .badge-step::before {
    content: ""; width: 5px; height: 5px; border-radius: 999px;
    background: var(--info);
    box-shadow: 0 0 0 3px rgba(90,121,165,0.18);
}
.jags-tour-head .progress-text {
    color: var(--muted); font-size: 11.5px;
    font-variant-numeric: tabular-nums; letter-spacing: 0.02em;
}
.jags-tour-head .close-btn {
    background: transparent; border: none; cursor: pointer;
    color: var(--muted); font-size: 22px; line-height: 1;
    padding: 0; width: 28px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px;
    transition: background 140ms var(--ease-out), color 140ms var(--ease-out);
}
.jags-tour-head .close-btn:hover { background: rgba(94,100,114,0.10); color: var(--text); }
.jags-tour-head .close-btn:focus-visible {
    outline: 2px solid var(--info); outline-offset: 2px;
}

.jags-tour-progress {
    height: 3px; background: rgba(39,66,112,0.08); margin: 0 20px;
    border-radius: 999px; overflow: hidden;
}
.jags-tour-progress .fill {
    height: 100%; width: 0%;
    background: linear-gradient(90deg, var(--secondary) 0%, var(--info) 100%);
    transition: width 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.jags-tour-dots {
    display: flex; gap: 5px; padding: 10px 20px 0; flex-wrap: wrap;
}
.jags-tour-dots span {
    width: 5px; height: 5px; border-radius: 999px;
    background: rgba(39,66,112,0.14);
    transition: background 200ms var(--ease-out), transform 200ms var(--ease-out), width 200ms var(--ease-out);
}
.jags-tour-dots span.done { background: rgba(39,66,112,0.55); }
.jags-tour-dots span.current {
    background: var(--primary);
    width: 16px;
}

.jags-tour-body {
    padding: 10px 20px 4px;
    /* Buttery step transitions — fade + tiny rise as the text swaps.
       JS toggles .is-stepping for one frame, then removes it after a
       requestAnimationFrame to fade the new content back in. */
    transition: opacity 180ms cubic-bezier(0.22, 1, 0.36, 1),
                transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
    will-change: opacity, transform;
}
.jags-tour-body.is-stepping {
    opacity: 0;
    transform: translateY(4px);
}
.jags-tour-body h3 {
    margin: 0 0 6px;
    font-size: 18px; line-height: 1.3;
    letter-spacing: -0.012em;
    color: var(--text);
    font-weight: 600;
}
.jags-tour-body p {
    margin: 0;
    color: var(--muted);
    font-size: 14px; line-height: 1.55;
    letter-spacing: -0.002em;
}
/* Reduced-motion users get an instant swap, no fade. */
@media (prefers-reduced-motion: reduce) {
    .jags-tour-body { transition: none; }
    .jags-tour-body.is-stepping { opacity: 1; transform: none; }
}
.jags-tour-actions {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 20px 18px;
    gap: 10px;
}
.jags-tour-actions .nav-group { display: flex; gap: 8px; }
.jags-tour-actions .btn {
    padding: 8px 14px; font-size: 13px;
    border-radius: 10px;
}
.jags-tour-actions .btn-primary {
    box-shadow: 0 4px 14px rgba(23,23,86,0.22);
}
.jags-tour-actions .btn-primary:focus-visible,
.jags-tour-actions .btn-ghost:focus-visible {
    outline: 2px solid var(--info); outline-offset: 2px;
}

/* While a tour is open, dim/de-saturate the rest of the app so the user's
   eye is drawn to the highlighted target. The target itself sits at a
   higher z-index and is exempt from the dim. */
body.jags-tour-active .app-shell {
    filter: saturate(0.82) brightness(0.9);
    transition: filter var(--motion-med) var(--ease-soft);
}
body.jags-tour-active .jags-tour-target,
body.jags-tour-active .jags-tour-target * {
    filter: none !important;
}

/* Spotlight target highlight — calmer ring, refined glow. */
.jags-tour-target {
    position: relative;
    z-index: 9001;
    border-radius: 12px;
    box-shadow:
      0 0 0 3px rgba(255,255,255,0.96),
      0 0 0 5px rgba(90,121,165,0.65),
      0 0 0 9px rgba(90,121,165,0.18),
      0 18px 40px -8px rgba(11,11,47,0.28);
    animation: jagsTargetPulse 2.6s ease-in-out infinite;
    transition: box-shadow 240ms var(--ease-out);
}
@keyframes jagsTargetPulse {
    0%, 100% {
        box-shadow:
          0 0 0 3px rgba(255,255,255,0.96),
          0 0 0 5px rgba(90,121,165,0.55),
          0 0 0 9px rgba(90,121,165,0.14),
          0 18px 40px -8px rgba(11,11,47,0.26);
    }
    50% {
        box-shadow:
          0 0 0 3px rgba(255,255,255,0.96),
          0 0 0 5px rgba(90,121,165,0.85),
          0 0 0 12px rgba(90,121,165,0.22),
          0 18px 44px -8px rgba(11,11,47,0.30);
    }
}

@media (max-width: 700px) {
    .jags-tour-card { width: calc(100vw - 24px); }
    .jags-tour-actions { flex-direction: column-reverse; align-items: stretch; }
    .jags-tour-actions .nav-group { width: 100%; justify-content: space-between; }
    .jags-tour-actions .btn { flex: 1; justify-content: center; }
}

/* Fully hide the tour during print so it never lands on paper */
@media print {
    #jags-tour, #jags-tour-launcher { display: none !important; }
    .jags-tour-target { box-shadow: none !important; animation: none !important; }
}

/* Broad print guard — final catch-all so no animation, transition, spinner,
   tour glow, or smooth-scroll polish leaks into printed output. Sits AFTER
   the existing print rules so it overrides anything the polish layer might
   have introduced. The earlier @media print blocks (Daily Report A3/landscape,
   colour preservation, sidebar/topbar/walkthrough/aircraft-images hide,
   print-color-adjust) keep their own !important rules and remain authoritative
   for layout. */
@media print {
    *, *::before, *::after {
        animation: none !important;
        transition: none !important;
        scroll-behavior: auto !important;
    }
}

/* ---------------------------------------------------------------
   Final polish pass — calmer hovers, tighter buttons, sharper focus
   rings, restraint on shadows. Loaded last so these rules win for
   the small set of selectors below without rewriting the rest of
   the system. Apple/Vercel/Linear-style restraint.
   --------------------------------------------------------------- */

/* Calmer button hovers — drop the +1px float so the UI doesn't feel
   fidgety. Keep the colour shift and a softer shadow lift. */
.btn-primary:hover  { transform: none; box-shadow: 0 2px 8px rgba(11, 11, 47, 0.18); }
.btn-secondary:hover { transform: none; }
.btn-ghost:hover    { transform: none; }
.btn-danger:hover   { transform: none; }

/* Consistent focus ring across buttons + nav. Replaces the various
   ad-hoc :focus-visible boxes scattered across the file. */
.btn:focus-visible,
.sidebar nav a:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(23, 23, 86, 0.22);
}

/* Hairline divider on the topbar so it floats over scrolled content
   instead of sitting on a hard line. */
.topbar { box-shadow: 0 1px 0 rgba(14, 14, 18, 0.04); }

/* Slightly tighter, calmer badge spacing — less "tag", more "chip". */
.badge { padding: 2px 8px; font-weight: 600; }

/* Tone the radial highlight inside .stat tiles so they don't read as
   "every card has a glow corner." */

/* Section titles read as proper headings — slightly tighter tracking,
   slightly more weight. */
.section-title h2 { font-weight: 650; letter-spacing: -0.02em; }

/* Card-hero: airy shadow with a slight navy tint so the brand moment
   feels lifted without competing with the page content. */
.card-hero { box-shadow: 0 30px 60px rgba(11, 11, 47, 0.10), 0 1px 2px rgba(14, 14, 18, 0.04); }

/* (Removed 2026-08) A later `.empty-state` redefinition here used to
   collapse the real component's 42px padding to 4px — the icon/title/CTA
   empty state is owned by its primary block earlier in this sheet. */

/* Quick-link rows (Pilot Portal, Maintenance, Display Center) —
   left-aligned ghost buttons read as a navigation list, not as a
   row of five identical CTAs. */
.btn-ghost.btn-quicklink {
    justify-content: flex-start;
    gap: 10px;
    padding: 10px 12px;
    font-weight: 500;
}
.btn-ghost.btn-quicklink .jags-icon {
    color: var(--secondary); opacity: 0.85;
    width: 16px; height: 16px;
}
.btn-ghost.btn-quicklink:hover .jags-icon { color: var(--primary); opacity: 1; }

/* Tighter alert padding so flash messages don't dominate the page
   heading row. */
.alert { padding: 10px 14px; }

/* Tables — calm zebra rows + subtle navy hover. */
table.tbl tbody tr:nth-child(even) td { background: var(--surface-low); }
table.tbl tbody tr:hover td { background: rgba(90, 121, 165, 0.06); }

/* Brand-sub in the sidebar — give the new "Aviation Management System"
   text a hair more breathing room than the old subtitle. */
.sidebar-brand .brand-sub { font-size: 10.5px; padding: 4px 6px 2px; }

/* ====================================================================
   Mobile UX layer — hamburger drawer, bottom nav, page helpers.
   Final mobile-refinement pass. Sits last so its rules win for
   sub-900px breakpoints without rewriting earlier responsive blocks.
   ==================================================================== */

/* Generic mobile/desktop visibility helpers (opt-in classes for pages). */
.mobile-only { display: none !important; }
@media (max-width: 900px) {
    .mobile-only { display: revert !important; }
    .desktop-only { display: none !important; }
}

/* Hamburger toggle in the topbar — hidden on desktop, visible on mobile. */
.mobile-nav-toggle {
    display: none;
    background: rgba(90,121,165,0.08);
    border: 1px solid var(--border);
    border-radius: 10px;
    color: var(--primary);
    width: 40px; height: 40px;
    align-items: center; justify-content: center;
    cursor: pointer; padding: 0;
    transition:
        background var(--motion-fast) var(--ease-out),
        color var(--motion-fast) var(--ease-out),
        box-shadow var(--motion-fast) var(--ease-out);
}
.mobile-nav-toggle:hover { background: rgba(90,121,165,0.18); }
.mobile-nav-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(90,121,165,0.40);
}
.mobile-nav-toggle .bars {
    display: inline-flex; flex-direction: column; gap: 4px;
    pointer-events: none;
}
.mobile-nav-toggle .bars span {
    display: block; width: 18px; height: 2px;
    background: currentColor; border-radius: 2px;
    transition: transform var(--motion-fast) var(--ease-out), opacity var(--motion-fast) var(--ease-out);
}
@media (max-width: 900px) {
    .mobile-nav-toggle { display: inline-flex; }
}
body.mobile-nav-open .mobile-nav-toggle .bars span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
body.mobile-nav-open .mobile-nav-toggle .bars span:nth-child(2) { opacity: 0; }
body.mobile-nav-open .mobile-nav-toggle .bars span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Drawer backdrop — covers the page while the slide-in nav is open. */
.mobile-drawer-backdrop {
    position: fixed;
    inset: 0;
    z-index: 9090;
    background: rgba(11,11,47,0.46);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--motion-med) var(--ease-out);
}
body.mobile-nav-open .mobile-drawer-backdrop {
    opacity: 1;
    pointer-events: auto;
}
.mobile-drawer-backdrop[aria-hidden="true"] {
    opacity: 0 !important;
    pointer-events: none !important;
}
@media (min-width: 901px) {
    .mobile-drawer-backdrop { display: none; }
    body.mobile-nav-open { overflow: visible !important; }
}

/* Lock body scroll while drawer is open. */
body.mobile-nav-open { overflow: hidden; }

/* Mobile drawer reuses the existing .sidebar element. Slide-in panel,
   role-aware nav, branding, account block. Desktop sidebar layout is
   untouched above 900px. */
@media (max-width: 900px) {
    .app-shell { grid-template-columns: minmax(0, 1fr); }
    .sidebar {
        position: fixed;
        top: 0; left: 0;
        width: min(286px, 84vw);
        height: 100vh;
        height: 100dvh;
        max-height: 100vh;
        max-height: 100dvh;
        z-index: 9100;
        background: var(--grad-sidebar);
        border-right: 1px solid var(--sidebar-border);
        border-bottom: none;
        box-shadow: 18px 0 40px rgba(5,7,22,0.42);
        padding: 18px 14px calc(20px + var(--safe-area-bottom));
        transform: translateX(-105%);
        visibility: hidden;
        pointer-events: none;
        transition:
            transform var(--motion-med) var(--ease-premium),
            visibility 0s linear var(--motion-med);
        overflow-y: auto;
        overflow-x: hidden;
        overscroll-behavior-y: contain;
        -webkit-overflow-scrolling: touch;
        will-change: transform;
    }
    body.mobile-nav-open .sidebar {
        transform: translateX(0);
        visibility: visible;
        pointer-events: auto;
        transition:
            transform var(--motion-med) var(--ease-premium),
            visibility 0s linear 0s;
    }
    .sidebar-brand { padding: 8px; margin-bottom: 14px; }
    .sidebar-brand img { max-height: 48px; }
    .sidebar-section { margin: 14px 6px 8px; }
    /* Excludes the workspace rail for the same reason as the grid above: this
       resets the page list to a single stacked column on phones, and the rail
       is a horizontal chip scroller. */
    .sidebar nav:not(.ws-rail-nav) {
        display: block;
        gap: 0;
    }
    .sidebar nav a {
        padding: 11px 12px;
        font-size: var(--text-base);
        margin-bottom: 2px;
    }
    .sidebar nav a.active::before { display: none; }
    .sidebar-account {
        position: sticky;
        bottom: 0;
        background: rgba(11, 14, 38, 0.96);
        -webkit-backdrop-filter: blur(8px);
        backdrop-filter: blur(8px);
        margin: 12px -4px -4px;
        padding: 12px;
        z-index: 1;
    }
}

/* Mobile bottom navigation — 5 thumb-friendly destinations on phones. */
.mobile-bottom-nav { display: none; }
@media (max-width: 900px) {
    .mobile-bottom-nav {
        position: fixed;
        bottom: 0; left: 0; right: 0;
        z-index: 8000;
        background: rgba(var(--glass-rgb), 0.96);
        -webkit-backdrop-filter: blur(14px) saturate(160%);
        backdrop-filter: blur(14px) saturate(160%);
        border-top: 1px solid var(--border);
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: 1fr;
        align-items: stretch;
        padding: 4px max(8px, env(safe-area-inset-left, 0px)) max(6px, env(safe-area-inset-bottom, 0px)) max(8px, env(safe-area-inset-right, 0px));
        box-shadow: 0 -4px 18px rgba(11,11,47,0.07);
    }
    .mobile-bottom-nav a,
    .mobile-bottom-nav button {
        position: relative;
        background: transparent;
        border: none;
        cursor: pointer;
        text-decoration: none;
        color: var(--muted);
        font-family: inherit;
        font-size: 10.5px;
        font-weight: 600;
        letter-spacing: 0.005em;
        line-height: 1.05;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 8px 4px 6px;
        border-radius: 10px;
        min-width: 0;
        transition:
            color var(--motion-fast) var(--ease-out),
            background var(--motion-fast) var(--ease-out);
    }
    .mobile-bottom-nav a .jags-icon,
    .mobile-bottom-nav button .jags-icon { width: 22px; height: 22px; opacity: 0.85; }
    .mobile-bottom-nav a .label,
    .mobile-bottom-nav button .label {
        max-width: 100%;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .mobile-bottom-nav a:hover,
    .mobile-bottom-nav button:hover {
        color: var(--primary);
        background: rgba(90,121,165,0.06);
    }
    .mobile-bottom-nav a:hover .jags-icon,
    .mobile-bottom-nav button:hover .jags-icon { opacity: 1; }
    .mobile-bottom-nav a.active { color: var(--primary); }
    .mobile-bottom-nav a.active .jags-icon { opacity: 1; }
    /* The "More" button opens the drawer; reflect that open state so the
       active destination in the bar is never ambiguous. aria-expanded is
       toggled in JS (see #jags-mobile-more handlers). */
    .mobile-bottom-nav #jags-mobile-more[aria-expanded="true"] { color: var(--primary); }
    .mobile-bottom-nav #jags-mobile-more[aria-expanded="true"] .jags-icon { opacity: 1; }
    .mobile-bottom-nav a.active::before {
        content: "";
        position: absolute;
        top: 0; left: 22%; right: 22%;
        height: 3px; border-radius: 0 0 3px 3px;
        background: var(--grad-jags);
    }
    .mobile-bottom-nav a:focus-visible,
    .mobile-bottom-nav button:focus-visible {
        outline: none;
        box-shadow: 0 0 0 3px rgba(90,121,165,0.40);
    }
    /* Reserve space below content so the bottom bar never covers actions. */
    .main > .content { padding-bottom: var(--mobile-bottom-nav-clearance); }
}

/* Hide mobile chrome on print and on wallboard / display pages. */
@media print {
    .mobile-bottom-nav,
    .mobile-drawer-backdrop,
    .mobile-nav-toggle { display: none !important; }
    body.mobile-nav-open .sidebar { transform: none !important; box-shadow: none !important; }
    body.mobile-nav-open { overflow: visible !important; }
}
.display-shell .mobile-bottom-nav,
.display-shell .mobile-drawer-backdrop,
.display-shell .mobile-nav-toggle { display: none !important; }

/* Tighter card/grid rhythm on phones. */
@media (max-width: 700px) {
    .stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-bottom: 14px; }
    .stat { padding: 12px 14px; border-radius: 12px; }
    .stat .value { font-size: 21px; }
    .stat .label { font-size: 10.5px; }
    .stat .delta { font-size: 11px; }
    .card { padding: 14px; border-radius: 12px; }
    .card + .card { margin-top: 14px; }
    .card-hero { padding: 18px 16px 20px; border-radius: 14px; }
    .card-hero h2 { font-size: 22px; line-height: 1.2; }
    .card-hero p { font-size: 13.5px; }
    .ac-grid { grid-template-columns: 1fr; gap: 12px; }
    .ac-card { padding: 14px; }
    .ac-card .reg { font-size: 19px; }
    .ac-card .actions { flex-wrap: wrap; gap: 6px; }
    .ac-card .actions .btn { flex: 1 1 110px; justify-content: center; }
    .form-actions { flex-wrap: wrap; gap: 8px; }
    .form-actions .btn { flex: 1 1 140px; justify-content: center; }
    .form-actions .btn-block { flex-basis: 100%; }
    .topbar { padding: 8px 12px; gap: 8px; }
    .topbar h1 {
        font-size: 15.5px;
        max-width: 100%;
        overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
        flex: 1 1 auto; min-width: 0;
    }
    .topbar-user { gap: 8px; }
    .dr-toolbar { padding: 12px 14px; gap: 8px; }
    .dr-toolbar .btn,
    .dr-toolbar a.btn { flex: 1 1 140px; justify-content: center; }
    .dr-toolbar > form { flex: 1 1 100%; }
    .dr-header { padding: 18px 16px; gap: 10px; }
    .dr-header .title { gap: 12px; }
    .dr-header .title img { width: 60px; height: 60px; }
    .dr-header h1 { font-size: 19px; }
    .dr-header .meta { text-align: left; font-size: 12.5px; }
    .dr-header .meta strong { font-size: 14px; }
    .ops-board-toolbar { padding: 10px 12px; gap: 6px; }
    .ops-board-toolbar .btn { flex: 1 1 130px; justify-content: center; }
    /* Single-column on phones: the label reads as a compact eyebrow directly
       above its value, with ONE dashed hairline between pairs. The base
       per-cell solid border-top is cleared here — in a stacked single column
       it would otherwise draw a stray rule between a label and its own value
       (the heavy "ladder" look). Desktop keeps its row rules; this is scoped
       to the phone breakpoint only. */
    .kv { grid-template-columns: 1fr; gap: 0; }
    .kv .k { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; border-top: none; padding: 9px 0 1px; }
    .kv .v { border-top: none; padding: 0 0 9px; border-bottom: 1px dashed var(--border); }
    .kv .k:last-of-type + .v { border-bottom: none; padding-bottom: 0; }
    .tabs { overflow-x: auto; flex-wrap: nowrap; }
    .tabs a { white-space: nowrap; padding: 9px 12px; font-size: 13px; }
}

/* Horizontal scroll hint chip for tables / boards that intentionally
   stay wide on mobile (Daily Report, Operations board, etc.). */
.mobile-scroll-hint { display: none; }
@media (max-width: 700px) {
    .mobile-scroll-hint {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 8px 12px;
        background: rgba(90,121,165,0.08);
        border: 1px solid rgba(90,121,165,0.20);
        border-radius: 10px;
        color: var(--secondary);
        font-size: 12px;
        line-height: 1.4;
        margin-bottom: 10px;
    }
    .mobile-scroll-hint::before {
        content: "↔";
        font-size: 14px;
        font-weight: 700;
        color: var(--primary);
        flex: 0 0 auto;
    }
}
@media print {
    .mobile-scroll-hint { display: none !important; }
}

/* Sticky thumb-anchored action bar — opt-in, used by form pages
   (Update Flight Hours etc.) so the primary CTA is always reachable. */
.sticky-mobile-actions { display: contents; }
@media (max-width: 700px) {
    .sticky-mobile-actions {
        position: sticky;
        bottom: calc(var(--mobile-bottom-nav-footprint) + 16px);
        z-index: 100;
        background: rgba(var(--glass-rgb), 0.96);
        -webkit-backdrop-filter: blur(14px) saturate(160%);
        backdrop-filter: blur(14px) saturate(160%);
        margin: 14px -14px -14px;
        padding: 12px 14px max(12px, env(safe-area-inset-bottom, 0px));
        border-top: 1px solid var(--border);
        border-bottom-left-radius: 12px;
        border-bottom-right-radius: 12px;
        display: flex; gap: 8px; flex-wrap: wrap;
    }
    .sticky-mobile-actions .btn { flex: 1 1 auto; justify-content: center; }
}
@media print {
    .sticky-mobile-actions { position: static !important; padding: 0 !important; margin: 0 !important; background: none !important; border: none !important; }
}

/* Mobile card list — pages that opt in render a desktop .table-wrap.desktop-only
   plus a parallel .mobile-card-list.mobile-only built from the same data. */
.mobile-card-list { display: none; }
@media (max-width: 700px) {
    .mobile-card-list { display: grid; gap: 10px; }
    .mobile-card-list-item {
        background: var(--card);
        border: 1px solid var(--border);
        border-radius: 12px;
        padding: 12px 14px;
        box-shadow: var(--shadow-sm);
    }
    .mobile-card-list-item .head {
        display: flex; align-items: baseline; justify-content: space-between;
        gap: 10px; margin-bottom: 6px;
    }
    .mobile-card-list-item .head .reg {
        font-size: 17px; font-weight: 700;
        color: var(--primary); letter-spacing: -0.02em;
    }
    .mobile-card-list-item .row {
        display: flex; justify-content: space-between; gap: 12px;
        font-size: 12.75px;
        padding: 4px 0;
    }
    .mobile-card-list-item .row + .row { border-top: 1px dashed var(--border); padding-top: 6px; }
    .mobile-card-list-item .row .k { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
    .mobile-card-list-item .row .v { font-weight: 600; text-align: right; min-width: 0; }
    .mobile-card-list-item .actions {
        display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap;
    }
    .mobile-card-list-item .actions .btn { flex: 1 1 auto; justify-content: center; padding: 8px 10px; }
}

/* Cascade fix: .mobile-only sets `display: revert !important;` below 900px,
   which would otherwise revert .mobile-card-list back to its default block
   layout (since !important on a shorthand-equivalent declaration wins).
   Re-pin grid + spacing for the combined selector so card lists keep the
   intended grid rhythm on phones and small tablets. */
@media (max-width: 900px) {
    .mobile-card-list.mobile-only {
        display: grid !important;
        gap: 10px;
    }
}

/* Walkthrough as a bottom sheet on phones — ensures the highlighted target
   is visible above the card and tap targets are large. */
@media (max-width: 700px) {
    .jags-tour-card.is-mobile-bottom {
        position: fixed !important;
        left: 12px !important;
        right: 12px !important;
        bottom: calc(12px + var(--safe-area-bottom)) !important;
        top: auto !important;
        width: auto !important;
        max-width: none !important;
        max-height: 70vh !important;
        overflow-y: auto !important;
        border-radius: 18px;
    }
    .jags-tour-card.is-mobile-bottom .jags-tour-actions {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 8px;
        padding: 14px 16px 16px;
    }
    .jags-tour-card.is-mobile-bottom .jags-tour-actions .nav-group { width: 100%; gap: 8px; }
    .jags-tour-card.is-mobile-bottom .jags-tour-actions .nav-group .btn { flex: 1; }
    .jags-tour-card.is-mobile-bottom .jags-tour-actions .btn { padding: 11px 14px; font-size: 13.5px; min-height: 42px; }
    .jags-tour-card.is-mobile-bottom .jags-tour-body { padding: 14px 16px 4px; }
    .jags-tour-card.is-mobile-bottom .jags-tour-body h3 { font-size: 17px; }
    .jags-tour-card.is-mobile-bottom .jags-tour-body p { font-size: 13.5px; }
    .jags-tour-card.is-mobile-bottom .jags-tour-head { padding: 14px 16px 8px; }
    .jags-tour-card.is-mobile-bottom .jags-tour-progress { margin: 0 16px; }
    .jags-tour-card.is-mobile-bottom .jags-tour-dots { padding: 8px 16px 0; }
}

/* ====================================================================
   Navigation polish — page-leave fade + thin top progress bar.
   The progress bar element is rendered by layout_footer() and toggled
   via the .visible class. Browser navigation does the heavy lifting;
   this layer just gives instant click feedback and a subtle "loading"
   hint on slower transitions.
   ==================================================================== */
.jags-nav-progress {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 2px;
    z-index: 9999;
    pointer-events: none;
    background: rgba(23,23,86,0.06);
    opacity: 0;
    transition: opacity var(--motion-fast) var(--ease-out);
    overflow: hidden;
}
.jags-nav-progress::before {
    content: "";
    position: absolute;
    top: 0; bottom: 0; left: 0;
    width: 38%;
    background: linear-gradient(90deg, transparent 0%, var(--secondary) 25%, var(--primary) 50%, var(--secondary) 75%, transparent 100%);
    box-shadow: 0 0 8px rgba(23, 23, 86, 0.32);
    transform: translateX(-110%);
    will-change: transform;
}
.jags-nav-progress.visible { opacity: 1; }
.jags-nav-progress.visible::before {
    animation: jagsNavSlide 1100ms cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
@keyframes jagsNavSlide {
    0%   { transform: translateX(-110%); }
    100% { transform: translateX(360%); }
}

/* Page-leave fade — kept very gentle so navigation never feels slower.
   Only the page content fades; topbar / sidebar / drawer / bottom nav
   stay fully opaque so the user keeps their bearings. The arrival side
   is handled by the existing .jagsPageIn entrance animation.
   `animation: none` is required because .main > .content has the entrance
   animation in `fill-mode: both`, whose held final-frame opacity:1 would
   otherwise win the cascade against this declaration. */
body.is-navigating .main > .content {
    animation: none;
    opacity: 0.62;
    transition: opacity 140ms var(--ease-out);
}

/* Print + display board safety — never animate, never show the bar. */
@media print {
    .jags-nav-progress { display: none !important; }
    body.is-navigating .main > .content { opacity: 1 !important; transition: none !important; }
}
.display-shell .jags-nav-progress { display: none !important; }

/* Reduced motion — keep the bar visible (so users still see *something*
   on slow loads) but stop the animation. Skip the leave fade entirely. */
@media (prefers-reduced-motion: reduce) {
    .jags-nav-progress.visible::before {
        animation: none !important;
        transform: translateX(0) !important;
        width: 100% !important;
        opacity: 0.55;
    }
    body.is-navigating .main > .content {
        opacity: 1 !important;
        transition: none !important;
    }
}

/* ------------------------------------------------------------------
   PWA install affordance.
   The trigger elements are always in the DOM but hidden by default.
   pwa-install.js sets one of these classes on <html>:
     .pwa-installable  beforeinstallprompt fired (Android, Desktop)
     .pwa-ios          iOS Safari (use Add-to-Home-Screen modal)
     .pwa-installed    already running standalone — hide everything
   ------------------------------------------------------------------ */
.jags-pwa-install-pill,
.jags-pwa-install-card { display: none; }

html.pwa-installable .jags-pwa-install-pill,
html.pwa-ios         .jags-pwa-install-pill { display: inline-flex; }

html.pwa-installable .jags-pwa-install-card,
html.pwa-ios         .jags-pwa-install-card { display: flex; }

html.pwa-installed .jags-pwa-install-pill,
html.pwa-installed .jags-pwa-install-card,
html.pwa-installed #jags-pwa-ios-modal { display: none !important; }

/* Instruction-modal copy is platform-aware: the default/iOS list shows the
   Safari Share-sheet steps; html.pwa-android (set by pwa-install.js on any
   non-iOS device) swaps in the Chrome ⋮-menu steps. Only the FALLBACK path
   ever opens this modal on Android — when beforeinstallprompt fired, the
   Install button triggers the native prompt instead. */
.jags-pwa-steps-android { display: none; }
html.pwa-android .jags-pwa-steps-ios { display: none; }
html.pwa-android .jags-pwa-steps-android { display: block; }

/* ------------------------------------------------------------------
   Public auth-shell install banner (login / register / pending …).
   The signed-in shell has a topbar pill + drawer card, but a brand-new
   staff member on the sign-up page had NO install affordance at all in
   Chrome on Android — Samsung Internet / Firefox surface their own
   install UI for any site with a manifest, which is why staff were told
   to "use a different browser to download the app". This banner gives
   Chrome (and iOS Safari) users the same one-tap install path before
   they ever sign in.
   Hidden by default; shown only when pwa-install.js marks the page
   installable (or iOS), never once installed, dismissible (14 days,
   body.jags-pwa-banner-dismissed via localStorage), and phone/tablet
   only — desktop keeps the uncluttered auth card.
   ------------------------------------------------------------------ */
.jags-pwa-auth-banner { display: none; }
html.pwa-installable body:not(.jags-pwa-banner-dismissed) .jags-pwa-auth-banner,
html.pwa-ios         body:not(.jags-pwa-banner-dismissed) .jags-pwa-auth-banner { display: flex; }
html.pwa-installed .jags-pwa-auth-banner { display: none !important; }
/* While the fixed banner is visible, reserve scroll room at the page bottom
   so it can never sit over the last tappable element (e.g. the final
   department card or the page footer links). */
@media (max-width: 900.98px) {
    html.pwa-installable body:not(.jags-pwa-banner-dismissed),
    html.pwa-ios         body:not(.jags-pwa-banner-dismissed) {
        padding-bottom: calc(110px + env(safe-area-inset-bottom, 0px));
    }
    html.pwa-installed body { padding-bottom: 0; }
}
.jags-pwa-auth-banner {
    position: fixed;
    left: 12px; right: 12px;
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    z-index: 8500; /* above page content, below the install modal (9000) */
    max-width: 480px;
    margin: 0 auto;
    align-items: center;
    gap: 12px;
    background: var(--card);
    border: 1px solid rgba(23, 23, 86, 0.14);
    border-radius: 14px;
    box-shadow: 0 12px 32px rgba(8, 10, 24, 0.18);
    padding: 10px 12px;
}
.jags-pwa-auth-banner__icon {
    flex: 0 0 auto;
    width: 38px; height: 38px;
    border-radius: 10px;
    background: var(--primary, #171756);
    color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
}
.jags-pwa-auth-banner__text { flex: 1 1 auto; min-width: 0; }
.jags-pwa-auth-banner__title {
    display: block;
    font-size: 13.5px; font-weight: 700; color: var(--primary, #171756);
    line-height: 1.25;
}
.jags-pwa-auth-banner__sub {
    display: block;
    font-size: 12px; color: var(--muted); line-height: 1.3; margin-top: 1px;
}
.jags-pwa-auth-banner__btn {
    flex: 0 0 auto;
    border: 0;
    border-radius: 999px;
    background: var(--primary, #171756);
    color: #fff;
    font-size: 12.5px; font-weight: 700;
    padding: 9px 16px;
    cursor: pointer;
    line-height: 1;
}
.jags-pwa-auth-banner__btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(23, 23, 86, 0.30);
}
.jags-pwa-auth-banner__dismiss {
    flex: 0 0 auto;
    border: 0; background: none;
    /* Was #8A90A0 — 3.19:1 on the light card, i.e. it failed in LIGHT mode
       too. --muted is the token the sibling .toast-close dismiss glyph
       already uses and it clears AA on both cards. */
    color: var(--muted);
    font-size: 18px; line-height: 1;
    padding: 6px;
    margin-left: -4px;
    cursor: pointer;
}
@media (min-width: 901px) {
    /* Desktop keeps the clean auth card; the signed-in topbar pill covers
       desktop installs. */
    .jags-pwa-auth-banner { display: none !important; }
}

/* Topbar pill — desktop and tablet only. The drawer card replaces it on
   small screens so the topbar stays uncluttered on phones. */
.jags-pwa-install-pill {
    align-items: center;
    gap: 6px;
    padding: 6px 12px 6px 10px;
    border: 1px solid rgba(23, 23, 86, 0.18);
    border-radius: 999px;
    background: rgba(23, 23, 86, 0.04);
    color: var(--primary, #171756);
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: 0.005em;
    cursor: pointer;
    line-height: 1;
    transition: background-color 120ms ease, border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
}
.jags-pwa-install-pill:hover {
    background: rgba(23, 23, 86, 0.10);
    border-color: rgba(23, 23, 86, 0.32);
    transform: translateY(-1px);
    box-shadow: 0 2px 6px rgba(23, 23, 86, 0.12);
}
.jags-pwa-install-pill:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(23, 23, 86, 0.30);
}
.jags-pwa-install-pill__icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 16px; height: 16px;
}
.jags-pwa-install-pill__label { white-space: nowrap; }

/* Below 900px the topbar gets crowded; the drawer card carries the action. */
@media (max-width: 900px) {
    html.pwa-installable .jags-pwa-install-pill,
    html.pwa-ios         .jags-pwa-install-pill { display: none; }
}

/* Drawer card — sits between Workspace nav and Account, inside the slide-in
   drawer on mobile and the static sidebar on desktop. */
.jags-pwa-install-card {
    align-items: center;
    gap: 10px;
    margin: 14px 14px 6px;
    padding: 10px 12px;
    background: linear-gradient(180deg, rgba(23, 23, 86, 0.06), rgba(23, 23, 86, 0.02));
    border: 1px solid rgba(23, 23, 86, 0.14);
    border-radius: 12px;
    color: var(--text, #1a1a1a);
}
.jags-pwa-install-card__icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px;
    border-radius: 8px;
    background: var(--primary, #171756);
    color: #fff;
    flex: 0 0 auto;
}
.jags-pwa-install-card__body { min-width: 0; flex: 1 1 auto; }
.jags-pwa-install-card__title {
    font-size: 13px; font-weight: 700;
    color: var(--text-strong, #0e0e22);
    line-height: 1.2;
}
.jags-pwa-install-card__sub {
    font-size: 11.5px; color: var(--muted, #6b6b7a);
    line-height: 1.3; margin-top: 2px;
}
.jags-pwa-install-card__btn {
    flex: 0 0 auto;
    padding: 6px 12px;
    border: 0;
    border-radius: 8px;
    background: var(--primary, #171756);
    color: #fff;
    font-size: 12px; font-weight: 600;
    cursor: pointer;
    transition: background-color 120ms ease, transform 120ms ease;
}
.jags-pwa-install-card__btn:hover { background: #0f0f3f; transform: translateY(-1px); }
.jags-pwa-install-card__btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(23, 23, 86, 0.35);
}
/* Dark-rail context — the install card lives inside the navy .sidebar, so
   its light gradient + dark title would vanish/clash. Re-tone it for dark.
   Scoped to .sidebar so the card stays light if ever reused on a light
   surface. The install PILL (.jags-pwa-install-pill) lives in the light
   topbar and is intentionally untouched. */
.sidebar .jags-pwa-install-card {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--sidebar-border);
    color: var(--sidebar-text);
}
.sidebar .jags-pwa-install-card__icon {
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
}
.sidebar .jags-pwa-install-card__title { color: #fff; }
.sidebar .jags-pwa-install-card__sub { color: var(--sidebar-muted); }
.sidebar .jags-pwa-install-card__btn {
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
}
.sidebar .jags-pwa-install-card__btn:hover { background: rgba(255, 255, 255, 0.22); }

/* iOS instruction modal — shown only when the user taps the install
   trigger on iOS. */
#jags-pwa-ios-modal[hidden] { display: none; }
#jags-pwa-ios-modal {
    position: fixed; inset: 0;
    z-index: 9000;
    display: flex; align-items: center; justify-content: center;
    padding: 16px;
}
.jags-pwa-modal-backdrop {
    position: absolute; inset: 0;
    background: rgba(8, 10, 24, 0.55);
    backdrop-filter: blur(2px);
}
.jags-pwa-modal-dialog {
    position: relative;
    max-width: 380px; width: 100%;
    background: var(--card);
    border-radius: 16px;
    box-shadow: 0 24px 60px rgba(8, 10, 24, 0.35);
    padding: 22px 22px 18px;
    color: var(--text, #1a1a1a);
}
.jags-pwa-modal-dialog__header {
    display: flex; align-items: center; gap: 12px; margin-bottom: 10px;
}
.jags-pwa-modal-dialog__logo {
    width: 40px; height: 40px;
    border-radius: 10px;
    background: var(--primary, #171756);
    color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
    flex: 0 0 auto;
}
.jags-pwa-modal-dialog__title {
    font-size: 16px; font-weight: 700;
    color: var(--text-strong, #0e0e22);
    line-height: 1.25;
}
.jags-pwa-modal-dialog__steps {
    margin: 8px 0 14px;
    padding: 0; list-style: none;
    font-size: 13.5px; line-height: 1.45;
    color: var(--text, #1a1a1a);
}
.jags-pwa-modal-dialog__steps li {
    padding: 6px 0;
    border-top: 1px dashed rgba(23, 23, 86, 0.18);
    display: flex; align-items: center; gap: 10px;
}
.jags-pwa-modal-dialog__steps li:first-child { border-top: 0; }
.jags-pwa-modal-dialog__steps .glyph {
    flex: 0 0 auto;
    width: 26px; height: 26px;
    border-radius: 6px;
    background: rgba(23, 23, 86, 0.08);
    color: var(--primary, #171756);
    display: inline-flex; align-items: center; justify-content: center;
}
.jags-pwa-modal-dialog__hint {
    font-size: 11.5px; color: var(--muted, #6b6b7a);
    margin-bottom: 14px;
}
.jags-pwa-modal-dialog__actions {
    display: flex; justify-content: flex-end;
}
.jags-pwa-modal-dialog__close {
    padding: 8px 16px;
    border: 0;
    border-radius: 8px;
    background: var(--primary, #171756);
    color: #fff;
    font-size: 13px; font-weight: 600;
    cursor: pointer;
}
.jags-pwa-modal-dialog__close:hover { background: #0f0f3f; }
.jags-pwa-modal-dialog__close:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(23, 23, 86, 0.35);
}
body.jags-pwa-modal-lock { overflow: hidden; }

/* Crew display lines (Captain / Co-pilot) */
.crew-line { line-height: 1.4; white-space: nowrap; }
.crew-role { font-weight: 600; color: var(--muted); font-size: 0.92em; }

/* Grounding info block on aircraft profile */
.grounding-info { padding: 12px 14px; border-left: 4px solid var(--danger); background: rgba(142,34,38,0.04); border-radius: 8px; margin-bottom: 14px; }
.grounding-info-badge { display: inline-block; margin-bottom: 6px; }
.grounding-info-reason { font-weight: 600; margin-bottom: 4px; }
.grounding-info-note { margin-bottom: 4px; white-space: pre-wrap; }
.grounding-info-meta { font-size: 12px; color: var(--muted); }
.grounding-info-override { margin-top: 8px; padding: 8px 10px; background: rgba(210,160,40,0.08); border-radius: 6px; font-size: 13px; }
.grounding-reason-link { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.grounding-reason-link:hover { color: var(--accent, #3367d6); }

/* =====================================================================
   Feature 08 — Special Request Type badges + subtle row/card highlights
   --------------------------------------------------------------------
   "Subtle" per spec means a small badge OR a 4px left-border accent.
   No loud full-card colour tints. Scoped to .rsv-srt-* and .rsv-card-hl-*
   so these rules cannot bleed into existing card / table styles.
   Accent colours reuse the existing palette (var(--danger), var(--info),
   var(--warning), var(--success)).
   ===================================================================== */
.rsv-srt-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.4;
    white-space: nowrap;
    border: 1px solid transparent;
    background: rgba(94, 100, 114, 0.10);
    color: var(--muted-strong);
}
.rsv-srt-medevac    { background: rgba(184,50,53,0.10); color: var(--status-danger-ink); border-color: rgba(184,50,53,0.30); }
.rsv-srt-vip        { background: rgba(216,181,109,0.18); color: var(--status-warning-ink); border-color: rgba(216,181,109,0.42); }
.rsv-srt-government { background: rgba(90,121,165,0.14); color: var(--status-info-ink); border-color: rgba(90,121,165,0.35); }
.rsv-srt-cargo      { background: rgba(74,103,51,0.12); color: var(--status-success-ink); border-color: rgba(74,103,51,0.35); }
.rsv-srt-default    { background: rgba(94,100,114,0.10); color: var(--muted-strong); }

/* 4px left-border accent for cards that carry a highlighted special-request
   type. Sits on the card; never paints the whole background.  */
.rsv-card-hl                   { border-left: 4px solid var(--muted); }
.rsv-card-hl-medevac           { border-left-color: var(--danger); }
.rsv-card-hl-vip               { border-left-color: var(--warning); }
.rsv-card-hl-government        { border-left-color: var(--info); }
.rsv-card-hl-cargo             { border-left-color: var(--success); }

/* Same accent for table rows on the Reservations / Operations Intake
   lists. Uses an inset box-shadow so the table's own borders stay intact. */
.rsv-row-hl > td:first-child            { box-shadow: inset 4px 0 0 0 var(--muted); }
.rsv-row-hl-medevac > td:first-child    { box-shadow: inset 4px 0 0 0 var(--danger); }
.rsv-row-hl-vip > td:first-child        { box-shadow: inset 4px 0 0 0 var(--warning); }
.rsv-row-hl-government > td:first-child { box-shadow: inset 4px 0 0 0 var(--info); }
.rsv-row-hl-cargo > td:first-child      { box-shadow: inset 4px 0 0 0 var(--success); }

/* Mobile collapse for the new fieldset on the reservation form. */
@media (max-width: 700px) {
    .rsv-pax-cargo-group [style*="grid-template-columns:1fr 1fr 1fr"] { grid-template-columns: 1fr !important; }
    .rsv-pax-cargo-group [style*="grid-column:span 2"]               { grid-column: 1 / -1 !important; }
}

/* =====================================================================
   Feature 04 — Reservation lifecycle status badges
   --------------------------------------------------------------------
   Canonical reservation statuses each get their own muted badge. Scoped
   to .rsv-status-* so the rules cannot leak into other badges. Emphasis
   is "subtle" per the canonical CSS rule — small badges, no loud full
   card colour tints.
   Color mapping per Feature 04 spec:
     Draft                  : neutral / grey
     Pending Review         : info blue
     Customer Confirmed     : success green
     Sent to Operations     : indigo / operations blue
     Returned to Reservations: amber
     Scheduled              : darker success green
     Unavailable            : amber / warning
     Cancelled              : danger
     Completed              : slate / neutral
   ===================================================================== */
.rsv-status-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.4;
    white-space: nowrap;
    border: 1px solid transparent;
    background: rgba(94, 100, 114, 0.10);
    color: var(--muted-strong);
}
.rsv-status-default            { background: rgba(94,100,114,0.10); color: var(--muted-strong); }
.rsv-status-draft              { background: rgba(94,100,114,0.10); color: var(--muted-strong); }
.rsv-status-pending-review     { background: rgba(90,121,165,0.14); color: var(--status-info-ink); border-color: rgba(90,121,165,0.30); }
.rsv-status-customer-confirmed { background: rgba(74,103,51,0.12);  color: var(--status-success-ink); border-color: rgba(74,103,51,0.30); }
.rsv-status-sent-to-operations { background: rgba(72,82,135,0.14);  color: var(--muted-strong); border-color: rgba(72,82,135,0.32); }
.rsv-status-returned           { background: rgba(216,181,109,0.18);color: var(--status-warning-ink); border-color: rgba(216,181,109,0.42); }
.rsv-status-scheduled          { background: rgba(48,80,38,0.14);   color: #294019; border-color: rgba(48,80,38,0.32); }
.rsv-status-unavailable        { background: rgba(216,181,109,0.18);color: var(--status-warning-ink); border-color: rgba(216,181,109,0.42); }
.rsv-status-cancelled          { background: rgba(184,50,53,0.10);  color: var(--danger); border-color: rgba(184,50,53,0.30); }
.rsv-status-completed          { background: rgba(94,100,114,0.14); color: var(--muted-strong); border-color: rgba(94,100,114,0.30); }

/* "Needs Operations Review" pill — only used inside the Unavailable
   review card on the reservation view + Operations Intake. */
.rsv-status-needs-review {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    background: rgba(182,136,58,0.18);
    color: var(--status-warning-ink);
    border: 1px solid rgba(182,136,58,0.42);
}

/* =====================================================================
   Feature 02 — Requested Aircraft Type + Advisory Availability Preview
   --------------------------------------------------------------------
   Subtle pill for the requested aircraft type plus a read-only card
   grid for the advisory preview. Rules are scoped to .rsv-acft-* and
   .rsv-availability-* so they cannot bleed into existing card / table
   styles. No loud full-card colour tints — see the canonical CSS rule
   in CANONICAL_NAMING_AND_SHARED_CONTRACTS.md §9.
   ===================================================================== */
.rsv-acft-type-pill {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.4;
    white-space: nowrap;
    border: 1px solid rgba(72,82,135,0.32);
    background: rgba(72,82,135,0.10);
    color: var(--muted-strong);
}
.rsv-acft-type-pill-backup {
    background: rgba(94,100,114,0.10);
    color: var(--muted-strong);
    border-color: rgba(94,100,114,0.30);
}
.rsv-acft-type-pill-prominent {
    /* Used in the Operations intake hero so the requested type catches
       the eye without overpowering the special-request-type badge. */
    background: rgba(48,80,38,0.12);
    color: #294019;
    border-color: rgba(48,80,38,0.34);
}

/* Advisory availability preview frame on the reservation form. */
.rsv-availability {
    background: rgba(247, 249, 252, 0.6);
    border-radius: 8px;
    padding: 12px;
}
.rsv-availability-warning {
    margin: 10px 0 0 0;
    padding: 8px 10px;
    background: rgba(182,136,58,0.10);
    border: 1px solid rgba(182,136,58,0.35);
    border-radius: 6px;
    font-size: 13px;
    color: var(--status-warning-ink);
}

/* Card grid for individual aircraft. */
.rsv-availability-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 10px;
}
.rsv-acft-card {
    display: flex;
    align-items: stretch;
    gap: 10px;
    padding: 10px;
    border: 1px solid rgba(0,0,0,0.08);
    border-radius: 8px;
    background: var(--card);
}
.rsv-acft-card-available    { border-left: 4px solid var(--success, #4A7B33); }
.rsv-acft-card-unavailable  {
    border-left: 4px solid rgba(184,50,53,0.55);
    /* Subtle dim — never paint the whole card. */
    opacity: 0.78;
    background: rgba(247, 249, 252, 0.85);
}
.rsv-acft-thumb {
    flex: 0 0 56px;
    width: 56px;
    height: 56px;
    border-radius: 6px;
    overflow: hidden;
    background: rgba(94,100,114,0.08);
    display: flex;
    align-items: center;
    justify-content: center;
}
.rsv-acft-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.rsv-acft-card-body {
    flex: 1 1 auto;
    min-width: 0;
}
.rsv-acft-card-head {
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex-wrap: wrap;
}
.rsv-acft-reg {
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.02em;
    color: var(--text, #0E0E12);
}
.rsv-acft-status {
    margin-top: 4px;
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: center;
}
.rsv-acft-status-pill {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 5px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.4;
    border: 1px solid transparent;
    background: rgba(94,100,114,0.10);
    color: var(--muted-strong);
}
.rsv-acft-status-serviceable        { background: rgba(74,103,51,0.12);  color: var(--status-success-ink); border-color: rgba(74,103,51,0.30); }
.rsv-acft-status-grounded           { background: rgba(184,50,53,0.10);  color: var(--danger); border-color: rgba(184,50,53,0.30); }
.rsv-acft-status-maintenance        { background: rgba(216,181,109,0.18);color: var(--status-warning-ink); border-color: rgba(216,181,109,0.42); }
.rsv-acft-status-inspection_required{ background: rgba(216,181,109,0.18);color: var(--status-warning-ink); border-color: rgba(216,181,109,0.42); }
.rsv-acft-status-inactive           { background: rgba(94,100,114,0.14); color: var(--muted-strong); border-color: rgba(94,100,114,0.30); }
.rsv-acft-unavail-pill {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 5px;
    font-size: 11px;
    font-weight: 600;
    background: rgba(184,50,53,0.10);
    color: var(--danger);
    border: 1px solid rgba(184,50,53,0.30);
}

/* =====================================================================
   2026-05-14 inline-workflow refinement — filter chip bar, assigned-
   aircraft chip on the Reservations list, delay-status chip, and the
   per-row inline-action chips on the Accounts dashboard.
   --------------------------------------------------------------------
   Scoped to .rsv-chip*, .rsv-aircraft-chip, .rsv-delay-chip and
   .rsv-chip-action / .rsv-inline-* so the rules cannot bleed into
   existing badge / button styles. Reuses the existing palette tokens
   (var(--primary), var(--danger), var(--warning), var(--success),
   var(--muted-strong)).
   ===================================================================== */

/* Quick-view filter chip bar — sits above the standard filter form on
   Reservations, Accounts dashboard, and Operations intake. */
.rsv-filter-chips { background: var(--surface-low); }
.rsv-chip {
    display: inline-block;
    padding: 5px 12px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--card);
    color: var(--text, #0E0E12);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.3;
    text-decoration: none;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.rsv-chip:hover  { background: var(--surface-container); border-color: var(--border-strong); }
.rsv-chip-active {
    background: var(--primary, #1F3F6E);
    color: #FFFFFF;
    border-color: var(--primary, #1F3F6E);
}
.rsv-chip-active:hover { background: var(--primary, #1F3F6E); color: #FFFFFF; }

/* Assigned-aircraft chip on the Reservations list — read-only. */
.rsv-aircraft-chip {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 5px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.02em;
    background: rgba(31,63,110,0.10);
    color: var(--primary, #1F3F6E);
    border: 1px solid rgba(31,63,110,0.30);
    font-variant-numeric: tabular-nums;
}

/* Delay status chip under the reservation status badge. */
.rsv-delay-chip {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 4px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.4;
    border: 1px solid transparent;
}
.rsv-delay-on-time   { background: rgba(74,103,51,0.10);   color: var(--status-success-ink);       border-color: rgba(74,103,51,0.30); }
.rsv-delay-delayed   { background: rgba(184,50,53,0.10);   color: var(--danger); border-color: rgba(184,50,53,0.30); }
.rsv-delay-awaiting  { background: rgba(216,181,109,0.18); color: var(--status-warning-ink);       border-color: rgba(216,181,109,0.42); }
.rsv-delay-weather   { background: rgba(94,100,114,0.12);  color: var(--muted-strong);       border-color: rgba(94,100,114,0.30); }
.rsv-delay-cancelled { background: rgba(184,50,53,0.10);   color: var(--danger); border-color: rgba(184,50,53,0.30); }

/* Inline action chips on the Accounts dashboard. Four small buttons +
   a collapsed sticky-note. Mobile usable; the row wraps naturally. */
.rsv-inline-actions { display: inline-block; }
.rsv-inline-actions-row {
    display: inline-flex;
    gap: 4px;
    flex-wrap: wrap;
    align-items: center;
}
.rsv-chip-action {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.3;
    border: 1px solid transparent;
    cursor: pointer;
    background: var(--card);
    color: var(--text, #0E0E12);
    transition: background 0.12s, border-color 0.12s;
}
.rsv-chip-action:hover    { background: rgba(0,0,0,0.04); }
.rsv-chip-action:disabled { opacity: 0.45; cursor: not-allowed; }
.rsv-chip-hold   { background: rgba(216,181,109,0.18); color: var(--status-warning-ink);       border-color: rgba(216,181,109,0.45); }
.rsv-chip-hold:hover   { background: rgba(216,181,109,0.30); }
.rsv-chip-block  { background: rgba(184,50,53,0.10);   color: var(--danger); border-color: rgba(184,50,53,0.32); }
.rsv-chip-block:hover  { background: rgba(184,50,53,0.18); }
.rsv-chip-review { background: rgba(31,63,110,0.10);   color: var(--primary, #1F3F6E); border-color: rgba(31,63,110,0.30); }
.rsv-chip-review:hover { background: rgba(31,63,110,0.18); }

/* =====================================================================
   2026-05-20 — Passenger / cargo / payment / capacity refinement.
   Scoped to .rsv-pay-chip*, .rsv-capacity-*, .rsv-sector-card,
   .rsv-pax-row, .rsv-cargo-row and .rsv-inline-form. Cannot touch
   existing badge / chip rules.
   ===================================================================== */
.rsv-pay-chip {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.02em;
    border: 1px solid transparent;
    font-variant-numeric: tabular-nums;
}
.rsv-pay-unpaid   { background: rgba(184,50,53,0.10);   color: var(--danger);            border-color: rgba(184,50,53,0.30); }
.rsv-pay-paid     { background: rgba(74,103,51,0.10);   color: var(--status-success-ink);                  border-color: rgba(74,103,51,0.32); }
.rsv-pay-company  { background: rgba(31,63,110,0.10);   color: var(--primary, #1F3F6E);  border-color: rgba(31,63,110,0.30); }
.rsv-pay-waived   { background: rgba(94,100,114,0.12);  color: var(--muted-strong);                  border-color: rgba(94,100,114,0.30); }
.rsv-pay-refunded { background: rgba(216,181,109,0.18); color: var(--status-warning-ink);                  border-color: rgba(216,181,109,0.42); }

.rsv-capacity-card { border-left: 4px solid var(--primary, #1F3F6E); }
.rsv-capacity-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px;
    margin-top: 8px;
}
.rsv-capacity-tile {
    background: rgba(31,63,110,0.05);
    border: 1px solid rgba(31,63,110,0.12);
    border-radius: 8px;
    padding: 10px 12px;
}
.rsv-capacity-num {
    font-size: 22px; font-weight: 700; line-height: 1.2; margin-top: 2px;
    font-variant-numeric: tabular-nums;
}
.rsv-capacity-num .muted { font-size: 16px; font-weight: 500; }
.rsv-capacity-pill {
    display: inline-block;
    margin-top: 6px;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 11px; font-weight: 600;
    border: 1px solid transparent;
}
.rsv-capacity-ok       { background: rgba(74,103,51,0.10);   color: var(--status-success-ink);       border-color: rgba(74,103,51,0.32); }
.rsv-capacity-over     { background: rgba(184,50,53,0.10);   color: var(--danger); border-color: rgba(184,50,53,0.30); }
.rsv-capacity-locked   { background: rgba(216,181,109,0.18); color: var(--status-warning-ink);       border-color: rgba(216,181,109,0.42); }
.rsv-capacity-unlocked { background: rgba(94,100,114,0.10);  color: var(--muted-strong);       border-color: rgba(94,100,114,0.30); }
.rsv-capacity-note {
    border-top: 1px dashed rgba(0,0,0,0.08);
    padding-top: 8px;
    font-size: 13px;
}

.rsv-sector-card {
    border: 1px solid rgba(0,0,0,0.08);
    border-radius: 10px;
    padding: 12px 14px;
    margin-bottom: 14px;
    background: var(--card);
}
.rsv-sector-outbound   { border-left: 4px solid var(--primary, #1F3F6E); }
.rsv-sector-return     { border-left: 4px solid #6E4A8F; }
.rsv-sector-unassigned { border-left: 4px solid rgba(94,100,114,0.45); }
.rsv-sector-head {
    display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
    margin-bottom: 6px; padding-bottom: 6px;
    border-bottom: 1px solid rgba(0,0,0,0.06);
}
.rsv-sector-head h3 { margin: 0; font-size: 16px; font-weight: 700; }

.rsv-pax-row, .rsv-cargo-row {
    padding: 8px 10px;
    border-radius: 6px;
    margin-bottom: 6px;
    border: 1px solid rgba(0,0,0,0.04);
    background: rgba(31,63,110,0.03);
}
.rsv-cargo-row { background: rgba(216,181,109,0.06); }
.rsv-pax-main, .rsv-cargo-main { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 6px; }
.rsv-pax-name, .rsv-cargo-desc { font-weight: 600; font-size: 14px; }
.rsv-pax-side  { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.rsv-attached-cargo { margin: 0 0 6px 14px; padding-left: 8px; border-left: 2px dashed rgba(216,181,109,0.5); }
.rsv-standalone-cargo { margin-top: 6px; padding-top: 4px; }
.rsv-add-form summary {
    cursor: pointer; font-weight: 600; font-size: 13px;
    color: var(--primary, #1F3F6E);
}
.rsv-inline-form .rsv-inline-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0 12px;
}
.rsv-inline-form .field { margin-bottom: 8px; }
.rsv-sector-quick, .rsv-link-quick {
    padding: 4px 6px;
    border-radius: 4px;
    border: 1px solid rgba(0,0,0,0.15);
    font-size: 12px;
}
.rsv-remove-btn { color: var(--danger); border-color: rgba(184,50,53,0.25); }
.rsv-pax-pay-action summary {
    cursor: pointer; font-size: 12px; font-weight: 600;
    color: var(--primary, #1F3F6E);
}
/* 2026-08-12 — one-click "Mark Paid" sitting beside the payment chip.
   Its own <form>, a sibling of the move-sector / remove forms, so it
   never nests inside another form. */
.rsv-pay-quick { display: inline-flex; margin: 0; }
.rsv-pay-quick-btn {
    padding: 3px 10px;
    font-size: 11px;
    line-height: 1.5;
    min-height: 28px;
    white-space: nowrap;
}

@media (max-width: 700px) {
    .rsv-capacity-grid { grid-template-columns: 1fr; }
    .rsv-pax-main, .rsv-cargo-main { flex-direction: column; align-items: stretch; }
    .rsv-pax-side  { justify-content: flex-start; }
    .rsv-pay-quick-btn { min-height: 34px; padding: 6px 12px; font-size: 12px; }
    .rsv-inline-form .rsv-inline-grid { grid-template-columns: 1fr; }
}

/* =====================================================================
   Reservations / Ops-intake mobile card list (2026-05-18)
   ---------------------------------------------------------------------
   The Reservations board and the Operations intake queue render a
   desktop .table-wrap.desktop-only AND a parallel
   .mobile-card-list.mobile-only.rsv-mobile-list built from the same
   data. These rules ONLY refine that mobile card on phones / tablets
   (<=900px). They build on the shared .mobile-card-list-item chrome
   (defined earlier) and are prefixed with .rsv-mobile-list so they
   cannot touch the desktop table or any other page. Desktop (>=901px)
   is byte-for-byte unchanged.
   ===================================================================== */
@media (max-width: 900px) {
    /* Reference is a single nowrap monospace badge — fixes the
       "RSV-\n2026-\n00085" hyphen-wrap seen on the squeezed table. */
    .rsv-mc-ref {
        display: inline-block;
        font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
        font-size: 12.5px; font-weight: 700; letter-spacing: 0.01em;
        color: var(--primary, #1F3F6E);
        background: rgba(31,63,110,0.08);
        border: 1px solid rgba(31,63,110,0.20);
        border-radius: 6px;
        padding: 3px 8px;
        white-space: nowrap;
    }
    .rsv-mobile-list .head {
        align-items: center;
        gap: 8px;
        flex-wrap: wrap;
        margin-bottom: 8px;
        padding-bottom: 8px;
        border-bottom: 1px solid var(--border);
    }
    .rsv-mc-status {
        display: inline-flex;
        flex-wrap: wrap;
        gap: 4px;
        justify-content: flex-end;
        text-align: right;
        min-width: 0;
    }
    .rsv-mc-customer {
        font-size: 15px;
        font-weight: 700;
        line-height: 1.3;
        color: var(--text-strong, #14223B);
        margin: 0 0 8px;
        overflow-wrap: anywhere;
    }
    /* Let long values (route, multi-line times) wrap inside the card
       instead of forcing horizontal overflow. */
    .rsv-mobile-list .row { align-items: flex-start; }
    .rsv-mobile-list .row .v { overflow-wrap: anywhere; }
    .rsv-mobile-list .row .v.rsv-mc-route { font-weight: 600; }
    /* Action buttons: full-width, comfortable tap targets, forms (Archive
       / Restore) stretch like the anchor buttons next to them. */
    .rsv-mc-actions {
        margin-top: 12px;
        gap: 8px;
        justify-content: stretch;
    }
    .rsv-mc-actions > a.btn,
    .rsv-mc-actions > form {
        flex: 1 1 auto;
        margin: 0;
    }
    .rsv-mc-actions > form { display: flex; }
    .rsv-mc-actions > form .btn,
    .rsv-mc-actions > form button { width: 100%; }
    .rsv-mc-actions .btn,
    .rsv-mc-actions .btn-sm { min-height: 44px; }
    /* Belt-and-suspenders: the global .main > .content already reserves
       space for the fixed bottom nav app-wide; this adds a little extra
       breathing room so the last card never visually meets the nav even
       mid-scroll, including the iPhone home-indicator safe area. */
    .rsv-mobile-list { padding-bottom: calc(var(--safe-area-bottom) + 8px); }
}

/* Sticky-note <details> embed inside the inline actions row. */
.rsv-inline-note-details { display: inline-block; margin-left: 4px; }
.rsv-inline-note-summary {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.3;
    background: rgba(94,100,114,0.10);
    color: var(--muted-strong);
    border: 1px solid rgba(94,100,114,0.30);
    cursor: pointer;
    list-style: none;
}
.rsv-inline-note-summary::-webkit-details-marker { display: none; }
.rsv-inline-note-details[open] .rsv-inline-note-summary { background: rgba(94,100,114,0.18); }
.rsv-inline-note-body { margin-top: 6px; max-width: 320px; }
.rsv-inline-note-body textarea {
    width: 100%;
    font-size: 12px;
    padding: 6px 8px;
    border-radius: 4px;
    border: 1px solid rgba(0,0,0,0.16);
}

.rsv-acft-reasons {
    margin: 6px 0 0 16px;
    padding: 0;
    font-size: 12px;
    color: var(--muted-strong);
}

/* =====================================================================
   Feature 01 — Reservations Aircraft Availability (read-only)
   --------------------------------------------------------------------
   Scoped to .rsv-aa-* so the rules cannot bleed into the operations
   board or the reservation form. The Advisory caption uses a small
   pill / inset, never a loud full-card colour tint, per
   CANONICAL_NAMING_AND_SHARED_CONTRACTS.md §9. The Reservations-safe
   flight table reuses the existing .tbl / .tbl-compact base styles and
   only adds row-state shading and small pill colours.
   ===================================================================== */
.rsv-aa-advisory {
    align-self: stretch;
    padding: 10px 14px;
    border-radius: 8px;
    background: rgba(255,255,255,0.18);
    border: 1px solid rgba(255,255,255,0.35);
    color: #FFFFFF;
    font-size: 13px;
    line-height: 1.4;
    max-width: 360px;
}
.rsv-aa-advisory-sub {
    margin-top: 2px;
    font-size: 12px;
    opacity: 0.85;
    font-weight: 400;
}
.rsv-aa-row-cancelled    { opacity: 0.55; }
.rsv-aa-row-unavailable  { background: rgba(184,50,53,0.04); }
.rsv-aa-reg              { font-weight: 700; color: var(--primary); letter-spacing: 0.02em; }
.rsv-aa-sub              { font-size: 11px; line-height: 1.3; }
.rsv-aa-cell-time        { font-variant-numeric: tabular-nums; white-space: nowrap; }
.rsv-aa-charter          { font-weight: 600; }
.rsv-aa-pill {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 5px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.4;
    border: 1px solid transparent;
    background: rgba(94,100,114,0.10);
    color: var(--muted-strong);
    white-space: nowrap;
}
.rsv-aa-pill-success {
    background: rgba(74,103,51,0.12);
    color: var(--status-success-ink);
    border-color: rgba(74,103,51,0.30);
}
.rsv-aa-pill-muted {
    background: rgba(94,100,114,0.10);
    color: var(--muted-strong);
    border-color: rgba(94,100,114,0.22);
}
.rsv-aa-pill-warn {
    background: rgba(182,136,58,0.14);
    color: #7B5318;
    border-color: rgba(182,136,58,0.40);
}

/* Availability advisory last-updated strip — sits directly under the
   summary on the Reservations Aircraft Availability page. Quiet by
   default, switches to a warn tint when the underlying timestamp is
   older than 24 hours, and to a muted "missing" tint when no source
   returned a timestamp at all. */
.rsv-aa-lastupdated {
    margin-top: 10px;
    padding: 10px 14px;
    border-radius: 8px;
    border: 1px solid rgba(94,100,114,0.22);
    background: rgba(94,100,114,0.06);
    font-size: 13px;
    line-height: 1.4;
}
.rsv-aa-lastupdated-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.rsv-aa-lastupdated-label {
    color: var(--muted-strong);
}
.rsv-aa-lastupdated-value {
    font-variant-numeric: tabular-nums;
}
.rsv-aa-lastupdated-sub {
    margin-top: 2px;
    font-size: 12px;
    color: var(--muted-strong);
}
.rsv-aa-lastupdated-fresh {
    border-color: rgba(74,103,51,0.30);
    background: rgba(74,103,51,0.06);
}
.rsv-aa-lastupdated-stale {
    border-color: rgba(182,136,58,0.40);
    background: rgba(182,136,58,0.10);
}
.rsv-aa-lastupdated-missing {
    border-color: rgba(94,100,114,0.30);
    background: rgba(94,100,114,0.08);
}

/* Operations decision summary on the Reservations dashboard list. Tiny,
   informational; never overwrites or duplicates the canonical status
   badge shown in the same row. */
.rsv-ops-summary {
    margin-top: 4px;
    font-size: 11px;
    line-height: 1.35;
    color: var(--muted-strong);
}

/* Mobile collapse for the new fieldset on the reservation form. */
@media (max-width: 700px) {
    .rsv-aircraft-type-group [style*="grid-template-columns:1fr 1fr"] { grid-template-columns: 1fr !important; }
    .rsv-availability-grid { grid-template-columns: 1fr !important; }
    .rsv-acft-card { padding: 8px; }
    .rsv-acft-thumb { width: 48px; height: 48px; flex-basis: 48px; }
    .rsv-aa-advisory { max-width: none; }
}

/* =====================================================================
   Feature 06 — Accounts / Cashier payment status badges
   --------------------------------------------------------------------
   Scoped to .pay-status-* so the rules cannot bleed into existing
   reservation status (.rsv-status-*) or special-request-type
   (.rsv-srt-*) badge styles. No loud full-card colour tints — small
   pills only, per CANONICAL_NAMING_AND_SHARED_CONTRACTS.md §9.
   ===================================================================== */
.pay-status-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.4;
    white-space: nowrap;
    border: 1px solid transparent;
    background: rgba(94, 100, 114, 0.10);
    color: var(--muted-strong);
}
.pay-status-default          { background: rgba(94,100,114,0.10); color: var(--muted-strong); }
.pay-status-pending          { background: rgba(216,181,109,0.18);color: var(--status-warning-ink);             border-color: rgba(216,181,109,0.42); }
.pay-status-paid             { background: rgba(74,103,51,0.12);  color: var(--status-success-ink);             border-color: rgba(74,103,51,0.30); }
.pay-status-account-credit   { background: rgba(72,82,135,0.14);  color: var(--muted-strong);             border-color: rgba(72,82,135,0.32); }
.pay-status-waived           { background: rgba(94,100,114,0.14); color: var(--muted-strong);             border-color: rgba(94,100,114,0.30); }
.pay-status-disputed         { background: rgba(182,50,53,0.18);  color: var(--danger);       border-color: rgba(182,50,53,0.45); }

/* Accounts role chip — matches the role-badge variant key 'accounts'. */
.badge-role-accounts {
    background: rgba(72,82,135,0.10);
    color: var(--muted-strong);
    border: 1px solid rgba(72,82,135,0.32);
}

/* Subtle 4px left-border accent on the Payment card (no full-card tint). */
.pay-card { border-left: 4px solid rgba(72,82,135,0.32); }

@media (max-width: 700px) {
    .pay-summary-grid { grid-template-columns: 1fr !important; }
    .pay-record-form [style*="grid-template-columns:1fr 1fr 1fr"] { grid-template-columns: 1fr !important; }
}

/* =====================================================================
   Feature 05 — Operations Reservation Intake Refinement
   --------------------------------------------------------------------
   Scoped to .ops-intake-* so the rules cannot bleed into existing
   stat-grid, badge, or card styles. No loud full-card colour tints —
   small chips plus optional 4px left-border accents per the canonical
   styling rule (see CANONICAL_NAMING_AND_SHARED_CONTRACTS.md §9).
   ===================================================================== */

/* Aircraft-availability hint chip used in the intake list and card. */
.ops-intake-acft-warn {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 5px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
    border: 1px solid rgba(94,100,114,0.30);
    background: rgba(94,100,114,0.10);
    color: var(--muted-strong);
    white-space: normal;
    line-height: 1.35;
}
.ops-intake-acft-warn-info  { background: rgba(74,103,51,0.10);   color: var(--status-success-ink); border-color: rgba(74,103,51,0.30); }
.ops-intake-acft-warn-warn  { background: rgba(216,181,109,0.18); color: var(--status-warning-ink); border-color: rgba(216,181,109,0.42); }
.ops-intake-acft-warn-block { background: rgba(184,50,53,0.10);   color: var(--danger); border-color: rgba(184,50,53,0.30); }

/* Latest Operations decision chip — used in the intake list "Last
   Decision" column and on both the intake detail card and the
   read-only Reservations-side decision card. */
.ops-intake-decision-chip {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 5px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
    border: 1px solid rgba(72,82,135,0.32);
    background: rgba(72,82,135,0.10);
    color: var(--muted-strong);
}

/* Decision card subtle 4px left-border accent — shown on intake detail
   and on the Reservations-side read-only summary. Never a full tint. */
.ops-intake-decision-card { border-left: 4px solid rgba(72,82,135,0.32); }

/* Payment-warning card on the intake detail. Subtle amber accent. */
.ops-intake-pay-warn { border-left: 4px solid rgba(216,181,109,0.55); }

/* Operations dashboard "Reservation Intake" summary card. Reuses the
   look of .stats-grid / .stat without depending on those rules so a
   refactor of either does not silently break the intake summary. */
.ops-intake-summary-card { border-left: 4px solid rgba(72,82,135,0.32); }

.ops-intake-summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 10px;
    margin-top: 8px;
}
.ops-intake-summary-tile {
    padding: 12px 14px;
    border: 1px solid var(--border, rgba(0,0,0,0.08));
    border-radius: 8px;
    background: var(--surface, #FFFFFF);
}
.ops-intake-summary-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted-strong);
}
.ops-intake-summary-value {
    font-size: 24px;
    font-weight: 700;
    line-height: 1.1;
    margin-top: 4px;
    color: var(--text-strong);
}
.ops-intake-summary-delta {
    margin-top: 2px;
    font-size: 11px;
    color: var(--muted);
}

/* "Warn" / "Info" tile variants — subtle left-border accent only. */
.ops-intake-tile-warn  { border-left: 4px solid rgba(216,181,109,0.55); }
.ops-intake-tile-info  { border-left: 4px solid rgba(72,82,135,0.40); }

@media (max-width: 700px) {
    .ops-intake-summary-grid { grid-template-columns: 1fr 1fr !important; }
}

/* =====================================================================
   Feature 07 — Customer Accounts / Credit Limits / Stop List
   --------------------------------------------------------------------
   Scoped to .cust-acct-* so the rules cannot bleed into Reservation
   status badges (.rsv-status-*), Payment status badges (.pay-status-*),
   or special-request-type badges (.rsv-srt-*). No loud full-card colour
   tints — small badges plus a tinted progress bar and a subtle 4px
   left-border accent on warning cards, per
   CANONICAL_NAMING_AND_SHARED_CONTRACTS.md §9.
   ===================================================================== */

/* Account status badges */
.cust-acct-status-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.4;
    white-space: nowrap;
    border: 1px solid transparent;
    background: rgba(94, 100, 114, 0.10);
    color: var(--muted-strong);
}
.cust-acct-status-default     { background: rgba(94,100,114,0.10); color: var(--muted-strong); }
.cust-acct-status-normal      { background: rgba(74,103,51,0.12);  color: var(--status-success-ink);             border-color: rgba(74,103,51,0.30); }
.cust-acct-status-watch       { background: rgba(90,121,165,0.14); color: var(--status-info-ink);             border-color: rgba(90,121,165,0.32); }
.cust-acct-status-near-limit  { background: rgba(216,181,109,0.18);color: var(--status-warning-ink);             border-color: rgba(216,181,109,0.42); }
.cust-acct-status-on-hold     { background: rgba(184,50,53,0.10);  color: var(--danger);       border-color: rgba(184,50,53,0.30); }
.cust-acct-status-stop-list   { background: rgba(184,50,53,0.16);  color: var(--danger);       border-color: rgba(184,50,53,0.45); }
.cust-acct-status-inactive    { background: rgba(94,100,114,0.14); color: var(--muted-strong);             border-color: rgba(94,100,114,0.30); }

/* Credit progress bar */
.cust-acct-progress {
    position: relative;
    height: 8px;
    background: rgba(94, 100, 114, 0.10);
    border-radius: 6px;
    overflow: hidden;
    border: 1px solid rgba(0, 0, 0, 0.06);
}
.cust-acct-progress-large { height: 14px; }
.cust-acct-progress-bar {
    height: 100%;
    width: 0;
    background: var(--muted-strong);
    transition: width 200ms ease;
}
.cust-acct-progress-normal     .cust-acct-progress-bar { background: var(--status-success); }
.cust-acct-progress-watch      .cust-acct-progress-bar { background: #5A79A5; }
.cust-acct-progress-near       .cust-acct-progress-bar { background: var(--status-warning); }
.cust-acct-progress-over       .cust-acct-progress-bar { background: var(--danger, #B83235); }
.cust-acct-progress-stop                                { background: rgba(184, 50, 53, 0.16); }
.cust-acct-progress-stop       .cust-acct-progress-bar { background: var(--danger, #B83235); width: 100% !important; }
.cust-acct-progress-inactive                            { background: rgba(94, 100, 114, 0.14); }
.cust-acct-progress-inactive   .cust-acct-progress-bar { background: rgba(94, 100, 114, 0.55); width: 100% !important; }
.cust-acct-progress-empty                               { background: rgba(94, 100, 114, 0.06); }
.cust-acct-progress-empty      .cust-acct-progress-bar { background: rgba(94, 100, 114, 0.30); }

/* Inline warning panels — subtle 4px left-border accent only */
.cust-acct-warning {
    border-radius: 8px;
    padding: 12px 14px;
    border: 1px solid rgba(0, 0, 0, 0.06);
    background: rgba(247, 249, 252, 0.6);
    border-left: 4px solid rgba(94, 100, 114, 0.40);
}
.cust-acct-warning-block {
    border-left-color: var(--danger, #B83235);
    background: rgba(184, 50, 53, 0.05);
}
.cust-acct-warning-warn {
    border-left-color: rgba(216, 181, 109, 0.85);
    background: rgba(216, 181, 109, 0.08);
}
.cust-acct-warning-info {
    border-left-color: rgba(90, 121, 165, 0.55);
    background: rgba(90, 121, 165, 0.05);
}

/* Override-queue card — same accent system as the warning panel.
   Used in customer_account_overrides.php. */
.cust-acct-override-card {
    padding: 14px 16px;
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 10px;
    background: var(--card);
    border-left: 4px solid var(--danger, #B83235);
}
.cust-acct-decision {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 5px;
    font-size: 11px;
    font-weight: 600;
    border: 1px solid transparent;
    background: rgba(94, 100, 114, 0.10);
    color: var(--muted-strong);
}
.cust-acct-decision-approved { background: rgba(74,103,51,0.12); color: var(--status-success-ink); border-color: rgba(74,103,51,0.30); }
.cust-acct-decision-rejected { background: rgba(184,50,53,0.10); color: var(--danger); border-color: rgba(184,50,53,0.30); }

@media (max-width: 700px) {
    .rsv-customer-account-group [style*="grid-template-columns:2fr 1fr"] { grid-template-columns: 1fr !important; }
}

/* ====================================================================
   Mobile app polish
   --------------------------------------------------------------------
   Final-pass refinements that build on the existing mobile layer.
   Sits last so its rules win for sub-900px breakpoints. Goal:
   smoother spacing, more comfortable touch targets, calmer headers,
   cleaner sticky surfaces, no horizontal page scroll except on tables
   that intentionally overflow. Desktop is untouched (rules are scoped
   to <=900px or <=700px).
   ==================================================================== */

/* Prevent any element from forcing a horizontal page scroll on phones —
   tables/scroll regions stay scrollable internally via their own wrappers
   (.table-wrap / .dr-scroll / .ops-board-scroll already opt in). */
@media (max-width: 900px) {
    html, body { overflow-x: hidden; }
    .main { min-width: 0; max-width: 100vw; }
    .main > .content { overflow-x: hidden; }
    .card, .stat, .ac-card, .mobile-card-list-item { max-width: 100%; }
    img, video { max-width: 100%; height: auto; }
}

/* Slightly more breathing room on phone content; tighten on small phones. */
@media (max-width: 900px) {
    .content { padding: 18px 16px; }
}
@media (max-width: 520px) {
    .content { padding: 14px 12px; }
}

/* Topbar — calmer rhythm on phones. Existing rules at line 4027 set
   the base; these refinements reduce the visual weight further on small
   phones so the page feels less crowded above the fold. */
@media (max-width: 700px) {
    .topbar { padding-top: 10px; padding-bottom: 10px; }
    .topbar h1 { font-size: 16px; letter-spacing: -0.01em; }
}
@media (max-width: 520px) {
    .topbar { padding: 9px 10px; gap: 6px; }
    .topbar h1 { font-size: 15px; }
    .topbar-user { gap: 6px; }
}

/* Section titles — keep heading + action button row from getting cramped
   on phones. Wrapping is allowed; the action drops to its own line below. */
@media (max-width: 700px) {
    .section-title { gap: 8px; margin-bottom: 12px; }
    .section-title h2 { font-size: 16px; line-height: 1.25; }
}

/* Touch targets — guarantee >=44px height on the most common controls.
   The .btn class is 44px tall by spec; this ensures inline anchors and
   icon buttons used in dense rows on mobile still hit that bar. */
@media (max-width: 900px) {
    .btn { min-height: 44px; }
    .btn-sm { min-height: 38px; }
    .btn-icon, button.btn-icon, a.btn-icon { min-width: 38px; min-height: 38px; }
    a.tab, .tabs a { min-height: 40px; display: inline-flex; align-items: center; }
    .topbar-bell { min-width: 38px; min-height: 38px; }
}

/* Form-actions row — when buttons stack, give them comfortable vertical
   rhythm. The existing rule already wraps and stretches; this just adds
   a min-height floor so a single-line CTA doesn't feel skinny on phones. */
@media (max-width: 700px) {
    .form-actions { gap: 10px; }
    .form-actions .btn { min-height: 44px; padding: 11px 14px; }
}

/* Smoother card spacing on phones — the existing rule sets 14px gap; on
   smaller screens drop a touch tighter so two stacked cards don't feel
   floaty against the bottom-nav. */
@media (max-width: 520px) {
    .card { padding: 13px; border-radius: 12px; }
    .card + .card { margin-top: 12px; }
    .stats-grid { gap: 8px; margin-bottom: 12px; }
    .stat { padding: 11px 12px; }
}

/* Tables / horizontal scroll regions — momentum scroll on iOS, soft
   scrollbars on iOS/Android. .table-wrap already has -webkit-overflow-
   scrolling; explicitly add it to the other intentional overflow wrappers
   used by Daily Report and the Operations board. */
.dr-scroll,
.ops-board-scroll {
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: rgba(39,66,112,0.30) transparent;
}
.dr-scroll::-webkit-scrollbar,
.ops-board-scroll::-webkit-scrollbar { height: 8px; }
.dr-scroll::-webkit-scrollbar-thumb,
.ops-board-scroll::-webkit-scrollbar-thumb { background: rgba(39,66,112,0.25); border-radius: 8px; }

/* Ensure long table rows wrap inside table-wrap rather than escaping the
   card on phones — keeps the page free of horizontal overflow when a
   single non-wrapping cell is wider than the viewport. */
@media (max-width: 700px) {
    .table-wrap { border-radius: 12px; }
}

/* Drawer polish — slightly larger nav rows on phones, snappier divider
   above the sticky account card so the bottom of the drawer reads as
   a separate, anchored element. */
@media (max-width: 900px) {
    .sidebar nav a {
        min-height: 44px;
        padding-top: 11px;
        padding-bottom: 11px;
    }
    .sidebar-account {
        border-top: 1px solid var(--border);
        box-shadow: 0 -4px 12px rgba(11,11,47,0.05);
    }
}

/* Bottom nav — guaranteed thumb-friendly height + a clear top hairline so
   the bar reads as anchored chrome rather than floating content. The bar
   already respects env(safe-area-inset-bottom); this ensures the visible
   tap area for each tab is at least 48px tall (icon + label + paddings). */
@media (max-width: 900px) {
    .mobile-bottom-nav a,
    .mobile-bottom-nav button {
        min-height: 48px;
    }
    .mobile-bottom-nav a:active,
    .mobile-bottom-nav button:active {
        background: rgba(90,121,165,0.10);
    }
    /* Reserved page-bottom padding adjusted slightly so a sticky button
       doesn't sit flush against the bottom nav on phones with no notch. */
    .main > .content { padding-bottom: var(--mobile-bottom-nav-clearance); }
}

/* ====================================================================
   Mobile / PWA top safe-area blur
   --------------------------------------------------------------------
   On phones (and especially the installed standalone PWA on iOS) we want
   the topbar to feel like a native app: its translucent frosted backing
   extends up into the iPhone notch / status-bar safe area so scrolled
   content visibly slides underneath a polished blur instead of meeting a
   hard white edge. Pure CSS — no extra DOM. The .topbar already has
   position: sticky, top: 0, a translucent background, and backdrop-
   filter; here we only deepen the frost on phones and add the safe-area
   inset padding so the blurred surface covers the notch.
   Desktop is intentionally unchanged. Display / FIDS surfaces (.display-
   shell) are scoped out via the existing chrome-hide rules at line 4003.
   ==================================================================== */
@media (max-width: 900px) {
    .topbar {
        /* Slightly stronger frost + softer hairline so the topbar reads
           as ambient chrome rather than a hard edge under scrolling. */
        background: rgba(var(--glass-rgb), 0.72);
        -webkit-backdrop-filter: saturate(180%) blur(18px);
        backdrop-filter: saturate(180%) blur(18px);
        border-bottom-color: rgba(226, 230, 238, 0.65);
        /* Extend the blurred surface into the iPhone notch / status-bar
           area. The visible content (h1, hamburger, bell, avatar) keeps
           its normal vertical padding; the inset is added on top. */
        padding-top: calc(10px + env(safe-area-inset-top));
        padding-left: max(14px, env(safe-area-inset-left));
        padding-right: max(14px, env(safe-area-inset-right));
    }
}
/* Slightly stronger frost when the app is launched from the home screen
   as an installed PWA — a touch more saturation so the topbar feels more
   "app native" against the device wallpaper / status bar. */
@media (display-mode: standalone) and (max-width: 900px) {
    .topbar {
        background: rgba(var(--glass-rgb), 0.66);
        -webkit-backdrop-filter: saturate(200%) blur(22px);
        backdrop-filter: saturate(200%) blur(22px);
    }
}
/* Display / wallboard surfaces opt out — those run fullscreen and have
   their own dark chrome at layout_display_open(). */
.display-shell .topbar { padding-top: 14px; background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; }
/* Print: kill the inset (the topbar is already display:none in print). */
@media print {
    .topbar { padding-top: 14px !important; }
}

/* Press / pressed states — fingers expect a quick visual ack on tap. The
   .btn classes already scale down on :active; extend that to cards/list
   items that act as link surfaces (kept very subtle so it does not feel
   gamified). */
@media (max-width: 900px) {
    .ac-card:active,
    .mobile-card-list-item:active {
        transform: scale(0.997);
        transition: transform 80ms var(--ease-out);
    }
}

/* Page header / breadcrumbs — keep clean on mobile, no heavy wrapping. */
@media (max-width: 700px) {
    .breadcrumbs { font-size: 12px; gap: 4px; }
    .breadcrumbs li { white-space: nowrap; }
}

/* Sticky form-action bars — when both .form-actions.sticky and
   .sticky-mobile-actions are on the page (rare), make sure the
   bottom-nav clearance lifts the action bar by the full nav height. */
@media (max-width: 700px) {
    .form-actions.sticky { box-shadow: 0 -6px 18px rgba(11,11,47,0.08); }
}

/* Modal/popover surfaces — add a subtle scrollbar treatment on phones so
   long popovers do not look like they overflow the screen. */
@media (max-width: 700px) {
    .user-menu-popover,
    .bell-popover {
        -webkit-overflow-scrolling: touch;
    }
}

/* Hide tiny chevrons / decorative svgs that were tuned for desktop hover
   when the screen is small enough that they crowd labels. Scoped narrowly
   so functional icons remain visible. */
@media (max-width: 520px) {
    .topbar .topbar-user .who { display: none; }
}

/* ====================================================================
   PWA double-tap zoom guard
   --------------------------------------------------------------------
   The viewport allows accessibility zoom. WebKit (Safari, iOS WKWebView,
   the standalone PWA shell) still benefits from explicit touch behavior
   so double-taps on controls do not trigger accidental zoom. Apply
   element under the finger declares touch-action: manipulation. Apply
   this globally to interactive surfaces and the app shell so a stray
   double-tap on a card / background / button doesn't zoom the page.

   Inputs are deliberately NOT given touch-action:manipulation so text
   selection, contextual menus, and accessibility gestures still work.
   Inputs are already 16px on mobile so iOS does not auto-zoom on focus.

   Iframes and any future map containers are explicitly excluded so
   pinch-zoom inside them keeps working.
   ==================================================================== */
/* Scroll-root chain — allow vertical panning EXPLICITLY.
   `pan-y pinch-zoom` preserves accessibility zoom while restoring normal
   vertical page scroll. Children that need pinch / horizontal pan
   (inputs, iframes, .display-shell, .table-wrap, .dr-scroll,
   .ops-board-scroll, [data-allow-zoom]) re-enable it via the
   `touch-action:auto` rule just below. */
html,
body,
.app-shell,
.main,
.content {
    touch-action: pan-y pinch-zoom;
}

/* Interactive / tap + chrome surfaces — suppress double-tap-to-zoom WITHOUT
   costing a page scroll.

   IMPORTANT (Android scroll fix, 2026-05-19): content CONTAINERS
   (.card / .card-hero / .stat / .mobile-card-list-item / .ac-card) were
   deliberately REMOVED from this list. On Chromium (Android Chrome,
   Samsung Internet, Pixel, and the installed PWA's WebView) a touch that
   STARTS on an element carrying `touch-action: manipulation` inside a
   `pan-y` scroll-root chain fails to promote the gesture to a page
   scroll. Because cards fill almost the whole page, the finger almost
   always lands on one, so the page would not scroll. iOS WebKit is
   lenient here, which is why the earlier `pan-y` fix cured iOS but the
   Samsung/Pixel/Android symptom remained.
   Do NOT add the content containers back here.

   DO NOT "FOLLOW UP" BY NARROWING THIS VALUE (Android incident, 2026-07-26).
   During that incident these selectors were changed `manipulation` ->
   `pan-y pinch-zoom`, on the theory that the `pan-x` component was stopping a
   vertical gesture from promoting. That change was REVERTED, because it is
   provably incapable of fixing a scroll bug:

     - `manipulation` is exactly `pan-x pan-y pinch-zoom` (Chrome serialises
       the long form back to the keyword), so `pan-y pinch-zoom` is a strict
       SUBSET of it.
     - The effective touch-action is the INTERSECTION of the touched element
       and its ancestors up to the element implementing the gesture.
     - Therefore, for any ancestor chain C:
           manipulation ∩ C  ⊇  (pan-y pinch-zoom) ∩ C
       The narrower value can only ever permit LESS. It cannot enable a
       gesture that was previously blocked, in any engine, quirk or not.

   It also caused real regressions, each measured: mobile `.tabs` strips and
   `.page-header-actions` rows (both `overflow-x:auto`) could no longer be
   swiped sideways, and inside `.ua-scroll` (`touch-action:pan-x`) the
   intersection became EMPTY — a total dead zone where the finger did nothing
   in any direction. `pinch-zoom` is also a Chromium-only keyword, so on iOS
   Safari and Firefox the whole declaration was invalid and dropped, silently
   restoring double-tap-to-zoom on every link and button.

   `manipulation` is the correct value here: universally supported, suppresses
   double-tap zoom, and permits both pan axes plus pinch so it never traps a
   gesture. If a page "resists scrolling", look for a bare `touch-action:pan-x`
   on a horizontal rail (that DOES block vertical page scroll) — not here. */
.topbar,
.sidebar,
.mobile-drawer-backdrop,
.mobile-bottom-nav,
.mobile-nav-toggle,
.btn,
button,
a,
.tabs a,
.field-check {
    touch-action: manipulation;
}

/* Content tiles must scroll the page on Chromium/Android: pin them to the
   same vertical-pan behaviour as the scroll roots above so a finger that
   lands anywhere on a card still scrolls the page. */
.card,
.card-hero,
.stat,
.mobile-card-list-item,
.ac-card {
    touch-action: pan-y;
}

/* Restore default touch-action where pinch-zoom or full gesture support
   matters: text inputs (so iOS magnifier + selection works), content-
   editable surfaces, embedded boards, and any explicit map-like opt-in
   surface (data-allow-zoom). Tables also keep manipulation off so the
   horizontal-scroll affordance feels natural. */
input,
textarea,
select,
[contenteditable],
iframe,
.display-shell,
.display-shell *,
.table-wrap,
.dr-scroll,
.ops-board-scroll,
[data-allow-zoom],
[data-allow-zoom] * {
    touch-action: auto;
}

/* NOTE (2026-07-26): a rail-descendant opt-out rule used to live here. It
   existed only to undo the damage of narrowing the interactive selectors
   above, and was removed with that change. It was also structurally unsound:
   an allowlist of four rail classes cannot cover the ~30 horizontal scrollers
   in this app, 22 of which are inline `style="overflow-x:auto"` wrappers with
   no class to target at all. Now that the interactive rule is `manipulation`
   (which already permits pan-x), links inside every rail pan sideways without
   needing an opt-out. */

/* Belt-and-braces: kill the 300ms tap delay where any UA still applies
   one. Both rules together suppress the double-tap-to-zoom heuristic on
   the affected surfaces without disabling vertical scroll. */
a, button, .btn, .mobile-bottom-nav a, .mobile-bottom-nav button,
.mobile-nav-toggle, .topbar-bell, .btn-icon {
    -ms-touch-action: manipulation;
}

/* iOS auto-zoom protection — the .field inputs already use 16px on mobile.
   Catch the bulk-edit table inputs which intentionally drop to 12.5–13px
   on desktop so they do not also zoom the viewport on iOS when focused. */

/* Tap highlight — replace the default heavy iOS gray flash with a calm
   brand-tinted ring so taps feel intentional, not jarring. */
a, button, .btn, .mobile-bottom-nav a, .mobile-bottom-nav button {
    -webkit-tap-highlight-color: rgba(39,66,112,0.12);
}

/* When a vertical scroll is in progress, prevent the topbar / drawer from
   bouncing past the page edge in the standalone PWA — keeps the chrome
   feeling anchored rather than rubber-banding away.

   MUST live on html (the root scroller), NEVER on body. The phone rule
   `html, body { overflow-x: hidden }` makes body its own scroll container,
   so `overscroll-behavior` on body became a MID-CHAIN boundary: a scroll
   starting over any wide table latched onto .table-wrap, could not move
   vertically, and the chain died at body before ever reaching the page
   scroller — every wide table was a full-size vertical-scroll dead zone in
   Chrome (measured 2026-08-10; the continuing "cannot scroll" reports on
   table-heavy pages). On the root, `contain` still suppresses rubber-band /
   pull-to-refresh past the page edge but leaves in-page chaining intact. */
@media (max-width: 900px) {
    html { overscroll-behavior-y: contain; }
    body { overscroll-behavior-y: auto; }
}

/* ====================================================================
   Quick-action cards + icon chips
   --------------------------------------------------------------------
   Reusable Apple-style "tile with leading icon, title, sub-line"
   pattern. Replaces the various inline `font-size:22px` glyph headers
   used across dashboard.php / technical_records.php / reports.php /
   exports.php. The tile is intentionally calm — soft surface lift on
   hover, subtle border-darken, no colour shift. The icon sits inside a
   small navy-tinted chip so it reads as intentional iconography rather
   than decoration.
   ==================================================================== */
.qa-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
}
a.qa-card, button.qa-card {
    display: flex; align-items: flex-start; gap: 12px;
    text-decoration: none; color: inherit;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px 16px;
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    text-align: left;
    font-family: inherit;
    transition:
        box-shadow var(--motion-med) var(--ease-soft),
        border-color var(--motion-med) var(--ease-soft),
        transform var(--motion-med) var(--ease-soft),
        background var(--motion-fast) var(--ease-out);
}
a.qa-card:hover, button.qa-card:hover {
    box-shadow: var(--shadow-md);
    border-color: rgba(39, 66, 112, 0.22);
    transform: translateY(-1px);
}
a.qa-card:focus-visible, button.qa-card:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(90, 121, 165, 0.40), var(--shadow-sm);
}
.qa-card .qa-icon {
    width: 38px; height: 38px;
    flex: 0 0 38px;
    border-radius: 10px;
    background: linear-gradient(180deg, rgba(39,66,112,0.10), rgba(39,66,112,0.04));
    color: var(--secondary);
    display: inline-flex; align-items: center; justify-content: center;
    transition: background var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out);
}
.qa-card:hover .qa-icon {
    background: linear-gradient(180deg, rgba(39,66,112,0.16), rgba(39,66,112,0.07));
    color: var(--primary);
}
.qa-card .qa-icon svg { width: 20px; height: 20px; }
.qa-card .qa-body { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; }
.qa-card .qa-title {
    font-weight: 700;
    font-size: 14.5px;
    color: var(--text-strong);
    letter-spacing: -0.01em;
    line-height: 1.3;
}
.qa-card .qa-sub {
    margin-top: 3px;
    font-size: 12.5px;
    color: var(--muted);
    line-height: 1.45;
}
.qa-card .qa-meta {
    margin-top: 8px;
    font-size: 11px;
    color: var(--secondary);
    font-weight: 600;
}
/* Highlight variant — used to call out a single primary action in a row
   of quick-action cards (e.g. Update Flight Hours on TR). */
.qa-card.qa-card-primary {
    border-color: rgba(39, 66, 112, 0.32);
    box-shadow: 0 6px 18px rgba(39,66,112,0.10);
}
.qa-card.qa-card-primary .qa-icon {
    background: linear-gradient(180deg, var(--primary), var(--secondary));
    color: #fff;
}
.qa-card.qa-card-primary:hover .qa-icon {
    background: linear-gradient(180deg, var(--primary-hover), var(--primary));
    color: #fff;
}
.qa-card.qa-card-primary .qa-title { color: var(--primary); }
/* Disabled / setup-required variant — same layout, no hover lift. */
.qa-card.qa-card-disabled {
    cursor: default;
    opacity: 0.62;
    box-shadow: none;
}
.qa-card.qa-card-disabled:hover { transform: none; box-shadow: none; border-color: var(--border); }
.qa-card.qa-card-disabled:hover .qa-icon { background: linear-gradient(180deg, rgba(39,66,112,0.10), rgba(39,66,112,0.04)); color: var(--secondary); }
.qa-card .qa-pill {
    display: inline-flex; align-items: center;
    margin-top: 8px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.012em;
    background: rgba(216,181,109,0.18);
    color: var(--status-warning-ink);
    border: 1px solid rgba(216,181,109,0.42);
}

/* ====================================================================
   Inline mini-charts (helpers.php → mini_bar_chart / mini_donut /
   mini_progress / mini_sparkline)
   --------------------------------------------------------------------
   Pure SVG, asset-free, semantic-colored. They sit ABOVE the existing
   tables, never replace them; tables remain the source of truth so a
   user with reduced motion / non-supporting browsers / print loses
   nothing.
   ==================================================================== */
.chart-card { padding: 18px 20px; }
.chart-card .chart-card-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; margin-bottom: 14px;
}
.chart-card .chart-card-head h3 {
    margin: 0;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text-strong);
}
.chart-card .chart-card-head .meta {
    font-size: 12px;
    color: var(--muted);
    font-weight: 500;
    text-align: right;
}
.chart-grid-2 {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 14px;
}
@media (max-width: 900px) {
    .chart-grid-2 { grid-template-columns: minmax(0, 1fr); }
}
.chart-empty {
    display: flex; align-items: center; justify-content: center;
    min-height: 120px;
    color: var(--muted);
    font-size: 13px;
    text-align: center;
    padding: 16px;
    border: 1px dashed var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-low);
}

/* Mini bar chart — horizontal bars with labels and trailing values. */
.mini-bar { display: block; max-width: 100%; }
.mini-bar .mb-label {
    fill: var(--muted-strong);
    font-size: 11.5px;
    font-weight: 600;
    font-family: var(--font-sans);
}
.mini-bar .mb-value {
    fill: var(--text-strong);
    font-size: 11.5px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    font-family: var(--font-mono);
}
.mini-bar .mb-track {
    fill: rgba(39,66,112,0.07);
}
.mini-bar .mb-fill                    { fill: var(--secondary); }
.mini-bar .mb-fill-primary            { fill: var(--secondary); }
.mini-bar .mb-fill-info               { fill: var(--info); }
.mini-bar .mb-fill-success            { fill: var(--status-success); }
.mini-bar .mb-fill-warn               { fill: var(--status-warning); }
.mini-bar .mb-fill-danger             { fill: var(--danger); }
.mini-bar .mb-fill-muted              { fill: rgba(94,100,114,0.55); }

/* Mini donut — segments around a centred total. */
.mini-donut { display: inline-block; }
.mini-donut .md-track    { stroke: rgba(39,66,112,0.10); }
.mini-donut .md-seg      { stroke: var(--secondary); }
.mini-donut .md-seg-primary { stroke: var(--secondary); }
.mini-donut .md-seg-info    { stroke: var(--info); }
.mini-donut .md-seg-success { stroke: var(--status-success); }
.mini-donut .md-seg-warn    { stroke: var(--status-warning); }
.mini-donut .md-seg-danger  { stroke: var(--danger); }
.mini-donut .md-seg-muted   { stroke: rgba(94,100,114,0.55); }
.mini-donut .md-center {
    fill: var(--text-strong);
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    font-family: var(--font-display);
}
.mini-donut .md-sub {
    fill: var(--muted);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.10em;
    font-family: var(--font-sans);
}

/* Mini progress bar (used in inspection-burn / readiness panels). */
.mini-progress { display: block; }
.mini-progress .mp-track             { fill: rgba(39,66,112,0.10); }
.mini-progress .mp-fill              { fill: var(--secondary); }
.mini-progress .mp-fill-primary      { fill: var(--secondary); }
.mini-progress .mp-fill-info         { fill: var(--info); }
.mini-progress .mp-fill-success      { fill: var(--status-success); }
.mini-progress .mp-fill-warn         { fill: var(--status-warning); }
.mini-progress .mp-fill-danger       { fill: var(--danger); }

/* Sparkline. */
.mini-spark { display: inline-block; vertical-align: middle; }
.mini-spark .ms-line          { stroke: var(--secondary); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.mini-spark .ms-primary       { stroke: var(--secondary); }
.mini-spark .ms-info          { stroke: var(--info); }
.mini-spark .ms-success       { stroke: var(--status-success); }
.mini-spark .ms-warn          { stroke: var(--status-warning); }
.mini-spark .ms-danger        { stroke: var(--danger); }

/* KPI tile mini-trend row — small muted sparkline + delta caption inside
   the existing .stat tile. Opt-in via .stat .stat-trend wrapper. */

/* Reduced-motion already neutralises animation; no animation here. */
@media print {
    .mini-bar, .mini-donut, .mini-progress, .mini-spark {
        /* Print engine renders these as inline SVG with no extra
           treatment — no animation to suppress, but ensure the chart
           card title meta line stays legible. */
        color-adjust: exact !important;
        -webkit-print-color-adjust: exact !important;
    }
}

/* ====================================================================
   Page-section icon chip — small leading badge for card titles that
   carry an SVG icon. Uses the same `.ttl-icon` aesthetic used by
   `.av2-card-head` so all department cards now share one language.
   ==================================================================== */

/* Card title row — pairs an icon chip with the title and a right-side
   meta string. Drop-in replacement for the existing `<div
   class="section-title">` pattern when an icon makes the card more
   scannable. */

/* ====================================================================
   Impeccable UI polish — surgical premium refinements
   --------------------------------------------------------------------
   Final additive layer. Refines existing components without renaming
   or removing any prior rule. Uses higher specificity (or new opt-in
   classes) so existing pages render unchanged unless they adopt the
   helper. Everything here lives on top of the JAGS blue token system
   (--primary / --secondary / --info / --grad-jags). No new palette.
   ==================================================================== */

/* ---- 1) Stat tile severity rail. -----------------------------------
   The base .stat tile only re-tints the .value text on warn/danger/
   success. At a glance the grid reads flat. A 2px top accent rail (and
   a faint tinted left edge) gives the tile semantic weight without
   shouting. Tonally calibrated to the existing semantic palette. */
.stat { position: relative; }
.stat::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: transparent;
    border-top-left-radius: var(--radius);
    border-top-right-radius: var(--radius);
    transition: background var(--motion-fast) var(--ease-out);
    pointer-events: none;
}
.stat-success::before { background: linear-gradient(90deg, rgba(74,103,51,0.55), rgba(74,103,51,0.0)); }
.stat-warn::before    { background: linear-gradient(90deg, rgba(216,181,109,0.75), rgba(216,181,109,0.0)); }
.stat-danger::before  { background: linear-gradient(90deg, rgba(184,50,53,0.70),  rgba(184,50,53,0.0)); }
/* Calm, JAGS-blue accent for tiles that want to register as "primary
   metric" rather than "alarm". Opt-in via .stat-primary. */

/* Small clickable label inside .stat .delta — already an <a> in most
   pages. Make the affordance crisper: subtle underline on hover,
   navy on focus. */
.stat .delta a {
    color: var(--secondary);
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: border-color var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out);
}
.stat .delta a:hover { color: var(--primary); border-bottom-color: rgba(39,66,112,0.35); }
.stat .delta a:focus-visible { outline: none; box-shadow: var(--ring-focus); border-radius: 3px; }

/* ---- 2) Hero action buttons. ----------------------------------------
   Pages emit white-on-gradient buttons inside .card-hero with inline
   styles (Operations, Reservations dashboards). Centralise: any .btn
   that lives inside .card-hero .hero-actions, or carries .btn-on-hero,
   picks up the white/translucent treatment automatically. Existing
   inline styles still win, so this is purely opt-in for future pages. */
.card-hero .hero-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.btn-on-hero,
.card-hero .hero-actions .btn-ghost {
    background: rgba(255,255,255,0.16);
    color: #fff;
    border-color: rgba(255,255,255,0.32);
}
.btn-on-hero:hover,
.card-hero .hero-actions .btn-ghost:hover {
    background: rgba(255,255,255,0.26);
    color: #fff;
    border-color: rgba(255,255,255,0.45);
}
.btn-on-hero-primary,
.card-hero .hero-actions .btn-primary {
    background: var(--card);
    color: var(--primary);
    border-color: #fff;
    font-weight: 700;
    box-shadow: 0 6px 18px rgba(0,0,0,0.16);
}
.btn-on-hero-primary:hover,
.card-hero .hero-actions .btn-primary:hover {
    background: #F2F4FA;
    color: var(--primary-hover);
    border-color: #F2F4FA;
}

/* ---- 3) Chart-empty refinement. ------------------------------------
   Default .chart-empty uses a dashed border that subliminally reads
   "broken / placeholder". Replace with a small icon-chip-style empty
   that reads as "intentionally minimal". Existing markup unchanged. */
.chart-empty {
    border: 1px solid var(--border);
    background: linear-gradient(180deg, var(--surface-low), #fff);
    color: var(--muted);
    font-weight: 500;
    border-radius: var(--radius);
    min-height: 140px;
}
.chart-empty::before {
    content: "";
    display: block;
    width: 28px; height: 28px;
    margin: 0 auto 8px;
    border-radius: 9px;
    background: linear-gradient(180deg, rgba(39,66,112,0.08), rgba(39,66,112,0.02));
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23274270' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='13' width='6' height='8' rx='1'/%3E%3Crect x='10' y='9' width='6' height='12' rx='1'/%3E%3Crect x='17' y='5' width='4' height='16' rx='1'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
    opacity: 0.85;
}
.chart-empty { flex-direction: column; }

/* ---- 4) Alert polish. ----------------------------------------------
   Strengthen the visual semantic weight: a 3px left rail and a tighter
   icon-bound layout. Backwards-compatible — existing .alert content
   continues to render. */
.alert {
    position: relative;
    overflow: hidden;
}
.alert::before {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--info);
    border-top-left-radius: var(--radius);
    border-bottom-left-radius: var(--radius);
}
.alert-success::before, .alert.success::before { background: var(--success); }
.alert-warn::before,    .alert.warn::before,
.alert-warning::before, .alert.warning::before { background: var(--warning); }
.alert-danger::before,  .alert.danger::before  { background: var(--danger); }
.alert-info::before,    .alert.info::before    { background: var(--info); }

/* ---- 5) Inline KPI delta pill. -------------------------------------
   Used by analytics to surface "+2.3 pts since Jan", "Latest month"
   captions, etc. Cleaner than the inline <div style="font-size:11px;
   text-transform:uppercase;..."> pattern repeated in analytics.php. */
.kpi-pill {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.012em;
    line-height: 1.4;
    background: rgba(90,121,165,0.10);
    color: var(--secondary);
    border: 1px solid rgba(90,121,165,0.22);
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
}
.kpi-pill.success { background: rgba(74,103,51,0.12);  color: var(--status-success-ink); border-color: rgba(74,103,51,0.32); }
.kpi-pill.warn    { background: rgba(216,181,109,0.18); color: var(--status-warning-ink); border-color: rgba(216,181,109,0.42); }
.kpi-pill.danger  { background: rgba(184,50,53,0.12);  color: var(--status-danger-ink); border-color: rgba(184,50,53,0.32); }
.kpi-pill.muted   { background: rgba(94,100,114,0.10); color: var(--muted-strong); border-color: rgba(94,100,114,0.22); }
/* Dark theme flips the pills to light ink on dark tints (same treatment as
   .badge-* above) — the light-ink hexes fail contrast on dark surfaces. */
html[data-theme="dark"] .kpi-pill.success { background: rgba(127,176,105,0.18); color: #A9D392; border-color: rgba(127,176,105,0.35); }
html[data-theme="dark"] .kpi-pill.warn    { background: rgba(224,178,92,0.20);  color: #E6C078; border-color: rgba(224,178,92,0.38); }
html[data-theme="dark"] .kpi-pill.danger  { background: rgba(224,121,123,0.18); color: #EDA0A2; border-color: rgba(224,121,123,0.35); }
html[data-theme="dark"] .kpi-pill.muted   { background: rgba(162,170,192,0.14); color: var(--muted); border-color: rgba(162,170,192,0.28); }
.kpi-pill .lbl {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.10em;
    color: inherit;
    opacity: 0.72;
    font-weight: 700;
}

/* Metric-trend row — pairs a label + value + sparkline in one calm
   horizontal strip. Drop-in replacement for the
       <div style="display:flex; align-items:center; gap:14px;">…</div>
   pattern in analytics.php. */

/* ---- 6) Compact stat grid. -----------------------------------------
   technical_records.php inlines a denser stat grid (140px minmax) for
   the Compliance Board counts. Surface that as a token so any page
   showing 5+ small counters can opt in via .stats-grid.stats-grid-tight
   or the freestanding .stats-grid-compact. */

/* ---- 7) Section eyebrow refinement. --------------------------------
   .section-title h2 is good, but the surrounding spacing reads slightly
   loose at the top of a card on busy pages. Tighten the rhythm by 2px
   and add a discreet underline on the section meta on hover (when it's
   a link). No effect on plain spans. */
.section-title { margin-bottom: 12px; }
.section-title a.muted {
    border-bottom: 1px solid transparent;
    transition: color var(--motion-fast) var(--ease-out), border-color var(--motion-fast) var(--ease-out);
}
.section-title a.muted:hover { color: var(--secondary); border-bottom-color: rgba(39,66,112,0.30); }

/* ---- 9) Card hero — refined defaults. ------------------------------
   Pages occasionally re-style .card-hero h2 with inline `font-size:28px`
   — smaller than the design-system token. We honour those overrides
   (they win), but tighten the *default* hero rhythm so pages that
   don't override pick up a slightly more refined value: 30px on
   desktop, scaling down to 24px on mobile. */
.card-hero h2 {
    font-size: clamp(24px, 3.5vw, 30px);
}
@media (max-width: 700px) {
    .card-hero { padding: 22px 22px; border-radius: var(--radius); }
}

/* ---- 10) Table head — slight crispening. ---------------------------
   The header gradient is fine; the tracking is fine. Add a 1px inner
   shadow on hover at the first row so the table feels tactile. Pure
   visual. No behaviour change. */
table.tbl thead th {
    background-image: linear-gradient(180deg, #F8FAFD 0%, #EEF2F9 100%);
    box-shadow: inset 0 -1px 0 var(--border);
}

/* ---- 11) Date filter row — opt-in form structure. ------------------
   analytics.php uses inline padding/border on each date picker. When a
   page wraps its inputs in .filter-row, give them the same modern
   chrome the .field form-control has. Existing inline styles still win;
   this is opt-in only. */
.filter-row {
    display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end;
}
.filter-row .fr-field {
    display: flex; flex-direction: column; gap: 4px;
    min-width: 0;
}
.filter-row .fr-field label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
    font-weight: 700;
}
.filter-row .fr-field select,
.filter-row .fr-field input[type=date],
.filter-row .fr-field input[type=text] {
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    font-size: 13.5px;
    font-family: inherit;
    color: var(--text);
    min-height: 36px;
    transition: border-color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out);
}
.filter-row .fr-field select:focus,
.filter-row .fr-field input:focus {
    outline: none;
    border-color: var(--secondary);
    box-shadow: var(--ring-focus);
}
.filter-row .fr-actions { display: flex; gap: 6px; align-items: center; }

/* ---- 12) Hero corner gradient refinement on .card-hero. ------------
   The existing radial spotlight on .card-hero is good but pages with
   tall heros (Operations dashboard with date) show a slight banding.
   Strengthen the top-left highlight to balance the top-right spotlight
   and give the hero a more "milled steel" feel. */
/* Faint dot field shared with the rail and the landing globe. */
.card-hero { background-image: radial-gradient(rgba(255,255,255,0.07) 1px, transparent 1.5px), var(--grad-jags), radial-gradient(circle at 0% 0%, rgba(255,255,255,0.10), transparent 50%); background-size: 14px 14px, auto, auto; }

/* ---- 13) Quick-action card right-arrow affordance. -----------------
   .qa-card is great but lacks a "this is interactive" cue. Add a faint
   right-side chevron that fades up on hover/focus. Purely decorative;
   no impact on screen reader since aria-hidden. */
a.qa-card { position: relative; padding-right: 32px; }
a.qa-card::after {
    content: "";
    position: absolute;
    right: 14px; top: 50%;
    width: 12px; height: 12px;
    margin-top: -6px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23274270' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 6l6 6-6 6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 12px 12px;
    opacity: 0.0;
    transform: translateX(-4px);
    transition: opacity var(--motion-med) var(--ease-soft), transform var(--motion-med) var(--ease-soft);
    pointer-events: none;
}
a.qa-card:hover::after,
a.qa-card:focus-visible::after { opacity: 0.55; transform: translateX(0); }
a.qa-card.qa-card-disabled::after { display: none; }

/* ---- 14) Mini-bar value typography. --------------------------------
   The mb-value font is mono, but mb-label is sans. Pull both into the
   same sans / tabular-num treatment so labels and values feel tied
   together on the same axis. The mb-fill colours stay semantic. */
.mini-bar .mb-label { font-size: 12px; fill: var(--text-strong); font-weight: 600; }
.mini-bar .mb-value { font-family: var(--font-sans); font-size: 12px; fill: var(--muted-strong); font-weight: 600; }

/* ---- 15) Compliance / regulatory pages — calmer left-rail card. ----
   technical_records.php emits an inline `border-left: 4px solid …` on
   the compliance summary card. Provide a token for this pattern so
   pages that opt-in don't need inline colour. */

/* ---- 16) Print niceties. -------------------------------------------
   Already broad print rules exist; add: ensure stat severity rails
   print in colour so the printed dashboard preserves semantic weight. */
@media print {
    .stat::before { print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; }
    .alert::before { print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; }
    a.qa-card::after { display: none; }
}

/* ---- 17) Focus ring tightening on interactive surfaces. ------------
   Cards and stats inside a clickable form should get the same focus
   ring as buttons. Keeps keyboard nav legible without painting an
   in-your-face outline. */
.card:focus-within { box-shadow: var(--ring-focus), var(--shadow-sm); }

/* ---- 18) Sidebar account row — small refinement. -------------------
   The .sidebar-account chip already groups avatar + name + sign-out.
   Add a subtle hover so it feels like a single tap target on touch
   devices (already has a sign-out button inside; we don't make the
   row a link). */
.sidebar-account { transition: background var(--motion-fast) var(--ease-out), border-color var(--motion-fast) var(--ease-out); }
.sidebar-account:hover { background: rgba(255,255,255,0.08); border-color: rgba(255,255,255,0.16); }

/* ---- 19) Bell badge — slightly heavier weight for legibility. ------
   At 10.5px the badge digits can feel thin on retina; bump weight and
   add a 0.5px stroke via text-shadow for crisper edges. */
.topbar-bell-badge {
    font-weight: 800;
    text-shadow: 0 0 0 currentColor;
    letter-spacing: -0.01em;
}

/* ---- 20) Calmer hover lift on .card. -------------------------------
   The existing transition is fine but the actual hover doesn't move
   .card surfaces. Cards inside .qa-grid already lift via .qa-card. For
   "interactive" cards opting into .card-interactive, give a tiny lift
   identical to .qa-card. */

/* ---- 21) Typographic settle + selection polish. --------------------
   Additive only — no existing rule is overridden. `text-wrap` is a
   progressive enhancement: a browser that doesn't support it ignores
   the declaration, so wrapping only ever improves and layout can never
   regress. Balancing headings and applying `pretty` to supporting copy
   removes the ragged single-word last line that separates a "designed"
   screen from a generated one. The selection rule ties highlighted text
   to the JAGS navy instead of the OS default blue. Display boards load
   a separate stylesheet (layout_display_open) and are unaffected; the
   .display-shell guard is defensive only, matching house style. */
h1, h2, h3, h4,
.page-header-text h1, .page-header-text h2,
.section-title h2, .card-section-title,
.empty-state h3, .modern-card-head h3, .av2-card-head h3 {
    text-wrap: balance;
}
p, .muted,
.page-header-text p, .empty-state p,
.field .hint, .sub-line, .feature-value .feat-sub, .av2-feature .feat-sub {
    text-wrap: pretty;
}
::selection {
    background: rgba(39, 66, 112, 0.20);
    color: var(--text-strong);
}
.display-shell ::selection {
    background: rgba(255, 255, 255, 0.22);
    color: #fff;
}

/* ====================================================================
   Premium mobile experience (2026-07-13)
   --------------------------------------------------------------------
   Reference-driven authenticated-app layer. This block is intentionally
   last in layout_css() so it can unify older page-local mobile treatments
   without changing desktop tables, print layouts, public displays, route
   permissions, or business logic.
   ==================================================================== */
:root {
    --jags-mobile-page-bg: #F3F6FA;
    --jags-mobile-surface: #FFFFFF;
    --jags-mobile-surface-soft: #EEF2F7;
    --jags-mobile-surface-strong: #E5EAF2;
    --jags-mobile-text: #0E0E12;
    --jags-mobile-text-muted: #5E6472;
    --jags-mobile-border: rgba(39, 66, 112, 0.10);
    --jags-mobile-radius-control: 12px;
    --jags-mobile-radius-compact: 16px;
    --jags-mobile-radius-card: 20px;
    --jags-mobile-radius-feature: 24px;
    --jags-mobile-radius-floating: 26px;
    --jags-mobile-space-1: 4px;
    --jags-mobile-space-2: 8px;
    --jags-mobile-space-3: 12px;
    --jags-mobile-space-4: 16px;
    --jags-mobile-space-5: 20px;
    --jags-mobile-space-6: 24px;
    --jags-mobile-space-7: 32px;
    --jags-mobile-shadow-card: 0 1px 2px rgba(14,14,18,.025), 0 10px 28px rgba(23,23,86,.045);
    --jags-mobile-shadow-floating: 0 2px 4px rgba(14,14,18,.04), 0 18px 40px rgba(23,23,86,.12);
    --jags-z-chrome: 8000;
    --jags-z-overlay: 9200;
    --jags-z-dialog: 9210;
}
/* Dark theme values for the premium mobile layer — same surface ladder as
   the main dark palette so phones and desktop read as one system. */
html[data-theme="dark"] {
    --jags-mobile-page-bg: #0E1220;
    --jags-mobile-surface: #171C2B;
    --jags-mobile-surface-soft: #1E2438;
    --jags-mobile-surface-strong: #29314A;
    --jags-mobile-text: #E6E9F2;
    --jags-mobile-text-muted: #A2AAC0;
    --jags-mobile-border: rgba(157, 176, 240, 0.14);
    --jags-mobile-shadow-card: 0 1px 2px rgba(0,0,0,.30), 0 10px 28px rgba(0,0,0,.35);
    --jags-mobile-shadow-floating: 0 2px 4px rgba(0,0,0,.35), 0 18px 40px rgba(0,0,0,.55);
}

.topbar-title-block { min-width: 0; }

/* Shared mobile status geometry: feature-specific selectors continue to own
   semantic colours, and dense desktop audit tables keep their current fit. */
@media (max-width: 900px) {
    .badge,
    .reservation-status-badge,
    .payment-status-badge,
    .clearance-status-badge,
    .requested-aircraft-badge,
    .customer-status-badge {
        border-radius: 999px;
        padding: 4px 9px;
        line-height: 1.2;
        font-weight: 700;
    }
}

/* Opt-in responsive data table. The mobile-table script copies each visible
   header into data-mobile-label, preserving the semantic table in the DOM
   while presenting operational rows as comfortably scannable cards. */
@media (max-width: 900px) {
    table[data-mobile-cards] { display: block; border: 0 !important; background: transparent !important; }
    table[data-mobile-cards] thead {
        position: absolute !important;
        width: 1px !important; height: 1px !important;
        padding: 0 !important; margin: -1px !important;
        overflow: hidden !important; clip: rect(0,0,0,0) !important;
        white-space: nowrap !important; border: 0 !important;
    }
    table[data-mobile-cards] tbody { display: grid; gap: 12px; }
    table[data-mobile-cards] tbody tr {
        display: block;
        padding: 8px 16px;
        border: 1px solid var(--jags-mobile-border) !important;
        border-radius: var(--jags-mobile-radius-card);
        background: var(--jags-mobile-surface);
        box-shadow: var(--jags-mobile-shadow-card);
        text-decoration: none !important;
    }
    table[data-mobile-cards] tbody td {
        display: grid;
        grid-template-columns: minmax(92px, 34%) minmax(0, 1fr);
        gap: 12px;
        align-items: start;
        width: auto !important;
        max-width: none !important;
        min-height: 40px;
        padding: 10px 0 !important;
        border: 0 !important;
        border-bottom: 1px solid var(--jags-mobile-border) !important;
        background: transparent !important;
        text-align: left !important;
        white-space: normal !important;
        overflow-wrap: anywhere;
    }
    table[data-mobile-cards] tbody td:last-child { border-bottom: 0 !important; }
    table[data-mobile-cards] tbody td::before {
        content: attr(data-mobile-label);
        color: var(--jags-mobile-text-muted);
        font-size: 12px;
        font-weight: 650;
        line-height: 1.35;
    }
    table[data-mobile-cards] tbody td.cell-actions,
    table[data-mobile-cards] tbody td[data-mobile-actions] {
        display: flex;
        flex-wrap: wrap;
        justify-content: flex-start !important;
        gap: 8px;
        padding-top: 12px !important;
    }
    table[data-mobile-cards] tbody td.cell-actions::before,
    table[data-mobile-cards] tbody td[data-mobile-actions]::before { display: none; }
    table[data-mobile-cards] tbody td form { margin: 0 !important; }
    table[data-mobile-cards] tbody td .btn,
    table[data-mobile-cards] tbody td button { min-height: 44px; }
    table[data-mobile-cards] + .mobile-scroll-hint,
    .table-wrap:has(> table[data-mobile-cards]) > .mobile-scroll-hint { display: none !important; }
    .table-wrap:has(> table[data-mobile-cards]) { overflow: visible; border: 0; background: transparent; }
}

/* Central action and More surfaces. */
.mobile-action-sheet { display: none; }
.mobile-action-sheet[hidden] { display: none !important; }
.fs-quick-edit-sheet { display: none; }
.fs-quick-edit-sheet[hidden] { display: none !important; }
@media (max-width: 900px) {
    .mobile-action-sheet {
        position: fixed;
        inset: 0;
        z-index: var(--jags-z-overlay);
        display: flex;
        align-items: flex-end;
        justify-content: center;
        padding: 14px 12px calc(14px + var(--safe-area-bottom));
        pointer-events: none;
        opacity: 0;
        background: rgba(11, 14, 38, 0);
        -webkit-backdrop-filter: blur(0);
        backdrop-filter: blur(0);
        transition:
            opacity 210ms var(--ease-out),
            background-color 210ms var(--ease-out),
            -webkit-backdrop-filter 210ms var(--ease-out),
            backdrop-filter 210ms var(--ease-out);
    }
    .mobile-action-sheet.is-open {
        pointer-events: auto;
        opacity: 1;
        background: rgba(11, 14, 38, 0.48);
        -webkit-backdrop-filter: blur(7px);
        backdrop-filter: blur(7px);
    }
    .mobile-action-sheet__panel {
        width: min(560px, 100%);
        max-height: min(76dvh, 680px);
        overflow: auto;
        padding: 10px 18px 20px;
        border: 1px solid rgba(var(--glass-rgb),.72);
        border-radius: 28px;
        background: rgba(var(--glass-rgb), .98);
        box-shadow: var(--jags-mobile-shadow-floating);
        transform-origin: bottom center;
        opacity: 0;
        transform: translate3d(0, 18px, 0) scale(.985);
        transition:
            transform var(--motion-med) var(--ease-premium),
            opacity 170ms var(--ease-out);
        will-change: transform, opacity;
    }
    .mobile-action-sheet.is-open .mobile-action-sheet__panel {
        opacity: 1;
        transform: translate3d(0, 0, 0) scale(1);
    }
    .mobile-action-sheet.is-closing .mobile-action-sheet__panel {
        transition-duration: 220ms, 150ms;
        transition-timing-function: cubic-bezier(.4,0,1,1), var(--ease-out);
    }
    .mobile-action-sheet__handle {
        width: 42px; height: 5px;
        margin: 0 auto 14px;
        border-radius: 999px;
        background: var(--jags-mobile-surface-strong);
    }
    .mobile-action-sheet__head {
        display: flex; align-items: center; justify-content: space-between;
        gap: 16px; margin-bottom: 14px;
    }
    .mobile-action-sheet__head h2 { font-size: 21px; }
    .mobile-action-sheet__close {
        width: 44px; height: 44px; padding: 0;
        display: inline-flex; align-items: center; justify-content: center;
        border: 0; border-radius: 14px;
        background: var(--jags-mobile-surface-soft);
        color: var(--jags-blue); cursor: pointer;
    }
    .mobile-action-sheet__grid { display: grid; grid-template-columns: 1fr; gap: 6px; }
    .mobile-action-sheet__item {
        min-height: 54px;
        display: flex; flex-direction: row; align-items: center; justify-content: flex-start;
        gap: 12px; padding: 9px 12px;
        border: 1px solid var(--jags-mobile-border);
        border-radius: var(--jags-mobile-radius-compact);
        background: var(--jags-mobile-surface-soft);
        color: var(--jags-mobile-text);
        font-weight: 700;
        opacity: 0;
        transform: translate3d(0, 8px, 0);
        transition:
            transform 190ms var(--ease-premium),
            opacity 150ms var(--ease-out);
        transition-delay: calc(var(--action-reverse-index, 0) * 8ms);
    }
    .mobile-action-sheet.is-open .mobile-action-sheet__item {
        opacity: 1;
        transform: translate3d(0, 0, 0);
        transition-delay: calc(34ms + (var(--action-index, 0) * 8ms));
    }
    .mobile-action-sheet.is-closing .mobile-action-sheet__item {
        transition-duration: 150ms, 120ms;
        transition-delay: calc(var(--action-reverse-index, 0) * 7ms);
    }
    .mobile-action-sheet__item .jags-icon { width: 22px; height: 22px; color: var(--jags-blue); }

    /* Flight Schedule mobile Quick Edit. The editor is deliberately outside
       the dense table so opening it never changes row width, row height, or
       the schedule rail's horizontal position. */
    .fs-quick-edit-sheet {
        position: fixed;
        left: 0;
        right: 0;
        top: var(--fs-visual-offset-top, 0px);
        height: var(--fs-visual-height, 100dvh);
        z-index: var(--jags-z-overlay);
        display: flex;
        align-items: flex-end;
        justify-content: center;
        padding: 8px 8px 0;
        pointer-events: none;
        opacity: 0;
        background: rgba(11,14,38,0);
        -webkit-backdrop-filter: blur(0);
        backdrop-filter: blur(0);
        transition: opacity 200ms var(--ease-out), background-color 200ms var(--ease-out), -webkit-backdrop-filter 200ms var(--ease-out), backdrop-filter 200ms var(--ease-out);
    }
    .fs-quick-edit-sheet.is-open {
        pointer-events: auto;
        opacity: 1;
        background: rgba(11,14,38,.48);
        -webkit-backdrop-filter: blur(6px);
        backdrop-filter: blur(6px);
    }
    .fs-quick-edit-sheet__panel {
        width: min(600px, 100%);
        max-height: calc(var(--fs-visual-height, 100dvh) - 8px);
        display: flex;
        flex-direction: column;
        overflow: hidden;
        border: 1px solid rgba(var(--glass-rgb),.72);
        border-bottom: 0;
        border-radius: 26px 26px 0 0;
        background: var(--card);
        box-shadow: 0 -20px 55px rgba(9,12,35,.24);
        opacity: 0;
        transform: translate3d(0, 18px, 0) scale(.99);
        transform-origin: bottom center;
        transition: transform var(--motion-med) var(--ease-premium), opacity 170ms var(--ease-out);
        will-change: transform, opacity;
    }
    .fs-quick-edit-sheet.is-open .fs-quick-edit-sheet__panel { opacity: 1; transform: translate3d(0,0,0) scale(1); }
    .fs-quick-edit-sheet.is-closing .fs-quick-edit-sheet__panel { transition-duration: 190ms, 140ms; transition-timing-function: cubic-bezier(.4,0,1,1), var(--ease-out); }
    .fs-quick-edit-sheet__handle { width: 42px; height: 5px; margin: 9px auto 4px; flex: 0 0 auto; border-radius: 999px; background: var(--jags-mobile-surface-strong); }
    .fs-quick-edit-sheet__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; padding: 10px 18px 12px; flex: 0 0 auto; border-bottom: 1px solid var(--jags-mobile-border); }
    .fs-quick-edit-sheet__head h2 { margin: 2px 0 0; font-size: 22px; color: var(--jags-blue); }
    .fs-quick-edit-sheet__head p { margin: 4px 0 0; color: var(--jags-mobile-text-muted); font-size: 13px; line-height: 1.35; }
    .fs-quick-edit-sheet__close { width: 44px; height: 44px; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 14px; background: var(--jags-mobile-surface-soft); color: var(--jags-blue); cursor: pointer; }
    .fs-quick-edit-sheet__status { min-height: 0; padding: 0 18px; flex: 0 0 auto; color: var(--danger); font-size: 13px; font-weight: 650; line-height: 1.4; }
    .fs-quick-edit-sheet__status:not(:empty) { min-height: 42px; padding-top: 10px; padding-bottom: 8px; border-bottom: 1px solid rgba(184,50,53,.16); background: rgba(184,50,53,.055); }
    .fs-quick-edit-sheet__host { min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
    .fs-quick-edit-sheet .fs-mobile-edit { display: grid; gap: 13px; margin: 0; padding: 16px 18px calc(14px + var(--safe-area-bottom)); }
    .fs-quick-edit-sheet .fs-mobile-edit[hidden] { display: none; }
    .fs-quick-edit-sheet .fs-mobile-flight-actions { position: sticky; bottom: calc(-14px - var(--safe-area-bottom)); z-index: 2; margin: 3px -18px calc(-14px - var(--safe-area-bottom)); padding: 12px 18px calc(14px + var(--safe-area-bottom)); border-top: 1px solid var(--jags-mobile-border); background: rgba(var(--glass-rgb), .97); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
    .fs-quick-edit-sheet .fs-mobile-flight-actions .btn { min-width: 0; }
    .fs-quick-edit-sheet form[data-fs-busy="1"] { opacity: .78; }
    .fs-quick-edit-sheet form[data-fs-busy="1"] input,
    .fs-quick-edit-sheet form[data-fs-busy="1"] select,
    .fs-quick-edit-sheet form[data-fs-busy="1"] textarea { pointer-events: none; }
    table.ops-board tr.fs-row-saved td { animation: fsRowSaved 1100ms var(--ease-out); }
    @keyframes fsRowSaved { 0%, 28% { background-color: rgba(34,139,87,.13); } 100% { background-color: transparent; } }
}

@media (max-width: 900px) {
    :root {
        --mobile-bottom-nav-height: 82px;
        --mobile-bottom-nav-footprint: calc(var(--mobile-bottom-nav-height) + var(--safe-area-bottom));
        --mobile-bottom-nav-clearance: calc(var(--mobile-bottom-nav-footprint) + 22px);
    }
    html, body { background: var(--jags-mobile-page-bg); }
    body { font-size: 15.5px; }
    .app-shell { min-height: 100dvh; }

    /* Native-style page header. It scrolls with the page instead of consuming
       permanent viewport height, while keeping safe-area padding in PWA mode. */
    .topbar {
        position: relative;
        z-index: 20;
        align-items: flex-start;
        padding: calc(18px + env(safe-area-inset-top, 0px)) max(18px, env(safe-area-inset-right, 0px)) 14px max(18px, env(safe-area-inset-left, 0px));
        border: 0;
        background: var(--jags-mobile-page-bg);
        box-shadow: none;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
    .topbar-leading { display: flex; align-items: flex-start; gap: 12px; min-width: 0; flex: 1 1 auto; }
    .topbar-title-block { display: flex; flex-direction: column; min-width: 0; padding-top: 1px; }
    .mobile-page-context,
    .mobile-page-meta { display: block; }
    .mobile-page-context {
        color: var(--jags-mobile-text-muted);
        font-size: 12.5px;
        font-weight: 650;
        line-height: 1.2;
        text-transform: none;
    }
    .mobile-page-meta {
        margin-top: 4px;
        color: var(--jags-mobile-text-muted);
        font-size: 13px;
        line-height: 1.25;
    }
    .topbar h1 {
        /* Bounded by the flex parent, NOT by 64vw. With `overflow: visible`
           and a viewport-relative cap, this could not shrink below its
           min-content width, so a one-word title held the whole leading
           column open and pushed the action cluster off the right edge —
           measured 435px of topbar in a 393px viewport once the cluster
           reached four controls. The title is the element that should yield:
           the page you are on is already obvious from context, whereas a
           control pushed off-screen is simply gone. */
        max-width: 100%;
        margin-top: 3px;
        overflow: hidden;
        color: var(--jags-mobile-text);
        /* Scales down on narrow phones so "Dashboard" still fits WHOLE at
           360-393px. The ellipsis below is the safety net for a genuinely
           long title, not the normal path. */
        font-size: clamp(21px, 6vw, 32px);
        font-weight: 750;
        line-height: 1.05;
        letter-spacing: -.03em;
        white-space: normal;
        text-overflow: ellipsis;
        text-wrap: balance;
    }
    .topbar > div:last-child { gap: 8px !important; padding-top: 18px; flex: 0 0 auto; }
    /* Narrow phones: the large title moves to its own row.
       A 27px native-style title and four 44px targets genuinely do not fit
       across a 393px phone — squeezing the title to suit would have meant
       ~17px type or an ellipsis on "Dashboard". This is the iOS large-title
       pattern the header is already shaped for (align-items:flex-start, a
       column title block, a header that scrolls rather than pinning), and it
       needs no markup change: the leading row wraps, the title block claims
       the full width, so row 1 is [menu ........ actions] and row 2 is the
       title at full size. Extra header height is fine here — this topbar
       scrolls away with the page. */
    @media (max-width: 520px) {
        .topbar {
            padding-left: max(14px, env(safe-area-inset-left, 0px));
            padding-right: max(14px, env(safe-area-inset-right, 0px));
            padding-bottom: 10px;
            flex-wrap: wrap;
            align-items: center;
            /* The shell is a grid with min-height:100dvh, so this header box
               stretches well past its content. Once it wraps, the default
               align-content:stretch spreads the two lines across all that
               height — 396px of header. Pack them to the top instead. */
            align-content: flex-start;
            row-gap: 8px;
        }
        /* `display: contents` promotes the menu button and the title block to
           direct flex items of the topbar, so they can be ordered across what
           was their wrapper. Without it the whole leading column wraps as one
           unit and the actions land on a third row. The wrapper is a plain
           div, so dissolving its box costs nothing semantically. */
        .topbar-leading { display: contents; }
        .mobile-nav-toggle { order: 1; }
        .topbar > div:last-child { order: 2; margin-left: auto; gap: 6px !important; padding-top: 0; }
        .topbar-title-block { order: 3; flex: 1 1 100%; padding-top: 0; }
        /* Full width of its own row, so the title goes back to the size the
           design intended — the reduced clamp above exists only for the
           single-row band (521-900px), where it shares the row with four
           44px targets. */
        .topbar h1 { margin-top: 2px; font-size: clamp(24px, 7vw, 32px); }
    }
    #jags-tour-launcher,
    .topbar-refresh,
    .topbar [data-system-run-button],
    .topbar .jags-system-run-button,
    .topbar .jags-title-badge,
    .topbar .jags-pwa-install-pill { display: none !important; }
    .mobile-nav-toggle,
    .topbar-bell,
    .user-menu-button { min-width: 44px; min-height: 44px; }
    .mobile-nav-toggle { border: 0; border-radius: 14px; background: var(--jags-mobile-surface); box-shadow: var(--jags-mobile-shadow-card); }
    .topbar-bell { width: 44px; height: 44px; border: 0; border-radius: 14px; background: var(--jags-mobile-surface); box-shadow: var(--jags-mobile-shadow-card); }
    .user-menu-button { padding: 3px; border-radius: 15px; background: var(--jags-mobile-surface); box-shadow: var(--jags-mobile-shadow-card); }
    .user-menu-button .jags-avatar { border-radius: 12px; }

    .content { padding: 8px max(16px, env(safe-area-inset-right, 0px)) var(--mobile-bottom-nav-clearance) max(16px, env(safe-area-inset-left, 0px)); }
    .main > .content { animation-duration: 180ms; }
    .content > .page-header { margin-top: 0; }
    .content > .page-header .page-header-text .eyebrow,
    .content > .page-header .page-header-text h1,
    .content > .page-header .page-header-text h2 { display: none; }
    .content > .page-header .page-header-text p {
        max-width: 46ch;
        margin: 0;
        font-size: 14px;
        line-height: 1.45;
    }
    .page-header { gap: 12px; margin-bottom: 18px; }
    .page-header-actions { width: 100%; display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; }
    .page-header-actions::-webkit-scrollbar { display: none; }
    .page-header-actions .btn { flex: 0 0 auto; }

    .card {
        padding: 18px;
        border-color: var(--jags-mobile-border);
        border-radius: var(--jags-mobile-radius-card);
        box-shadow: var(--jags-mobile-shadow-card);
    }
    .card + .card { margin-top: 16px; }
    .card-hero {
        padding: 22px 20px 24px;
        border-radius: var(--jags-mobile-radius-feature);
        box-shadow: 0 18px 38px rgba(23,23,86,.16);
    }
    .card-hero h2,
    .card-hero .pp-hero-title { font-size: clamp(26px, 7vw, 31px) !important; line-height: 1.08; }
    .card-hero p { max-width: 48ch; font-size: 14.5px; line-height: 1.5; }
    .stats-grid { gap: 12px; margin-bottom: 18px; }
    .stat { min-height: 112px; padding: 17px 16px; border-radius: var(--jags-mobile-radius-compact); box-shadow: var(--jags-mobile-shadow-card); }
    .stat .value { font-size: 27px; line-height: 1; }
    .stat .label { margin-top: 8px; font-size: 12px; line-height: 1.25; text-transform: none; letter-spacing: 0; }
    .section-title { margin-bottom: 14px; gap: 10px; }
    .section-title h2 { font-size: 19px; line-height: 1.15; }
    .qa-grid { grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px; }
    a.qa-card, button.qa-card { min-height: 112px; padding: 16px 30px 16px 16px; border-radius: var(--jags-mobile-radius-card); }
    .mobile-card-list { gap: 12px; }
    .mobile-card-list-item { padding: 16px; border-radius: var(--jags-mobile-radius-card); box-shadow: var(--jags-mobile-shadow-card); }
    .fs-mobile-schedule[hidden] { display: none !important; }
    .fs-mobile-schedule:not(.fs-mobile-cards-optional) + .mobile-scroll-hint,
    .fs-mobile-schedule:not(.fs-mobile-cards-optional) ~ .ops-board-scroll { display: none !important; }
    .ops-board-wrap.fs-mobile-card-mode .mobile-scroll-hint,
    .ops-board-wrap.fs-mobile-card-mode .ops-board-scroll { display: none !important; }
    .fs-mobile-mode-tabs { order: 8; width: 100%; padding: 4px; border-radius: 14px; background: var(--jags-mobile-surface-soft); }
    .fs-mobile-mode-tabs button { flex: 1; min-height: 42px; border: 0; border-radius: 11px; background: transparent; color: var(--jags-mobile-text-muted); font-weight: 750; }
    .fs-mobile-mode-tabs button.active { background: var(--card); color: var(--jags-blue); box-shadow: 0 3px 10px rgba(23,23,86,.10); }
    .fs-quick-views { margin: 0 0 10px; padding: 0; overflow-x: auto; scrollbar-width: none; }
    .fs-quick-views > div { flex-wrap: nowrap !important; width: max-content; }
    .fs-filter-bar { margin-bottom: 12px; padding: 12px; }
    .fs-filter-date-row { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 10px; align-items: end; }
    .fs-filter-details > summary { min-height: 48px; display: flex; align-items: center; padding: 0 14px; border: 1px solid var(--jags-mobile-border); border-radius: 14px; color: var(--jags-blue); font-weight: 750; cursor: pointer; list-style: none; }
    .fs-filter-details > summary::-webkit-details-marker { display: none; }
    .fs-filter-sheet { position: absolute; z-index: 18; left: 16px; right: 16px; margin-top: 8px; padding: 16px; border: 1px solid var(--jags-mobile-border); border-radius: 18px; background: var(--card); box-shadow: var(--jags-mobile-shadow-floating); }
    .fs-filter-sheet .form-grid { grid-template-columns: 1fr; }
    .ops-board-tabs { display: none !important; }
    .fs-mobile-flight-card { display: block; }
    .fs-mobile-flight-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
    .fs-mobile-flight-head h3 { margin-top: 4px; font-size: 22px; color: var(--jags-blue); }
    .fs-mobile-route { margin-top: 14px; font-size: 18px; font-weight: 750; letter-spacing: -.02em; }
    .fs-mobile-times { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
    .fs-mobile-times > div { padding: 12px; border-radius: 14px; background: var(--jags-mobile-surface-soft); }
    .fs-mobile-times span,
    .fs-mobile-crew span { display: block; color: var(--jags-mobile-text-muted); font-size: 12px; font-weight: 650; }
    .fs-mobile-times strong { display: block; margin-top: 3px; font-size: 20px; font-variant-numeric: tabular-nums; }
    .fs-mobile-crew { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-top: 12px; }
    .fs-mobile-crew strong { text-align: right; }
    .fs-mobile-flight-actions { margin-top: 16px; }
    .fs-mobile-flight-actions .btn:first-child { flex: 1 1 auto; }
    /* Fuel / follower / client rows reuse the .fs-mobile-crew chrome; the
       extras below cover remarks, status chips and the quick-edit form. */
    .fs-mobile-remarks { margin-top: 12px; padding: 10px 12px; border-radius: 12px; background: var(--jags-mobile-surface-soft); font-size: 14px; line-height: 1.4; overflow-wrap: anywhere; }
    .fs-mobile-handoff { border-left: 3px solid rgba(34,139,87,0.55); background: rgba(34,139,87,0.06); }
    .fs-mobile-handoff strong { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: #1f7a4d; margin-right: 6px; }
    .fs-mobile-chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
    .fs-mobile-editing { border: 2px solid var(--jags-blue); }
    .fs-mobile-edit { display: grid; gap: 12px; margin-top: 14px; }
    /* Load-bearing: the grid display above beats the UA [hidden] rule, so
       the always-rendered quick-edit form needs an explicit override or
       every card would render with its editor expanded. */
    .fs-mobile-edit[hidden] { display: none; }
    /* Same load-bearing reason for the summary rows: `.fs-mobile-crew`
       declares display:flex above, and an author display beats the UA
       [hidden] rule, so the optional Client / Follower rows would render
       even when marked hidden. (`.fs-mobile-remarks` declares no display,
       so its [hidden] already works and needs no override.) */
    .fs-mobile-crew[hidden] { display: none; }
    .fs-mobile-edit input[type=text],
    .fs-mobile-edit select,
    .fs-mobile-edit textarea { width: 100%; }
    .empty-state { padding: 30px 18px 28px; border-radius: var(--jags-mobile-radius-card); }
    .empty-state h3 { font-size: 18px; }
    .field label { font-size: 13px; }
    .field input, .field select, .field textarea { min-height: 48px; border-radius: var(--jags-mobile-radius-control); font-size: 16px; }
    /* iOS Safari zooms the viewport when any focused editable control is
       below 16px. Cover controls outside the canonical .field wrapper too
       (People search, Messages composer, table filters, Quick Edit, auth). */
    input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]):not([type="button"]):not([type="submit"]):not([type="reset"]),
    select,
    textarea,
    [contenteditable="true"] {
        font-size: 16px !important;
    }
    .btn { min-height: 48px; border-radius: 14px; padding: 11px 16px; }
    .btn-sm { min-height: 44px; padding: 9px 12px; }
    .form-actions .btn { min-height: 48px; }
    .tabs, .segmented-control {
        padding: 4px; gap: 4px;
        border: 1px solid var(--jags-mobile-border);
        border-radius: 16px;
        background: var(--jags-mobile-surface-soft);
    }
    .tabs a, .segmented-control a, .segmented-control button { min-height: 44px; border-radius: 12px; }

    /* Floating five-destination dock. */
    .mobile-bottom-nav {
        left: 50%; right: auto;
        bottom: calc(8px + var(--safe-area-bottom));
        width: min(560px, calc(100vw - 24px));
        min-height: 72px;
        padding: 6px;
        grid-template-columns: repeat(5, minmax(0,1fr));
        grid-auto-flow: initial;
        grid-auto-columns: initial;
        border: 1px solid rgba(var(--glass-rgb),.78);
        border-radius: var(--jags-mobile-radius-floating);
        background: rgba(var(--glass-rgb),.94);
        box-shadow: var(--jags-mobile-shadow-floating);
        transform: translateX(-50%);
        transition: opacity var(--motion-med) var(--ease-out), transform var(--motion-med) var(--ease-out);
    }
    .mobile-bottom-nav a,
    .mobile-bottom-nav button { min-height: 58px; padding: 7px 3px 5px; border-radius: 16px; font-size: 12px; }
    .mobile-bottom-nav a.active { color: var(--jags-blue); background: rgba(90,121,165,.10); }
    .mobile-bottom-nav a.active::before { display: none; }
    .mobile-bottom-nav a .jags-icon,
    .mobile-bottom-nav button .jags-icon { width: 23px; height: 23px; }
    .mobile-bottom-nav .mobile-nav-primary {
        align-self: center;
        min-height: 76px;
        margin-top: -20px;
        overflow: visible;
        color: var(--jags-blue);
        background: transparent;
    }
    .mobile-bottom-nav .mobile-nav-primary .jags-icon-wrap {
        width: 54px; height: 54px;
        display: inline-flex; align-items: center; justify-content: center;
        border: 4px solid rgba(255,255,255,.96);
        border-radius: 18px;
        background: var(--jags-blue);
        color: #fff;
        box-shadow: 0 10px 24px rgba(23,23,86,.25);
        transform: translate3d(0,0,0) rotate(0) scale(1);
        transition: transform var(--motion-fast) var(--ease-premium), box-shadow var(--motion-fast) var(--ease-out);
    }
    #jags-mobile-action-trigger.is-action-open .jags-icon-wrap {
        transform: translate3d(0,-2px,0) rotate(45deg) scale(.94);
        box-shadow: 0 8px 20px rgba(23,23,86,.20);
    }
    .mobile-bottom-nav .mobile-nav-primary .jags-icon { width: 25px; height: 25px; opacity: 1; }
    .mobile-bottom-nav .mobile-nav-primary .label { color: var(--jags-blue); font-weight: 750; }
    body.mobile-nav-open .mobile-bottom-nav { opacity: 0; pointer-events: none; transform: translate(-50%, 12px); }

    /* The existing permission-aware drawer becomes a polished More sheet. */
    .sidebar {
        top: auto; left: 50%; bottom: calc(10px + var(--safe-area-bottom));
        width: min(600px, calc(100vw - 24px));
        height: min(82dvh, 720px);
        max-height: calc(100dvh - 24px - var(--safe-area-bottom));
        padding: 16px 14px calc(18px + var(--safe-area-bottom));
        border: 1px solid rgba(255,255,255,.12);
        border-radius: 28px;
        box-shadow: 0 28px 70px rgba(5,7,22,.44);
        transform: translate(-50%, calc(100% + 40px));
        transition: transform var(--motion-med) var(--ease-premium), visibility 0s linear var(--motion-med);
    }
    body.mobile-nav-open .sidebar { transform: translate(-50%, 0); }
    /* No brand mark on the phone sheet (owner decision 2026-09-10). The user
       reached this sheet by tapping that exact icon on their home screen —
       repeating it at the top of the sheet says nothing and costs the space
       where navigation should start. Home is not lost with it: it is the first
       workspace chip and the first item in the bottom nav.
       Desktop keeps the mark, where the 56px rail has no other brand presence. */
    .sidebar-brand { display: none; }
    .sidebar nav a { min-height: 48px; border-radius: 12px; font-size: 14px; }
    .sidebar-account { border-top-color: rgba(255,255,255,.10); box-shadow: 0 -8px 24px rgba(5,7,22,.22); }

    /* Mobile minimums win even when the user previously selected Compact. */
    body[data-density="compact"] .card { padding: 18px; border-radius: var(--jags-mobile-radius-card); }
    body[data-density="compact"] .card + .card { margin-top: 16px; }
    body[data-density="compact"] .field input,
    body[data-density="compact"] .field select,
    body[data-density="compact"] .field textarea { min-height: 48px; font-size: 16px; }
    .jags-toast .toast-close { min-width: 44px; min-height: 44px; }
    a:focus-visible,
    button:focus-visible,
    input:focus-visible,
    select:focus-visible,
    textarea:focus-visible,
    [tabindex]:focus-visible {
        outline: 3px solid #274270 !important;
        outline-offset: 3px !important;
        box-shadow: none;
    }
}

@media (max-width: 380px) {
    .topbar { padding-left: 12px; padding-right: 12px; }
    .topbar h1 { max-width: 58vw; font-size: 26px; }
    .topbar > div:last-child { gap: 5px !important; }
    .topbar-bell, .user-menu-button { min-width: 42px; min-height: 42px; }
    .content { padding-left: 12px; padding-right: 12px; }
    .qa-grid { grid-template-columns: 1fr; }
    .mobile-action-sheet__grid { grid-template-columns: 1fr; }
    .mobile-bottom-nav { width: calc(100vw - 16px); }
    .mobile-bottom-nav a, .mobile-bottom-nav button { font-size: 10.5px; }
}

@media (prefers-reduced-motion: reduce) {
    .mobile-action-sheet,
    .mobile-action-sheet__panel,
    .mobile-action-sheet__item,
    .fs-quick-edit-sheet,
    .fs-quick-edit-sheet__panel,
    .mobile-bottom-nav .mobile-nav-primary .jags-icon-wrap { transition-duration: .01ms !important; transition-delay: 0ms !important; }
    .mobile-bottom-nav, .sidebar { transition-duration: .01ms !important; }
}

@media print {
    .mobile-action-sheet { display: none !important; }
}

/* Page canvas texture (2026-10-19): the same faint dot field as the rail,
   the heroes and the landing globe, so every page shares one surface.
   Cards stay solid; it only shows in the gutters. Screen only. */
@media screen {
    body {
        background-image:
            radial-gradient(rgba(39, 66, 112, 0.075) 1px, transparent 1.4px),
            radial-gradient(120% 60% at 50% -10%, rgba(90, 121, 165, 0.08), transparent 60%);
        background-size: 18px 18px, 100% 100%;
        background-attachment: fixed, fixed;
    }
    html[data-theme="dark"] body {
        background-image:
            radial-gradient(rgba(157, 176, 240, 0.06) 1px, transparent 1.4px),
            radial-gradient(120% 60% at 50% -10%, rgba(124, 165, 216, 0.08), transparent 60%);
    }
}

/* Workspace bar texture + motion (2026-10-19): a faint dot field that echoes
   the landing globe, a soft light pooled at the top of the rail, icons that
   lift on hover and a lit edge on the current workspace. Desktop only. */
@media (min-width: 901px) {
    .sidebar {
        background:
            radial-gradient(rgba(138, 163, 214, 0.10) 1px, transparent 1.5px) 0 0 / 14px 14px,
            radial-gradient(130% 55% at 0% 0%, rgba(138, 163, 214, 0.16), transparent 62%),
            var(--grad-sidebar);
    }
    .ws-rail-icon { transition: transform 200ms var(--ease-premium); }
    .ws-rail-btn:hover .ws-rail-icon { transform: translateY(-1px) scale(1.08); }
    .ws-rail-btn.is-current {
        box-shadow: inset 0 0 0 1px rgba(138, 163, 214, 0.24), 0 8px 20px -10px rgba(138, 163, 214, 0.6);
    }
    .ws-panel nav a { transition: background 160ms var(--ease-soft), transform 200ms var(--ease-premium); }
    .ws-panel nav a:hover { transform: translateX(2px); }
}
/* Fleet readiness widget: a fuller meter that fills in on arrival. */
.dw-fr-status { font-size: 16px; letter-spacing: -0.01em; }
.dw-fr-meter { height: 8px; gap: 3px; transform-origin: left center; animation: dwFrGrow 900ms var(--ease-premium) both; }
.dw-fr-meter i { border-radius: 999px; background-image: linear-gradient(rgba(255, 255, 255, 0.24), rgba(255, 255, 255, 0)); }
.dw-legend span { padding: 2px 0; border-bottom: 1px dashed var(--border-subtle); }
.dw-legend span:last-child { border-bottom: 0; }
@keyframes dwFrGrow { from { transform: scaleX(0.04); opacity: 0.4; } }
@media (prefers-reduced-motion: reduce) {
    .dw-fr-meter { animation: none; }
    .ws-rail-icon, .ws-panel nav a { transition: none; }
}

/* Workspace globe — desktop backdrop on landing pages (assets/globe/globe.js).
   Sits under the whole shell; body goes transparent so the canvas shows
   between cards over the html background. Phones, touch and print never
   show it. Colours are read by the script, so both themes retint here. */
.jags-globe { display: none; }
@media (min-width: 901px) and (hover: hover) and (pointer: fine) {
    body.has-globe { background: transparent; }
    .jags-globe {
        display: block; position: fixed; inset: 0; width: 100vw; height: 100vh;
        z-index: -1; pointer-events: none; opacity: 0;
        transition: opacity 900ms var(--ease-premium);
    }
    .jags-globe.is-on { opacity: 1; }
    /* Cards let the globe through faintly; no backdrop blur, which would
       re-blur every animated frame. Text stays on a >=80% card surface. */
    body.has-globe .card:not(.card-hero),
    body.has-globe .stat,
    body.has-globe .qa-card,
    body.has-globe .dw {
        background: color-mix(in srgb, var(--surface-primary) 82%, transparent);
    }
    /* The greeting is the one place the globe is meant to be seen: the
       dashboard's Today strip drops its card and sits on the open sky. */
    body.has-globe .dw-welcome,
    body.has-globe .dw-welcome:hover {
        background: transparent; border-color: transparent; box-shadow: none;
        padding: 6px 2px 10px;
    }
    body.has-globe .dw-welcome-h { font-size: 26px; letter-spacing: -0.02em; }
    body.has-globe .dw-welcome-sum { font-size: 13.5px; }
}
.jags-globe {
    --globe-dot: rgba(39, 66, 112, 0.30);
    --globe-dot-hi: rgba(23, 23, 86, 0.62);
    --globe-arc: var(--jags-blue-soft);
    --globe-node: var(--primary);
    --globe-craft: var(--text-strong);
    --globe-glow: rgba(90, 121, 165, 0.18);
    --globe-ocean: rgba(90, 121, 165, 0.045);
    --globe-grid: rgba(39, 66, 112, 0.07);
    --globe-label-bg: color-mix(in srgb, var(--surface-primary) 94%, transparent);
    --globe-label-ink: var(--text-strong);
}
html[data-theme="dark"] .jags-globe {
    --globe-dot: rgba(157, 176, 240, 0.22);
    --globe-dot-hi: rgba(180, 195, 245, 0.70);
    --globe-glow: rgba(124, 165, 216, 0.22);
    --globe-ocean: rgba(124, 165, 216, 0.05);
    --globe-grid: rgba(157, 176, 240, 0.07);
}
@media print { .jags-globe { display: none !important; } }

/* ======================================================================
   CHANGE REQUEST HUB (2026-08-24; trimmed 2026-09-06)
   My Requests, the request thread and the reviewer reply form. The global
   "suggest / report" trigger, the three-path sheet and the attachment
   composer were retired with the submission route in the 2026-09 product
   strip; their rules are gone. See
   docs/reports/2026-09-06-usage-based-product-strip.md.

   Token-only by construction: every colour here is a var(), so the dark
   theme is inherited rather than re-specified. There is no
   html[data-theme="dark"] block for this feature and there must not be
   one — if something reads wrong in dark mode, the token is wrong, not
   the component.
   ====================================================================== */

/* --- Hub pages --------------------------------------------------------- */
.cr-shell { max-width: 760px; margin: 0 auto; }



.cr-back {
    display: inline-flex; align-items: center; gap: 6px;
    min-height: 40px;
    color: var(--muted); font-size: var(--text-sm); font-weight: 600; text-decoration: none;
}
.cr-back:hover { color: var(--text); }
.cr-back:focus-visible { outline: none; box-shadow: var(--ring-focus); border-radius: var(--radius-sm); }

/* --- Composer ---------------------------------------------------------- */
/* These are cards. Match the incumbent .card exactly rather than landing 2px
   and one shadow-step away from it — request_view.php renders a real .card
   directly above .cr-reply, and a near-miss reads worse than a difference. */
.cr-reply {
    padding: 22px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-card);
    background: var(--card);
    box-shadow: var(--shadow-card);
}

.cr-field { display: block; }
.cr-field__label {
    display: block; margin-bottom: 6px;
    font-size: var(--text-sm); font-weight: 600; color: var(--muted-strong);
}
.cr-field textarea {
    width: 100%;
    padding: 12px 13px;
    border: 1px solid var(--border-strong); border-radius: var(--radius-control);
    background: var(--surface-low); color: var(--text);
    font: inherit; font-size: var(--text-base); line-height: 1.55;
    resize: vertical;
}
.cr-field textarea::placeholder { color: var(--muted); }
.cr-field textarea:focus { outline: none; border-color: var(--secondary); box-shadow: var(--ring-focus); }

/* --- Attachment controls ---------------------------------------------- */
.cr-attach__row { display: flex; flex-wrap: wrap; gap: 8px; }
.cr-chip {
    display: inline-flex; align-items: center; gap: 7px;
    min-height: 40px; padding: 0 13px;
    border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
    background: var(--surface-low); color: var(--text);
    font-size: var(--text-sm); font-weight: 600; cursor: pointer;
    transition: background var(--motion-fast) var(--ease-soft), border-color var(--motion-fast) var(--ease-soft);
}
.cr-chip:hover { background: var(--surface-container); border-color: var(--secondary); }
.cr-chip:focus-within, .cr-chip:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.cr-chip svg { color: var(--secondary); }
.cr-chip[disabled] { opacity: .55; cursor: not-allowed; }

/* --- Captured context -------------------------------------------------- */
.cr-ctx { display: flex; flex-wrap: wrap; gap: 8px 26px; margin: 0; }
.cr-ctx > div { display: grid; gap: 2px; }
.cr-ctx dt { font-size: var(--text-xs); color: var(--muted); }
.cr-ctx dd { margin: 0; font-size: var(--text-sm); font-weight: 600; color: var(--text); }


.cr-submit { min-height: 46px; padding: 0 24px; font-size: var(--text-base); }

/* --- My Requests ------------------------------------------------------- */
.cr-listhead {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
    margin: 4px 0 20px;
}
.cr-listhead h1 { margin: 0 0 6px; font-size: var(--text-2xl); letter-spacing: -0.02em; color: var(--text-strong); }
.cr-listhead p { margin: 0; color: var(--muted); font-size: var(--text-base); }

.cr-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.cr-list__item > a {
    display: block; padding: var(--space-4);
    border: 1px solid var(--border-subtle); border-radius: var(--radius-card);
    background: var(--card); color: var(--text); text-decoration: none;
    transition: border-color var(--motion-fast) var(--ease-soft), background var(--motion-fast) var(--ease-soft);
}
.cr-list__item > a:hover { border-color: var(--border); background: var(--surface-high); }
.cr-list__item > a:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.cr-list__top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cr-ref {
    font-size: var(--text-sm); font-weight: 700; letter-spacing: .02em;
    font-variant-numeric: tabular-nums;
    color: var(--secondary);
}
.cr-ref--lg { font-size: var(--text-base); }
.cr-list__excerpt {
    margin: 9px 0 0; font-size: var(--text-sm); line-height: 1.5; color: var(--text);
}
.cr-list__meta {
    display: flex; flex-wrap: wrap; gap: 6px 14px;
    margin-top: 9px; font-size: var(--text-xs); color: var(--muted);
}

/* --- Request detail ---------------------------------------------------- */
.cr-received {
    display: flex; align-items: flex-start; gap: 12px;
    margin: 10px 0 18px; padding: 14px 16px;
    border: 1px solid var(--success); border-radius: var(--radius-card);
    background: var(--status-success-soft);
}
.cr-received__tick { color: var(--success); flex: 0 0 auto; display: inline-flex; }
.cr-received div { display: grid; gap: 3px; }
.cr-received strong { font-size: var(--text-base); color: var(--text-strong); }
.cr-received span { font-size: var(--text-sm); color: var(--muted-strong); }

.cr-detail__head { margin: 8px 0 16px; }
.cr-detail__ident { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.cr-detail__when { margin: 8px 0 0; font-size: var(--text-sm); color: var(--muted); }

.cr-original__body {
    margin: 0; font-size: var(--text-base); line-height: 1.62; color: var(--text);
    max-width: 70ch; white-space: pre-line;
}
.cr-ctx { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }

.cr-triage__grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 12px; margin-bottom: 12px;
}
.cr-triage__grid label { display: grid; gap: 6px; }
.cr-triage__grid span { font-size: var(--text-sm); font-weight: 600; color: var(--muted-strong); }
.cr-triage__grid select {
    min-height: 42px; padding: 0 11px;
    border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
    background: var(--surface-low); color: var(--text);
    font: inherit; font-size: var(--text-base);
}
.cr-triage__grid select:focus { outline: none; border-color: var(--secondary); box-shadow: var(--ring-focus); }
.cr-triage__form .cr-field textarea { font-size: var(--text-base); }
.cr-triage__hint { margin: 12px 0 16px; font-size: var(--text-sm); color: var(--muted); max-width: 68ch; }

/* --- Attachments ------------------------------------------------------- */
.cr-att-grid { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.cr-att--image {
    display: block; overflow: hidden;
    border: 1px solid var(--border); border-radius: var(--radius-control);
    line-height: 0;
}
.cr-att--image img { display: block; max-width: 220px; max-height: 160px; object-fit: cover; }
.cr-att--image:hover { border-color: var(--secondary); }
.cr-att--image:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.cr-att--file {
    display: inline-flex; align-items: center; gap: 9px;
    min-height: 44px; padding: 0 13px;
    border: 1px solid var(--border); border-radius: var(--radius-control);
    background: var(--surface-low); color: var(--text);
    font-size: var(--text-sm); font-weight: 600; text-decoration: none;
}
.cr-att--file:hover { border-color: var(--secondary); }
.cr-att--file:focus-visible { outline: none; box-shadow: var(--ring-focus); }
.cr-att--file svg { color: var(--secondary); }
.cr-att--audio {
    display: grid; gap: 6px;
    padding: 11px 13px;
    border: 1px solid var(--border); border-radius: var(--radius-control);
    background: var(--surface-low);
}
.cr-att--audio audio { width: min(320px, 100%); height: 38px; }
.cr-att__meta { font-size: var(--text-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.cr-att__name { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- Thread ------------------------------------------------------------ */
.cr-thread { margin-top: 26px; }
.cr-thread__title {
    margin: 0 0 14px; font-size: var(--text-base); font-weight: 700;
    letter-spacing: .01em; color: var(--text-strong);
}
.cr-thread__empty { margin: 0 0 16px; font-size: var(--text-sm); color: var(--muted); max-width: 62ch; }

.cr-msgs { list-style: none; margin: 0 0 18px; padding: 0; display: grid; gap: 10px; }
.cr-msg {
    padding: 13px 15px;
    border: 1px solid var(--border); border-radius: var(--radius-card);
    background: var(--card);
}
/* A reviewer's message is the one a submitter is scanning for, so that is the
   side that gets marked. --surface-container is a real step from --card (not
   the adjacent rung --surface-low was), and the accent rule carries the
   distinction without relying on colour at all. */
.cr-msg.is-mine { background: var(--surface-low); }
.cr-msg--reviewer {
    background: var(--surface-container);
    border-left: 3px solid var(--accent);
}
.cr-msg__head { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; margin-bottom: 6px; }
.cr-msg__head strong { font-size: var(--text-sm); color: var(--text-strong); }
.cr-msg__role {
    padding: 2px 7px; border-radius: var(--radius-round);
    background: var(--accent-soft);
    color: var(--secondary);
    font-size: var(--text-xs); font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
}
.cr-msg__head time { margin-left: auto; font-size: var(--text-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.cr-msg__body { margin: 0; font-size: var(--text-base); line-height: 1.58; color: var(--text); white-space: pre-line; }


.cr-reply__foot {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap; margin-top: 12px;
}

@media (max-width: 640px) {
    .cr-reply { padding: 15px; }
    .cr-att--image img { max-width: 150px; max-height: 120px; }
    .cr-reply__foot { flex-direction: column; align-items: stretch; }
    .cr-reply__foot .btn { width: 100%; }
}

/* Paper output never carries the Hub chrome. */
@media print {
    .cr-back, .cr-reply, .cr-triage { display: none !important; }
}

/* Flight time by aircraft weight — one line under a pilot's rolling windows. */
.ph-split{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 14px;margin-top:12px;padding-top:10px;border-top:1px solid var(--border);font-size:12.5px;color:var(--muted)}
.ph-split-label{font-size:10.5px;font-weight:750;text-transform:uppercase;letter-spacing:.06em}
.ph-split-item b{font:600 13px/1 ui-monospace,SFMono-Regular,Menlo,monospace;font-variant-numeric:tabular-nums;color:var(--text)}
.ph-split-item.is-muted b{color:var(--muted)}
.ph-split-types{opacity:.8}
.ph-split-note{flex-basis:100%;font-size:11px}
@media(max-width:560px){.ph-split{gap:4px 10px}.ph-split-item{flex-basis:100%}}
