/* =============================================================================
   Enki theme — dark industrial with +25% futuristic dial
   Layered on top of Syncfusion.Blazor.Themes fluent-dark.css.

   Palette and approach are heavily inspired by sibling AMR tool "Nabu"
   (amrtools.com) to give SDI users a coherent internal-tool house style.
   Extra knobs over Nabu:
     - Hairline cyan gradient borders on primary cards
     - Subtle accent glow on focused / active elements
     - Corner-bracket (HUD) treatments on stat cards
     - Sharper 2px radius everywhere instead of 6-8px
     - Tabular monospace numerals in data-heavy contexts
   ============================================================================= */

:root {
    /* Surfaces */
    --enki-bg:           #07111f;
    --enki-bg-raised:    #0a1628;
    --enki-surface:      #0f1e2f;
    --enki-surface-2:    #122438;
    --enki-surface-3:    #162a41;

    /* Borders */
    --enki-border:       #1a3049;
    --enki-border-soft:  #152840;
    --enki-border-hot:   rgba(0, 212, 255, 0.45);

    /* Accents */
    --enki-accent:         #00d4ff;
    --enki-accent-dim:     #4ddfff;
    --enki-accent-deep:    #007a94;
    --enki-accent-glow:    rgba(0, 212, 255, 0.18);
    --enki-accent-faint:   rgba(0, 212, 255, 0.08);
    /* Domain-specific accents — only used to colour the inspector
       peek-strip titles today (Mike, 2026-05-23). Distinct hues let
       the operator pick out Time vs Frequency at a glance amidst
       the otherwise-cyan page chrome. */
    --enki-accent-violet:  #B47CFF;
    --enki-accent-magenta: #F06292;

    /* Shot-plan segment palette — distinct hues per segment so the
       MD values in the panel tables read-link to their band on the
       depth-track preview. Deliberately avoids both the cyan chrome
       (--enki-accent, which would dissolve the segment into the
       page) and the status colours below (--enki-warn / --enki-ok /
       --enki-alert, which would imply state the segment doesn't
       actually carry). */
    --enki-segment-teal:   #26C6DA;
    --enki-segment-orange: #FF7043;
    --enki-segment-lime:   #9CCC65;

    /* Status */
    --enki-alert:        #ff4757;
    --enki-alert-dim:    #ff6b7a;
    --enki-warn:         #ffb84a;
    --enki-ok:           #2ed573;

    /* Agreement on CHARTS (ruled D4-A, 2026-10-01) — a lightness ramp, never the status
       colours above: a marker's lightness says how far it DISAGREES — pale is the worst
       agreement, dark the best, so the marks that disagree stand out on the dark page
       (Mike, 2026-10-03) — and its hue is left for the RUN. Neutral greys, so a simulated
       colour-blind reader sees exactly the
       same three steps; each has at least 3:1 on --enki-bg and --enki-surface. Pills and
       banners keep --enki-ok / --enki-warn / --enki-alert, because they carry words. Read
       by AgreementRamp (Components/Shared) for T5's measured markers and the run page's
       approach chart, and by the 3-D view through the colour the server sends each shot;
       measured by AgreementRampTests. */
    --enki-ramp-pale:    #f8f8f8;
    --enki-ramp-mid:     #b1b1b1;
    --enki-ramp-dark:    #6a6a6a;

    /* Text */
    --enki-text:         #e6edf3;
    --enki-text-dim:     #8b9ba8;
    --enki-text-muted:   #5c6e7e;
    --enki-text-inv:     #07111f;

    /* Type */
    --enki-font-sans:    system-ui, -apple-system, "Segoe UI", Roboto,
                         "Helvetica Neue", Arial, sans-serif;
    --enki-font-mono:    ui-monospace, "Cascadia Code", "JetBrains Mono",
                         "Fira Code", Consolas, monospace;

    /* Metrics */
    --enki-radius:       2px;
    --enki-radius-lg:    3px;
    --enki-topbar-h:     72px;
    --enki-sidebar-w:    320px;

    /* Motion */
    --enki-ease:         cubic-bezier(.2, .6, .2, 1);
}

/* ---------- global reset ---------- */

html, body {
    background: var(--enki-bg);
    color: var(--enki-text);
    font-family: var(--enki-font-sans);
    font-size: 17px;   /* ~20% bigger than the 14px default; every rem-
                          based dimension in the theme scales with this. */
    line-height: 1.5;
    letter-spacing: 0.01em;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

body {
    /* Very low-opacity grid texture — implies depth without being noisy */
    background-image:
        linear-gradient(var(--enki-bg-raised) 1px, transparent 1px),
        linear-gradient(90deg, var(--enki-bg-raised) 1px, transparent 1px);
    background-size: 48px 48px;
    background-position: -1px -1px;
    background-attachment: fixed;
}

/* A subtle radial vignette softens the grid toward the center */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    background: radial-gradient(ellipse at 50% 30%,
                transparent 0%,
                rgba(7, 17, 31, 0.6) 60%,
                rgba(7, 17, 31, 0.95) 100%);
    pointer-events: none;
    z-index: 0;
}

a, .btn-link {
    color: var(--enki-accent);
    text-decoration: none;
    transition: color 150ms var(--enki-ease);
}
a:hover, .btn-link:hover {
    color: var(--enki-accent-dim);
    text-decoration: none;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--enki-text);
    font-weight: 500;
    letter-spacing: -0.01em;
}

code, kbd, samp, pre,
.enki-mono, .enki-num {
    font-family: var(--enki-font-mono);
    font-variant-numeric: tabular-nums;
}

/* ---------- generic surfaces ---------- */

.enki-card {
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    padding: 1.25rem 1.5rem;
    position: relative;
}

/* Corner-bracket frame — HUD accent on primary containers */
.enki-bracket-frame {
    position: relative;
}
.enki-bracket-frame::before,
.enki-bracket-frame::after {
    content: "";
    position: absolute;
    width: 12px;
    height: 12px;
    border: 1px solid var(--enki-accent);
    opacity: 0.7;
    pointer-events: none;
}
.enki-bracket-frame::before {
    top: -1px;
    left: -1px;
    border-right: none;
    border-bottom: none;
}
.enki-bracket-frame::after {
    bottom: -1px;
    right: -1px;
    border-left: none;
    border-top: none;
}

/* Gradient hairline border on hover (subtle bloom) */
.enki-card.enki-card-hot {
    border-color: var(--enki-border-hot);
    box-shadow: 0 0 0 1px var(--enki-accent-faint),
                0 4px 24px -8px var(--enki-accent-glow);
}

/* ---------- stat cards ---------- */

.enki-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1rem;
    margin: 1.5rem 0;
}

.enki-stat-card {
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    padding: 1.5rem 1.75rem;
    text-align: center;
    position: relative;
    overflow: hidden;
}
.enki-stat-card::before,
.enki-stat-card::after {
    content: "";
    position: absolute;
    width: 14px;
    height: 14px;
    border: 1px solid var(--enki-accent);
    opacity: 0.55;
}
.enki-stat-card::before {
    top: 0;
    left: 0;
    border-right: none;
    border-bottom: none;
}
.enki-stat-card::after {
    bottom: 0;
    right: 0;
    border-left: none;
    border-top: none;
}
.enki-stat-value {
    font-family: var(--enki-font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 2.75rem;
    font-weight: 300;
    line-height: 1.1;
    color: var(--enki-accent);
    letter-spacing: -0.02em;
}
.enki-stat-value.enki-stat-value-alert {
    color: var(--enki-alert);
}
/* Audit-home failed-load state. Drops the giant 2.75rem number down
   to body-text size so "Failed" reads as a label rather than a
   gigantic word, and tints it the alert colour to match the inline
   error message below. Pairs with AuditHome.razor's per-card
   error-detail line. */
.enki-stat-value.enki-stat-failed {
    font-size: 1rem;
    color: var(--enki-alert-dim);
    font-family: inherit;
    letter-spacing: 0;
}
/* In-flight loading state on a stat-value tile. Sibling of
   .enki-stat-failed — the goal is to keep the giant numeral
   typography reserved for actual numbers, so a spinning load
   doesn't masquerade as a giant heading. Pairs with the small
   spinner + "Loading" text rendered inside .enki-stat-value-loading. */
.enki-stat-value.enki-stat-loading {
    font-size: 1rem;
    color: var(--enki-text-muted);
    font-family: inherit;
    letter-spacing: 0;
}
.enki-stat-value-loading {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}
.enki-stat-label {
    margin-top: 0.25rem;
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
}

/* ---------- section headers ---------- */

.enki-section-title {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 1.5rem;
    font-weight: 500;
    margin: 0 0 0.25rem;
    color: var(--enki-text);
}
.enki-section-title::before {
    content: "";
    display: block;
    width: 4px;
    height: 1.25rem;
    background: var(--enki-accent);
    border-radius: 1px;
}
.enki-section-subtitle {
    color: var(--enki-text-dim);
    font-size: 0.875rem;
    margin-bottom: 1.25rem;
}

/* Small-caps chip / kicker */
.enki-kicker {
    font-size: 0.7rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
}

/* ---------- buttons (overriding Bootstrap remnants) ---------- */

.btn-outline-primary {
    --bs-btn-color: var(--enki-accent);
    --bs-btn-border-color: var(--enki-border-hot);
    --bs-btn-hover-color: var(--enki-text-inv);
    --bs-btn-hover-bg: var(--enki-accent);
    --bs-btn-hover-border-color: var(--enki-accent);
    --bs-btn-focus-shadow-rgb: 0, 212, 255;
    --bs-btn-active-bg: var(--enki-accent);
    --bs-btn-active-border-color: var(--enki-accent);
    border-radius: var(--enki-radius);
    letter-spacing: 0.05em;
    font-weight: 500;
    transition: all 150ms var(--enki-ease);
}
.btn-outline-primary:hover {
    box-shadow: 0 0 0 1px var(--enki-accent-faint),
                0 0 12px -2px var(--enki-accent-glow);
}

/* ---------- tables (fallback before Syncfusion overrides load) ---------- */

.table {
    --bs-table-color: var(--enki-text);
    --bs-table-bg: transparent;
    --bs-table-border-color: var(--enki-border);
    --bs-table-striped-bg: var(--enki-surface-2);
    --bs-table-hover-bg: var(--enki-surface-3);
    color: var(--enki-text);
}
.table thead th {
    color: var(--enki-text-muted);
    font-size: 0.7rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    font-weight: 500;
    border-bottom: 1px solid var(--enki-border);
    padding: 0.75rem 1rem;
}
.table tbody td {
    border-top: 1px solid var(--enki-border-soft);
    padding: 0.75rem 1rem;
    font-variant-numeric: tabular-nums;
}

/* ---------- plain HTML tables (.enki-table) ----------
   The hand-rolled (non-Syncfusion) tables across the app use this class
   — the license tool picker + detail tables, audit tables, run
   cloud/shot-plan/assembly panels, calibration compare, column mapping.
   It deliberately mirrors the .e-grid header/cell treatment above so a
   bespoke table reads as a sibling of the Syncfusion grids instead of a
   raw browser-default table. */
.enki-table {
    width: 100%;
    border-collapse: collapse;
    color: var(--enki-text);
}
.enki-table thead th {
    text-align: left;
    color: var(--enki-text-muted);
    font-size: 0.7rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    font-weight: 500;
    padding: 0.6rem 0.9rem;
    border-bottom: 1px solid var(--enki-border);
    white-space: nowrap;
}
.enki-table tbody td {
    padding: 0.6rem 0.9rem;
    border-top: 1px solid var(--enki-border-soft);
    font-variant-numeric: tabular-nums;
    vertical-align: middle;
}
.enki-table tbody tr {
    transition: background 120ms var(--enki-ease);
}
.enki-table tbody tr:hover {
    background: var(--enki-surface-2);
}
/* Selected-row tint — the license tool picker carries a "Use" checkbox
   per row; the whole row lights faint-accent when picked so the
   selection reads at a glance, not just the small checkbox. */
.enki-table tbody tr.is-selected {
    background: var(--enki-accent-faint);
}
.enki-table tbody tr.is-selected:hover {
    background: var(--enki-accent-glow);
}

/* ---------- alerts ---------- */

.alert {
    padding: 0.75rem 1rem;
    margin-top: 1rem;
    border-radius: var(--enki-radius);
}
.alert-danger {
    background: rgba(255, 71, 87, 0.12);
    color: var(--enki-alert-dim);
    border: 1px solid rgba(255, 71, 87, 0.4);
    border-radius: var(--enki-radius);
}
.alert-success {
    background: rgba(0, 212, 255, 0.10);
    color: var(--enki-accent);
    border: 1px solid var(--enki-border-hot);
}

/* ---------- forms / focus rings ---------- */

.form-control,
.form-select {
    background: var(--enki-surface);
    color: var(--enki-text);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    transition: border-color 150ms var(--enki-ease),
                box-shadow 150ms var(--enki-ease);
}
.form-control:focus,
.form-select:focus {
    background: var(--enki-surface);
    color: var(--enki-text);
    border-color: var(--enki-accent);
    box-shadow: 0 0 0 3px var(--enki-accent-glow);
    outline: none;
}

/* ---------- Syncfusion Fluent Dark overrides ---------- */
/* Pull Syncfusion colors inline with the Enki palette so the SfGrid feels
   native. Fluent Dark uses its own --syncfusion-... variables; we override
   the most visible ones. */

.e-grid,
.e-grid .e-gridheader,
.e-grid .e-gridcontent {
    background: var(--enki-surface);
    color: var(--enki-text);
    border-color: var(--enki-border) !important;
}
.e-grid .e-headercell {
    background: var(--enki-bg-raised);
    color: var(--enki-text-muted);
    border-color: var(--enki-border) !important;
    font-size: 0.7rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    font-weight: 500;
}
.e-grid .e-rowcell {
    border-color: var(--enki-border-soft) !important;
    font-variant-numeric: tabular-nums;
    color: var(--enki-text);
}
.e-grid .e-row:hover .e-rowcell {
    background: var(--enki-surface-2) !important;
}
.e-grid .e-altrow {
    background: var(--enki-bg-raised) !important;
}

/* ---------- spinners / loading ---------- */

@keyframes enki-pulse {
    0%, 100% { opacity: 0.4; }
    50%      { opacity: 1; }
}
.enki-loading {
    color: var(--enki-text-dim);
    font-family: var(--enki-font-mono);
    animation: enki-pulse 1.4s ease-in-out infinite;
}

/* Top-anchored loading overlay — cyan spinner ring on a dark veil.
   Fades in ~180ms after nav starts so fast transitions don't flash it;
   fades out on enhanced-nav complete. Paired with the top-bar sliver
   below and both are controlled by wwwroot/js/enki-nav.js.

   Anchored near the top of the viewport (rather than dead-centre) so
   on tall pages — runs grids, surveys grids, audit feeds — the spinner
   doesn't appear to hover over a specific row of data. Top placement
   reads as "header-level navigation status" instead of "the row I
   clicked is loading", which clears the original misperception
   reported in the GUI review. */
#enki-loading-overlay {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding-top: 6rem;
    gap: 1.1rem;
    background: rgba(7, 17, 31, 0.78);
    backdrop-filter: blur(2px);
    opacity: 0;
    pointer-events: none;
    z-index: 9999;
    transition: opacity 180ms ease;
}
#enki-loading-overlay.is-loading {
    opacity: 1;
    pointer-events: auto;
}
#enki-loading-overlay .enki-spinner {
    width: 3rem;
    height: 3rem;
    border-width: 3px;
}
#enki-loading-overlay .enki-loading-text {
    margin-top: 0.25rem;
}

/* Global top-of-page navigation indicator — fixed cyan sliver that
   surfaces on any click-through to another page and fades out when
   enhanced navigation resolves. Controlled by wwwroot/js/enki-nav.js. */
#enki-nav-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    z-index: 10000;
    pointer-events: none;
    opacity: 0;
    overflow: hidden;
    transition: opacity 120ms ease;
}
#enki-nav-progress.is-loading {
    opacity: 1;
}
#enki-nav-progress::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg,
        transparent 0%,
        var(--enki-accent-dim) 40%,
        var(--enki-accent) 50%,
        var(--enki-accent-dim) 60%,
        transparent 100%);
    transform: translateX(-100%);
    box-shadow: 0 0 10px var(--enki-accent-glow);
}
#enki-nav-progress.is-loading::before {
    animation: enki-nav-progress-slide 1.2s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes enki-nav-progress-slide {
    from { transform: translateX(-100%); }
    to   { transform: translateX(100%); }
}

/* Indeterminate progress bar — a slim track with a cyan gradient sliver
   sliding left-to-right. Used for "data loading" states where we don't
   know the percentage, only that something is in flight. */
.enki-progress-bar {
    position: relative;
    width: 100%;
    height: 2px;
    background: var(--enki-border-soft);
    overflow: hidden;
    border-radius: 1px;
}
.enki-progress-bar::before {
    content: "";
    position: absolute;
    left: -40%;
    top: 0;
    bottom: 0;
    width: 40%;
    background: linear-gradient(90deg,
        transparent 0%,
        var(--enki-accent-dim) 30%,
        var(--enki-accent) 50%,
        var(--enki-accent-dim) 70%,
        transparent 100%);
    box-shadow: 0 0 10px var(--enki-accent-glow);
    animation: enki-progress-slide 1.4s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes enki-progress-slide {
    0%   { left: -40%; }
    100% { left: 100%; }
}

/* Wrapper for the common "spinner + label" loading pattern — centered
   vertically so it doesn't look abandoned on a short page. */
.enki-loading-block {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    padding: 3rem 0 2rem;
}
.enki-loading-text {
    font-size: 0.7rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    font-family: var(--enki-font-mono);
    animation: enki-pulse 1.4s ease-in-out infinite;
}

/* Circular spinner — two cyan-weighted quadrants rotating on a dim
   track. Softer + on-brand compared to Bootstrap's stock .spinner-border. */
@keyframes enki-spin {
    to { transform: rotate(360deg); }
}
.enki-spinner {
    width: 2.5rem;
    height: 2.5rem;
    border: 2px solid var(--enki-border);
    border-top-color: var(--enki-accent);
    border-right-color: var(--enki-accent-dim);
    border-radius: 50%;
    box-shadow: 0 0 12px var(--enki-accent-glow);
    animation: enki-spin 0.9s linear infinite;
}
.enki-spinner-sm {
    width: 1rem;
    height: 1rem;
    border-width: 1.5px;
}

/* ---------- utility ---------- */

.enki-dim  { color: var(--enki-text-dim); }
.enki-muted{ color: var(--enki-text-muted); }
.enki-dash { color: var(--enki-text-muted); font-family: var(--enki-font-mono); }

/* replace stray Bootstrap focus pyramid with our accent ring */
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus,
.form-control:focus, .form-check-input:focus {
    box-shadow: 0 0 0 3px var(--enki-accent-glow);
}

/* =============================================================================
   Forms — input / label / button treatments for CRUD pages.
   ============================================================================= */

.enki-form { display: flex; flex-direction: column; gap: 0.35rem; }

.enki-form-group { margin-top: 1rem; }

/* A group of inputs that belong to one setting (the approach-scan sampling
   defaults on the run forms: mode + points + spacing). A real <fieldset>
   so the legend is announced with each field, with the browser's box
   chrome removed — the section-title legend does the visual grouping the
   way the h3 sections on the same forms already do. */
.enki-form-fieldset {
    margin: 1rem 0 0;
    padding: 0;
    border: none;
    min-width: 0;
}
.enki-form-fieldset > legend {
    padding: 0;
}

.enki-form-label {
    display: block;
    font-size: 0.7rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    font-weight: 500;
}
.enki-form-label.required::after {
    content: "*";
    color: var(--enki-accent);
    margin-left: 0.25rem;
}

/* Inline override that opts a span out of the parent's text-transform.
   Used for case-significant unit suffixes inside otherwise-uppercased
   labels — e.g. "Total field (nT)" should read "TOTAL FIELD (nT)" not
   "TOTAL FIELD (NT)" — and anywhere else a literal stays meaningful
   only with its original case. Letter-spacing reset because the parent
   uppercase block adds 0.2em which makes "nT" look stretched. */
.enki-keep-case {
    text-transform: none;
    letter-spacing: 0;
}

.enki-input,
.enki-form-input,
.enki-form-textarea,
.enki-form-select {
    width: 100%;
    margin-top: 0.35rem;
    padding: 0.6rem 0.8rem;
    font-family: var(--enki-font-mono);
    font-size: 0.9rem;
    color: var(--enki-text);
    background: var(--enki-bg-raised);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    transition: border-color 150ms var(--enki-ease),
                box-shadow 150ms var(--enki-ease);
    outline: none;
}
.enki-input:focus,
.enki-form-input:focus,
.enki-form-textarea:focus,
.enki-form-select:focus {
    border-color: var(--enki-accent);
    box-shadow: 0 0 0 3px var(--enki-accent-glow);
}
.enki-input::placeholder,
.enki-form-input::placeholder,
.enki-form-textarea::placeholder {
    color: var(--enki-text-muted);
}
.enki-form-textarea { min-height: 5rem; resize: vertical; }

/* Native date / time picker chrome is black-on-white by default — invert it
   so the calendar icon stays legible on the dark Enki surface. WebKit-only
   selector covers Chrome / Edge; Firefox doesn't expose a hook but its
   indicator already inherits the input colour, so this is fine. */
.enki-form-input[type="date"]::-webkit-calendar-picker-indicator,
.enki-form-input[type="time"]::-webkit-calendar-picker-indicator,
.enki-form-input[type="datetime-local"]::-webkit-calendar-picker-indicator {
    filter: invert(1) opacity(0.7);
    cursor: pointer;
}
.enki-form-input[type="date"]::-webkit-calendar-picker-indicator:hover,
.enki-form-input[type="time"]::-webkit-calendar-picker-indicator:hover,
.enki-form-input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover {
    filter: invert(1) opacity(1);
}

/* Read-only "computed value" cell on an edit page. Visually a sibling
   of .enki-form-input but rendered as <output> so screen readers
   identify it as a result region rather than a disabled input. The
   dimmed background tells sighted users at a glance that this cell
   isn't editable. */
.enki-form-readout {
    display: block;
    background: var(--enki-surface-alt, rgba(255, 255, 255, 0.03));
    color: var(--enki-text-dim);
    cursor: default;
    user-select: text;
}
.enki-form-readout:focus,
.enki-form-readout:focus-visible {
    /* No focus ring — read-only cells aren't tab-stops in normal use,
       but if a screen reader navigates to one we still want the
       outline suppressed. */
    outline: none;
    border-color: var(--enki-border);
    box-shadow: none;
}

/* ----- SfChart host ----------------------------------------------------
   SfChart needs an ancestor with a definite pixel-resolvable size
   to measure against. Giving the host explicit dimensions (rather
   than %) and letting the chart manage its own internal SVG sizing
   keeps the layout stable. */
.enki-plot-host {
    display: block;
    width: 100%;
    height: 720px;
    position: relative;
}

/* Side-by-side pair of plot hosts, used by the wells-plot Side
   Elevations and Tangent tabs. Auto-fit + minmax means the two
   charts share the panel equally on a wide screen, but each chart
   gets at least 360 px; below that threshold they stack into a
   single column. Each child .enki-plot-host keeps its own 720 px
   height, so the pair total is one row (≈720 px) wide-screen, two
   rows (≈1440 px) narrow-screen. */
.enki-plot-pair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
    gap: 0.75rem;
}

/* <select> styled to match text inputs — strip the native browser chrome
   and paint a cyan caret in its place. */
.enki-form-select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    padding-right: 2.25rem;
    cursor: pointer;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none' stroke='%2300d4ff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M3 5 L6 8 L9 5'/></svg>");
    background-repeat: no-repeat;
    background-position: right 0.85rem center;
}
.enki-form-select option {
    background: var(--enki-surface);
    color: var(--enki-text);
    padding: 0.4rem 0.6rem;
}
.enki-form-select option:checked {
    background: var(--enki-surface-2);
    color: var(--enki-accent);
}

.enki-form-input.invalid,
.enki-form-textarea.invalid,
.enki-form-input.is-user-invalid,
.enki-form-textarea.is-user-invalid {
    border-color: var(--enki-alert);
    box-shadow: 0 0 0 3px rgba(255, 71, 87, 0.18);
}

/* Live error message dropped next to the input by wwwroot/js/enki-forms.js
   once the user has blurred it with invalid content. Server-side
   ValidationMessage and the summary still render on submit. */
.enki-field-msg {
    margin-top: 0.25rem;
}

.enki-form-hint {
    margin-top: 0.3rem;
    font-size: 0.75rem;
    color: var(--enki-text-muted);
    font-family: var(--enki-font-mono);
    letter-spacing: 0.02em;
}

/* Derived (read-only computed) value shown inside a form so the user
   can see how an output is being computed from their inputs — e.g.
   "Total correction = Declination + Grid correction" on the magnetics
   forms. Visually distinct from an input (muted background, no
   border, no cursor) so it doesn't look editable. */
.enki-form-derived-value {
    margin-top: 0.25rem;
    padding: 0.4rem 0.65rem;
    background: var(--enki-surface-2);
    border-radius: 4px;
    font-family: var(--enki-font-mono);
    font-size: 0.875rem;
    color: var(--enki-text);
}

/* Pill-style toggle for binary opt-ins (e.g. the from-system gates
   on the Shot config form, or the master "Use run-level default
   configs" switch on the Run detail). Native HTML checkbox restyled
   via appearance:none so screen readers + form submit still treat it
   as a checkbox; the visual matches the Enki cyan accent + surface
   token system. */
.enki-toggle {
    appearance: none;
    -webkit-appearance: none;
    box-sizing: border-box;
    width: 32px;
    height: 18px;
    margin: 0;
    border-radius: 9px;
    background: var(--enki-surface-2);
    border: 1px solid var(--enki-border);
    cursor: pointer;
    position: relative;
    transition: background 150ms var(--enki-ease),
                border-color 150ms var(--enki-ease);
    flex: 0 0 auto;
}
.enki-toggle::before {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--enki-text-muted);
    transition: left 150ms var(--enki-ease),
                background 150ms var(--enki-ease);
}
.enki-toggle:checked {
    background: var(--enki-accent-faint);
    border-color: var(--enki-border-hot);
}
.enki-toggle:checked::before {
    left: 16px;
    background: var(--enki-accent);
}
.enki-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--enki-accent-glow);
}
.enki-toggle:disabled {
    cursor: not-allowed;
    opacity: 0.5;
}

/* Read-only cell rendered in place of a numeric input when its
   matching .enki-toggle is on. Visually a sibling of .enki-form-input
   (same height + border so the row doesn't jump) but with a muted
   status-style label centred inside. Used by the Gradient/Rotary
   config forms for "NOT USED" / "from bin / client" sentinel
   placeholders. */
.enki-form-input-skipped {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    padding: 0.55rem 0.75rem;
    background: var(--enki-surface);
    border: 1px solid var(--enki-border-soft);
    border-radius: var(--enki-radius);
    color: var(--enki-text-muted);
    font-family: var(--enki-font-mono);
    font-size: 0.8rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    min-height: calc(1.5rem + 1.1rem + 2px); /* match enki-form-input box */
}

.enki-form-error,
.validation-message {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.8rem;
    color: var(--enki-alert-dim);
    font-family: var(--enki-font-mono);
}

/* EditForm's <ValidationSummary> — sits at the top of the form when any
   field is invalid, showing the full list. Hidden when empty. */
.enki-validation-summary,
.validation-errors {
    margin: 0 0 1.25rem;
    padding: 0.75rem 1rem 0.75rem 2.25rem;
    list-style: none;
    background: rgba(255, 71, 87, 0.12);
    border: 1px solid rgba(255, 71, 87, 0.4);
    color: var(--enki-alert-dim);
    border-radius: var(--enki-radius);
    font-size: 0.85rem;
    position: relative;
}
.enki-validation-summary:empty,
.validation-errors:empty { display: none; }
.enki-validation-summary::before,
.validation-errors::before {
    content: "!";
    position: absolute;
    left: 0.9rem;
    top: 0.7rem;
    font-family: var(--enki-font-mono);
    font-weight: 700;
    color: var(--enki-alert);
}
.enki-validation-summary li,
.validation-errors li {
    margin-top: 0.15rem;
}
.enki-validation-summary li:first-child,
.validation-errors li:first-child { margin-top: 0; }

.enki-form-actions {
    display: flex;
    gap: 0.75rem;
    margin-top: 1.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--enki-border-soft);
}

.enki-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.55rem 1.15rem;
    font-family: var(--enki-font-sans);
    font-size: 0.8rem;
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--enki-text-dim);
    background: transparent;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    cursor: pointer;
    text-decoration: none;
    transition: all 150ms var(--enki-ease);
}
.enki-button:hover,
.enki-button:focus-visible {
    color: var(--enki-text);
    border-color: var(--enki-accent-dim);
    background: var(--enki-surface-2);
    outline: none;
    text-decoration: none;
}
.enki-button[disabled] { opacity: 0.6; cursor: wait; }

.enki-button-primary {
    color: var(--enki-accent);
    border-color: var(--enki-border-hot);
    background: var(--enki-accent-faint);
}
.enki-button-primary:hover,
.enki-button-primary:focus-visible {
    color: var(--enki-text-inv);
    background: var(--enki-accent);
    border-color: var(--enki-accent);
    box-shadow: 0 0 14px -2px var(--enki-accent);
}

/* The "commit your pending edits" cue — a Write button lights green
   when the card holds unwritten changes (the remote console's frame /
   gyro config cards), distinct from the cyan primary "suggested next
   step". Green = there is something to send to the tool. */
.enki-button-success {
    color: var(--enki-ok);
    border-color: rgba(46, 213, 115, 0.45);
    background: rgba(46, 213, 115, 0.10);
}
.enki-button-success:hover,
.enki-button-success:focus-visible {
    color: var(--enki-text-inv);
    background: var(--enki-ok);
    border-color: var(--enki-ok);
    box-shadow: 0 0 14px -2px var(--enki-ok);
}

.enki-button-danger {
    color: var(--enki-alert-dim);
    border-color: rgba(255, 71, 87, 0.4);
}
.enki-button-danger:hover,
.enki-button-danger:focus-visible {
    color: white;
    background: var(--enki-alert);
    border-color: var(--enki-alert);
    box-shadow: 0 0 12px -2px rgba(255, 71, 87, 0.6);
}

/* Neutral mid-weight button — quieter than -primary, used for the chat
   pane's attach / show-image / download / "new messages" actions so they
   read as secondary affordances inside a card, not calls to action.
   (Referenced in ChatPane.razor but previously undefined → fell back to
   the plain .enki-button face.) */
.enki-button-secondary {
    color: var(--enki-text);
    border-color: var(--enki-border);
    background: var(--enki-surface-2);
}
.enki-button-secondary:hover,
.enki-button-secondary:focus-visible {
    border-color: var(--enki-accent);
    box-shadow: 0 0 12px -4px var(--enki-accent);
}

/* =============================================================================
   Detail grid — two-column key/value rows for entity detail pages.
   ============================================================================= */

.enki-detail-grid {
    display: grid;
    grid-template-columns: 180px 1fr;
    gap: 0.6rem 1.5rem;
    margin-top: 1rem;
    padding: 1.25rem 1.5rem;
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
}
.enki-detail-label {
    font-size: 0.7rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    align-self: center;
}
.enki-detail-value {
    color: var(--enki-text);
    font-family: var(--enki-font-mono);
    font-variant-numeric: tabular-nums;
    word-break: break-word;
}
.enki-detail-value.enki-dash {
    color: var(--enki-text-muted);
}

/* Small uppercase divider used inside .enki-detail-grid to break a
   long key/value list into named sections (Sensor pose / Target /
   NEV / HRA / …). Spans both columns of the grid via grid-column
   1 / -1; muted color + bottom border keeps it quiet relative to
   the value rows. Used by the three Solution view components. */
.enki-detail-grid > .enki-section-divider {
    grid-column: 1 / -1;
    color: var(--enki-text-muted);
    font-size: 0.7rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin-top: 0.6rem;
    padding-bottom: 0.25rem;
    border-bottom: 1px solid var(--enki-border);
}
.enki-detail-grid > .enki-section-divider:first-child {
    margin-top: 0;
}

/* Two-column split for solution viewers (Mike, 2026-05-18). Wraps two
   .enki-detail-grid halves side-by-side under the result card so the
   13-to-19-row label/value lists fit in roughly half the vertical
   space. Each half loses its own background / border / padding —
   the outer .enki-card already provides the panel. Bigger label +
   value font sizes vs the standard .enki-detail-grid because the
   solution viewer doubles as a read-only reference the operator
   skims at distance. Collapses to single-column under 800px so the
   layout doesn't get cramped on narrow viewports. */
.enki-solution-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 1.75rem;
    margin-top: 0.5rem;
}
.enki-solution-split > .enki-detail-grid {
    margin-top: 0;
    padding: 0;
    background: transparent;
    border: 0;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
    gap: 0.5rem 1rem;
    align-content: start;
}
.enki-solution-split .enki-detail-label {
    font-size: 0.85rem;
    letter-spacing: 0.12em;
}
.enki-solution-split .enki-detail-value {
    font-size: 1.05rem;
}
.enki-solution-split .enki-section-divider {
    font-size: 0.8rem;
}
@media (max-width: 900px) {
    .enki-solution-split {
        grid-template-columns: 1fr;
        gap: 0.25rem;
    }
}

/* Status pill */
.enki-status-pill {
    display: inline-block;
    padding: 0.15rem 0.6rem;
    font-size: 0.65rem;
    font-weight: 500;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    border-radius: 999px;
    border: 1px solid var(--enki-border);
    color: var(--enki-text-dim);
}
.enki-status-pill.enki-status-active {
    color: var(--enki-accent);
    border-color: var(--enki-border-hot);
    background: var(--enki-accent-faint);
}
.enki-status-pill.enki-status-inactive {
    color: var(--enki-warn, #ffb84a);
    border-color: rgba(255, 184, 74, 0.4);
    background: rgba(255, 184, 74, 0.08);
}
.enki-status-pill.enki-status-archived {
    color: var(--enki-text-muted);
    border-color: var(--enki-border);
}

/* Anchor variant — used by the Shots grid to make Failed pills
   clickable into the shot detail page. Strip default anchor color +
   underline so the pill keeps its own state palette; bump intensity
   on hover so the affordance is unmistakable. */
.enki-status-pill-link {
    cursor: pointer;
    text-decoration: none;
}
.enki-status-pill-link:hover,
.enki-status-pill-link:focus-visible {
    text-decoration: underline;
    filter: brightness(1.25);
}

/* Compact pill — Shots-grid Status column where Primary + Gyro pills
   sit side-by-side in one cell. Single-glyph state encoded into the
   pill body (the long-form word lives in the hover title); the column
   stays ~150px instead of the 400+px the four v1 columns ate. */
.enki-status-pair {
    display: inline-flex;
    gap: 0.4rem;
    align-items: center;
}
.enki-status-pill-mini {
    padding: 0.08rem 0.35rem;
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: none;
    min-width: 26px;
    text-align: center;
    font-family: var(--enki-font-mono);
    line-height: 1.2;
}

/* =============================================================================
   Shots-grid live-refresh toast — fades in then out via a single CSS
   animation so the server-side fire-and-forget timer only has to clear
   the message; no JS interop. The fade duration here matches the
   Shots.razor.cs ToastLifetime constant — keep them in sync.
   ============================================================================= */
.enki-shot-toast {
    position: fixed;
    top: calc(var(--enki-topbar-h) + 0.75rem);
    right: 1.25rem;
    z-index: 50;
    pointer-events: none;
}
.enki-shot-toast-pill {
    display: inline-block;
    padding: 0.45rem 0.95rem;
    font-size: 0.8rem;
    font-weight: 500;
    border-radius: 999px;
    color: var(--enki-accent);
    border: 1px solid var(--enki-border-hot);
    background: var(--enki-accent-faint);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
    animation: enki-shot-toast-life 4s ease-in-out forwards;
}
@keyframes enki-shot-toast-life {
    0%   { opacity: 0; transform: translateY(-6px); }
    10%  { opacity: 1; transform: translateY(0); }
    80%  { opacity: 1; }
    100% { opacity: 0; transform: translateY(-6px); }
}

/* Link styled as a row link in the SfGrid */
.enki-row-link {
    color: var(--enki-accent);
    font-family: var(--enki-font-mono);
}
.enki-row-link:hover { color: var(--enki-accent-dim); text-decoration: underline; }

/* ShotName cell wrapper — lets the per-shot regenerate action sit beside
   the name link in the frozen ShotName column without the long mono name
   shoving it out of the cell: the link flexes + truncates, the action
   stays fixed. Action only rendered for simulated gradient shots the
   operator can write (Shots.GridLayout RenderShotNameColumn). */
.enki-shotname-cell {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    width: 100%;
    min-width: 0;
}
.enki-shotname-cell .enki-row-link {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Subtle in-cell row action (the regenerate ↻ glyph) — a faint accent
   affordance that lights up on hover / keyboard focus. */
.enki-row-action {
    flex: 0 0 auto;
    border: none;
    background: transparent;
    color: var(--enki-accent);
    cursor: pointer;
    font-size: 0.95em;
    line-height: 1;
    padding: 0.05rem 0.3rem;
    border-radius: var(--enki-radius);
    opacity: 0.65;
    transition: opacity 150ms var(--enki-ease),
                background 150ms var(--enki-ease);
}
.enki-row-action:hover,
.enki-row-action:focus-visible {
    opacity: 1;
    background: var(--enki-accent-faint);
    outline: none;
}

/* Inline accent link that sits inside prose — used when a hint sentence
   references an action the operator can take ("…— assign a tool —…"),
   so the action is one click away rather than buried somewhere lower on
   the page. Dotted underline distinguishes it from a regular link the
   first time the operator sees one. */
.enki-inline-link {
    color: var(--enki-accent);
    text-decoration: underline;
    text-decoration-style: dotted;
    text-underline-offset: 2px;
}
.enki-inline-link:hover { color: var(--enki-accent-dim); text-decoration-style: solid; }

/* Inline-editable cell input. Reads as a plain numeric span until
   the operator focuses it — no border, no spinner, transparent
   background — then takes a soft accent ring + standard input
   background so it's obviously editable. Used today by the Shots
   grid's Sensor MD column (PUT /shots/{id}/sensor-md on commit). */
.enki-cell-input {
    width: 100%;
    border: 1px solid transparent;
    background: transparent;
    color: inherit;
    padding: 2px 4px;
    text-align: right;
    border-radius: 3px;
    outline: none;
    box-sizing: border-box;
}
.enki-cell-input:hover {
    border-color: var(--enki-border);
}
.enki-cell-input:focus {
    border-color: var(--enki-accent);
    background: var(--enki-bg-input, rgba(0, 0, 0, 0.25));
    box-shadow: 0 0 0 1px var(--enki-accent);
}
/* Hide the up/down spinner buttons — they fight the mono layout
   and operators commit with Enter / blur, not the spinner. */
.enki-cell-input::-webkit-outer-spin-button,
.enki-cell-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.enki-cell-input[type=number] {
    -moz-appearance: textfield;
}

/* "Reset layout" escape hatch shown above the grid when server-side
   persistence is on. Right-aligned, muted, surfaces only on hover so
   it doesn't compete with the grid toolbar for attention. */
.enki-grid-reset-bar {
    display: flex;
    justify-content: flex-end;
    padding: 4px 0 6px 0;
}
.enki-grid-reset-link {
    background: none;
    border: none;
    color: var(--enki-text-muted);
    font-size: 0.78rem;
    cursor: pointer;
    padding: 2px 8px;
    border-radius: 3px;
    font-family: inherit;
}
.enki-grid-reset-link:hover {
    color: var(--enki-accent);
    text-decoration: underline;
}

/* =============================================================================
   Shell — top bar + sidebar + content grid.
   ============================================================================= */

.enki-shell {
    /* Pin the shell to exactly the viewport height so the topbar stays
       put and the sidebar + content each scroll on their OWN axis. The
       old min-height:100vh let the shell grow with the content, which
       stretched the sidebar's grid cell to the full content height — so
       its overflow-y never engaged and reaching a nav item below the fold
       meant scrolling the whole document (topbar and all). dvh tracks the
       mobile browser chrome; vh is the fallback for engines without it. */
    height: 100vh;
    height: 100dvh;
    display: grid;
    grid-template-columns: var(--enki-sidebar-w) 1fr;
    grid-template-rows: var(--enki-topbar-h) 1fr;
    grid-template-areas:
        "topbar  topbar"
        "sidebar content";
    position: relative;
    z-index: 1;
    overflow: hidden;
    transition: grid-template-columns 0.18s var(--enki-ease);
}

/* Sidebar collapse toggle (CSS-only, no JS / no Blazor interactive).
   Hidden checkbox lives just outside .enki-shell in MainLayout.razor;
   <label for="…"> in the topbar is the click target. When checked,
   the general-sibling selector flips the grid template so the sidebar
   column collapses to zero width. State doesn't persist across
   navigations — by design; persistence would need a cookie / storage
   round trip and operators rarely toggle this on every page. */
.enki-sidebar-toggle-cb {
    position: absolute;
    width: 0;
    height: 0;
    opacity: 0;
    pointer-events: none;
}

.enki-brand-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    user-select: none;
    border-radius: var(--enki-radius);
    transition: background 0.15s, transform 0.15s var(--enki-ease);
}
.enki-brand-toggle:hover .enki-brand-logo {
    /* Brighten the wave + intensify the bracket frame on hover so the
       operator gets the affordance cue without the logo gaining any
       extra chrome. */
    filter: drop-shadow(0 0 10px var(--enki-accent-glow));
}
.enki-brand-toggle:hover .enki-brand-logo path[opacity] {
    opacity: 0.9;
}
.enki-brand-toggle:focus-visible {
    outline: 2px solid var(--enki-accent-glow);
    outline-offset: 2px;
}

.enki-sidebar-toggle-cb:checked ~ .enki-shell {
    grid-template-columns: 0 1fr;
}
.enki-sidebar-toggle-cb:checked ~ .enki-shell .enki-sidebar {
    visibility: hidden;
    border-right: none;
    overflow: hidden;
}

/* Off-canvas sidebar drawer on narrow screens (redesign Phase 5). Below the
   breakpoint the sidebar overlays the content instead of holding a grid
   column: off-canvas by default, sliding in when the toggle is checked, with
   a scrim to dismiss. The brand-logo label is the toggle; enki-nav.js
   unchecks it on navigation so a tapped link closes the drawer. Desktop
   behaviour above the breakpoint is unchanged. (The toggle's meaning inverts
   below the breakpoint — checked = open — which is fine; the checkbox state
   isn't meant to survive a resize across it.) */
.enki-sidebar-scrim { display: none; }

@media (max-width: 900px) {
    .enki-shell,
    .enki-sidebar-toggle-cb:checked ~ .enki-shell { grid-template-columns: 0 1fr; }

    .enki-sidebar {
        position: fixed;
        top: var(--enki-topbar-h);
        left: 0;
        width: min(82vw, 288px);
        height: calc(100dvh - var(--enki-topbar-h));
        transform: translateX(-100%);
        transition: transform 0.22s var(--enki-ease);
        z-index: 120;
    }
    .enki-sidebar-toggle-cb:checked ~ .enki-shell .enki-sidebar {
        visibility: visible;
        transform: translateX(0);
        border-right: 1px solid var(--enki-border);
        overflow: hidden;   /* nav scrolls inside; footer stays pinned */
        box-shadow: 8px 0 34px -12px rgba(0, 0, 0, 0.7);
    }
    .enki-sidebar-scrim {
        position: fixed;
        inset: var(--enki-topbar-h) 0 0 0;
        z-index: 110;
        background: rgba(2, 8, 16, 0.55);
        animation: enki-cmd-fade 0.15s ease;
    }
    .enki-sidebar-toggle-cb:checked ~ .enki-sidebar-scrim { display: block; }
}

.enki-topbar {
    grid-area: topbar;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 1.5rem 0 1.25rem;
    background: linear-gradient(180deg, #0a1628 0%, #07111f 100%);
    border-bottom: 1px solid var(--enki-border);
    position: relative;
}
.enki-topbar::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 1px;
    background: linear-gradient(90deg,
        transparent 0%,
        var(--enki-accent-deep) 20%,
        var(--enki-accent) 50%,
        var(--enki-accent-deep) 80%,
        transparent 100%);
    opacity: 0.6;
}

.enki-brand {
    display: flex;
    align-items: center;
    gap: 0.85rem;
}
.enki-brand-logo {
    width: 40px;
    height: 40px;
    color: var(--enki-accent);
    filter: drop-shadow(0 0 6px var(--enki-accent-glow));
}
.enki-brand-text {
    display: flex;
    flex-direction: column;
    line-height: 1.1;
    text-decoration: none;
    color: inherit;
    border-radius: var(--enki-radius);
    transition: opacity 0.15s;
}
.enki-brand-text:hover .enki-brand-name {
    color: var(--enki-accent);
}
.enki-brand-text:hover .enki-brand-tagline {
    color: var(--enki-text-dim);
}
.enki-brand-text:focus-visible {
    outline: 2px solid var(--enki-accent-glow);
    outline-offset: 2px;
}
.enki-brand-name {
    font-size: 1.5rem;
    font-weight: 300;
    letter-spacing: 0.08em;
    color: var(--enki-text);
}
.enki-brand-tagline {
    margin-top: 2px;
    font-size: 0.65rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    font-weight: 500;
}

.enki-topbar-user {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--enki-text-dim);
    font-size: 0.875rem;
}

/* Topbar version chips — "Version vX · API vY" beside the bell. Labels
   uppercase-tracked like the brand tagline; numbers mono and
   untransformed so the "v" prefix reads naturally. The full build
   stamps (+commit) ride the title tooltip. */
.enki-topbar-versions {
    display: flex;
    align-items: baseline;
    gap: 0.45rem;
    margin-right: 1rem;
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: 500;
    color: var(--enki-text-muted);
    white-space: nowrap;
    cursor: default;
}
.enki-version-num {
    font-family: var(--enki-font-mono);
    text-transform: none;
    letter-spacing: 0.05em;
    /* Softened accent — the numbers are the data, so they get the
       HUD's value colour, one tier below the full interactive cyan
       so the chrome stays quiet. */
    color: var(--enki-accent-dim);
}

.enki-sidebar {
    grid-area: sidebar;
    background: linear-gradient(180deg, #0a1628 0%, #081422 100%);
    border-right: 1px solid var(--enki-border);
    /* Flex column so the nav scrolls and the footer stays pinned at the
       bottom. min-height:0 lets it shrink below content within the fixed
       grid row; the scroll lives on .enki-nav (overflow-y:auto), so the
       sidebar itself must stay overflow:visible — otherwise it clips the
       footer's launcher/bell popovers (the bell panel is wider than the
       320px sidebar and opens rightward over the content). The collapsed
       + mobile-drawer states re-apply overflow:hidden on their own. */
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: visible;
}

.enki-content {
    grid-area: content;
    padding: 2rem 2.25rem;
    /* The content pane owns the vertical scroll now — not the document —
       so the topbar and sidebar stay pinned while the page body scrolls. */
    min-height: 0;
    overflow-y: auto;
    overflow-x: auto;
}
.enki-content article {
    max-width: 1400px;
}

/* Topbar scope-path (redesign Phase 2). The Home → Org → Job → Well/Run
   spine lives in the chrome now (Breadcrumb.razor, its own interactive
   island), with a sibling-switcher dropdown on each entity segment. Sits
   between the brand and the topbar controls; individual labels ellipsis so
   a deep path can never push the version/bell/user off the edge. Slash
   separators read more naturally than chevrons in this typeface. */
.enki-crumbs {
    flex: 1 1 auto;
    min-width: 0;
    /* Trailing buffer so the terminal caret on entity-last pages (a Run / Well /
       Job overview, where the current entity is the last crumb and still owns a
       switcher) has room to expand into instead of sitting flush against the
       overflow-clip edge below. */
    padding-inline-end: 0.4rem;
    margin: 0 1rem;
    font-size: 0.85rem;
    /* Clip the row horizontally (single line; labels already ellipsis at
       max-width:22ch each) but keep the vertical axis visible so the
       sibling-switcher dropdowns can drop below the crumb line. A plain
       overflow:hidden here clipped them entirely (the nav row is only
       ~27px tall, the popup renders below it). overflow-x:clip pairs with
       overflow-y:visible without the visible->auto coercion. */
    overflow-x: clip;
    overflow-y: visible;
}
.enki-crumbs ol {
    list-style: none; margin: 0; padding: 0;
    display: flex; align-items: center; flex-wrap: nowrap; min-width: 0;
}
.enki-crumb {
    display: inline-flex; align-items: center;
    position: relative;               /* anchor for the dropdown popover */
    min-width: 0;
}
.enki-crumb-link, .enki-crumb-current, .enki-crumb-plain {
    max-width: 22ch;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    padding: 0.15rem 0.35rem; border-radius: var(--enki-radius);
    font-family: var(--enki-font-mono, ui-monospace, monospace);
}
.enki-crumb-link {
    color: var(--enki-text-dim); text-decoration: none;
    transition: background 120ms ease, color 120ms ease;
}
.enki-crumb-link:hover, .enki-crumb-link:focus-visible {
    color: var(--enki-accent); background: var(--enki-accent-faint); text-decoration: none;
}
.enki-crumb-current { color: var(--enki-text); }
/* A path level that exists in the URL but has no page behind it (Tie-ons,
   Survey 12, Magnetics). Muted so it reads as structure rather than as a
   link the user is failing to hit. */
.enki-crumb-plain { color: var(--enki-text-muted); }
.enki-crumb-sep { margin: 0 0.1rem; color: var(--enki-text-muted); user-select: none; flex-shrink: 0; }

/* Sibling-switcher caret — collapsed to zero width at rest so the breadcrumb
   reads as pure text AND reclaims the horizontal space. (A reserved-but-hidden
   slot still ate ~20px per caret, which ran the row tight and left the last
   caret sheared against the container's overflow-clip on entity-last pages.)
   The caret expands in on hover / keyboard-focus / while its dropdown is open;
   the width animates, and because the caret is a flex item the surrounding
   labels ellipsis-shrink to absorb its growth, so a caret can never be clipped.
   Trade vs. the reserved slot: hovering a MID-path crumb slides the crumbs to
   its right by one caret-width (softened by the transition) — but hovering the
   LAST crumb, where the shearing happened, shifts nothing. pointer-events:none
   at rest keeps the collapsed button from swallowing clicks; it stays in the
   tab order for keyboard reach. */
.enki-crumb-switch {
    /* A bare chevron, never the browser's button: no fill, border or padding.
       The old caret never needed this because it was zero-width at rest — made
       always visible (0.54.11) it showed as a grey boxed button (2026-09-28). */
    appearance: none; -webkit-appearance: none;
    background: transparent; border: 0; padding: 0;
    display: inline-grid; place-items: center;
    width: 0; height: 1.3rem; flex-shrink: 0; overflow: hidden;
    margin-left: 0; border-radius: var(--enki-radius);
    color: var(--enki-text-muted); cursor: pointer;
    opacity: 0; pointer-events: none;
    transition: width 120ms ease, margin 120ms ease, opacity 120ms ease,
                background 120ms ease, color 120ms ease, transform 120ms ease;
}
.enki-crumb:hover .enki-crumb-switch,
.enki-crumb:focus-within .enki-crumb-switch,
.enki-crumb-switch:focus-visible,
.enki-crumb-switch.open {
    width: 1.3rem; margin-left: 0.15rem;
    opacity: 1; pointer-events: auto;
}
/* The type words' switchers are ALWAYS visible (ruled by Mike 2026-09-28): the
   hidden-until-hover caret above is why the old name switchers went unnoticed.
   Every switcher now sits on a type word (Organizations, Jobs, Wells, Runs,
   Models, Logs), so the rest caret simply shows, a touch dimmer than on hover. */
.enki-crumb-type .enki-crumb-switch {
    width: 1.15rem; height: 1.15rem; margin: 0 0.1rem 0 -0.2rem;   /* tucked beside the word */
    border-radius: 0.3rem;
    color: var(--enki-text-muted); opacity: 1; pointer-events: auto;
}
.enki-crumb-type .enki-crumb-switch svg { width: 0.72rem; height: 0.72rem; }
.enki-crumb-type .enki-crumb-switch:hover,
.enki-crumb-type .enki-crumb-switch.open { color: var(--enki-accent); background: var(--enki-accent-faint); }
.enki-crumb-type .enki-crumb-sep { margin-left: 0.2rem; }   /* the chevron never touches the "/" */
.enki-crumb-switch svg { width: 0.8rem; height: 0.8rem; }
.enki-crumb-switch:hover { color: var(--enki-accent); background: var(--enki-accent-faint); }
.enki-crumb-switch.open { color: var(--enki-accent); background: var(--enki-accent-faint); transform: rotate(180deg); }
.enki-crumb-switch:focus-visible {
    outline: none; box-shadow: 0 0 0 1px var(--enki-accent-faint), 0 0 0 3px var(--enki-accent-glow);
}

/* Dropdown popover — drops below the caret into the content area. */
.enki-crumb-pop {
    position: absolute; top: calc(100% + 0.4rem); left: 0; z-index: 60;
    min-width: 15rem; max-width: 20rem; max-height: 20rem; overflow-y: auto;
    padding: 0.35rem;
    background: var(--enki-surface-1, #0c1a2c);
    border: 1px solid var(--enki-border-bright, var(--enki-border));
    border-radius: 0.6rem;
    box-shadow: 0 18px 44px -18px rgba(0, 0, 0, 0.75);
    animation: enki-crumb-pop-in 0.12s var(--enki-ease);
}
@keyframes enki-crumb-pop-in { from { opacity: 0; transform: translateY(-4px); } }
.enki-crumb-pop-label {
    padding: 0.4rem 0.5rem 0.35rem;
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-size: 0.6rem; letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--enki-text-muted);
}
/* Type-to-filter over a long list (ruled 2026-09-28: more than ~10 entries). */
.enki-crumb-pop-filter {
    display: block; width: calc(100% - 0.4rem); margin: 0 0.2rem 0.35rem;
    padding: 0.35rem 0.55rem; font-size: 0.85rem;
    color: var(--enki-text); background: var(--enki-surface-2);
    border: 1px solid var(--enki-border); border-radius: var(--enki-radius);
}
.enki-crumb-pop-filter:focus { outline: none; border-color: var(--enki-accent); box-shadow: 0 0 0 2px var(--enki-accent-faint); }
.enki-crumb-pop-note {
    padding: 0.5rem 0.55rem; color: var(--enki-text-muted); font-size: 0.82rem;
    display: flex; align-items: center; gap: 0.5rem;
}
.enki-crumb-pop-item {
    display: flex; align-items: center; gap: 0.6rem; width: 100%;
    text-align: left; padding: 0.5rem 0.55rem; border-radius: var(--enki-radius);
    color: var(--enki-text-dim); font-size: 0.87rem; cursor: pointer;
    transition: background 100ms ease, color 100ms ease;
}
.enki-crumb-pop-item:hover, .enki-crumb-pop-item:focus-visible {
    background: var(--enki-surface-2); color: var(--enki-text); outline: none;
}
.enki-crumb-pop-item.on { color: var(--enki-accent); }
.enki-crumb-pop-dot {
    width: 0.4rem; height: 0.4rem; border-radius: 50%;
    background: var(--enki-text-muted); flex-shrink: 0;
}
.enki-crumb-pop-item.on .enki-crumb-pop-dot { background: var(--enki-accent); box-shadow: 0 0 6px var(--enki-accent-glow); }
.enki-crumb-pop-name { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.enki-crumb-pop-cur {
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--enki-text-muted); flex-shrink: 0;
}

/* Full-viewport click-catcher behind an open dropdown. */
.enki-crumb-scrim { position: fixed; inset: 0; z-index: 55; background: transparent; }

/* =============================================================================
   Command palette (redesign Phase 3) — ⌘K "go to anything".
   ============================================================================= */

/* Topbar trigger. Native onclick (see MainLayout) so it works from the
   static layout; ⌘K opens it too. */
.enki-cmdk-trigger {
    display: inline-flex; align-items: center; gap: 0.5rem;
    height: 2rem; padding: 0 0.55rem 0 0.7rem;
    border: 1px solid var(--enki-border); border-radius: 0.5rem;
    color: var(--enki-text-muted); background: transparent; cursor: pointer;
    font-size: 0.8rem; transition: border-color 150ms ease, color 150ms ease;
}
.enki-cmdk-trigger:hover { border-color: var(--enki-accent); color: var(--enki-text); }
.enki-cmdk-trigger:focus-visible {
    outline: none; border-color: var(--enki-accent);
    box-shadow: 0 0 0 3px var(--enki-accent-glow);
}
.enki-cmdk-trigger svg { width: 0.9rem; height: 0.9rem; color: var(--enki-text-muted); }
.enki-cmdk-trigger-kbd {
    font-family: var(--enki-font-mono, ui-monospace, monospace); font-size: 0.7rem;
    color: var(--enki-text-muted); border: 1px solid var(--enki-border);
    border-radius: 0.3rem; padding: 0.05rem 0.3rem;
}
@media (max-width: 1000px) { .enki-cmdk-trigger-text { display: none; } }

.enki-cmd-scrim {
    position: fixed; inset: 0; z-index: 200;
    background: rgba(4, 10, 18, 0.62);
    backdrop-filter: blur(2px);
    display: flex; justify-content: center; align-items: flex-start;
    padding-top: 12vh;
    animation: enki-cmd-fade 0.14s ease;
}
@keyframes enki-cmd-fade { from { opacity: 0; } }
.enki-cmd {
    width: min(600px, 92vw);
    background: var(--enki-surface-1, #0c1a2c);
    border: 1px solid var(--enki-border-bright, var(--enki-border));
    border-radius: 0.85rem; overflow: hidden;
    box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.8), 0 0 0 1px var(--enki-accent-faint);
    animation: enki-cmd-pop 0.16s var(--enki-ease);
}
@keyframes enki-cmd-pop { from { opacity: 0; transform: translateY(-8px); } }
.enki-cmd-input {
    display: flex; align-items: center; gap: 0.7rem;
    padding: 0.85rem 1rem; border-bottom: 1px solid var(--enki-border);
}
.enki-cmd-input svg { width: 1.1rem; height: 1.1rem; color: var(--enki-accent); flex-shrink: 0; }
.enki-cmd-input input {
    flex: 1; min-width: 0; background: none; border: none; outline: none;
    color: var(--enki-text); font-size: 1rem; font-family: inherit;
}
.enki-cmd-input input::placeholder { color: var(--enki-text-muted); }
.enki-cmd-esc {
    font-family: var(--enki-font-mono, ui-monospace, monospace); font-size: 0.65rem;
    color: var(--enki-text-muted); border: 1px solid var(--enki-border);
    border-radius: 0.3rem; padding: 0.1rem 0.35rem; flex-shrink: 0;
}
.enki-cmd-list { max-height: 44vh; overflow-y: auto; padding: 0.4rem; }
.enki-cmd-group {
    padding: 0.6rem 0.6rem 0.35rem;
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--enki-text-muted);
}
.enki-cmd-note { padding: 1rem 0.7rem; color: var(--enki-text-muted); font-size: 0.85rem; display: flex; align-items: center; gap: 0.5rem; }
.enki-cmd-item {
    display: flex; align-items: center; gap: 0.75rem; width: 100%;
    text-align: left; padding: 0.55rem 0.6rem; border-radius: 0.5rem;
    color: var(--enki-text-dim); cursor: pointer; border: none; background: none;
    transition: background 90ms ease, color 90ms ease;
}
.enki-cmd-item.sel,
.enki-cmd-item:hover { background: var(--enki-accent-faint); color: var(--enki-text); }
.enki-cmd-item:hover .enki-cmd-ic,
.enki-cmd-item.sel .enki-cmd-ic { color: var(--enki-accent); border-color: var(--enki-accent-glow); }
.enki-cmd-ic {
    width: 1.9rem; height: 1.9rem; flex-shrink: 0;
    display: grid; place-items: center; border-radius: 0.4rem;
    background: var(--enki-surface-2); border: 1px solid var(--enki-border);
    color: var(--enki-text-muted);
}
.enki-cmd-item.sel .enki-cmd-ic { color: var(--enki-accent); border-color: var(--enki-accent-glow); }
.enki-cmd-ic svg { width: 1.05rem; height: 1.05rem; }
.enki-cmd-main { min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; flex: 1; }
.enki-cmd-label { color: var(--enki-text); font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.enki-cmd-sub { font-family: var(--enki-font-mono, ui-monospace, monospace); font-size: 0.7rem; color: var(--enki-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.enki-cmd-kind {
    margin-left: auto; flex-shrink: 0;
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-size: 0.6rem; letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--enki-text-muted);
}
.enki-cmd-foot {
    display: flex; gap: 1.1rem; padding: 0.55rem 1rem;
    border-top: 1px solid var(--enki-border);
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-size: 0.65rem; color: var(--enki-text-muted);
}
.enki-cmd-foot span { display: inline-flex; align-items: center; gap: 0.4rem; }
.enki-cmd-key { border: 1px solid var(--enki-border); border-radius: 0.25rem; padding: 0.05rem 0.3rem; color: var(--enki-text-dim); }
@media (prefers-reduced-motion: reduce) { .enki-cmd-scrim, .enki-cmd { animation: none; } }

/* Global launcher (redesign Phase 4) — apps-grid popover for the cross-org
   sections, reachable from any scope. */
.enki-launcher { position: relative; display: inline-flex; }
.enki-launcher-btn {
    width: 2rem; height: 2rem; display: grid; place-items: center;
    border: 1px solid transparent; border-radius: 0.5rem;
    color: var(--enki-text-muted); background: transparent; cursor: pointer;
    transition: color 150ms ease, background 150ms ease, border-color 150ms ease;
}
.enki-launcher-btn svg { width: 1.15rem; height: 1.15rem; }
.enki-launcher-btn:hover { color: var(--enki-text); background: var(--enki-surface-2); }
.enki-launcher-btn.open { color: var(--enki-accent); background: var(--enki-accent-faint); border-color: var(--enki-accent-glow); }
.enki-launcher-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--enki-accent-glow); }

.enki-launcher-pop {
    position: absolute; top: calc(100% + 0.5rem); right: 0; z-index: 60;
    width: 19rem; max-height: 70vh; overflow-y: auto; padding: 0.5rem;
    background: var(--enki-surface-1, #0c1a2c);
    border: 1px solid var(--enki-border-bright, var(--enki-border));
    border-radius: 0.75rem;
    box-shadow: 0 24px 60px -22px rgba(0, 0, 0, 0.8);
    animation: enki-crumb-pop-in 0.13s var(--enki-ease);
}
.enki-launcher-group {
    padding: 0.55rem 0.5rem 0.35rem;
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--enki-text-muted);
}
.enki-launcher-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.25rem; }
.enki-launcher-item, .enki-launcher-row {
    display: flex; align-items: center; gap: 0.6rem; width: 100%;
    text-align: left; padding: 0.5rem 0.5rem; border-radius: 0.5rem;
    color: var(--enki-text-dim); cursor: pointer; border: none; background: none;
    transition: background 90ms ease, color 90ms ease;
}
.enki-launcher-item { font-size: 0.82rem; gap: 0.55rem; }
.enki-launcher-row  { font-size: 0.87rem; gap: 0.7rem; }
.enki-launcher-list { display: flex; flex-direction: column; }
.enki-launcher-item:hover, .enki-launcher-row:hover,
.enki-launcher-item:focus-visible, .enki-launcher-row:focus-visible {
    background: var(--enki-accent-faint); color: var(--enki-text); outline: none;
}
.enki-launcher-ic {
    width: 1.6rem; height: 1.6rem; flex-shrink: 0;
    display: grid; place-items: center; border-radius: 0.35rem;
    color: var(--enki-text-muted);
}
.enki-launcher-item:hover .enki-launcher-ic, .enki-launcher-row:hover .enki-launcher-ic { color: var(--enki-accent); }
.enki-launcher-ic svg { width: 1rem; height: 1rem; }
.enki-launcher-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.enki-launcher-scrim { position: fixed; inset: 0; z-index: 55; background: transparent; }

#blazor-error-ui {
    color-scheme: dark;
    background: var(--enki-alert);
    color: white;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 0.75rem 1.25rem;
    position: fixed;
    display: none;
    z-index: 1000;
    box-shadow: 0 -2px 12px rgba(255, 71, 87, 0.4);
}
#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
    font-size: 1.25rem;
}

/* =============================================================================
   Sidebar navigation — grouped links with active accent bar.
   ============================================================================= */

.enki-nav {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    /* The nav owns the vertical scroll; the sidebar footer stays pinned. */
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 1.25rem 0;
}

/* Sidebar footer — utility chrome pinned at the bottom of the menu column
   (launcher / bug report / notification bell + version stamps), relocated
   from the topbar so the breadcrumb has the top to itself. */
.enki-sidebar-foot {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.7rem 0.85rem 0.8rem;
    border-top: 1px solid var(--enki-border-soft);
    background: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.18));
}
.enki-sidebar-foot-actions {
    display: flex;
    align-items: center;
    gap: 0.3rem;
}
.enki-sidebar-foot-ver {
    display: flex;
    gap: 0.35rem;
    padding-left: 0.2rem;
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-size: 0.66rem;
    letter-spacing: 0.02em;
    color: var(--enki-text-muted);
}
.enki-sidebar-foot-ver .enki-version-num { color: var(--enki-text-dim); }

/* Launcher + bell popovers open UPWARD from the footer (they'd fall off the
   bottom otherwise), anchored to the button's left edge. */
.enki-sidebar-foot .enki-launcher-pop {
    top: auto; bottom: calc(100% + 0.5rem);
    right: auto; left: 0;
}
.enki-sidebar-foot .enki-bell-panel {
    top: auto; bottom: calc(100% + 0.45rem);
    right: auto; left: 0;
}
.enki-nav-group {
    display: flex;
    flex-direction: column;
}
.enki-nav-group + .enki-nav-group {
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--enki-border-soft);
    margin-left: 1rem;
    margin-right: 1rem;
}

/* ----- Scope header (redesign Phase 1) -----
   The "you are here" block at the top of a contextual sidebar
   (Organization / Job / Well / Run): a one-click "up" to the parent's
   listing, then the scope icon + name + parent context. Sticky so it
   stays anchored while a longer scope (a Well's eight sections) scrolls.
   The name is mono to match the HUD id treatment used elsewhere. */
.enki-scope-head {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    padding: 0.1rem 1rem 0.8rem;
    margin-bottom: 0.5rem;
    background: linear-gradient(180deg, #0a1628 78%, transparent);
    border-bottom: 1px solid var(--enki-border-soft);
}
.enki-scope-up {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    align-self: flex-start;
    padding: 0.2rem 0.45rem;
    border-radius: var(--enki-radius);
    font-size: 0.66rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    text-decoration: none;
    transition: color 150ms var(--enki-ease), background 150ms var(--enki-ease);
}
.enki-scope-up svg { width: 0.85rem; height: 0.85rem; flex-shrink: 0; }
.enki-scope-up:hover { color: var(--enki-accent); background: var(--enki-surface-2); text-decoration: none; }
.enki-scope-up:focus-visible {
    outline: none;
    box-shadow: 0 0 0 1px var(--enki-accent-faint), 0 0 0 3px var(--enki-accent-glow);
}
.enki-scope-id {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0 0.4rem;
}
.enki-scope-icon {
    width: 2.1rem;
    height: 2.1rem;
    flex-shrink: 0;
    display: grid;
    place-items: center;
    border-radius: 0.5rem;
    background: var(--enki-accent-faint);
    color: var(--enki-accent);
    border: 1px solid var(--enki-accent-glow);
}
.enki-scope-icon svg { width: 1.2rem; height: 1.2rem; }
.enki-scope-meta { min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.enki-scope-name {
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-size: 0.95rem;
    color: var(--enki-text);
    letter-spacing: 0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.enki-scope-sub {
    font-size: 0.7rem;
    color: var(--enki-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.enki-nav-label {
    padding: 0.25rem 1.25rem 0.5rem;
    font-size: 0.65rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
/* "ADMIN" badge in the topbar of AdminLayout. Visually distinct from
   the tenant-scope chip (which is small + accent-colored). This one is
   bigger + warning-colored so an operator never confuses an admin
   tab with a regular tab. */
.enki-admin-badge {
    display: inline-block;
    padding: 0.1rem 0.55rem;
    margin-left: 0.6rem;
    border-radius: 999px;
    background: var(--enki-accent-warning, #c97a2c);
    color: #fff;
    font-size: 0.6rem;
    letter-spacing: 0.18em;
    font-weight: 600;
    vertical-align: middle;
}

/* Tenant-scope chip in the topbar of MainLayout. Sibling of
   .enki-admin-badge but quieter: ADMIN is filled + warning-colored
   because confusing admin with non-admin is dangerous; TENANT is an
   accent outline because it's just orientation, not a privilege cue.
   Surfaces when UrlContextParser resolves an active tenant from the
   route. */
.enki-tenant-badge {
    display: inline-block;
    padding: 0.05rem 0.45rem;
    margin-left: 0.6rem;
    border-radius: var(--enki-radius);
    background: transparent;
    border: 1px solid var(--enki-accent);
    color: var(--enki-accent);
    font-family: var(--enki-font-mono);
    font-size: 0.55rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    vertical-align: middle;
    line-height: 1.4;
}

/* Stat card variant that's clickable. Used by AdminHome.razor to
   present each admin section as a navigable card. */
.enki-link-card {
    cursor: pointer;
    text-decoration: none;
    display: block;
    transition: border-color 150ms var(--enki-ease),
                transform 150ms var(--enki-ease);
}
.enki-link-card:hover {
    border-color: var(--enki-accent);
    transform: translateY(-2px);
    text-decoration: none;
}
.enki-stat-value-text {
    font-size: 1.1rem;
    font-weight: 500;
    color: var(--enki-text);
    margin: 0.25rem 0;
}
.enki-stat-hint {
    font-size: 0.8rem;
    color: var(--enki-text-muted);
    margin-top: 0.4rem;
}

/* Badge showing which tenant a nav group is scoped to. Sits next to the
   uppercase group label; letter-spacing resets because the code itself
   should read naturally, not as tracked-out ALL CAPS. */
.enki-nav-scope {
    font-size: 0.6rem;
    letter-spacing: 0.04em;
    text-transform: none;
    padding: 0.1rem 0.45rem;
    border: 1px solid var(--enki-border-soft);
    border-radius: 999px;
    color: var(--enki-accent);
    background: rgba(0, 0, 0, 0.25);
    font-weight: 500;
    font-family: var(--enki-font-mono, ui-monospace, monospace);
}
.enki-nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 1.25rem;
    margin: 0 0.5rem;
    border-radius: var(--enki-radius);
    color: var(--enki-text-dim);
    font-size: 0.9rem;
    font-weight: 400;
    text-decoration: none;
    position: relative;
    transition: background 150ms var(--enki-ease),
                color 150ms var(--enki-ease);
}
.enki-nav-item:hover {
    color: var(--enki-text);
    background: var(--enki-surface-2);
    text-decoration: none;
}
.enki-nav-item:focus-visible {
    outline: none;
    box-shadow: 0 0 0 1px var(--enki-accent-faint),
                0 0 0 3px var(--enki-accent-glow);
}
.enki-nav-item.active {
    color: var(--enki-accent);
    background: var(--enki-accent-faint);
}
.enki-nav-item.active::before {
    content: "";
    position: absolute;
    left: -0.5rem;
    top: 10%;
    bottom: 10%;
    width: 2px;
    background: var(--enki-accent);
    box-shadow: 0 0 6px var(--enki-accent);
    border-radius: 1px;
}
/* ----- Drill-in breadcrumb sub-items -----
   Used in the Operations group when a Job (and optionally a Well) is
   in scope. Each entry is a smaller, dimmer link than its parent
   .enki-nav-item, prefixed by a short horizontal rail that visually
   wires it to the row above. depth-2 nudges the wells row further
   right + extends the rail to match.
   .active picks up the same accent treatment as .enki-nav-item so
   the entire path (Jobs → Job → Well) lights up as you drill. */
.enki-nav-subitem {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 1rem 0.4rem 2.6rem;
    margin: 0 0.5rem;
    border-radius: var(--enki-radius);
    color: var(--enki-text-muted);
    font-size: 0.82rem;
    text-decoration: none;
    position: relative;
    transition: background 150ms var(--enki-ease),
                color 150ms var(--enki-ease);
}
.enki-nav-subitem:hover {
    color: var(--enki-text);
    background: var(--enki-surface-2);
    text-decoration: none;
}
.enki-nav-subitem:focus-visible {
    outline: none;
    box-shadow: 0 0 0 1px var(--enki-accent-faint),
                0 0 0 3px var(--enki-accent-glow);
}
.enki-nav-subitem.active {
    color: var(--enki-accent);
    background: var(--enki-accent-faint);
}
.enki-nav-subitem-rail {
    /* Short horizontal connector — sits in the gutter that the
       icons would otherwise occupy on the parent row. Gives the eye
       a tiny "this is a child of the row above" cue without a full
       tree-draw. */
    display: inline-block;
    width: 0.6rem;
    height: 1px;
    background: var(--enki-border-soft);
    flex-shrink: 0;
    position: absolute;
    left: 1.9rem;
}
.enki-nav-subitem-2 {
    padding-left: 3.6rem;
}
.enki-nav-subitem-2 .enki-nav-subitem-rail {
    left: 2.9rem;
}
.enki-nav-subitem-label {
    /* Truncate long well/job names so a chatty seed doesn't blow up
       the sidebar width. Title attribute could be added later if
       hover-to-see-full-name proves useful. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.enki-nav-icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: currentColor;
}

/* =============================================================================
   Login / logout pill in the top bar.
   ============================================================================= */

.enki-user-name {
    font-family: var(--enki-font-mono);
    font-size: 0.85rem;
    color: var(--enki-text);
    padding: 0.25rem 0.75rem;
    border-left: 1px solid var(--enki-border);
    margin-right: 0.5rem;
}
/* Username doubles as the entry-point to /account/settings. Without
   the underline-on-hover + pointer cursor, users read the username as
   static text and never discover the page. */
.enki-user-link {
    text-decoration: none;
    cursor: pointer;
    transition: color 150ms var(--enki-ease);
}
.enki-user-link:hover,
.enki-user-link:focus-visible {
    color: var(--enki-accent);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}
.enki-user-form {
    display: inline;
}
.enki-pill-button {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.4rem 0.95rem;
    font-size: 0.8rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--enki-text-dim);
    background: transparent;
    border: 1px solid var(--enki-border);
    border-radius: 999px;
    text-decoration: none;
    cursor: pointer;
    transition: all 150ms var(--enki-ease);
    font-family: var(--enki-font-sans);
}
.enki-pill-button:hover,
.enki-pill-button:focus-visible {
    color: var(--enki-accent);
    border-color: var(--enki-border-hot);
    background: var(--enki-accent-faint);
    box-shadow: 0 0 0 3px var(--enki-accent-glow);
    outline: none;
    text-decoration: none;
}
.enki-pill-button.enki-pill-primary {
    color: var(--enki-accent);
    border-color: var(--enki-border-hot);
    background: var(--enki-accent-faint);
}
.enki-pill-button.enki-pill-primary:hover,
.enki-pill-button.enki-pill-primary:focus-visible {
    background: var(--enki-accent);
    color: var(--enki-text-inv);
    box-shadow: 0 0 12px -2px var(--enki-accent);
}
.enki-pill-button.is-loading {
    opacity: 0.7;
}

/* =============================================================================
   Responsive: narrow viewport stacks the layout.
   ============================================================================= */

@media (max-width: 768px) {
    .enki-shell {
        grid-template-columns: 1fr;
        grid-template-rows: var(--enki-topbar-h) auto 1fr;
        grid-template-areas:
            "topbar"
            "sidebar"
            "content";
    }
    .enki-sidebar {
        border-right: none;
        border-bottom: 1px solid var(--enki-border);
    }
    .enki-brand-tagline { display: none; }
    /* Ambient info — the stacked topbar has no room for it. */
    .enki-topbar-versions { display: none; }
}

/* ----------------------------------------------------------------------
   Hide spinner / up-down arrows on numeric inputs.

   Two surfaces to suppress:
     1. Syncfusion's <SfNumericTextBox>, which Normal-edit mode in SfGrid
        uses by default for `double` columns. Up/down render as
        .e-spin-up / .e-spin-down inside an .e-input-group container.
     2. Browser-native <input type="number"> spinners (WebKit's
        ::-webkit-*-spin-button pseudo-elements; Firefox's
        -moz-appearance:textfield switch).

   Survey-trajectory values are continuous quantities the user types
   in full — single-step nudges aren't useful and crowd narrow columns.
   Lives here (not in Surveys.razor.css) because Blazor's
   component-scoped CSS isolation rewrite doesn't reliably reach
   Syncfusion's own DOM via ::deep on a routable page; global wins.
   ---------------------------------------------------------------------- */

.e-spin-up,
.e-spin-down {
    display: none !important;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

input[type="number"] {
    -moz-appearance: textfield;
}

/* ---------- <UnitInput> wrapper -----------------------------------------
   The unit-aware editor wraps its <input> + abbreviation in an inline-
   flex span so the suffix sits flush-right against the field without
   breaking baseline. Matches the visual rhythm of <UnitFormatted> at
   read time (mono number + faint unit). The suffix is non-interactive
   and dimmed so the eye lands on the number first.
   ---------------------------------------------------------------------- */

.enki-unit-input {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    width: 100%;
}

.enki-unit-input > input {
    flex: 1 1 auto;
    min-width: 0;
}

.enki-unit-input-suffix {
    color: var(--enki-text-dim, #8a8a8a);
    font-size: 0.85em;
    white-space: nowrap;
    pointer-events: none;
    flex: 0 0 auto;
}

/* ============================================================
   Audit feed utilities — used by /admin/audit/* + per-tenant
   audit page. Kept here so the visual language stays in one
   theme file instead of scattering through component styles.
   ============================================================ */

/* Small inline chip for ChangedColumns property names. Lighter
   than .enki-status-pill — purely informational, no state. */
.enki-tag {
    display: inline-block;
    padding: 0.1rem 0.45rem;
    font-size: 0.7rem;
    font-family: var(--enki-font-mono);
    color: var(--enki-text-muted);
    border: 1px solid var(--enki-border);
    border-radius: 0.25rem;
    background: rgba(255, 255, 255, 0.03);
}

/* Flex row of filter inputs with end-aligned preset buttons. */
.enki-filter-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: flex-end;
    margin-bottom: 1rem;
}

.enki-filter-group {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 12rem;
}

.enki-filter-group .enki-button {
    margin-right: 0.25rem;
}

/* Text-only button — no border, no background. For inline
   "Show details" / "24h" / "7d" toggles where a full button
   would be visually heavy. */
.enki-button-link {
    background: transparent;
    border: none;
    color: var(--enki-accent);
    cursor: pointer;
    padding: 0.15rem 0.35rem;
    font-size: 0.8rem;
    font-family: inherit;
}

.enki-button-link:hover,
.enki-button-link:focus-visible {
    text-decoration: underline;
    color: var(--enki-accent);
    outline: none;
}

/* Segmented control — pick exactly one of two or three modes. A joined
   row reads as a single control in a way a pair of loose radios does
   not, and it carries the same accent the rest of the app uses for
   "this is the live selection".

   Generic on purpose. .enki-trace-mode-switch and .enki-camera-layout-btn
   are two near-identical bespoke copies of this shape that predate it;
   new surfaces use these instead of adding a third. Folding those two in
   is a separate change — both sit on live rendering paths. */
.enki-segmented {
    display: inline-flex;
    border: 1px solid var(--enki-border-soft);
    border-radius: var(--enki-radius);
    overflow: hidden;
}

.enki-segmented-btn {
    appearance: none;
    border: none;
    border-right: 1px solid var(--enki-border-soft);
    background: var(--enki-surface-2);
    color: var(--enki-text-dim);
    padding: 0.35rem 0.95rem;
    font: inherit;
    font-size: 0.8rem;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: background 150ms var(--enki-ease),
                color      150ms var(--enki-ease);
}

.enki-segmented-btn:last-child {
    border-right: none;
}

.enki-segmented-btn:hover:not([disabled]) {
    background: var(--enki-surface-3);
    color: var(--enki-accent);
}

.enki-segmented-btn.is-active {
    background: var(--enki-accent);
    color: var(--enki-bg-raised);
    font-weight: 600;
}

.enki-segmented-btn[disabled] {
    opacity: 0.6;
    cursor: not-allowed;
}

/* ---------- Modal dialogs ----------
   Shared by EnkiConfirmDialog and EnkiReasonDialog. The overlay
   fills the viewport and dims the page; clicking it cancels the
   dialog. The dialog box itself stops propagation. */

.enki-modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(7, 17, 31, 0.72);
    backdrop-filter: blur(2px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 1rem;
}

.enki-modal {
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    box-shadow:
        0 18px 48px -8px rgba(0, 0, 0, 0.6),
        0 0 0 1px var(--enki-accent-faint);
    min-width: 320px;
    max-width: 520px;
    width: 100%;
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    outline: none;
    color: var(--enki-text);
}

.enki-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.85rem 1rem;
    border-bottom: 1px solid var(--enki-border-soft);
}

.enki-modal-title {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--enki-text);
}

.enki-modal-close {
    background: transparent;
    border: 0;
    color: var(--enki-text-muted);
    font-size: 1.4rem;
    line-height: 1;
    padding: 0.15rem 0.5rem;
    cursor: pointer;
    border-radius: var(--enki-radius);
    transition: color 150ms var(--enki-ease), background 150ms var(--enki-ease);
}
.enki-modal-close:hover,
.enki-modal-close:focus-visible {
    color: var(--enki-text);
    background: var(--enki-surface-2);
    outline: none;
}

.enki-modal-body {
    padding: 1rem;
    overflow-y: auto;
    flex: 1;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--enki-text-dim);
}

.enki-modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--enki-border-soft);
}

/* Reason-dialog specifics: label + textarea + char counter row. */

.enki-modal-label {
    display: block;
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
    color: var(--enki-text);
}

.enki-modal-textarea {
    width: 100%;
    background: var(--enki-bg-raised);
    color: var(--enki-text);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    padding: 0.55rem 0.75rem;
    font-family: var(--enki-font-sans);
    font-size: 0.9rem;
    line-height: 1.4;
    resize: vertical;
    transition: border-color 150ms var(--enki-ease);
}
.enki-modal-textarea:focus {
    border-color: var(--enki-accent);
    outline: none;
    box-shadow: 0 0 0 2px var(--enki-accent-glow);
}

/* Number-dialog input (office depth override) — mono single-line field. */
.enki-modal-input {
    width: 100%;
    background: var(--enki-bg-raised);
    color: var(--enki-text);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    padding: 0.55rem 0.75rem;
    font-family: var(--enki-font-mono);
    font-size: 0.95rem;
    line-height: 1.4;
    transition: border-color 150ms var(--enki-ease);
}
.enki-modal-input:focus {
    border-color: var(--enki-accent);
    outline: none;
    box-shadow: 0 0 0 2px var(--enki-accent-glow);
}

.enki-modal-hint {
    margin-top: 0.4rem;
    font-size: 0.78rem;
    color: var(--enki-text-muted);
}

.enki-modal-meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 0.35rem;
    font-size: 0.78rem;
}

.enki-modal-error {
    color: var(--enki-alert-dim);
}

.enki-modal-counter {
    color: var(--enki-text-muted);
    font-family: var(--enki-font-mono);
}

/* Side-by-side JSON Before/After grid for the audit-row expander.
   Falls back to single-column on narrow viewports. */
.enki-json-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
    margin-top: 0.5rem;
}

@media (max-width: 720px) {
    .enki-json-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   Bug-report launcher + wizard
   ============================================================ */

/* Topbar trigger — mirrors the notification bell button so the two
   sit as a matched pair. */
.enki-bugreport-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    color: var(--enki-text-dim);
    cursor: pointer;
    transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
.enki-bugreport-button:hover,
.enki-bugreport-button:focus-visible {
    color: var(--enki-accent);
    border-color: var(--enki-border-hot);
    background: var(--enki-accent-faint);
    outline: none;
}
.enki-bugreport-icon { width: 1.15rem; height: 1.15rem; }

/* A touch wider than the base 520px modal — the wizard is a form. */
.enki-bugreport-modal { max-width: 560px; }

.enki-hidden { display: none; }

/* Step indicator. */
.enki-wizard-steps {
    display: flex;
    gap: 0.4rem;
    margin: 0 0 1rem;
    padding: 0;
    list-style: none;
    counter-reset: enki-wizard-step;
}
.enki-wizard-steps li {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    padding-top: 0.4rem;
    border-top: 2px solid var(--enki-border-soft);
    counter-increment: enki-wizard-step;
}
.enki-wizard-steps li::before {
    content: counter(enki-wizard-step);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    font-size: 0.72rem;
    background: var(--enki-surface-2);
    color: var(--enki-text-muted);
}
.enki-wizard-steps li.is-current {
    color: var(--enki-accent);
    border-top-color: var(--enki-accent);
}
.enki-wizard-steps li.is-current::before {
    background: var(--enki-accent);
    color: var(--enki-text-inv);
}
.enki-wizard-steps li.is-done {
    color: var(--enki-text-dim);
    border-top-color: var(--enki-accent-dim);
}
.enki-wizard-steps li.is-done::before {
    background: var(--enki-accent-dim);
    color: var(--enki-text-inv);
}

/* Screenshot drop / browse zone. The InputFile input covers the label
   so a click anywhere in the zone opens the picker. */
.enki-bugreport-dropzone {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 4.5rem;
    padding: 1rem;
    border: 1px dashed var(--enki-border-hot);
    border-radius: var(--enki-radius);
    background: var(--enki-bg-raised);
    color: var(--enki-text-muted);
    font-size: 0.85rem;
    cursor: pointer;
    transition: border-color 150ms var(--enki-ease), background 150ms var(--enki-ease);
}
.enki-bugreport-dropzone:hover {
    border-color: var(--enki-accent);
    color: var(--enki-text-dim);
}
.enki-bugreport-dropzone input[type="file"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

/* Thumbnail grid of pending attachments. */
.enki-bugreport-thumbs {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr));
    gap: 0.6rem;
    margin-top: 0.85rem;
}
.enki-bugreport-thumb {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.enki-bugreport-thumb img {
    width: 100%;
    height: 4.5rem;
    object-fit: cover;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    background: var(--enki-bg-raised);
}
.enki-bugreport-thumb-remove {
    position: absolute;
    top: -0.5rem;
    right: -0.5rem;
    width: 1.35rem;
    height: 1.35rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font-size: 1rem;
    line-height: 1;
    color: var(--enki-text-inv);
    background: var(--enki-alert);
    border: 0;
    border-radius: 50%;
    cursor: pointer;
}
.enki-bugreport-thumb-name {
    font-size: 0.68rem;
    color: var(--enki-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Review-step context table. */
.enki-bugreport-context {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.enki-bugreport-context > div {
    display: grid;
    grid-template-columns: 7rem 1fr;
    gap: 0.5rem;
    align-items: baseline;
}
.enki-bugreport-context dt {
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    margin: 0;
}
.enki-bugreport-context dd {
    margin: 0;
    font-size: 0.85rem;
    color: var(--enki-text-dim);
    word-break: break-word;
}

/* Status / severity pills for the triage list + detail. */
.enki-badge {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    border: 1px solid transparent;
    white-space: nowrap;
}
.enki-badge.is-blocker   { color: var(--enki-alert);       border-color: var(--enki-alert); }
.enki-badge.is-major     { color: var(--enki-warn);        border-color: var(--enki-warn); }
.enki-badge.is-minor     { color: var(--enki-accent-dim);  border-color: var(--enki-accent-dim); }
.enki-badge.is-cosmetic  { color: var(--enki-text-muted);  border-color: var(--enki-border); }
.enki-badge.is-submitted { color: var(--enki-warn);        border-color: var(--enki-warn); }
.enki-badge.is-filed     { color: var(--enki-ok);          border-color: var(--enki-ok); }
.enki-badge.is-dismissed { color: var(--enki-text-muted);  border-color: var(--enki-border); }
.enki-badge.is-source-enki    { color: var(--enki-accent-dim); border-color: var(--enki-accent-dim); }
.enki-badge.is-source-esagila { color: var(--enki-warn);       border-color: var(--enki-warn); }

/* Client-context bag (Esagila) pretty-printed on the detail page. */
.enki-context-json {
    margin: 0;
    padding: 0.75rem;
    background: var(--enki-bg-raised);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    font-family: var(--enki-font-mono);
    font-size: 0.78rem;
    line-height: 1.5;
    color: var(--enki-text-dim);
    white-space: pre-wrap;
    word-break: break-word;
    overflow-x: auto;
}

/* Bug-report detail sections. */
.enki-detail-section { margin-bottom: 1.5rem; }
.enki-detail-subtitle {
    margin: 0 0 0.4rem;
    font-size: 0.78rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
}
.enki-prewrap {
    margin: 0;
    white-space: pre-wrap;
    word-break: break-word;
    color: var(--enki-text-dim);
    font-size: 0.9rem;
    line-height: 1.5;
}

/* Detail-page screenshot gallery. */
.enki-bugreport-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
    gap: 0.75rem;
    margin: 0.5rem 0 1rem;
}
.enki-bugreport-gallery a {
    display: block;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    overflow: hidden;
    background: var(--enki-bg-raised);
}
.enki-bugreport-gallery img {
    display: block;
    width: 100%;
    height: 9rem;
    object-fit: contain;
    background: var(--enki-bg-raised);
}

/* Success confirmation. */
.enki-bugreport-success {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0.5rem;
    padding: 1rem 0;
}
.enki-bugreport-success-icon {
    width: 2.5rem;
    height: 2.5rem;
    color: var(--enki-accent);
}
.enki-bugreport-success-title {
    margin: 0;
    font-size: 1rem;
    color: var(--enki-text);
}

.enki-json-pre {
    margin: 0;
    padding: 0.5rem 0.75rem;
    font-family: var(--enki-font-mono);
    font-size: 0.75rem;
    color: var(--enki-text);
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid var(--enki-border);
    border-radius: 0.25rem;
    max-height: 24rem;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
}

/* ============================================================
   Page header — title on the left, action buttons on the right.
   Used by PageHeader.razor; ensures detail-page action buttons
   stay above the fold instead of hiding at the bottom of long
   pages.
   ============================================================ */

.enki-page-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.enki-page-header-text {
    flex: 1 1 280px;
    min-width: 280px;
}

/* Inline chip alongside the H1 (status pill, mono ID, etc.) —
   smaller + dimmer than the title itself so it reads as
   metadata, not a peer heading. */
.enki-page-header-suffix {
    margin-left: 0.5rem;
    font-size: 0.65em;
    font-weight: 400;
    opacity: 0.85;
    vertical-align: middle;
}

.enki-page-header-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: flex-start;
}

@media (max-width: 720px) {
    .enki-page-header-actions {
        width: 100%;
    }
}

/* =============================================================================
   Modal dialog — wraps the native <dialog> with the same surface treatment as
   .enki-card, plus a darkened backdrop. Open/close handled by enki-dialog.js
   (Blazor pages call window.enkiDialog.open(id) / .close(id)).
   ============================================================================= */

.enki-dialog {
    width: min(560px, calc(100vw - 2rem));
    max-height: calc(100vh - 4rem);
    padding: 0;
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    color: var(--enki-text);
    box-shadow: 0 24px 60px -16px rgba(0, 0, 0, 0.6);
}
.enki-dialog::backdrop {
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(2px);
}
.enki-dialog-header {
    padding: 1rem 1.5rem;
    border-bottom: 1px solid var(--enki-border-soft);
}
.enki-dialog-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--enki-text);
}
.enki-dialog-subtitle {
    margin: 0.25rem 0 0;
    font-size: 0.8rem;
    color: var(--enki-text-dim);
}
.enki-dialog-body {
    padding: 1rem 1.5rem;
    overflow-y: auto;
    max-height: calc(100vh - 18rem);
}
.enki-dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.75rem;
    padding: 1rem 1.5rem;
    border-top: 1px solid var(--enki-border-soft);
}

/* =============================================================================
   Resume last run — Home page card stack + sidebar pin.

   One card per tenant the user has a recorded last-viewed Run in
   (composite-PK upsert on UserRunPointer enforces one pointer per
   user-tenant pair). Three visual states driven by Availability:
     ok       — bright, primary "Resume" link
     archived — dimmed, link still works (Run detail page surfaces
                archived rows via IgnoreQueryFilters)
     missing  — greyed, no link, dismiss-only

   Dismiss (×) button is always rendered (decision #4) so users
   can clear stale-but-valid pointers too.
   ============================================================================= */

.enki-resume-stack {
    margin-top: 2rem;
}
/* Resume last run and Resume last model side by side where there is room,
   one above the other where there is not (0.54.33). auto-fit collapses the
   empty track, so a user with only one kind gets the full width. */
.enki-resume-columns {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
    column-gap: 1.5rem;
    align-items: start;
}
.enki-resume-stack-title {
    margin-bottom: 0.25rem;
}
.enki-resume-stack-subtitle {
    margin-bottom: 1rem;
}

.enki-resume-card {
    position: relative;
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    padding: 1rem 1.25rem 1rem;
    margin-bottom: 0.75rem;
    transition: border-color 150ms var(--enki-ease),
                background  150ms var(--enki-ease);
}
.enki-resume-card.enki-resume-card-ok:hover {
    border-color: var(--enki-border-hot);
    background: var(--enki-surface-2);
}
.enki-resume-card.enki-resume-card-archived,
.enki-resume-card.enki-resume-card-missing {
    background: rgba(0, 0, 0, 0.15);
    border-style: dashed;
}
.enki-resume-card.enki-resume-card-missing {
    opacity: 0.7;
}

.enki-resume-card-title {
    margin: 0.25rem 0 0.35rem;
    font-size: 1.1rem;
    font-weight: 400;
    letter-spacing: 0.02em;
    color: var(--enki-text);
}
.enki-resume-card-title-link {
    text-decoration: none;
    color: inherit;
}
.enki-resume-card-title-link:hover .enki-resume-card-title,
.enki-resume-card-title-link:focus-visible .enki-resume-card-title {
    color: var(--enki-accent);
}

.enki-resume-card-context {
    margin: 0 0 0.75rem;
    font-size: 0.85rem;
}
.enki-resume-card-sep {
    margin: 0 0.4rem;
    opacity: 0.5;
}

.enki-resume-card-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.enki-resume-card-time {
    font-size: 0.8rem;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}
.enki-resume-card-action {
    flex-shrink: 0;
}

/* Dismiss (×) button — absolutely positioned in the card's top-right
   corner. Subtle by default, lights up on hover so it's discoverable
   without dominating the card. */
.enki-resume-card-dismiss {
    position: absolute;
    top: 0.4rem;
    right: 0.5rem;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    line-height: 1;
    font-size: 1.1rem;
    color: var(--enki-text-muted);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    cursor: pointer;
    transition: color 150ms var(--enki-ease),
                background 150ms var(--enki-ease),
                border-color 150ms var(--enki-ease);
}
.enki-resume-card-dismiss:hover:not([disabled]),
.enki-resume-card-dismiss:focus-visible {
    color: var(--enki-text);
    background: var(--enki-surface-2);
    border-color: var(--enki-border);
    outline: none;
}
.enki-resume-card-dismiss[disabled] {
    cursor: default;
    opacity: 0.4;
}

/* ----- Sidebar resume pin -----
   One per tenant pointer with Availability == "ok". The tenant code
   subscript distinguishes pins across tenants when the run names
   collide ("RR03" in two tenants reads as two identical pins
   without it). Truncation cap on the run name keeps narrow-viewport
   sidebars from overflowing. */
.enki-nav-resume-pin {
    align-items: baseline;
    flex-wrap: wrap;
    row-gap: 0.15rem;
}
.enki-nav-resume-pin-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.enki-nav-resume-pin-tenant {
    font-size: 0.6rem;
    letter-spacing: 0.04em;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    color: var(--enki-accent);
    background: rgba(0, 0, 0, 0.25);
    border: 1px solid var(--enki-border-soft);
    font-family: var(--enki-font-mono, ui-monospace, monospace);
    font-weight: 500;
    flex-shrink: 0;
}

/* =============================================================================
   Shot Trace Inspector — peek strip + expanded view.

   Lives on ShotDetail.razor between the primary capture card and the
   primary config form. Peek strip is the collapsed default (TIME label
   + sparkline + chips + readout + chevron); expand reveals a split-
   focus layout (1 large primary + 2 secondary thumbnails for the other
   modes) plus a range navigator with draggable handles for the
   operator window. Compare-mode toggle stacks all three signals
   full-width with a shared X axis.
   ============================================================================= */

.enki-trace-inspector {
    overflow: hidden;
}

/* Peek strip: ~96px tall row, five zones grid. Domain title on the
   left (Mike, 2026-05-22 — added so it's clear this is the Time
   inspector before the Frequency one lands). */
.enki-trace-peek-strip {
    display: grid;
    grid-template-columns: auto 200px 1fr auto auto;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 1rem;
    min-height: 96px;
}

.enki-trace-domain-title {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding-right: 0.75rem;
    border-right: 1px solid var(--enki-border-soft);
    min-width: 110px;
}

.enki-trace-domain-title-name {
    font-size: 1.1rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--enki-accent);
    line-height: 1.15;
}

.enki-trace-domain-title-sub {
    font-size: 0.65rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
}

/* Inspector titles use the page's default cyan accent — the
   per-domain colour lives on the sparkline trace itself (Time →
   violet, Frequency → magenta, see Shot{Trace,Frequency}Sparkline)
   so the bar header stays consistent with every other section
   title while the operationally-meaningful waveform carries the
   distinguishing hue. Mike, 2026-05-23. */

/* Info chip — used for "Using time window" indicator on the frequency
   inspector peek strip. Neutral fill, info-blue text. */
.enki-trace-chip-info {
    background: rgba(79, 195, 247, 0.08);
    color: var(--enki-accent, #4FC3F7);
    border: 1px solid rgba(79, 195, 247, 0.25);
}

.enki-trace-peek-loading {
    opacity: 0.7;
}

.enki-trace-sparkline-slot {
    height: 72px;
    width: 180px;
    overflow: hidden;
    /* SfChart's <ChartArea> already wraps its drawing surface; the slot
       just provides the container size. */
}

.enki-trace-skeleton {
    background: linear-gradient(
        90deg,
        var(--enki-surface) 0%,
        var(--enki-surface-2) 50%,
        var(--enki-surface) 100%);
    background-size: 200% 100%;
    animation: enki-trace-skeleton-pulse 1.6s var(--enki-ease) infinite;
    border-radius: var(--enki-radius);
}

@keyframes enki-trace-skeleton-pulse {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* Chip cluster — usually one chip, occasionally two when there's both
   a window + a warning. */
.enki-trace-chips {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
}

.enki-trace-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.15rem 0.6rem;
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    border-radius: 999px;
    border: 1px solid var(--enki-border);
    color: var(--enki-text-dim);
    background: var(--enki-surface-2);
    white-space: nowrap;
}

.enki-trace-chip::before {
    content: "";
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 999px;
    background: currentColor;
    flex-shrink: 0;
}

.enki-trace-chip-clean {
    color: var(--enki-text-dim);
}

.enki-trace-chip-trimmed {
    color: var(--enki-accent);
    border-color: var(--enki-border-hot);
    background: var(--enki-accent-faint);
}

.enki-trace-chip-warning {
    color: var(--enki-warn);
    border-color: rgba(255, 184, 74, 0.4);
    background: rgba(255, 184, 74, 0.08);
}

.enki-trace-chip-error {
    color: var(--enki-alert);
    border-color: rgba(255, 71, 87, 0.4);
    background: rgba(255, 71, 87, 0.08);
}

.enki-trace-chip-pending {
    color: var(--enki-text-muted);
}

.enki-trace-readout {
    text-align: right;
    font-size: 0.85rem;
    color: var(--enki-text-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.enki-trace-chevron {
    padding: 0.25rem 0.5rem;
    font-size: 0.9rem;
    color: var(--enki-text-dim);
}

.enki-trace-chevron:not([disabled]):hover {
    color: var(--enki-accent);
}

.enki-trace-chevron[disabled] {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ---------- Expanded view (phase 3) ---------- */

.enki-trace-expanded {
    padding: 0 1rem 1rem;
    border-top: 1px solid var(--enki-border-soft);
}

/* Focus layout: a single full-width chart showing one mode (default
   Detrend), switched via the mode segmented control below it. The old
   split-focus grid + secondary mini-charts were removed — operators read
   Detrend almost always, and Compare mode covers the cross-signal case. */
.enki-trace-primary-cell {
    background: var(--enki-surface-2);
    border: 1px solid var(--enki-border-soft);
    border-radius: var(--enki-radius);
    overflow: hidden;
    min-height: 420px;
    position: relative;
}

.enki-trace-primary-full {
    margin: 0.75rem 0 0;
    min-height: 460px;
}

.enki-trace-primary-chart {
    width: 100%;
    height: 100%;
    min-height: 420px;
}

.enki-trace-primary-full .enki-trace-primary-chart {
    min-height: 460px;
}

/* Mode segmented control — Trend / Detrend / Raw. */
.enki-trace-mode-switch {
    display: inline-flex;
    margin: 0.5rem 0 0.25rem;
    border: 1px solid var(--enki-border-soft);
    border-radius: var(--enki-radius);
    overflow: hidden;
}

.enki-trace-mode-btn {
    appearance: none;
    border: none;
    border-right: 1px solid var(--enki-border-soft);
    background: var(--enki-surface-2);
    color: var(--enki-text-dim);
    padding: 0.35rem 0.95rem;
    font: inherit;
    font-size: 0.8rem;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: background 150ms var(--enki-ease),
                color      150ms var(--enki-ease);
}

.enki-trace-mode-btn:last-child {
    border-right: none;
}

.enki-trace-mode-btn:hover {
    background: var(--enki-surface-3);
    color: var(--enki-accent);
}

.enki-trace-mode-btn.is-active {
    background: var(--enki-accent);
    color: var(--enki-bg-raised);
    font-weight: 600;
}

/* Live operator-window overlay — two red vertical lines tracking the slider
   thumbs over the focus chart (positioned client-side by traceWindowLines.js),
   the time-series twin of the frequency peak line. Hidden by default; shown +
   moved while editing, hidden once the window saves (yellow chart markers
   take over). The chart cell is already position:relative. */
.enki-trace-chart-wrap {
    position: relative;
}

.enki-trace-window-line {
    position: absolute;
    width: 2px;
    margin-left: -1px;
    background: var(--enki-alert);
    box-shadow: 0 0 6px rgba(255, 71, 87, 0.7);
    pointer-events: none;
    display: none;
    z-index: 6;
}

/* Toolbar row (channel toggles + compare-mode button) */
.enki-trace-toolbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 0.75rem 0 0.5rem;
    flex-wrap: wrap;
}

.enki-trace-toolbar-spacer {
    flex: 1;
}

/* Channel toggle chips */
.enki-trace-channel-toggles {
    display: flex;
    gap: 0.35rem;
    flex-wrap: wrap;
}

.enki-trace-channel-chip {
    padding: 0.2rem 0.6rem;
    font-size: 0.8rem;
    font-family: var(--enki-font-mono);
    letter-spacing: 0.02em;
    border-radius: var(--enki-radius);
    border: 1px solid var(--enki-border);
    background: var(--enki-surface);
    color: var(--enki-text-dim);
    cursor: pointer;
    transition: color 100ms, background 100ms, border-color 100ms;
}

.enki-trace-channel-chip-on {
    color: var(--enki-accent);
    border-color: var(--enki-border-hot);
    background: var(--enki-accent-faint);
}

.enki-trace-channel-chip-off {
    color: var(--enki-text-muted);
    background: var(--enki-surface);
    opacity: 0.6;
}

/* Colour swatch inside each chip — matches the channel's line on the chart,
   so the toggle row doubles as the colour legend. Dims with the chip when the
   channel is hidden (the -off opacity carries through). */
.enki-trace-channel-swatch {
    display: inline-block;
    width: 11px;
    height: 3px;
    margin-right: 5px;
    border-radius: 1px;
    vertical-align: middle;
}

/* Keeps a "Mag N" button + its axis chips (or the All-axis trio) together
   when the row wraps. */
.enki-trace-channel-group {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

/* Group toggle buttons (Mag N / All X·Y·Z) — heavier weight to read as
   group headers vs. individual channel chips. */
.enki-trace-channel-group-btn {
    font-weight: 600;
}

/* The group buttons' swatch is a multi-segment bar (a gradient with hard
   stops, set inline) of the colours they control, so it's wider than the
   single-channel swatch to keep the segments legible. */
.enki-trace-channel-swatch-multi {
    width: 20px;
    height: 4px;
}

/* "Show all" reset — an accent action (not a per-channel toggle); greys out
   when every channel is already visible (nothing to reset). */
.enki-trace-channel-showall {
    color: var(--enki-accent);
}

.enki-trace-channel-showall:disabled {
    color: var(--enki-text-muted);
    opacity: 0.45;
    cursor: default;
}

.enki-trace-channel-chip:hover {
    color: var(--enki-text);
    border-color: var(--enki-border-hot);
}

/* Window controls row */
.enki-trace-window-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.5rem 0;
    flex-wrap: wrap;
}

.enki-trace-window-input {
    width: 7rem;
    font-family: var(--enki-font-mono);
}

.enki-trace-window-hint {
    margin-left: 0.5rem;
    font-style: italic;
    opacity: 0.7;
}

/* =========================================================================
   Frequency stats heatmap — magnetometer rows × X/Y/Z columns, cells shaded
   by the selected metric (green→red for SNR/amp/noise, diverging for phase).
   Metric switch is a small segmented control above the grid.
   ========================================================================= */
.enki-stat-heatmaps {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    align-items: flex-start;
    margin-top: 0.75rem;
}

.enki-stat-heat-title {
    font-size: 0.8rem;
    font-family: var(--enki-font-mono);
    font-weight: 600;
    color: var(--enki-text-dim);
    margin-bottom: 0.35rem;
}

.enki-stat-heat-table {
    border-collapse: separate;
    border-spacing: 3px;
    font-size: 0.8rem;
}

.enki-stat-heat-table thead th {
    color: var(--enki-text-muted);
    font-weight: 600;
    text-align: center;
    padding: 0.1rem 0.4rem;
}

.enki-stat-heat-rowhead {
    text-align: right;
    color: var(--enki-text-dim);
    font-weight: 600;
    white-space: nowrap;
    padding-right: 0.5rem;
}

.enki-stat-heat-cell {
    text-align: center;
    padding: 0.4rem 0.7rem;
    border-radius: 4px;
    min-width: 70px;
    color: var(--enki-text);
    white-space: nowrap;
}

.enki-stat-heat-legend {
    margin-top: 0.5rem;
}

/* Spinner overlay that covers the primary chart while SfChart's JS
   side rebuilds on a mode swap (~700 ms for 12 channels × 2000 samples).
   Reuses the existing .enki-spinner so the rotating affordance matches
   the rest of the app. */
.enki-trace-spinner-overlay {
    position: absolute;
    inset: 0;
    background: rgba(7, 17, 31, 0.65);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    z-index: 10;
    pointer-events: none;
}

.enki-trace-spinner-label {
    font-size: 0.85rem;
    color: var(--enki-text-dim);
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* Inline warning / error banners inside the expanded inspector body.
   The peek-strip chip surfaces the existence of a warning; this is
   where the actual text lives. */
.enki-trace-banner {
    margin: 0.5rem 0;
    padding: 0.5rem 0.75rem;
    border-radius: var(--enki-radius);
    font-size: 0.85rem;
    line-height: 1.4;
}

.enki-trace-banner-warning {
    color: var(--enki-warn);
    border: 1px solid rgba(255, 184, 74, 0.4);
    background: rgba(255, 184, 74, 0.08);
}

.enki-trace-banner-error {
    color: var(--enki-alert);
    border: 1px solid rgba(255, 71, 87, 0.4);
    background: rgba(255, 71, 87, 0.08);
}

/* Operator-window range slider — two native thumbs on one rail with a
   filled band between them (replaces the old Syncfusion range navigator).
   Each input is pointer-transparent except its thumb, so the two thumbs
   are independently grabbable; the start/end min-gap is held in C#. Styled
   to match the frequency peak slider below. */
.enki-range-slider {
    margin: 0.5rem 0 0.2rem;
    padding: 0 0.25rem;
}

.enki-range-slider-readout {
    margin-bottom: 0.4rem;
}

.enki-range-slider-track {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.enki-range-slider-rail-wrap {
    position: relative;
    flex: 1 1 auto;
    height: 16px;
    display: flex;
    align-items: center;
}

.enki-range-slider-rail {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    height: 6px;
    border-radius: 3px;
    background: var(--enki-surface-3);
}

.enki-range-slider-fill {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 6px;
    border-radius: 3px;
    background: var(--enki-accent);
    opacity: 0.55;
    pointer-events: none;
}

.enki-range-slider-input {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 16px;
    margin: 0;
    -webkit-appearance: none;
    appearance: none;
    background: transparent;
    outline: none;
    pointer-events: none; /* only the thumbs capture pointer events */
}

.enki-range-slider-input::-webkit-slider-runnable-track {
    background: transparent;
    border: none;
    height: 16px;
}

.enki-range-slider-input::-moz-range-track {
    background: transparent;
    border: none;
    height: 16px;
}

.enki-range-slider-input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--enki-accent);
    border: 2px solid var(--enki-bg-raised);
    box-shadow: 0 0 5px rgba(0, 212, 255, 0.6);
    cursor: pointer;
    pointer-events: auto;
}

.enki-range-slider-input::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--enki-accent);
    border: 2px solid var(--enki-bg-raised);
    box-shadow: 0 0 5px rgba(0, 212, 255, 0.6);
    cursor: pointer;
    pointer-events: auto;
}

/* Frequency peak picker — a single-thumb slider over the [low, high]
   cutoff band. No PSD behind it; the chart above already shows the
   spectrum. */
.enki-peak-slider {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0.4rem 0 0.2rem;
    padding: 0 0.25rem;
}

.enki-peak-slider-end {
    font-size: 0.7rem;
    color: var(--enki-text-muted, #6f8aa8);
    white-space: nowrap;
    min-width: 3.4rem;
    text-align: center;
}

.enki-peak-slider-input {
    flex: 1 1 auto;
    -webkit-appearance: none;
    appearance: none;
    height: 6px;
    border-radius: 3px;
    background: var(--enki-surface-3);
    outline: none;
    cursor: pointer;
}

.enki-peak-slider-input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--enki-accent);
    border: 2px solid var(--enki-bg-raised);
    box-shadow: 0 0 5px rgba(0, 212, 255, 0.6);
    cursor: pointer;
}

.enki-peak-slider-input::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--enki-accent);
    border: 2px solid var(--enki-bg-raised);
    box-shadow: 0 0 5px rgba(0, 212, 255, 0.6);
    cursor: pointer;
}

.enki-peak-slider-input::-moz-range-track {
    height: 6px;
    border-radius: 3px;
    background: var(--enki-surface-3);
}

/* Chart wrapper — positioning context for the live red peak line. */
.enki-freq-chart-wrap {
    position: relative;
}

/* Live red peak line — a client-side overlay (JS-positioned) that tracks the
   slider thumb while the operator is picking a peak ("unlocked"). Hidden by
   default; shown + moved by freqPeakSlider.js, hidden again on lock. */
.enki-peak-live-line {
    position: absolute;
    width: 2px;
    margin-left: -1px;
    background: var(--enki-alert);
    box-shadow: 0 0 6px rgba(255, 71, 87, 0.7);
    pointer-events: none;
    display: none;
    z-index: 6;
}

/* "Find bandwidth" button sits inline with the peak input. */
.enki-trace-find-band {
    white-space: nowrap;
}

/* Controls hint turns alert-coloured while a peak pick is pending. */
.enki-trace-window-hint-unlocked {
    color: var(--enki-alert);
}

/* Actions row — reason input + Save / Reset buttons. Phase 5. */
.enki-trace-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.5rem 0;
    flex-wrap: wrap;
}

.enki-trace-reason-input {
    flex: 1;
    min-width: 240px;
    max-width: 540px;
}

.enki-trace-action-message {
    font-size: 0.8rem;
}

/* =============================================================================
   Generic Expandable Section (EnkiExpandableSection)
   Collapsible card mirroring the trace/frequency inspector peek-strip
   visual for sections that don't carry a sparkline preview. Used on
   ShotDetail for Gradient/Rotary config + result; the operator gets a
   one-line status at a glance and expands the section on demand.
   ============================================================================= */

.enki-expand-section {
    overflow: hidden;
}

.enki-expand-strip {
    display: grid;
    grid-template-columns: auto auto 1fr auto;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 1rem;
    min-height: 64px;
}

.enki-expand-strip-title {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding-right: 0.75rem;
    border-right: 1px solid var(--enki-border-soft);
    min-width: 110px;
}

.enki-expand-strip-title-name {
    font-size: 1.1rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--enki-accent);
    line-height: 1.15;
}

.enki-expand-strip-title-sub {
    font-size: 0.65rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
}

.enki-expand-strip-chips {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
}

/* Live-state chips inside the strip (RemoteOps presence / session).
   Same family as .enki-status-pill but sized for the collapsed strip;
   success = live truck / active session, warning = needs attention
   (awaiting consent, suspended link), muted = offline / unavailable. */
.enki-chip {
    display: inline-block;
    padding: 0.1rem 0.55rem;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    border-radius: 999px;
    border: 1px solid var(--enki-border);
    color: var(--enki-text-dim);
    white-space: nowrap;
}
.enki-chip-success {
    color: var(--enki-success, #6ee7b7);
    border-color: rgba(110, 231, 183, 0.4);
    background: rgba(110, 231, 183, 0.08);
}
.enki-chip-warning {
    color: var(--enki-warn, #ffb84a);
    border-color: rgba(255, 184, 74, 0.4);
    background: rgba(255, 184, 74, 0.08);
}
.enki-chip-muted {
    color: var(--enki-text-muted);
    border-color: var(--enki-border);
}
.enki-chip-danger {
    color: var(--enki-alert, #ff6b6b);
    border-color: rgba(255, 71, 87, 0.45);
    background: rgba(255, 71, 87, 0.1);
}

.enki-expand-strip-readout {
    text-align: right;
    font-size: 0.85rem;
    color: var(--enki-text-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.enki-expand-strip-chevron {
    padding: 0.25rem 0.5rem;
    font-size: 0.9rem;
    color: var(--enki-text-dim);
}

.enki-expand-strip-chevron:not([disabled]):hover {
    color: var(--enki-accent);
}

.enki-expand-section-body {
    padding: 0 1rem 1rem;
    border-top: 1px solid var(--enki-border-soft);
}

/* ---- Site-inventory expandable-bar body ----------------------------------
   Compact kind-grouped listing used inside JobInventoryCard. Designed to
   read as a quiet bulleted catalogue rather than six full data-tables —
   the previous version drowned 6-12 items in tables-with-headers. */

.enki-inv-group {
    margin-top: 1rem;
}

.enki-inv-group:first-child {
    margin-top: 0.5rem;
}

.enki-inv-group-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    border-bottom: 1px solid var(--enki-border-soft);
    padding-bottom: 0.2rem;
    margin-bottom: 0.3rem;
}

.enki-inv-group-label {
    font-size: 0.7rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    font-weight: 600;
}

.enki-inv-group-count {
    margin-left: 0.4rem;
    color: var(--enki-text-dim);
    font-weight: 400;
}

.enki-inv-add {
    font-size: 0.78rem;
    padding: 0 0.2rem;
}

.enki-inv-empty {
    font-size: 0.8rem;
    color: var(--enki-text-dim);
    font-style: italic;
    padding: 0.2rem 0 0.4rem;
}

.enki-inv-table {
    width: 100%;
    border-collapse: collapse;
}

.enki-inv-table td {
    padding: 0.2rem 0.5rem;
    border: 0;
    vertical-align: middle;
}

.enki-inv-table td:first-child {
    padding-left: 0;
}

.enki-inv-table td:last-child {
    padding-right: 0;
}

.enki-inv-serial {
    width: 10rem;
    color: var(--enki-text);
}

.enki-inv-summary {
    color: var(--enki-text-dim);
    font-size: 0.88rem;
}

.enki-inv-status,
.enki-inv-notes {
    color: var(--enki-text-dim);
    font-size: 0.85rem;
}

.enki-inv-action {
    width: 2rem;
    text-align: right;
}

.enki-inv-remove {
    font-size: 1.1rem;
    line-height: 1;
    padding: 0 0.3rem;
    color: var(--enki-text-dim);
}

.enki-inv-remove:not([disabled]):hover {
    color: var(--enki-danger, #d04040);
}

.enki-inv-picker {
    margin: 0.5rem 0 0.75rem;
    padding: 0.5rem 0.75rem;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid var(--enki-border-soft);
    border-radius: 4px;
}

.enki-inv-picker-actions {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

/* =============================================================================
   Remote Warrior Console (SDI-ENG-PLAN-005-P4) — the WarriorPage mirror.
   Three columns (wider control, narrower telemetry, chat rail; stacking under 1200px), the
   fixed-height quote/InfoBar header with THE one connection pill, gentle
   staleness greying (values persist, nothing spins), per-control pending
   narration, and the danger CONFIRM face for the arm/confirm interlock.
   ============================================================================= */

.enki-console-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: 56px;            /* fixed like WarriorPage row 0 — no layout jump */
    padding: 0.25rem 0.75rem;
    margin-bottom: 0.6rem;
    border: 1px solid var(--enki-border-soft);
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.02);
}
.enki-console-quote-zone { flex: 1; min-width: 0; }
.enki-console-quote {
    font-style: italic;
    color: var(--enki-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The mirrored page-status InfoBar — severity colors match the truck's
   WinUI InfoBar kinds (informational / success / warning / error). */
.enki-console-infobar {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.35rem 0.6rem;
    border-radius: 4px;
    border: 1px solid var(--enki-border);
}
.enki-console-infobar-info    { border-color: var(--enki-accent-deep); background: var(--enki-accent-faint); }
.enki-console-infobar-success { border-color: rgba(110, 231, 183, 0.4); background: rgba(110, 231, 183, 0.08); color: var(--enki-success, #6ee7b7); }
.enki-console-infobar-warning { border-color: rgba(255, 184, 74, 0.4);  background: rgba(255, 184, 74, 0.08);  color: var(--enki-warn, #ffb84a); }
.enki-console-infobar-error   { border-color: rgba(208, 64, 64, 0.5);   background: rgba(208, 64, 64, 0.10);   color: var(--enki-danger, #ff7b7b); }
.enki-console-infobar-close {
    background: none;
    border: none;
    color: inherit;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 0.2rem;
}

/* THE one connection pill (§5.6) — the only element that talks about
   the link. */
.enki-console-pill {
    display: inline-block;
    padding: 0.15rem 0.7rem;
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    border-radius: 999px;
    border: 1px solid var(--enki-border);
    font-family: var(--enki-font-mono);
    white-space: nowrap;
}
.enki-console-pill-live    { color: var(--enki-success, #6ee7b7); border-color: rgba(110, 231, 183, 0.4); background: rgba(110, 231, 183, 0.08); }
.enki-console-pill-warn    { color: var(--enki-warn, #ffb84a);    border-color: rgba(255, 184, 74, 0.4);  background: rgba(255, 184, 74, 0.08); }
.enki-console-pill-offline { color: var(--enki-danger, #ff7b7b);  border-color: rgba(208, 64, 64, 0.5);   background: rgba(208, 64, 64, 0.10); }
.enki-console-pill-muted   { color: var(--enki-text-muted); }

/* Session/control strip under the header. */
.enki-console-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.75rem;
}

/* The console renders three columns: a WIDER control column (Tool / Frame /
   Commands / File — wide selects, dropdowns, the capture path), a NARROWER
   telemetry column (label/value tiles that wrap happily), and the docked chat
   rail. ~1.3 : 0.75 : 1 keeps the control:telemetry ratio close to the truck's
   old 9.5/5.5 Telemetry tab while giving chat a full peer column. Collapses to
   one stacked column below 1200px (WarriorPage's AdaptiveTrigger point).
   minmax(0,…) per track so a long unbroken card line can't inflate a column. */
.enki-console-with-chat {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.75fr);
    gap: 0.6rem;
    align-items: start;
}
@media (max-width: 1199px) {
    .enki-console-with-chat { grid-template-columns: 1fr; }
}
/* Data columns sit at their NATURAL height, cards packed top-down with one
   consistent gap — no space-between distribution, so no dead air between
   cards. */
.enki-console-col {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    min-width: 0;
}
/* The chat alone fills to the height of the tallest column. align-self:stretch
   overrides the grid's start-alignment so the rail stretches to the row height,
   and the scrollback (flex-basis 0) fills that height — while its MESSAGE COUNT
   never drives the row taller than the data columns (basis 0 + a small min-
   height floor cap its natural contribution; overflow scrolls). Scoped to the
   console rail; the compact RemoteOpsPanel keeps its bounded list. */
.enki-console-chat-rail {
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-self: stretch;
}
.enki-console-chat-rail .enki-chat-pane { flex: 1; min-height: 0; }
.enki-console-chat-rail .enki-chat-list { flex: 1 1 0; max-height: none; min-height: 8rem; }

/* Remote chat (ChatPane.razor) — terminal/HUD treatment on the console's
   dark+cyan+mono language: mono line-ids/timestamps, accent-tinted own lines
   (the cyan read-tick = everyone saw it), HUD day rules + system lines, inline
   attachment cards, a terminal composer. Boxed in both placements; compact
   trims the header for the docked/pop-out. */
.enki-chat-pane {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--enki-border, rgba(255, 255, 255, 0.12));
    border-radius: var(--enki-radius-lg);
    padding: 0.6rem 0.75rem;
    background: var(--enki-card-bg, rgba(255, 255, 255, 0.03));
}
.enki-chat-pane-compact { border: none; padding: 0; background: transparent; }
.enki-chat-pane-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
}
.enki-chat-pane-title {
    font-family: var(--enki-font-mono);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--enki-accent);
    font-size: 0.9rem;
}
.enki-chat-pane-compact .enki-chat-pane-title { display: none; }

/* Header export-action group: pushed to the right of the header row. */
.enki-chat-export {
    margin-left: auto;
    display: inline-flex;
    gap: 0.35rem;
}

/* Client search/filter row over the loaded scrollback. */
.enki-chat-search { margin: 0.25rem 0; }
.enki-chat-search input { width: 100%; }

/* Roster / presence strip: office participant chips + the truck chip with a
   glowing presence dot (reusing the console .enki-console-dot idiom). */
.enki-chat-roster {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem;
    margin: 0.25rem 0;
}
.enki-chat-roster .enki-chip { display: inline-flex; align-items: center; gap: 0.35rem; }
.enki-chat-roster .enki-console-dot { width: 8px; height: 8px; }

/* Virtualized scrollback list (id=_listElementId; geometry read by the
   enkiChatScroll JS module). Compact placement trims the height. */
.enki-chat-list {
    max-height: 460px;
    min-height: 8rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-gutter: stable;
    scrollbar-width: thin;
    scrollbar-color: var(--enki-border) transparent;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 0.25rem 0.5rem;
}
.enki-chat-list-compact { max-height: 320px; min-height: 6rem; }
.enki-chat-list::-webkit-scrollbar { width: 8px; }
.enki-chat-list::-webkit-scrollbar-thumb { background: var(--enki-border); border-radius: 4px; }
.enki-chat-list::-webkit-scrollbar-track { background: transparent; }

/* Day separator — a HUD hairline rule with a centered mono label. */
.enki-chat-day-separator {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0.5rem 0 0.3rem;
}
.enki-chat-day-separator::before,
.enki-chat-day-separator::after { content: ""; flex: 1; height: 1px; background: var(--enki-border); }
.enki-chat-day-separator span {
    flex: none;
    padding: 0;
    font-family: var(--enki-font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
}

/* Server-authored system event line — centered, mono, with a ◇ marker. */
.enki-chat-system {
    align-self: center;
    text-align: center;
    font-style: normal;
    font-family: var(--enki-font-mono);
    font-size: 0.68rem;
    letter-spacing: 0.03em;
    color: var(--enki-text-muted);
    padding: 0.1rem 0.7rem;
    border: 1px dashed var(--enki-border-soft);
    border-radius: 999px;
}
.enki-chat-system::before { content: "\25C7 "; color: var(--enki-accent-deep); }

/* Message bubbles (chat-receipts-plan §6): MY lines right, everyone else's
   (the field rig OR another office user) left — alignment + chip + name
   differentiate, never colour alone. The legacy office/field classes are kept
   for any other consumer. */
.enki-chat-msg-office,
.enki-chat-msg-field,
.enki-chat-msg-mine,
.enki-chat-msg-others {
    padding: 0.4rem 0.6rem;
    max-width: min(85%, 32rem);
    border-radius: var(--enki-radius-lg);
}
.enki-chat-msg-office,
.enki-chat-msg-mine   { align-self: flex-end; }
.enki-chat-msg-field,
.enki-chat-msg-others { align-self: flex-start; }
/* MY lines get the accent-tint HUD read (the .enki-card-hot recipe); everyone
   else's stay the plain surface card. Alignment + chip + name remain the
   non-colour signal (a11y). */
.enki-chat-msg-mine {
    border-color: var(--enki-border-hot);
    background:
        linear-gradient(180deg, rgba(0, 212, 255, 0.06), rgba(0, 212, 255, 0.02)),
        var(--enki-surface-2);
    box-shadow: inset 0 0 0 1px var(--enki-accent-faint), 0 0 18px -8px var(--enki-accent-glow);
}

/* Bubble header row: sender group on the left, receipt time on the right. */
.enki-chat-msg-header {
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
    align-items: baseline;
}
.enki-chat-msg-sender {
    display: inline-flex;
    gap: 0.35rem;
    align-items: baseline;
}
.enki-chat-msg-chip { font-size: 0.56rem; }
.enki-chat-msg-retracted { font-style: italic; }
.enki-chat-msg-body {
    white-space: pre-wrap;
    word-break: break-word;
}

/* Receipt time + line-id + tick cluster — mono, tabular, terminal. */
.enki-chat-msg-meta {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    white-space: nowrap;
    font-family: var(--enki-font-mono);
    font-variant-numeric: tabular-nums;
}
.enki-chat-msg-id   { font-size: 0.6rem;  color: var(--enki-text-muted); }
.enki-chat-msg-time { font-size: 0.66rem; color: var(--enki-text-dim); }
/* Per-message receipt tick (chat-receipts-plan §6): muted for Sent, dims for
   Delivered, goes accent (with a faint glow) once every current recipient has
   read. Tight letter-spacing so the double-tick reads as one glyph. */
.enki-chat-tick { font-size: 0.9em; letter-spacing: -0.06em; }
.enki-chat-tick-delivered { color: var(--enki-text-dim); }
.enki-chat-tick-read { color: var(--enki-accent); text-shadow: 0 0 6px var(--enki-accent-glow); }

/* Attachment cards under a message. */
.enki-chat-attachments {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-top: 0.4rem;
}
.enki-chat-attachment-figure { margin: 0; }
.enki-chat-attachment-img {
    max-width: 100%;
    max-height: 300px;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    display: block;
}
.enki-chat-attachment-figure figcaption {
    font-family: var(--enki-font-mono);
    font-size: 0.62rem;
    color: var(--enki-text-muted);
    margin-top: 0.2rem;
}
/* file card: [ext badge] · name/size · Save */
.enki-chat-att-file {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.5rem;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    background: var(--enki-surface-3);
}
.enki-chat-att-badge {
    flex: none;
    font-family: var(--enki-font-mono);
    font-size: 0.56rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    color: var(--enki-accent-dim);
    border: 1px solid var(--enki-accent-deep);
    background: var(--enki-accent-faint);
    border-radius: var(--enki-radius);
    padding: 0.35rem 0.45rem;
}
.enki-chat-att-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.enki-chat-att-name { font-family: var(--enki-font-mono); font-size: 0.74rem; color: var(--enki-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.enki-chat-att-size { font-family: var(--enki-font-mono); font-size: 0.6rem; color: var(--enki-text-muted); }
.enki-chat-att-dl {
    flex: none;
    font-family: var(--enki-font-mono);
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--enki-accent-dim);
    background: transparent;
    border: 1px solid var(--enki-accent-deep);
    border-radius: var(--enki-radius);
    padding: 0.35rem 0.6rem;
    cursor: pointer;
}
.enki-chat-att-dl:hover { background: var(--enki-accent-faint); }
/* withheld / scanning / blocked card */
.enki-chat-att-withheld {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.5rem;
    border: 1px solid rgba(255, 184, 74, 0.35);
    border-radius: var(--enki-radius);
    background: rgba(255, 184, 74, 0.05);
}
.enki-chat-att-withheld .enki-chat-att-name { color: var(--enki-text-dim); flex: 1; }

/* "Seen by" high-water marker on the last rendered message. */
.enki-chat-seen-by {
    text-align: right;
    padding-right: 0.4rem;
}

/* "New messages" pin: only shows while scrolled up. */
.enki-chat-new-messages-pin {
    align-self: center;
    margin: 0.2rem 0;
}

/* Typing line — mono, holds its slot, with a terminal block caret. */
.enki-chat-typing {
    min-height: 1.2rem;
    font-style: normal;
    font-family: var(--enki-font-mono);
    font-size: 0.66rem;
    letter-spacing: 0.08em;
    color: var(--enki-text-dim);
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.enki-chat-caret {
    display: inline-block;
    width: 0.5em;
    height: 1em;
    background: var(--enki-accent);
    transform: translateY(0.12em);
}
@media (prefers-reduced-motion: no-preference) {
    .enki-chat-caret { animation: enki-chat-blink 1.05s steps(1) infinite; }
}
@keyframes enki-chat-blink { 50% { opacity: 0; } }

/* Composer — a terminal input box: > prompt · textarea · attach · send. */
.enki-chat-composer { display: flex; flex-direction: column; gap: 0.4rem; margin-top: 0.3rem; }
.enki-chat-cbox {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    background: var(--enki-surface);
    padding: 0.45rem 0.5rem 0.45rem 0.6rem;
    transition: border-color 0.15s var(--enki-ease), box-shadow 0.15s var(--enki-ease);
}
.enki-chat-cbox:focus-within { border-color: var(--enki-accent); box-shadow: 0 0 0 3px var(--enki-accent-glow); }
/* The textarea is multi-row (rows="2"), so its text sits on the FIRST line while
   the row bottom-aligns the buttons. The prompt therefore top-aligns and shares the
   textarea's first-line geometry (font-size, line-height, top padding) so the > lands
   on the line you type on — not a row below it. */
.enki-chat-prompt {
    align-self: flex-start;
    font-family: var(--enki-font-mono);
    color: var(--enki-accent);
    font-size: 0.95rem;
    line-height: 1.5;
    padding-top: 0.15rem;
    user-select: none;
}
.enki-chat-composer-input {
    flex: 1;
    resize: none;
    /* Start at one line (rows="1") and grow with content up to max-height, then
       scroll — no JS autosize. Browsers without field-sizing fall back to the
       rows="1" single line (scroll on overflow), which is fine. */
    field-sizing: content;
    min-height: 1.5rem;
    max-height: 8rem;
    background: transparent;
    border: 0;
    color: var(--enki-text);
    font-family: var(--enki-font-sans);
    font-size: 0.95rem;
    line-height: 1.5;
    padding: 0.15rem 0;
}
.enki-chat-composer-input:focus { outline: none; }
.enki-chat-composer-input::placeholder { color: var(--enki-text-muted); }
.enki-chat-send { flex: none; }

/* Attach control — a compact icon button wrapping a hidden InputFile. */
.enki-chat-attach-label {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    color: var(--enki-text-dim);
    cursor: pointer;
    font-size: 1rem;
    transition: color 0.15s, border-color 0.15s;
}
.enki-chat-attach-label:hover { color: var(--enki-accent-dim); border-color: var(--enki-accent-deep); }
.enki-chat-attach-label.disabled { cursor: default; opacity: 0.6; }
.enki-chat-file-input { display: none; }

/* Submit-side attach error banner: trims the .alert default top margin. */
/* Density toggle (header): Bubbles | Transcript segmented control. */
.enki-chat-density { margin-left: auto; display: inline-flex; border: 1px solid var(--enki-border); border-radius: var(--enki-radius); overflow: hidden; }
.enki-chat-density-btn {
    appearance: none; background: transparent; border: 0; cursor: pointer;
    font-family: var(--enki-font-mono); font-size: 0.56rem; font-weight: 600;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--enki-text-dim);
    padding: 3px 9px;
}
.enki-chat-density-btn + .enki-chat-density-btn { border-left: 1px solid var(--enki-border); }
.enki-chat-density-btn.on { background: var(--enki-accent-faint); color: var(--enki-accent-dim); box-shadow: inset 0 -2px 0 var(--enki-accent); }

/* Dense "transcript" density — one mono log row per line (time · #id · chip · who · body · tick). */
.enki-chat-row {
    display: grid;
    grid-template-columns: auto auto auto 1fr auto;
    align-items: baseline;
    gap: 0.5rem;
    padding: 1px 0.35rem;
    border-left: 2px solid transparent;
    font-family: var(--enki-font-mono);
    font-size: 0.78rem;
    line-height: 1.4;
}
.enki-chat-row:hover { background: var(--enki-surface-2); }
.enki-chat-row-mine { border-left-color: var(--enki-border-hot); }
.enki-chat-row-time { color: var(--enki-text-dim); font-variant-numeric: tabular-nums; }
.enki-chat-row-id { color: var(--enki-text-muted); font-size: 0.7rem; }
.enki-chat-row-body { color: var(--enki-text); min-width: 0; word-break: break-word; }
.enki-chat-row-who { color: var(--enki-text-muted); margin-right: 0.4rem; }
.enki-chat-row .enki-chat-msg-chip { font-size: 0.52rem; }
.enki-chat-row .enki-chat-tick { justify-self: end; }
.enki-chat-row-clip {
    display: inline-flex; align-items: center; gap: 0.25rem;
    margin: 0 0.15rem; padding: 0 0.4rem;
    font-family: var(--enki-font-mono); font-size: 0.7rem;
    color: var(--enki-accent-dim); background: var(--enki-surface-3);
    border: 1px solid var(--enki-border); border-radius: 999px; cursor: pointer;
}
.enki-chat-row-clip:hover { border-color: var(--enki-accent-deep); }
.enki-chat-row-clip.muted { color: var(--enki-text-muted); cursor: default; }

.enki-chat-attach-error { margin-top: 0.25rem; }

/* Cards: the truck's centered semibold titles. */
.enki-console-card { position: relative; padding: 0.6rem 0.7rem; transition: opacity 0.6s ease; }
.enki-console-card-title {
    text-align: center;
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: 0.35rem;
}
/* Success pill tucked into a card's top-left corner (e.g. "written to tool")
   — absolute so it rides the centered title's row instead of adding a row. */
.enki-console-card-badge {
    position: absolute;
    top: 0.5rem;
    left: 0.7rem;
    z-index: 1;
}

/* §5.6: tile groups grey GENTLY past 5 s without a tick — values
   persist; the pill carries the age. */
.enki-console-stale { opacity: 0.55; }

/* Control rows + labeled fields. */
.enki-console-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin: 0.25rem 0;
}
/* Centered action row — e.g. Frame Config's Read / Write / Revert buttons
   beneath the dropdowns. */
.enki-console-row-center { justify-content: center; }
.enki-console-label { color: var(--enki-text-dim); }
.enki-console-field {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
}
.enki-console-field-label {
    font-size: 0.7rem;
    letter-spacing: 0.05em;
    color: var(--enki-text-muted);
}
.enki-console-select { min-width: 14rem; }
/* Gyro numeric fields never exceed ~6 digits (e.g. -0.0148); size the box to
   fit that plus the number spinner rather than leaving a wide empty field. */
.enki-console-number { max-width: 5.5rem; }
.enki-console-file-input { max-width: 16rem; }
.enki-console-truncate {
    max-width: 28rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.enki-console-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    cursor: pointer;
    margin: 0;
}

/* Read-only (viewer) value lists. */
.enki-console-readout {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.15rem 0.9rem;
    margin: 0.25rem 0 0;
}
.enki-console-readout dt { color: var(--enki-text-muted); font-size: 0.8rem; margin: 0; }
.enki-console-readout dd { margin: 0; }

/* Per-control pending narration + inline outcome notes (§5.2). */
.enki-console-pending {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    margin: 0.2rem 0;
}
.enki-console-pending-text {
    font-size: 0.8rem;
    color: var(--enki-accent-dim);
    font-family: var(--enki-font-mono);
}
.enki-console-note { font-size: 0.8rem; margin: 0.2rem 0; }
.enki-console-note-ok      { color: var(--enki-success, #6ee7b7); }
.enki-console-note-failure { color: var(--enki-warn, #ffb84a); }

/* Determinate progress meter — used ONLY when real percent exists. */
.enki-console-meter {
    width: 12rem;
    height: 4px;
    border-radius: 2px;
    background: var(--enki-border-soft);
    overflow: hidden;
}
.enki-console-meter-wide { flex: 1; min-width: 8rem; }
.enki-console-meter-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--enki-accent-deep), var(--enki-accent));
    transition: width 0.4s ease;
}

/* Counter tiles (Statistics / Current Operation / Panel Status). */
.enki-console-counters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    margin: 0.25rem 0;
}
.enki-console-counter {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 0.1rem;
}
/* Statistics counters: only NON-ZERO counters render (the truck's hide-zeros rule), so the
   set grows from a couple to ~18 over the first seconds of a session. Reserve ~two rows and
   top-align so the card holds a steady height instead of jumping taller row by row with use. */
.enki-console-wrap {
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 0.4rem 1.1rem;
    min-height: 3.5rem;
}

/* Panel/Tool availability dots. */
.enki-console-dot-pair { display: inline-flex; align-items: center; gap: 0.4rem; }
.enki-console-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    display: inline-block;
}
.enki-console-dot-on  { background: var(--enki-success, #6ee7b7); box-shadow: 0 0 6px rgba(110, 231, 183, 0.6); }
.enki-console-dot-off { background: var(--enki-danger, #d04040); }

/* §4.2: the arm banner + the CONFIRM face. */
.enki-console-arm-banner {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.7rem;
    margin-bottom: 0.4rem;
    border: 1px solid rgba(255, 184, 74, 0.5);
    border-radius: 4px;
    background: rgba(255, 184, 74, 0.10);
    color: var(--enki-warn, #ffb84a);
}
.enki-console-arm-pending {
    font-size: 0.85rem;
    color: var(--enki-warn, #ffb84a);
    font-family: var(--enki-font-mono);
}
.enki-console-confirm {
    font-weight: 700;
    letter-spacing: 0.03em;
    animation: enki-console-confirm-pulse 1.2s ease-in-out infinite;
}
@keyframes enki-console-confirm-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(208, 64, 64, 0.45); }
    50%      { box-shadow: 0 0 0 4px rgba(208, 64, 64, 0.15); }
}

/* =============================================================================
   Licensing — generate wizard + grouped feature flags.
   Shared by LicenseCreate (the 4-step generate wizard) and LicenseDetail
   (the read-only view) so the two never drift. Kept in the global theme
   (not an inline <style>) because a component's inline styles only load
   when that component renders — LicenseDetail must not depend on
   LicenseCreate having rendered first.
   ============================================================================= */

.lic-step { display: flex; flex-direction: column; }

/* Wizard footer: Cancel sits far-left, Back / Next (or Generate) right. */
.lic-wizard-footer { justify-content: space-between; align-items: center; }
.lic-wizard-nav { display: flex; gap: 0.75rem; }

/* Feature groups — an uppercase rail title over a two-column grid of
   feature rows. Each row is a toggle (create) or an on/off pill (detail). */
.lic-feature-group { margin-top: 1.1rem; }
.lic-feature-group-title {
    font-size: 0.7rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--enki-text-muted);
    font-weight: 500;
    padding-bottom: 0.4rem;
    margin-bottom: 0.6rem;
    border-bottom: 1px solid var(--enki-border-soft);
}
.lic-feature-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem 1rem;
}
.lic-feature {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.5rem 0.7rem;
    cursor: pointer;
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    transition: border-color 0.12s var(--enki-ease), background 0.12s var(--enki-ease);
}
.lic-feature:hover {
    border-color: var(--enki-border-hot);
    background: var(--enki-surface-2);
}
.lic-feature .enki-toggle { margin-top: 0.15rem; }
.lic-feature-text { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.lic-feature-label { font-size: 0.9rem; color: var(--enki-text); }
.lic-feature-desc { font-size: 0.75rem; color: var(--enki-text-muted); line-height: 1.35; }

/* Read-only variant (LicenseDetail): label/description on the left, an
   on/off status pill on the right; no hover affordance. */
.lic-feature-readonly {
    align-items: center;
    justify-content: space-between;
    cursor: default;
}
.lic-feature-readonly:hover {
    border-color: var(--enki-border);
    background: var(--enki-surface);
}

/* Tool picker (wizard step 2) — the bare .enki-table dressed up into a
   framed data panel: rounded outer border, a lifted header band, cyan
   accent checkboxes, a generation chip, and a left accent rail on the
   selected row (on top of the .enki-table .is-selected tint). Scoped to
   .lic-tool-table so none of this leaks to the other .enki-table users. */
.lic-tool-table-wrap {
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    overflow: hidden;            /* clip header band + selected rail to the radius */
    margin: 0.5rem 0 0.25rem;
}
.lic-tool-table { margin: 0; }
.lic-tool-table thead th { background: var(--enki-bg-raised); }
.lic-tool-table input[type="checkbox"] {
    accent-color: var(--enki-accent);
    width: 16px;
    height: 16px;
    cursor: pointer;
    vertical-align: middle;
}
.lic-tool-table tbody tr.is-selected td:first-child {
    box-shadow: inset 2px 0 0 var(--enki-accent);
}
/* Serial is the row's hero (full-strength text); the cal date sits one
   step back so the eye lands on the serial first. */
.lic-tool-serial { color: var(--enki-text); }
.lic-tool-cal { color: var(--enki-text-dim); }
.lic-num { text-align: right; font-variant-numeric: tabular-nums; }

.lic-gen-badge {
    display: inline-block;
    padding: 0.05rem 0.5rem;
    font-size: 0.7rem;
    font-family: var(--enki-font-mono);
    letter-spacing: 0.04em;
    color: var(--enki-accent);
    border: 1px solid var(--enki-border-hot);
    border-radius: 999px;
    background: var(--enki-accent-faint);
}

/* Review manifest (wizard step 4). */
.lic-review-section { margin-top: 1.25rem; }
.lic-chip-row { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.lic-review-group { margin-bottom: 0.6rem; }
.lic-review-group-label {
    display: block;
    font-size: 0.72rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--enki-text-dim);
    margin-bottom: 0.3rem;
}

@media (max-width: 640px) {
    .lic-feature-list { grid-template-columns: 1fr; }
}

/* ── Notification bell (SDI-ENG-PLAN-005-P7 §10.1) ────────────────────────
   Topbar chrome beside LoginDisplay: a bell button with an unread badge and a
   dropdown feed. Plain HTML/CSS overlay (the EnkiConfirmDialog idiom — no
   Syncfusion SfDialog); the backdrop closes on outside click without JS. */
.enki-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.enki-bell-button {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    color: var(--enki-text-dim);
    cursor: pointer;
    transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
.enki-bell-button:hover,
.enki-bell.is-open .enki-bell-button {
    color: var(--enki-accent);
    border-color: var(--enki-border-hot);
    background: var(--enki-accent-faint);
}
.enki-bell-icon { width: 1.15rem; height: 1.15rem; }

.enki-bell-badge {
    position: absolute;
    top: -3px;
    right: -3px;
    min-width: 1.05rem;
    height: 1.05rem;
    padding: 0 0.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.66rem;
    font-weight: 700;
    line-height: 1;
    color: var(--enki-text-inv);
    background: var(--enki-alert);   /* defined status token, not an undefined --enki-danger + baked hex */
    border-radius: 999px;
    box-shadow: 0 0 0 2px var(--enki-surface);
}

.enki-bell-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: transparent;
}

.enki-bell-panel {
    position: absolute;
    top: calc(100% + 0.45rem);
    right: 0;
    z-index: 1001;
    width: 22rem;
    max-width: 90vw;
    max-height: 28rem;
    display: flex;
    flex-direction: column;
    background: var(--enki-surface-2);
    border: 1px solid var(--enki-border);
    border-radius: 10px;
    box-shadow: 0 12px 30px -8px rgba(0, 0, 0, 0.55);
    overflow: hidden;
}

.enki-bell-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.6rem 0.8rem;
    border-bottom: 1px solid var(--enki-border-soft);
}
.enki-bell-panel-title {
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--enki-text);
}
.enki-bell-mark-all {
    background: transparent;
    border: none;
    padding: 0;
    font-size: 0.72rem;
    color: var(--enki-accent);
    cursor: pointer;
}
.enki-bell-mark-all:hover { color: var(--enki-accent-dim); text-decoration: underline; }

.enki-bell-empty {
    padding: 1.5rem 0.8rem;
    text-align: center;
    font-size: 0.8rem;
    color: var(--enki-text-muted);
}

.enki-bell-list {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow-y: auto;
}

.enki-bell-item { border-bottom: 1px solid var(--enki-border-soft); }
.enki-bell-item:last-child { border-bottom: none; }

.enki-bell-item-button {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    width: 100%;
    text-align: left;
    padding: 0.6rem 0.8rem;
    background: transparent;
    border: none;
    border-left: 3px solid transparent;
    cursor: pointer;
}
.enki-bell-item.is-unread .enki-bell-item-button { border-left-color: var(--enki-accent); background: var(--enki-accent-faint); }
.enki-bell-item-button:hover { background: var(--enki-surface-3); }

.enki-bell-item-title {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--enki-text);
}
.enki-bell-item.is-read .enki-bell-item-title { font-weight: 500; color: var(--enki-text-dim); }
.enki-bell-item-preview {
    font-size: 0.74rem;
    color: var(--enki-text-dim);
    white-space: pre-wrap;
    word-break: break-word;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.enki-bell-item-time {
    font-size: 0.68rem;
    color: var(--enki-text-muted);
}

/* ── Notification preferences table (P7 §10.1, AccountSettings) ──────────── */
.enki-notify-prefs {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
}
.enki-notify-prefs th {
    text-align: left;
    padding: 0.5rem 0.6rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--enki-text-dim);
    border-bottom: 1px solid var(--enki-border-soft);
}
.enki-notify-prefs td {
    padding: 0.6rem;
    border-bottom: 1px solid var(--enki-border-soft);
    vertical-align: top;
}
.enki-notify-prefs tr:last-child td { border-bottom: none; }
.enki-notify-pref-name { font-weight: 600; color: var(--enki-text); }
.enki-notify-pref-hint { font-size: 0.74rem; color: var(--enki-text-muted); margin-top: 0.15rem; }

/* =============================================================================
   Dockable panels (EnkiDock) — Components/Shared/Dock/EnkiDockPanel.
   Docked and Floating are the SAME element, class-swapped. enki-dock.js owns the
   floating element's position/size; the rules below are the pre-attach defaults +
   shared chrome. Float band 50-999 (below the modal + loading bands).
   ============================================================================= */
:root {
    --enki-dock-z: 500;
    --enki-dock-ease: 150ms cubic-bezier(.2, .6, .2, 1);
    --enki-dock-gap: 0.75rem;
}

.enki-dock { display: flex; flex-direction: column; }

.enki-dock-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--enki-surface-3);
}
.enki-dock-head-titles { display: flex; flex-direction: column; min-width: 0; }
.enki-dock-title {
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--enki-accent);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.enki-dock-sub { font-size: .82rem; opacity: .7; text-transform: uppercase; }
.enki-dock-head-chips { display: flex; gap: 0.35rem; margin-left: auto; align-items: center; }
.enki-dock-actions { display: flex; gap: 0.25rem; margin-left: auto; }
.enki-dock-head-chips + .enki-dock-actions { margin-left: 0.5rem; }
.enki-dock-btn {
    background: transparent;
    border: 1px solid var(--enki-surface-3);
    color: inherit;
    border-radius: var(--enki-radius-lg);
    padding: 0.1rem 0.4rem;
    line-height: 1.2;
    cursor: pointer;
    transition: background var(--enki-dock-ease), border-color var(--enki-dock-ease);
}
.enki-dock-btn:hover { background: var(--enki-surface-2); border-color: var(--enki-accent); }
.enki-dock-body { flex: 1 1 auto; min-height: 0; }

/* Floating = position:fixed reposition of the SAME instance. enki-dock.js sets
   top/left/width/height inline on attach; these are the pre-attach defaults. */
.enki-dock--floating {
    position: fixed;
    top: calc(var(--enki-topbar-h) + var(--enki-dock-gap));
    left: 180px;
    width: 520px;
    height: 440px;
    z-index: var(--enki-dock-z);
    min-width: 320px;
    min-height: 200px;
    max-width: 96vw;
    max-height: calc(100vh - var(--enki-topbar-h) - 2 * var(--enki-dock-gap));
    resize: both;
    overflow: hidden;
    box-shadow: 0 8px 28px rgba(0, 0, 0, .45);
    transition: box-shadow var(--enki-dock-ease);
}
.enki-dock--floating .enki-dock-body { overflow: auto; }
.enki-dock--floating .enki-dock-head { cursor: move; user-select: none; }

/* Popped-out placeholder shown in the source circuit while a child window hosts
   the live instance. */
.enki-dock-popped-note {
    padding: 1rem;
    opacity: .85;
    display: flex;
    gap: 0.5rem;
    align-items: center;
    flex-wrap: wrap;
}
.enki-dock-popup-hint { color: var(--enki-warn); margin-top: 0.35rem; }

/* Cross-window awareness strip: a live pop-out of this panel is open in another window. A thin
   accent row between the dock header and body, with a "bring it back" (close the other) action. */
.enki-dock-elsewhere {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3rem 0.75rem;
    font-size: 0.82rem;
    color: var(--enki-text-muted);
    background: var(--enki-accent-soft, rgba(120, 160, 255, 0.10));
    border-bottom: 1px solid var(--enki-border-soft);
}
.enki-dock-elsewhere button { padding: 0; font-size: 0.82rem; }

/* Standalone run-page chat dock (RunDetail): the ChatPane's base 460px list cap already
   bounds it when docked; when FLOATED, fill the float box the way the console rail does
   (the rail's flex rules don't reach here, so scope equivalents to this wrapper). */
.enki-run-chat-dock .enki-dock--floating .enki-dock-body { display: flex; flex-direction: column; }
.enki-run-chat-dock .enki-dock--floating .enki-chat-pane { flex: 1; min-height: 0; }
.enki-run-chat-dock .enki-dock--floating .enki-chat-list { flex: 1 1 0; max-height: none; min-height: 8rem; }

/* Cameras hosted inside their EnkiDockPanel (the dock supplies the card frame + "Cameras"
   header): the embedded CameraSection drops its own card/title, so give it comfortable
   padding to match the other console cards' inner spacing. */
.enki-camera-embedded { padding: 0.5rem 0.75rem; }

/* Camera panes — base (docked/inline) sizing: a wrapping row of ~240px panes,
   each frame capped so the console column doesn't grow unbounded. */
.enki-camera-grid { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.enki-camera-pane { flex: 1 1 240px; min-width: 220px; }
.enki-camera-chip { display: flex; justify-content: center; margin-bottom: 0.5rem; }
.enki-camera-frame { min-height: 140px; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.enki-camera-img { max-width: 100%; max-height: 280px; object-fit: contain; display: block; }

/* Float + pop-out window — a bounded-HEIGHT container. Instead of the docked
   wrap-and-overflow-scroll, tile the cameras into a grid that FILLS the space
   and scale each frame to its cell, so one camera fills the window and several
   share it evenly. Scoped to the camera dock's float + the pop-out wrapper so
   the inline console layout is untouched. */
.enki-camera-dock .enki-dock--floating .enki-dock-body,
.enki-popout-camera { display: flex; flex-direction: column; min-height: 0; }
.enki-camera-dock .enki-dock--floating .enki-camera-embedded,
.enki-popout-camera .enki-camera-embedded { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.enki-camera-dock .enki-dock--floating .enki-camera-grid,
.enki-popout-camera .enki-camera-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    grid-auto-rows: minmax(0, 1fr);
    flex: 1 1 auto;
    min-height: 0;
}
.enki-camera-dock .enki-dock--floating .enki-camera-pane,
.enki-popout-camera .enki-camera-pane { min-width: 0; display: flex; flex-direction: column; }
.enki-camera-dock .enki-dock--floating .enki-camera-frame,
.enki-popout-camera .enki-camera-frame { flex: 1 1 auto; min-height: 100px; }
.enki-camera-dock .enki-dock--floating .enki-camera-img,
.enki-popout-camera .enki-camera-img { max-height: 100%; }

/* ===== Camera viewer controls (P5D §6): layout presets + per-camera on/off =====
   The toolbar carries the link banner (left) + the layout preset buttons (right).
   A fixed preset pins its column count via an INLINE grid style on .enki-camera-grid
   (GridStyle in the code-behind): inline wins over the float/pop-out auto-fit override,
   which is higher-specificity than any preset class could be. Auto leaves the
   per-context CSS (docked flex-wrap / windowed auto-fit) in charge. In a flex column
   host (float + pop-out) the grid still carries flex:1 1 auto from its context rule, so
   the toolbar + tray take content height and the grid fills the rest. */
.enki-camera-toolbar {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: 0.5rem 1rem; margin-bottom: 0.5rem; flex: 0 0 auto;
}
.enki-camera-toolbar > .enki-form-hint { margin: 0; min-width: 0; }
.enki-camera-layout { display: inline-flex; gap: 0.2rem; flex: 0 0 auto; }
.enki-camera-layout-btn {
    padding: 0.15rem 0.55rem; font-size: 0.72rem; letter-spacing: 0.03em; line-height: 1.5;
    border: 1px solid var(--enki-border-soft); border-radius: 4px;
    background: transparent; color: var(--enki-text-dim); cursor: pointer;
}
.enki-camera-layout-btn:hover { color: var(--enki-accent); border-color: var(--enki-accent); }
.enki-camera-layout-btn.is-active {
    background: var(--enki-accent); color: #fff; border-color: var(--enki-accent);
}
/* A fixed preset makes the grid explicit; let panes shrink below their 220px base so a
   3-up in a narrow docked column can't overflow (the float/pop-out already do this). */
.enki-camera-grid--fixed .enki-camera-pane { min-width: 0; flex: initial; }

/* Per-tile head: the label + the "off" (hide) control on one row. */
.enki-camera-pane-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.enki-camera-tile-btn {
    flex: 0 0 auto; border: none; background: transparent; color: var(--enki-text-muted);
    font-size: 0.85rem; line-height: 1; padding: 0.15rem 0.3rem; border-radius: 3px; cursor: pointer;
}
.enki-camera-tile-btn:hover { background: rgba(127, 127, 127, 0.14); color: var(--enki-accent); }
/* The label truncates so the action cluster (fullscreen / still / off) always fits,
   even on a narrow 190px filmstrip tile. */
.enki-camera-pane-head .enki-console-card-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.enki-camera-tile-actions { display: inline-flex; gap: 0.1rem; flex: 0 0 auto; }
/* Browser-fullscreen a single camera frame: the video scaled up to fill the screen on
   black. width/height:100v* + object-fit:contain SCALE the video up to the viewport while
   preserving aspect (letterbox only on the mismatched axis) — max-width/height alone only
   CAP, so a 640x360 frame would otherwise sit tiny at native size in a big black field. */
.enki-camera-frame:fullscreen { background: #000; min-height: 0; }
.enki-camera-frame:fullscreen .enki-camera-img {
    width: 100vw; height: 100vh; max-width: none; max-height: none; object-fit: contain;
}

/* "Open camera wall" launch link under the console camera dock (P5D §9). */
.enki-camera-wall-launch { text-align: right; margin-top: 0.4rem; }
.enki-camera-wall-launch .enki-button-link { font-size: 0.8rem; }

/* Hidden tray: the cameras this viewer turned off — one chip each to bring back. */
.enki-camera-hidden-tray { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin-top: 0.6rem; flex: 0 0 auto; }
.enki-camera-hidden-tray > .enki-form-hint { margin: 0; }
.enki-camera-hidden-chip {
    padding: 0.1rem 0.5rem; font-size: 0.72rem; border: 1px dashed var(--enki-border-soft);
    border-radius: 4px; background: transparent; color: var(--enki-text-dim); cursor: pointer;
}
.enki-camera-hidden-chip:hover { color: var(--enki-accent); border-color: var(--enki-accent); }
.enki-camera-showall {
    border: none; background: transparent; color: var(--enki-accent); cursor: pointer;
    font-size: 0.72rem; padding: 0.1rem 0.3rem;
}

/* Spotlight / filmstrip (P5D §6, D2): one camera promoted large with the rest as a
   scrollable filmstrip. In a bounded flex-column host (float + pop-out) the main tile
   fills the space and the strip is a fixed-height row; docked (block flow) the main tile
   uses a comfortable fixed height. These rules sit AFTER the float/pop-out frame rules so
   the main-tile frame wins their equal-specificity tie. */
.enki-camera-spotlight { display: flex; flex-direction: column; gap: 0.6rem; flex: 1 1 auto; min-height: 0; }
.enki-camera-spotlight-main { flex: 1 1 auto; min-height: 0; display: flex; }
.enki-camera-spotlight-main .enki-camera-pane { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.enki-camera-spotlight-main .enki-camera-frame { flex: 1 1 auto; min-height: 220px; }
.enki-camera-spotlight-main .enki-camera-img { max-height: 100%; }
.enki-camera-filmstrip { display: flex; gap: 0.5rem; overflow-x: auto; flex: 0 0 auto; padding-bottom: 0.25rem; }
.enki-camera-filmstrip .enki-camera-pane { flex: 0 0 190px; min-width: 190px; }
.enki-camera-filmstrip .enki-camera-frame { min-height: 90px; }
.enki-camera-filmstrip .enki-camera-img { max-height: 130px; }

/* A frame that can be clicked to focus (spotlight) its camera. */
.enki-camera-frame-selectable { cursor: pointer; }
.enki-camera-frame-selectable:hover { outline: 2px solid var(--enki-accent); outline-offset: -2px; }

/* Docked camera dock: drop the outer .enki-card 1.25rem/1.5rem padding so the dock header's OWN
   padding is the frame (matching the run-chat dock) — no triple-nested card -> header -> embedded
   padding, which read as loose dead space around the control. A small top margin sets it off from
   the instrument columns above. */
.enki-camera-dock { margin-top: 0.6rem; }
.enki-camera-dock .enki-dock:not(.enki-dock--floating) { padding: 0; overflow: hidden; }
.enki-camera-dock .enki-dock--docked .enki-camera-embedded { padding: 0.5rem 0.75rem 0.6rem; }

/* Console peer (console-split, 2026-07-14). The Warrior Console dock matches the camera dock so the
   two peers are the SAME height when separated: zero the default .enki-card padding that otherwise
   inflates the compact popped / open-elsewhere strip (bare console dock measured 119px vs the
   camera's 77px — that gap was purely the card padding), and re-add comfortable inner padding ONLY
   when the full console body is docked. */
.enki-console-dock { margin-top: 0.6rem; }
.enki-console-dock .enki-dock:not(.enki-dock--floating) { padding: 0; }
.enki-console-dock .enki-dock--docked .enki-dock-body { padding: 0.5rem 0.75rem 0.6rem; }

/* Collapsible dock (RunChatDock): a collapsed panel hides its body and turns the header
   into a clickable status bar; the last-message preview in the chips area truncates rather
   than pushing the actions off. The chips flex-grow is scoped to the run-chat dock so other
   panels' StatusChips are unaffected. */
.enki-dock--collapsed .enki-dock-body { display: none; }
.enki-dock--collapsed .enki-dock-head { cursor: pointer; border-bottom: none; }
.enki-run-chat-dock .enki-dock-head-chips { flex: 1 1 auto; min-width: 0; justify-content: flex-start; }
.enki-dock-bar-preview { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }

/* Make the run-page chat dock read like the neighbouring EnkiExpandableSection sections
   (Surveys / Activity / Remote operations): its own top margin so it doesn't butt against
   Surveys, a flush 64px strip, the 1.1rem uppercase title with a right-border separator, and
   subtle link-style action buttons + a hairline above the expanded body. Scoped so the
   console + cameras docks keep their own dock chrome. */
.enki-run-chat-dock { margin-top: 0.75rem; }
.enki-run-chat-dock .enki-dock:not(.enki-dock--floating) { padding: 0; overflow: hidden; }
.enki-run-chat-dock .enki-dock-popped-back { white-space: nowrap; }
.enki-run-chat-dock .enki-dock-head { padding: 0.5rem 1rem; gap: 0.75rem; min-height: 64px; border-bottom: none; }
.enki-run-chat-dock .enki-dock-head-titles { padding-right: 0.75rem; border-right: 1px solid var(--enki-border-soft); min-width: 110px; }
.enki-run-chat-dock .enki-dock-title { font-size: 1.1rem; font-weight: 600; letter-spacing: 0.08em; line-height: 1.15; }
.enki-run-chat-dock .enki-dock-sub { font-size: 0.65rem; letter-spacing: 0.12em; color: var(--enki-text-muted); opacity: 1; }
.enki-run-chat-dock .enki-dock-btn { border: none; background: transparent; color: var(--enki-text-dim); font-size: 0.9rem; padding: 0.25rem 0.4rem; }
.enki-run-chat-dock .enki-dock-btn:hover { border: none; background: transparent; color: var(--enki-accent); }
.enki-run-chat-dock .enki-dock--docked:not(.enki-dock--collapsed) .enki-dock-body { border-top: 1px solid var(--enki-border-soft); padding: 0.5rem 1rem 0.75rem; }
.enki-run-chat-dock .enki-dock--docked:not(.enki-dock--collapsed) .enki-chat-list { max-height: 26rem; }

/* Popped-out chat window (PoppedRunChat): the section header + a Compact, frameless ChatPane
   fill the window, and the scrollback fills instead of Compact's 320px cap so it uses the
   whole height. */
.enki-popped-chat { display: flex; flex-direction: column; min-height: calc(100vh - 1.5rem); overflow: hidden; }
.enki-popped-chat-body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 0 1rem 1rem; }
.enki-popped-chat-body .enki-chat-pane { flex: 1; min-height: 0; }
.enki-popped-chat-body .enki-chat-list { flex: 1 1 0; max-height: none; min-height: 8rem; }

/* Popped-out camera window (PoppedRunCameras): the section header + the fill-and-tile
   camera surface fill the window. The grid tiling itself is the shared .enki-popout-camera
   rules above (same as the float); here we just make the fill region grow under the header. */
.enki-popped-camera { display: flex; flex-direction: column; min-height: calc(100vh - 1.5rem); overflow: hidden; }
.enki-popped-camera-head { flex: 0 0 auto; }
.enki-popped-camera > .enki-popout-camera { flex: 1 1 auto; padding: 0 0.5rem 0.5rem; }

/* ---------- System Pulse (admin/system) ----------
   The pulse panels are dense: four-column hotspot tables carrying endpoint
   routes and raw SQL, side by side. They were laid out as flex rows of
   `flex: 1; min-width: 380px` cards holding plain auto-layout tables, and
   the tables overflowed their own cards - the `max-width` on the name cell
   is only ADVISORY under `table-layout: auto`, so with `white-space: nowrap`
   on the three numeric columns the table computed a content width wider than
   the card and spilled past its border (the "max" column landing on top of
   the neighbouring panel). Scoped to .pulse-* so none of it leaks to the
   other .enki-table users. */

/* auto-fit grid rather than flex: cards come out equal-width and wrap as
   whole units, instead of two peers squeezing each other below the width
   their content actually needs. */
.pulse-grid {
    display: grid;
    gap: 1rem;
    margin-top: 1rem;
    align-items: start;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 32rem), 1fr));
}
/* The liveness tiles are small and uniform - a tighter track. */
.pulse-grid-tiles {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
    margin-top: 1.25rem;
}
/* Last-resort horizontal scroll INSIDE the card, so a very narrow viewport
   scrolls one panel rather than pushing the whole page sideways. */
.pulse-scroll {
    overflow-x: auto;
}
/* table-layout: fixed is what makes the colgroup authoritative and makes
   text-overflow: ellipsis actually fire on the name column. */
.pulse-table {
    table-layout: fixed;
    width: 100%;
    margin-top: 0.5rem;
}
.pulse-table .pulse-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pulse-table .pulse-num {
    text-align: right;
    white-space: nowrap;
}
/* Routes and SQL are long and truncation is expected here, so the full
   value is on the element's title - hover reveals it. */
.pulse-table .pulse-name[title] {
    cursor: help;
}
/* The dense mono column (SQL) sits a step down so more of it survives. */
.pulse-table .pulse-mono {
    font-size: 0.75rem;
}
/* Tighter cell padding than the default .enki-table: these panels are
   read as a dashboard, not scanned row-by-row like the audit tables. */
.pulse-table thead th,
.pulse-table tbody td {
    padding: 0.45rem 0.7rem;
}

/* Scan step: the "run tabs with rows" count opens to list which runs a
   report contributed. Read-only — the include/exclude decision lives on the
   Runs step, which has the MD range and shot count to judge by. */
.wiz-runs > summary {
    cursor: pointer;
    list-style: none;
    display: inline-flex; align-items: center; gap: 0.3rem;
    border-bottom: 1px dotted var(--enki-text-muted);
}
.wiz-runs > summary::-webkit-details-marker { display: none; }
.wiz-runs > summary::after {
    content: "\25BE";          /* small down triangle, U+25BE, rotates when open */
    font-size: 0.75em; color: var(--enki-text-muted);
    transition: transform 120ms ease;
}
.wiz-runs[open] > summary::after { transform: rotate(180deg); }
.wiz-runs > summary:hover, .wiz-runs > summary:focus-visible { color: var(--enki-accent); }
.wiz-run-list {
    margin: 0.35rem 0 0; padding: 0; list-style: none;
    display: flex; flex-direction: column; gap: 0.2rem;
}
.wiz-run-list li { display: flex; align-items: center; gap: 0.35rem; white-space: nowrap; }

/* Scaffold runs step: where a run's values came from, as a light rather than
   three lines of filename per row. Green = the run's own report. Amber =
   settings or rows borrowed from another workbook (legitimate — every
   workbook is a snapshot of the whole job — but the case to check). Red = no
   shot rows in any workbook, so committing it creates an empty run. */
.wiz-src > summary {
    cursor: pointer; list-style: none;
    display: inline-block; width: 0.7rem; height: 0.7rem;
    border-radius: 50%; border: 1px solid rgba(0,0,0,0.35);
}
.wiz-src > summary::-webkit-details-marker { display: none; }
.wiz-src > summary:focus-visible { outline: 2px solid var(--enki-accent); outline-offset: 2px; }
.wiz-src-green { background: #2e9e5b; }
.wiz-src-amber { background: #d08b2c; }
.wiz-src-red   { background: #c2453f; }
.wiz-src-detail {
    margin-top: 0.3rem; font-size: 0.85em; line-height: 1.35;
    color: var(--enki-text-dim); white-space: nowrap;
}

/* Scaffold runs step: a run's notes. The count stays the affordance — a
   fourteen-run batch cannot carry three lines of prose per row — but the notes
   themselves are the reasons behind the include tick beside them, so the count
   is a button that opens a row of real, selectable text under its own run. A
   native title tooltip cannot be selected, copied or read on a touch screen.
   (Mike, 2026-09-16.) */
.wiz-note-toggle {
    cursor: pointer;
    background: none; border: 0; padding: 0;
    font: inherit; color: var(--enki-warn, #d08770);
    border-bottom: 1px dotted currentColor;
}
.wiz-note-toggle:hover { color: var(--enki-accent); }
.wiz-note-toggle:focus-visible { outline: 2px solid var(--enki-accent); outline-offset: 2px; }
.wiz-note-row > td { background: var(--enki-surface-2); }
.wiz-note-list {
    margin: 0; padding: 0 0 0 1.1rem;
    line-height: 1.45; color: var(--enki-text);
    /* Body colour, body size: these are the reasons behind the include tick,
       not a footnote. Dimmer than the row they explain, and quieter than the
       control that reveals them, is backwards. The measure is capped so a
       200-character bridle note wraps inside the viewport rather than at the
       scroll width of a nine-column table. */
    max-width: min(90ch, 100%);
}
.wiz-note-list li { margin: 0.15rem 0; }

/* The wizard table shell. `.wiz-scroll` and `.wiz-row-dim` were only ever
   defined inside ImportWizardModal's own <style> block, and that modal is
   mounted from the Shots page and nowhere else — so on the scaffold wizard,
   which uses the same vocabulary, neither rule was in the DOM at all. The
   scaffold's runs table therefore ran the page wide instead of scrolling
   inside its box, and because Notes is the LAST column the warning count was
   the first thing pushed off the right edge; an excluded run was not dimmed
   either. Defined here so both pages get them. */
.wiz-scroll { max-height: 42vh; overflow: auto; }
.wiz-row-dim > td { opacity: 0.55; }

/* =============================================================================
   Model workbench (plan-model-workbench P1). One scroll in the order of the
   work: R1 chips over an always-open blockers strip, the sticky hypothesis bar
   (R2), the tracks, then Notes / Hypotheses / Setup. The bar sticks inside
   .enki-content (the pane that scrolls; the topbar sits outside it). top: 0
   fails safe: at worst the pane's padding shows as a strip above the stuck
   bar, never the bar's own top row pushed out of view.
   ============================================================================= */
.workbench-blockers {
    margin-top: 0.75rem;
    padding: 0.6rem 1rem;
    border: 1px solid var(--enki-border);
    border-left: 3px solid var(--enki-alert);
    border-radius: var(--enki-radius-lg);
    background: rgba(255, 71, 87, 0.06);
}
.workbench-blockers .enki-list { margin: 0.25rem 0 0; }

.workbench-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.75rem;
}
.workbench-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.25rem 0.75rem;
    font-size: 0.78rem;
    color: var(--enki-text);
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: 999px;
    cursor: pointer;
}
.workbench-chip:hover { border-color: var(--enki-border-hot); }
.workbench-chip[aria-expanded="true"] {
    border-color: var(--enki-accent);
    box-shadow: 0 0 0 1px var(--enki-accent-glow);
}
.workbench-chip-static { cursor: default; color: var(--enki-text-dim); }
.workbench-chip-static:hover { border-color: var(--enki-border); }
.workbench-chip-ok    { border-left: 3px solid var(--enki-ok); }
.workbench-chip-warn  { border-left: 3px solid var(--enki-warn); }
.workbench-chip-alert { border-left: 3px solid var(--enki-alert); }

.workbench-chip-panel {
    margin-top: 0.5rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    background: var(--enki-surface);
}

.workbench-bar {
    position: sticky;
    top: 0;
    z-index: 20;
    margin-top: 1rem;
    padding: 0.75rem 1rem;
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    box-shadow: 0 8px 18px rgba(0, 0, 0, 0.45);
}
.workbench-bar:empty { display: none; }

/* The bar is sticky, so every row it takes is a row of tracks hidden — at a
   1060 × 794 laptop view it stood 423 px of the 794 (the 2026-09-27 audit). One
   wrapping row: the window, the knobs, the fit and the save flow side by side,
   in tighter inputs, labels and buttons; hints, status lines and errors take a
   line of their own under them. Scoped here, so a standalone panel is as before.
   Every piece is a region of its own (WorkbenchRegions), so every piece is a
   direct child of the bar: a status block that is not a <p> or an .alert must be
   named in the full-width rule below, or it flows into the row of controls. */
.workbench-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.45rem 1.5rem;
    padding: 0.5rem 0.85rem;
}
.workbench-bar > p,
.workbench-bar > .alert,
.workbench-bar > #shift-refused {
    order: 10;
    flex-basis: 100%;
    margin: 0 !important;
}
.workbench-bar .enki-form-label { font-size: 0.62rem; letter-spacing: 0.06em; }
.workbench-bar .enki-form-input {
    width: 5.6rem !important;
    margin-top: 0.15rem;
    padding: 0.3rem 0.5rem;
    font-size: 0.85rem;
}
.workbench-bar #scan-save-name { width: 9rem !important; }
.workbench-bar .enki-button { padding: 0.35rem 0.8rem; font-size: 0.72rem; }
.workbench-bar #scan-window-row,
.workbench-bar #shift-form,
.workbench-bar #scan-save-row,
.workbench-bar .fit-row { gap: 0.6rem !important; margin-top: 0 !important; }
.workbench-bar .enki-form-hint { font-size: 0.72rem; }

/* The main window's line about a fit made in the window holding Hypotheses
   (plan-model-workbench-windows §6, Mike's ruling W10) is ONE line in every state: the
   sentence never wraps — it clips with an ellipsis, its whole in the tooltip — and Take
   the fitted shift sits beside it. In the bar (only while Hypotheses is away) it is a
   row item where the Fit and Save rows were — never in the full-width rule above — basis
   14rem, less than the Fit row alone (the Fit button beside its 47-character options
   line), so it fits on whatever row the Fit row took and adds none; no taller than the
   Save row's labelled box. With Hypotheses home it sits under the bar (GM-101 measured
   258 of 794 px: no room for a line more). WorkbenchRegionsTests reads these rules. */
.desk-fit {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}
.workbench-bar > .desk-fit { flex: 1 1 14rem; min-width: 0; }
.desk-fit-line {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.desk-fit > .enki-button { flex: none; }

/* The fit's options fold under one line that still says what they are set to. */
.fit-options > summary { cursor: pointer; }
.fit-options[open] > summary { margin-bottom: 0.25rem; }
.fit-options label { margin: 0 0.9rem 0 0; }

/* A linked model window (plan-model-workbench-windows §3.1) is a whole page on
   PopOutLayout, whose 0.75rem suits a popped panel, not a page: it takes the main
   page's gutter (.enki-content). !important because PopOutLayout sets its padding
   inline; :has scopes all of this to the model's linked window. Its header has no
   Back, Edit or Delete, so the empty actions row would only add a gap. */
.enki-popout-shell:has(> #workbench-window-head) {
    padding: 1.5rem clamp(0.75rem, 3vw, 2.25rem) !important;
}
.enki-popout-shell:has(> #workbench-window-head) .enki-page-header { margin-bottom: 0.5rem; }
.enki-popout-shell:has(> #workbench-window-head) .enki-page-header-actions { display: none; }
/* The head says whether the window is linked and which question every number
   below answers — read at a glance, so neither sits in the faint hint tone. */
.workbench-window-head .workbench-link-state { color: var(--enki-text-dim); }
.workbench-window-head .workbench-question-line { color: var(--enki-text); }
/* What a linked window can do about its link (increment 4c) — Unlink this window, Link again,
   Make this the main window — small, on one row under the link state it changes. The main
   window's unlinked line and an earlier desk's offer carry their buttons inline, as links. */
.workbench-link-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.1rem 0.75rem;
    margin: 0.1rem 0 0.25rem;
}
.workbench-link-actions .enki-button,
#desk-unlinked .enki-button,
.desk-earlier .enki-button,
.desk-layout .enki-button { padding: 0.1rem 0.3rem; font-size: 0.75rem; }
.desk-earlier,
.desk-layout {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.1rem 0.5rem;
}
/* The saved layouts' lines (plan-model-workbench-windows §8, increment 5a) sit under the bar in
   the earlier desk's look — never in the sticky bar, which has no room for a line more (GM-101). */
/* ◐ Asking (plan-model-workbench-windows §5): the previous numbers stay, greyed, until the
   window's own answer to the main window's question lands — the question line, the
   tracks and their footer, and the notes. The head carries the class; :has reaches the
   sections below it, all inside the linked window's own shell. */
.workbench-window-head.workbench-asking .workbench-question-line,
.enki-popout-shell:has(> #workbench-window-head.workbench-asking) :is(.depth-stack, #measured-signal-footer, #workbench-notes) {
    opacity: 0.45;
    filter: grayscale(1);
    transition: opacity 0.15s ease-out;
}

/* The desk (plan-model-workbench-windows §3.3): a section's header tools — Open in new
   window, Move to window N, Send back — sit small and right-aligned above it; where a
   section left for another window, the main window shows the dock's popped strip in its
   place, its sentence in the reading case (the dock's own subtitle is upper-case). */
.workbench-section-tools {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: baseline;
    gap: 0.1rem 0.75rem;
    margin-top: 0.75rem;
    font-size: 0.75rem;
}
.workbench-section-tools + .workbench-section > .enki-expand-section,
.workbench-section-tools + .workbench-section > .enki-card:first-child { margin-top: 0.25rem !important; }
.workbench-section-tools .workbench-section-tool { padding: 0.1rem 0.3rem; font-size: 0.75rem; }
.workbench-section-tools-note { flex-basis: 100%; text-align: right; margin: 0; }
.workbench-desk-strip { margin-top: 0.75rem; }
/* The tracks keep their tools while away (they may open in another window as well), so
   their strip sits under the tools as the card it stands in for did. */
.workbench-section-tools + .workbench-desk-strip { margin-top: 0.25rem; }
.workbench-desk-strip .workbench-desk-strip-text { font-size: 0.82rem; color: var(--enki-text-dim); white-space: normal; }
/* Hypotheses folds (0.54.32): the fold's own rule sits over its body, so the saved scans' rule —
   which parts them from a fit's report above — is dropped when nothing is above them. */
.workbench-hypotheses > .saved-scans:first-child { margin-top: 0.75rem !important; padding-top: 0 !important; border-top: 0 !important; }

.depth-ribbon { margin-top: 1rem; }
.depth-ribbon-caption { margin-bottom: 0.35rem; }
.depth-ribbon-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.1rem 0.75rem;
    align-items: center;
    margin-bottom: 0.35rem;
    font-size: 0.75rem;
}
.depth-ribbon-label { color: var(--enki-text-dim); }
.depth-ribbon-range { color: var(--enki-text-dim); font-size: 0.72rem; }
/* The track is the full card width, like the tracks above, so a bar sits under
   the depths it names (the tracks' own fractions, TrackAxis.LeftFraction–RightFraction). */
.depth-ribbon-track {
    grid-column: 1 / -1;
    position: relative;
    height: 10px;
    background: rgba(255, 255, 255, 0.03);
    border-radius: var(--enki-radius);
}
.depth-ribbon-bar {
    position: absolute;
    top: 1px;
    height: 8px;
    border: 1px solid;
    border-radius: var(--enki-radius);
    opacity: 0.85;
}
.depth-ribbon-bar-hollow { opacity: 0.7; }
.depth-ribbon-edge {
    position: absolute;
    top: -3px;
    font-size: 0.72rem;
    color: var(--enki-text);
}
.depth-ribbon-edge-left  { left: 0; }
.depth-ribbon-edge-right { right: 0; }
.depth-ribbon-swatch {
    display: inline-block;
    width: 0.6rem;
    height: 0.6rem;
    margin-right: 0.35rem;
    border-radius: var(--enki-radius);
    vertical-align: middle;
}
/* The rug (P3, 0.54.49): a tick per capture, centred on its depth on the tracks' fractions —
   filled in the run's colour where a track draws it, a ring of it where none does. */
.depth-rug-track { height: 14px; }
.depth-rug-tick {
    position: absolute;
    top: 1px;
    width: 4px;
    height: 12px;
    margin-left: -2px;
    box-sizing: border-box;
    border: 1px solid;
    border-radius: 1px;
}
.depth-rug-tick-hollow { border-width: 1.5px; }
.depth-rug-edge { top: 0; }
.depth-rug-not-ticked, .depth-rug-census { margin: 0.15rem 0 0.35rem; }

/* A run's colour (ruled D1-A, 2026-10-01): the run owns it — the swatch on its own page and
   in the colour picker's tiles (D5-A); the model page's swatches are the ribbon's own above. */
.run-colour-swatch {
    display: inline-block;
    width: 0.75rem;
    height: 0.75rem;
    margin-right: 0.35rem;
    border-radius: var(--enki-radius);
    vertical-align: middle;
}
.enki-detail-grid > .enki-detail-wide { grid-column: 1 / -1; }
.member-colour { white-space: nowrap; }
.member-colour-name { font-size: 0.8rem; color: var(--enki-text-dim); }
.member-colour-choose { padding: 0; }
.member-colour-choose .member-colour-name { text-decoration: underline dotted; }
.run-colour-picker {
    margin: 0.5rem 0;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius-lg);
    background: var(--enki-surface-2);
}
.run-colour-tiles { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0.5rem 0; }
.run-colour-tile {
    display: inline-flex;
    align-items: center;
    gap: 0.1rem;
    padding: 0.25rem 0.5rem;
    font-size: 0.8rem;
    color: var(--enki-text);
    background: var(--enki-surface);
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    cursor: pointer;
}
.run-colour-tile:hover:not(:disabled) { border-color: var(--enki-border-hot); }
.run-colour-tile:disabled { cursor: default; }
.run-colour-tile-current { border-color: var(--enki-text); }
.run-colour-tile-mark { margin-left: 0.25rem; color: var(--enki-text-dim); }
.run-colour-picker-lead, .run-colour-picker-foot { margin: 0; }
.run-colour-tile-own { font-style: italic; }
.run-colour-picker-wears, .run-colour-custom-neighbours { margin: 0.25rem 0 0; }

/* A custom colour (0.54.41, reversing D5-A's "tiles only"): Syncfusion's inline colour
   picker beside the typed colour and its live warnings. The warnings are words a reader
   acts on — never a disabled Save — so they read as notes, in the warn colour's margin. */
.run-colour-custom-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.25rem 0 0.5rem; }
.run-colour-custom-actions .enki-button-link { padding-left: 0; }
.run-colour-custom {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1rem;
    margin: 0 0 0.5rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--enki-border);
    border-radius: var(--enki-radius);
    background: var(--enki-surface);
}
.run-colour-custom-picker { flex: 0 0 auto; }
.run-colour-custom-side { flex: 1 1 16rem; min-width: 16rem; display: flex; flex-direction: column; gap: 0.5rem; }
.run-colour-custom-hex-label { margin: 0; }
.run-colour-custom-hex-row { display: flex; align-items: center; gap: 0.5rem; }
.run-colour-custom-preview {
    width: 1.75rem;
    height: 1.75rem;
    margin-right: 0;
    border: 1px solid var(--enki-border);
}
.run-colour-custom-hex.enki-input { width: 9rem; margin-top: 0; padding: 0.35rem 0.5rem; text-transform: uppercase; }
.run-colour-warnings { display: flex; flex-direction: column; gap: 0.35rem; }
.run-colour-warnings .enki-form-hint { margin: 0; }
.run-colour-warning-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 0.25rem; }
.run-colour-warning {
    padding: 0.15rem 0 0.15rem 0.5rem;
    font-size: 0.8rem;
    color: var(--enki-text);
    border-left: 2px solid var(--enki-warn);
}
.run-colour-not-a-colour { color: var(--enki-warn); }
.run-colour-custom-buttons { display: flex; align-items: center; gap: 0.5rem; }
