/* ============================================================
   Theme tokens — dark (default) + light override.
   2026-08-19: per the user, live — the whole dashboard was hardcoded dark-only.
   Semantic CSS variables (not a 1:1 hex mirror — several near-duplicate shades
   that had organically accumulated across sessions, e.g. #8b949e/#9aa5af/#b8c4ce
   all meaning "muted text", got consolidated into one token each) so a single
   [data-theme="light"] block re-themes the whole app. Toggled via a
   data-theme attribute on <html>, set by static/theme.js — defaults to dark
   (no attribute) on a first-ever visit, remembers the user's choice after that
   via localStorage. See index.html's #theme-toggle-btn.
   ============================================================ */
:root {
    --bg-page: #0d1117;
    --bg-chrome: #1a1a2e;
    --text-on-chrome: #fff;
    --bg-panel: #161b22;
    --bg-nested: #1c2128;
    --border: #30363d;
    --text-primary: #e6edf3;
    --text-secondary: #c9d1d9;
    --text-muted: #8b949e;
    --text-faint: #6e7681;
    --accent: #4a90d9;
    --success: #3fb950;
    --danger: #f85149;
    --warning: #ffb84d;
    --warning-text: #d29922;
    /* Hover/active tint for controls sitting directly on --bg-chrome (the top toolbar) --
       a plain translucent white worked when chrome was always dark, but needs to flip
       toward black in light mode or it's illegible (white-on-near-white). */
    --chrome-hover-bg: rgba(255,255,255,0.1);
    --chrome-active-bg: rgba(255,255,255,0.18);
    --border-on-chrome: #2d3748;
    --panel-hover-bg: rgba(255,255,255,0.03);
    /* 2026-08-19: per the user -- "all of the borders are a little too thin," generally,
       not a light/dark-specific complaint, so this lives once in the shared :root rather
       than being redefined per theme. One variable driving all ~66 standard `1px solid
       var(--border...)` rules (see the bulk replace in this file's own history) means any
       future width tweak is a one-line change instead of another repo-wide sweep. */
    --border-width: 1.5px;
    /* 2026-08-19: green "completed"/"recorded value" pill backgrounds + the value pill's own
       text color -- previously a bare rgba(63,185,80,...) tint + literal #7ee0b8 sprinkled
       directly on several rules, unthemeable. Dark values here match what was already there
       (no visual change in dark mode); light mode gets its own pass below. */
    --success-bg: rgba(63,185,80,0.14);
    --success-border: rgba(63,185,80,0.4);
    --value-text: #7ee0b8;
}

:root[data-theme="light"] {
    --bg-page: #f6f8fa;
    --bg-chrome: #eef2f7;
    --text-on-chrome: #1f2328;
    --bg-panel: #ffffff;
    --bg-nested: #eef1f4;
    --border: #d0d7de;
    /* 2026-08-19: per the user, live -- "no gray on the light view, all black for higher
       contrast." The old grays (#656d76/#6e7781 for muted/faint especially) were GitHub
       Primer's own tokens and technically passed WCAG AA (5.25:1 / 4.55:1), but read as too
       light in practice on a lot of small meta text. All four bumped to near-black --
       primary is now literal pure black, the other three stay just barely differentiated
       (not identical) so hierarchy between heading/body/meta text doesn't disappear
       entirely, but nothing here reads as "gray" anymore (12.6:1 / 10.4:1 minimum). */
    --text-primary: #000000;
    --text-secondary: #1a1a1a;
    --text-muted: #333333;
    --text-faint: #404040;
    --accent: #0969da;
    /* 2026-08-19: per the user, live -- #1a7f37 (GitHub Primer's own light-mode success
       token) technically passes WCAG AA at 5.0:1 on white, but read as too light/washed-out
       in practice, especially on small checkmark glyphs. #116329 (Primer's "success
       emphasis" darker shade) computes to 7.27:1 -- meaningfully darker, not just a token
       swap. */
    --success: #116329;
    --danger: #cf222e;
    --warning: #9a6700;
    --warning-text: #9a6700;
    --chrome-hover-bg: rgba(0,0,0,0.06);
    --chrome-active-bg: rgba(0,0,0,0.1);
    --border-on-chrome: #c8ccd1;
    --panel-hover-bg: rgba(0,0,0,0.035);
    /* 2026-08-19: per the user, live -- the old dark-mode rgba(63,185,80,...) tint read as
       washed-out pastel on a white panel background. Built off the new darker --success
       (#116329) at a slightly higher opacity so it stays clearly visible on white instead of
       nearly disappearing. */
    --success-bg: rgba(17,99,41,0.12);
    --success-border: rgba(17,99,41,0.35);
    --value-text: #116329;
}

/* 2026-08-19: per the user -- Google Sans first choice, Roboto as the real explicit
   fallback (also per the user). Confirmed live (WebSearch + WebFetch against
   fontsource.org/fonts/google-sans/cdn) that Google Sans is now genuinely available under
   the SIL Open Font License v1.1 via Fontsource's jsDelivr-backed CDN -- not the
   Google-internal/unavailable font it used to be. Pinned to an exact version (5.3.1), not
   @latest, for reproducible caching. Roboto itself is loaded as a real webfont via
   index.html's Google Fonts <link> -- it isn't a Windows system font, so leaving it to the
   OS would silently skip straight past it to plain sans-serif on this dev environment. */
@font-face {
    font-family: 'Google Sans Variable';
    font-style: normal;
    font-display: swap;
    font-weight: 400 700;
    src: url(https://cdn.jsdelivr.net/fontsource/fonts/google-sans:vf@5.3.1/latin-wght-normal.woff2) format('woff2-variations');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

/* Reset */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
    font-family: 'Google Sans Variable', Roboto, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: var(--bg-page);
    color: var(--text-primary);
    height: 100vh;
    display: flex;
    flex-direction: column;
}

/* Toolbar */
.toolbar {
    background: var(--bg-chrome);
    color: var(--text-on-chrome);
    padding: 0 16px;
    height: 56px;
    display: flex;
    align-items: center;
    gap: 0;
    flex-shrink: 0;
    /* 2026-09-12: below ~1150px there's genuinely not enough room for both status
       badges + all 5 nav buttons + the theme toggle even at zero title width --
       scroll instead of letting toolbar-right's flex-shrink:0 content visually
       overlap the title (confirmed: it renders past its own flex item's left edge
       rather than wrapping or clipping). */
    overflow-x: auto;
    overflow-y: hidden;
}
.toolbar-left, .toolbar-right {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1 0 auto;
}
.toolbar-right { justify-content: flex-end; }
/* 2026-09-12: without this, tab-nav buttons with two-word labels ("Device Client",
   "Android Device") wrap their text onto a second line once the toolbar gets tight
   (e.g. adding the env-indicator badge pushed this over the edge around ~1100px),
   breaking out of the toolbar's fixed 56px height. */
.tab-nav { flex-shrink: 0; }
.tab-btn { white-space: nowrap; }
/* 2026-08-19: light/dark toggle, per the user -- top-right of the toolbar. Plain emoji
   (not inline SVG) is fine here, unlike the glasses' own WebView shell -- this is a normal
   Chromium-based desktop browser, no tofu-rendering risk. Icon/label swap handled by
   theme.js. */
.theme-toggle-btn {
    background: transparent; border: var(--border-width) solid var(--border-on-chrome); border-radius: 6px;
    color: var(--text-on-chrome); font-size: 16px; line-height: 1; cursor: pointer;
    width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
    margin-left: 8px; flex-shrink: 0; padding: 0;
}
.theme-toggle-btn:hover { background: var(--chrome-hover-bg); }
/* 2026-09-17: the composite demo's tablet-hole iframe (composite-demo.html) runs this whole
   page at a small internal canvas width (letterboxed hole size / 0.8 -- 529px on the
   secondary monitor, 794px on the primary), which triggered the toolbar's overflow-x:auto
   scrollbar every time the composite demo ran. Per the user: shrink the toolbar's own content
   instead of showing a scrollbar.

   2026-09-22: was a @media (max-width: 900px) breakpoint, tuned to the composite-demo widths
   above. Adding the "Health Checks" tab (6th nav button, split out of Connector) plus the
   admin/env badges pushed the toolbar's real required width past 900px too, so a normal,
   reasonably-wide demo browser window (not narrow enough to trigger the old breakpoint, not
   wide enough to fit six full-size buttons + two badges + title) hit the exact same
   overflow-x:auto scrollbar live during a demo. Per the user: applying the compact styles
   unconditionally (not gated behind any window-width threshold) is preferred over chasing
   another magic breakpoint number that a future 7th button or badge would just re-break --
   "squish the buttons down to five pixels, there should not be a scroll bar" ever, at any
   width. overflow-x:auto on .toolbar itself is left in place as a last-resort safety net for
   anything narrower still (e.g. the composite demo's 529px canvas), not removed. */
.toolbar { padding: 0; gap: 0; overflow-y: hidden; }
.toolbar-left, .toolbar-right { gap: 1px; }
.toolbar-right .tab-nav { padding-left: 3px; margin-left: 1px; }
.tab-nav { gap: 1px; }
.toolbar-title { display: none; }
.tab-btn { padding: 3px 4px; font-size: 11px; }
.tab-btn-featured { padding: 4px 6px; font-size: 11px; }
.theme-toggle-btn { width: 20px; height: 20px; font-size: 11px; margin-left: 1px; }
.hamburger-btn { width: 20px; height: 20px; font-size: 13px; }
/* Supplementary context (which env/user), not needed to navigate -- dropped entirely
   rather than truncated; a truncated icon+text badge (tried first) still cost real width
   for illegible output. */
.user-indicator, .admin-indicator, .env-indicator { display: none; }
/* Swaps each tab button's real (too-wide) label for its data-short alternative. The real
   text node is shrunk to invisible/zero-width (font-size:0 on the button) rather than
   removed, so the DOM/accessible name and existing click handlers (which read nothing
   from the text) are untouched; ::after supplies the actual visible label at a real,
   readable font-size. */
.tab-btn[data-short] { font-size: 0; }
.tab-btn[data-short]::after { content: attr(data-short); font-size: 11px; font-weight: inherit; }
/* 2026-09-12: shrinks (with ellipsis) before the nav buttons/badges have to, on a
   narrow window -- was flex-shrink:0 (never shrinks), which left nothing to absorb
   the squeeze once the env-indicator badge added more content to the toolbar. */
.toolbar-title {
    font-size: 18px;
    font-weight: 600;
    white-space: nowrap;
    flex-shrink: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 0 12px;
}
.auth-status { font-size: 13px; color: var(--text-muted); }
.user-indicator {
    font-size: 13px;
    color: #68d391;
    font-weight: 500;
    padding: 4px 10px;
    background: rgba(104, 211, 145, 0.1);
    border: 1px solid rgba(104, 211, 145, 0.3);
    border-radius: 12px;
    white-space: nowrap;
    flex-shrink: 0;
}
.admin-indicator {
    color: #90cdf4;
    background: rgba(144, 205, 244, 0.1);
    border-color: rgba(144, 205, 244, 0.3);
}
/* 2026-09-12: which named environment (environments.json) this harness process
   is pointed at -- local vs. remote color-coded so it's obvious at a glance. */
.env-indicator {
    font-size: 13px;
    font-weight: 500;
    padding: 4px 10px;
    border-radius: 12px;
    white-space: nowrap;
    flex-shrink: 0;
}
.env-indicator-local {
    color: #90cdf4;
    background: rgba(144, 205, 244, 0.1);
    border: 1px solid rgba(144, 205, 244, 0.3);
}
.env-indicator-remote {
    color: #f6ad55;
    background: rgba(246, 173, 85, 0.1);
    border: 1px solid rgba(246, 173, 85, 0.3);
}

/* App body — three-column layout */
.app-body {
    display: grid;
    grid-template-columns: var(--dc-w1, 280px) 6px 1fr 6px var(--dc-w3, 300px);
    grid-template-rows: 1fr;
    gap: 0;
    column-gap: 0;
    padding: 12px;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}
.app-body > .panel { margin: 0 6px; }
.dc-resize-h {
    width: 6px;
    cursor: col-resize;
    border-radius: 3px;
    background: transparent;
    transition: background 0.15s;
    align-self: stretch;
}
.dc-resize-h:hover, .dc-resize-h.dragging { background: var(--accent); }
/* 2026-08-19: while the Frontline Live list panel is collapsed to its narrow rail, its
   drag handle has nothing meaningful to resize (inspections.js's mousedown handler already
   no-ops there too) -- inert rather than inviting a drag that does nothing. */
.ir-list-panel.collapsed ~ .dc-resize-h { cursor: default; pointer-events: none; }

/* 2026-10-14 (browser E2E finding): the three-column dashboard grid left ~32px for the detail panel at phone
   width. On narrow screens stack the list above the detail panel and drop the drag handles. */
@media (max-width: 700px) {
    .app-body.ir-body {
        grid-template-columns: 1fr;
        grid-template-rows: minmax(150px, 36vh) minmax(0, 1fr);
        row-gap: 8px;
    }
    .app-body.ir-body > .dc-resize-h { display: none; }
    .app-body.ir-body > .panel { margin: 0; min-width: 0; }
    .app-body.ir-body > .ir-list-panel.collapsed { grid-row: auto; }
}

/* Panels */
.panel {
    background: var(--bg-panel);
    border-radius: 8px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    overflow: auto;
    box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.panel-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: var(--border-width) solid var(--border);
    padding-bottom: 8px;
}

/* Buttons */
.btn-primary {
    background: var(--accent);
    color: #fff;
    border: none;
    border-radius: 6px;
    padding: 8px 16px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
}
.btn-primary:hover:not(:disabled) { background: #357abd; }
.btn-primary:disabled, .btn-secondary:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.btn-secondary {
    background: transparent;
    color: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 6px;
    padding: 6px 12px;
    cursor: pointer;
    font-size: 13px;
}
.btn-secondary:hover:not(:disabled) { background: rgba(74,144,217,0.15); }
/* 2026-10-04, per the user, explicitly -- "big and obvious... big blue button" for the
   report PDF/email actions on a completed inspection. Deliberately bigger than
   .btn-primary (this is a once-per-inspection, consequential action worth standing out,
   not a routine toolbar button) -- same accent color family so it still reads as part of
   the same design system, not a mismatched one-off. */
.ir-report-actions {
    display: flex;
    gap: 10px;
    margin-top: 10px;
}
.btn-report-action {
    background: var(--accent);
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 14px 22px;
    cursor: pointer;
    font-size: 16px;
    font-weight: 700;
    display: flex;
    align-items: center;
    gap: 8px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.25);
}
.btn-report-action:hover:not(:disabled) { background: #357abd; }
/* 2026-10-05, per the user, explicitly: "grayed out" -- a literal neutral gray, not just a
   faded version of the blue, so it reads unambiguously as "not available yet" rather than
   "a slightly dimmer version of the real button." */
.btn-report-action:disabled {
    background: var(--border); color: var(--text-muted);
    cursor: default; box-shadow: none; opacity: 1;
}
.btn-warning {
    background: transparent;
    color: #f0a020;
    border: 1px solid #f0a020;
    border-radius: 6px;
    padding: 6px 12px;
    cursor: pointer;
    font-size: 13px;
    font-weight: 500;
}
.btn-warning:hover:not(:disabled) { background: rgba(240,160,32,0.15); }
.btn-warning:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-warning.btn-warning-active {
    background: #f0a020;
    color: #1c1408;
}
.btn-warning.btn-warning-active:hover { background: #d68f1c; }

/* Task filter bar */
.task-filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 8px 0 4px;
    border-bottom: var(--border-width) solid var(--border);
    margin-bottom: 8px;
}
.task-filter-btn {
    background: transparent;
    border: var(--border-width) solid var(--border);
    border-radius: 12px;
    padding: 3px 10px;
    font-size: 13px;
    cursor: pointer;
    color: var(--text-muted);
}
.task-filter-btn:hover { border-color: var(--accent); color: var(--accent); }
.task-filter-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Task cards */
.task-card {
    border: var(--border-width) solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 14px;
    background: var(--bg-panel);
}
.task-card:hover { border-color: var(--accent); background: #1c2840; }
.task-card-title { font-weight: 500; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: flex; align-items: center; gap: 6px; }
.task-version-badge { font-size: 11px; font-weight: 600; color: var(--text-muted); background: var(--bg-nested); border-radius: 4px; padding: 1px 5px; flex-shrink: 0; }
.task-card-footer { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.task-status {
    font-size: 12px;
    border-radius: 10px;
    padding: 2px 8px;
    white-space: nowrap;
}
.task-status.status-notStarted  { background: var(--bg-nested); color: var(--text-muted); }
.task-status.status-inProgress  { background: #1c3052; color: #90cdf4; }
.task-status.status-paused      { background: #2d2000; color: #fbd38d; }
.task-status.status-completed   { background: #0f2e1e; color: #68d391; }
.task-status.status-cancelled   { background: #2d0f0f; color: #fca5a5; }
.task-status.status-errored     { background: #2d0f0f; color: #fc8181; font-weight: 700; }
.btn-danger { padding: 4px 10px; font-size: 13px; border-radius: 4px; border: 1px solid #f87171; background: #2d0f0f; color: #fca5a5; cursor: pointer; }
.btn-danger:hover { background: #3d1515; border-color: #ef4444; }

/* Step renderer — the element tree renders into here */
.page {
    display: flex;
    flex-direction: column;
    height: 100%;
    gap: 8px;
}
header, .step-header { background: var(--bg-nested); border-radius: 6px; padding: 8px 12px; }
main, .step-main { flex: 1; overflow: auto; padding: 8px; }
footer, .step-footer { border-top: var(--border-width) solid var(--border); padding: 8px 12px; }

.default-header { font-size: 16px; font-weight: 600; }
.default-footer { display: flex; flex-direction: row; gap: 8px; justify-content: flex-end; }

/* Info cards */
.info-card {
    border: var(--border-width) solid var(--border);
    border-radius: 6px;
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 14px;
    margin-bottom: 8px;
}
.info-card.highlighted { border-color: var(--accent); background: #1c3052; }
.info-card.outlined { border-width: 2px; }
.info-card-label { font-size: 12px; color: var(--text-muted); text-transform: uppercase; }
.info-card-value { font-size: 16px; font-weight: 600; }
.info-card-icon { font-size: 18px; }

/* Action hint */
.action-hint {
    background: #2d2000;
    border: 1px solid #92400e;
    border-radius: 6px;
    padding: 8px 12px;
    font-size: 14px;
    color: #fbd38d;
    display: flex;
    align-items: center;
    gap: 8px;
}
/* Loading-type hints get a distinct spinning ring instead of a static
   glyph — reuses the wf-spin keyframes already defined for the device
   client's loading overlay so the "please wait" treatment is consistent
   across the app. */
.action-hint-loading {
    background: #1c2733;
    border-color: var(--border);
    color: var(--text-muted);
}
.action-hint-spinner {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: wf-spin 0.7s linear infinite;
}
/* Opt-in icon pulse for ActionHint (props.pulse: true) — see renderer.js's
   ActionHint case for the harness-only convention this implements. Kept
   subtle (small scale delta, gentle easing) — a status ambient cue, not an
   attention-grabbing alert. */
.action-hint-icon-pulse {
    display: inline-block;
    animation: action-hint-icon-pulse 1.4s ease-in-out infinite;
}
@keyframes action-hint-icon-pulse {
    0%, 100% { transform: scale(1);    opacity: 1; }
    50%      { transform: scale(1.18); opacity: 0.6; }
}

/* Buttons inside step renderer */
button.footerAction {
    background: var(--accent);
    color: #fff;
    border: none;
    border-radius: 6px;
    padding: 10px 20px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
}
button.footerAction:hover { background: #357abd; }
button.footerHelp {
    background: transparent;
    color: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 6px;
    padding: 8px 16px;
    cursor: pointer;
    font-size: 14px;
}
button.footerHelp:hover { background: rgba(74,144,217,0.15); }

/* Progress bar */
progress { width: 100%; height: 8px; border-radius: 4px; }
.progress-bar-wrapper { display: flex; align-items: center; gap: 8px; width: 100%; }
.progress-bar-wrapper progress { flex: 1; }
.progress-bar-label { font-size: 0.85em; color: #a0aec0; white-space: nowrap; }

/* Unknown elements */
.unknown-element {
    background: #2d0f0f;
    border: 1px dashed #fc8181;
    border-radius: 4px;
    padding: 6px 10px;
    font-size: 12px;
    color: #fca5a5;
}
.unknown-element::before { content: "⚠ Unknown: " attr(data-type); }

/* Grid */
.grid { display: grid; grid-auto-flow: column; gap: 8px; }

/* Project Upsilon's 25-slot cart grid (Deposit Item) — force a real 5x5
   layout instead of the default single-row grid-auto-flow: column. */
.grid[data-name="CartGrid"] { grid-template-columns: repeat(5, 1fr); grid-auto-flow: row; gap: 4px; }
.grid[data-name="CartGrid"] .info-card { padding: 4px; min-width: 0; }
.grid[data-name="CartGrid"] .info-card-label { font-size: 10px; }

/* Action list */
.action-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.action-list li button {
    width: 100%;
    text-align: left;
    background: var(--bg-nested);
    border: var(--border-width) solid var(--border);
    border-radius: 6px;
    padding: 10px 12px;
    cursor: pointer;
    font-size: 14px;
    color: var(--text-primary);
}
.action-list li button:hover { background: #1c3052; border-color: var(--accent); }

/* Step log */
#step-log { list-style: none; font-size: 14px; display: flex; flex-direction: column; gap: 6px; }
#step-log li {
    padding: 6px 10px;
    border-left: 3px solid var(--border);
    background: var(--bg-nested);
    border-radius: 0 4px 4px 0;
}
#step-log li.complete { border-left-color: #48bb78; }
#step-log li.current { border-left-color: var(--accent); font-weight: 600; }
#step-log li.error { border-left-color: #fc8181; background: #2d0f0f; }

/* Notification banner — inline, part of the step view (no popups/dialogs:
   the real smart-glasses client only ever shows the current step's view) */
.notification-banner {
    border-radius: 6px;
    padding: 10px 14px;
    margin-bottom: 12px;
    font-size: 14px;
}
.notification-banner-title { font-weight: 600; margin-bottom: 4px; }
.notification-banner-error {
    background: #2d0f0f;
    border: 1px solid #fc8181;
    color: #fc8181;
}
.notification-banner-success {
    background: #0f2d17;
    border: 1px solid #48bb78;
    color: #48bb78;
}

/* Input field */
/* 2026-09-27: input[type="password"] added -- confirmed live, the password field on the
   login page had no explicit background at all (only "text"/"number" were listed here),
   so it fell back to the browser's own default white while its sibling username field
   correctly showed this app's dark theme. This is a shared rule, not scoped to login.html,
   so every password field in the app gets the fix, not just that one page's. */
input[type="text"], input[type="number"], input[type="password"] {
    border: var(--border-width) solid var(--border);
    border-radius: 6px;
    padding: 8px 12px;
    font-size: 14px;
    width: 100%;
    background: var(--bg-page);
    color: var(--text-primary);
}
input[type="text"]:focus, input[type="number"]:focus, input[type="password"]:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(74,144,217,0.15);
}

/* Scan widget */
.scan-widget { display: flex; flex-direction: column; gap: 8px; padding: 16px; }
.scan-widget-hint { font-size: 14px; color: var(--text-muted); font-weight: 500; }
.scan-widget-row { display: flex; gap: 8px; align-items: center; }
.scan-input { padding: 12px; font-size: 16px; border: 2px solid var(--accent); border-radius: 8px; flex: 1; background: var(--bg-page); color: var(--text-primary); }
.scan-widget-btn { padding: 10px 20px; white-space: nowrap; }
.scan-timeout { font-size: 13px; color: #fc8181; margin-top: 4px; }

/* Numeric keypad — self-contained digit entry, see renderer.js's
   NumericKeypad case. Digit/backspace taps only ever repaint
   .numeric-keypad-display locally; nothing here is bound to taskData. */
.numeric-keypad { display: flex; flex-direction: column; gap: 12px; padding: 16px; max-width: 360px; }
.numeric-keypad-display {
    border: 2px solid var(--accent);
    background: #1c3052;
    border-radius: 8px;
    padding: 18px;
    text-align: center;
    font-size: 28px;
    font-weight: 700;
    color: var(--text-primary);
}
.numeric-keypad-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.numeric-keypad-key {
    background: var(--bg-nested);
    color: var(--text-primary);
    border: var(--border-width) solid var(--border);
    border-radius: 6px;
    padding: 18px 0;
    font-size: 18px;
    font-weight: 600;
    cursor: pointer;
}
.numeric-keypad-key:hover { background: #242c36; }
.numeric-keypad-key-backspace { background: transparent; color: var(--accent); border-color: var(--accent); }
.numeric-keypad-key-backspace:hover { background: rgba(74,144,217,0.15); }
.numeric-keypad-key-confirm { background: var(--accent); color: #fff; border: none; }
.numeric-keypad-key-confirm:hover { background: #357abd; }

/* Step container */
.step-container { display: flex; flex-direction: column; flex: 1; }
.placeholder { padding: 40px; color: var(--text-muted); text-align: center; }

/* Completed workflow card */
.step-complete-card { display: flex; flex-direction: column; align-items: center; justify-content: center; flex: 1; padding: 48px; text-align: center; gap: 8px; }
.step-complete-card h3 { font-size: 20px; color: #48bb78; margin: 0; }
.step-complete-card p { font-size: 14px; color: var(--text-muted); margin: 0; }

/* Workflow info (Done step) */
.workflow-info { text-align: center; padding: 24px 16px; }
.workflow-info h2 { font-size: 20px; margin-bottom: 8px; }
.workflow-info p { color: var(--text-muted); font-size: 14px; }

/* Verify report */
.verify-report {
    border: 2px solid #48bb78;
    border-radius: 8px;
    padding: 16px;
    background: #0f2e1e;
    font-size: 14px;
}
.verify-report.failed { border-color: #fc8181; background: #2d0f0f; }
.verify-report.pass { border-color: #48bb78; background: #0f2e1e; }
.verify-report.fail { border-color: #fc8181; background: #2d0f0f; }
.verify-report .assert-pass { color: #4ade80; }
.verify-report .assert-fail { color: #fc8181; }
.hidden { display: none; }

/* ─── Tab nav ─────────────────────────────────────────────────── */
.tab-nav {
    display: flex;
    gap: 4px;
}
.toolbar-right .tab-nav {
    border-left: var(--border-width) solid var(--border-on-chrome);
    padding-left: 12px;
    margin-left: 4px;
}
.tab-btn {
    background: transparent;
    color: var(--text-muted);
    border: none;
    padding: 6px 16px;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    transition: background 0.15s, color 0.15s;
}
.tab-btn:hover { background: var(--chrome-hover-bg); color: var(--text-on-chrome); }
.tab-btn.active { background: var(--chrome-active-bg); color: var(--text-on-chrome); }

/* 2026-08-17: "Frontline Live" -- per the user, explicitly: "the one thing you want to
   really go to when you're looking at the website." Made deliberately louder than every
   other tab, not just another item in the row -- bright blue, bigger, a real shadow/glow,
   so it reads as the primary destination rather than one option among several. */
.tab-btn-featured {
    background: linear-gradient(135deg, #2f9bff, #1668d6);
    color: #fff;
    font-weight: 700;
    font-size: 15px;
    padding: 8px 22px;
    box-shadow: 0 0 0 1px rgba(255,255,255,0.15), 0 2px 10px rgba(47,155,255,0.55);
}
.tab-btn-featured:hover {
    background: linear-gradient(135deg, #4facff, #2f7fe6);
    color: #fff;
    box-shadow: 0 0 0 1px rgba(255,255,255,0.25), 0 2px 16px rgba(47,155,255,0.75);
}
.tab-btn-featured.active {
    background: linear-gradient(135deg, #4facff, #2f7fe6);
    color: #fff;
    box-shadow: 0 0 0 2px #9dd3ff, 0 2px 16px rgba(47,155,255,0.8);
}

/* ─── Hamburger menu ──────────────────────────────────────────── */
/* 2026-09-26: per the user, explicitly -- Connector/Authoring/Device Client/Android
   Device are real diagnostic/dev tools, not part of the everyday view. Tucked behind
   this menu instead of removed; see index.html's own comment on the markup for why the
   dropdown's buttons are still plain .tab-btn/data-tab elements (reuses client.js's
   existing generic tab-switching wiring unchanged). Open/close behavior lives in
   hamburger-menu.js. */
.hamburger-menu { position: relative; }
.hamburger-btn {
    background: transparent; border: var(--border-width) solid var(--border-on-chrome); border-radius: 6px;
    color: var(--text-on-chrome); font-size: 18px; line-height: 1; cursor: pointer;
    width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
    padding: 0;
}
.hamburger-btn:hover, .hamburger-btn.open { background: var(--chrome-hover-bg); }
/* position:fixed (not absolute), with top/left set from JS on open -- found live: .toolbar
   has its own overflow-y:hidden (see that rule's comment, added to stop two-word tab
   labels wrapping past the toolbar's fixed 56px height), which silently clipped an
   absolutely-positioned dropdown the instant it needed to render below the toolbar's own
   height, leaving only a ~6px sliver visible. position:fixed's containing block is the
   viewport, not any scrolling/clipping ancestor, so it isn't subject to that clip. */
.hamburger-dropdown {
    position: fixed; z-index: 50;
    flex-direction: column; gap: 2px; min-width: 180px;
    background: var(--bg-panel); border: var(--border-width) solid var(--border-on-chrome);
    border-radius: 8px; padding: 6px; box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
.hamburger-dropdown.hidden { display: none; }
.hamburger-dropdown .tab-btn { text-align: left; width: 100%; }

/* ─── Tab panels ──────────────────────────────────────────────── */
.tab-panel { display: flex; flex-direction: column; flex: 1; overflow: hidden; min-height: 0; }
.tab-panel.hidden { display: none; }

.admin-status-msg { font-size: 13px; color: #68d391; margin-left: 8px; }
.at-status-bar { padding: 6px 16px; min-height: unset; }

/* ─── Connector actions panel ─────────────────────────────────── */
.connector-actions {
    background: var(--bg-nested);
    padding: 10px 16px;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    flex-shrink: 0;
    border-bottom: var(--border-width) solid var(--border);
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.connector-label {
    font-size: 13px;
    color: var(--text-muted);
    font-weight: 500;
    margin-right: 4px;
}
/* 2026-09-21: the Health Checks tab -- diagnostic/setup tooling (auth
   reset, server config, live connectivity checks) split out of the
   Connector tab entirely. #tab-health-checks itself needs the same
   scrollable-page padding every other plain tab-panel gets by default;
   these section wrappers just group its contents visually.
   2026-09-21 (later same day): "make it look nicer... plenty of space...
   don't make everything so small" -- redone as a dashboard: bigger base
   font, card-grid check results with icons, a real SVG chart with axes/
   gridlines/hover instead of a strip of bare divs. */
#tab-health-checks {
    padding: 24px 28px;
    overflow-y: auto;
    font-size: 15px;
}
.hc-page-section {
    margin-bottom: 28px;
}
.hc-page-section-title {
    font-size: 20px;
    font-weight: 600;
    margin-bottom: 12px;
}
.hc-page-actions {
    display: flex;
    align-items: center;
    gap: 12px;
}
/* 2026-09-21: read-only view of the harness's currently-active connection
   settings (GET /api/environment). */
.server-config-panel {
    background: var(--bg-nested);
    border: var(--border-width) solid var(--border);
    border-radius: 10px;
    padding: 18px 22px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 14px 24px;
    font-size: 15px;
}
.server-config-row {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.server-config-label {
    color: var(--text-muted);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
/* 2026-09-21: "Health Check" panel -- real connectivity/latency checks for
   Anthropic, Google STT, NATS, Asset Service, and the Workflow Service. See
   gamma_health.py. */
.health-check-panel {
    background: var(--bg-nested);
    border: var(--border-width) solid var(--border);
    border-radius: 10px;
    padding: 18px 22px;
    display: flex;
    flex-direction: column;
    gap: 18px;
}
/* 2026-09-26: "Pairing" panel -- QR + short code for a glasses device to
   auto-configure itself. See main.py's /api/pairing/generate. */
.pairing-result {
    margin-top: 14px;
    background: var(--bg-nested);
    border: var(--border-width) solid var(--border);
    border-radius: 10px;
    padding: 18px 22px;
    display: flex;
    align-items: center;
    gap: 20px;
}
/* 2026-09-28: real bug, reported live -- .pairing-result's own `display: flex` above and
   the generic `.hidden { display: none; }` rule (much earlier in this file) have IDENTICAL
   specificity, so on an element carrying both classes, the LATER-declared rule in the
   stylesheet wins regardless of which class "should" apply semantically -- .pairing-result
   silently never actually hid, showing an empty QR <img> with no src (a broken-image icon)
   and blank code/expiry text on every page load, before any code had ever been generated.
   Every OTHER hide/show element in this file already uses this same compound-selector
   pattern (e.g. .modal-overlay.hidden, .tab-panel.hidden) -- this one was just missed when
   the pairing panel was built. */
.pairing-result.hidden { display: none; }
.pairing-hint {
    margin-top: 14px; color: var(--text-muted); font-size: 0.9em;
}
.pairing-result.expired .pairing-qr-img {
    opacity: 0.3;
    filter: grayscale(1);
}
.pairing-qr-img {
    /* 2026-09-28: per the user, live -- "way too small... very difficult to scan." 3x'd
       (160px -> 480px). Safe to upscale this much without blurring: the underlying PNG
       (adb_client.generate_qr_png_base64, qrcode.make() defaults) renders at a
       comfortably higher native resolution than even this, not a tiny thumbnail. */
    width: 480px;
    height: 480px;
    border-radius: 6px;
    background: #fff;
    padding: 8px;
}
.pairing-details {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.pairing-expiry {
    color: var(--text-muted);
    font-size: 14px;
}
.pairing-expiry.expired {
    color: #f87171;
}
.pairing-identity-note {
    font-size: 13px;
    color: var(--text-muted);
}
.pairing-identity-note.pairing-identity-warning {
    color: #d29922;
}
.hc-toolbar {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}
.hc-toolbar .btn-primary, .hc-toolbar .btn-secondary {
    font-size: 15px !important;
    padding: 9px 18px !important;
}
.hc-status {
    font-size: 14px;
    color: var(--text-muted);
}
/* Dashboard-card grid, one card per check. */
.hc-checks {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 14px;
}
.hc-check-card {
    background: var(--bg-panel);
    border: var(--border-width) solid var(--border);
    border-left: 4px solid var(--border);
    border-radius: 8px;
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.hc-check-card.ok { border-left-color: #68d391; }
.hc-check-card.fail { border-left-color: #ff8888; }
.hc-check-card-header {
    display: flex;
    align-items: center;
    gap: 10px;
}
.hc-check-icon { font-size: 24px; line-height: 1; flex-shrink: 0; }
.hc-check-name { font-weight: 600; font-size: 16px; flex: 1; }
.hc-check-status-badge {
    font-size: 12px;
    font-weight: 600;
    padding: 2px 9px;
    border-radius: 10px;
    white-space: nowrap;
}
.hc-check-status-badge.ok { background: rgba(104,211,145,0.15); color: #68d391; }
.hc-check-status-badge.fail { background: rgba(255,136,136,0.15); color: #ff8888; }
.hc-check-status-badge.na { background: rgba(255,255,255,0.06); color: var(--text-muted); }
.hc-check-latency {
    color: var(--text-muted);
    font-size: 14px;
}
.hc-check-latency strong { color: var(--text-primary, inherit); font-size: 16px; }
.hc-check-detail {
    color: var(--text-muted);
    font-size: 13px;
    word-break: break-word;
    line-height: 1.4;
}
.hc-section-title {
    font-size: 16px;
    font-weight: 600;
    margin-top: 6px;
}
.hc-latency-empty {
    font-size: 14px;
    color: var(--text-muted);
    font-style: italic;
    padding: 40px 0;
    text-align: center;
}

/* ─── Call-detail list -- 2026-09-21, replaced the earlier bar chart ────
   Real feedback: the chart's labels were internal jargon, it only ever
   showed Anthropic calls, and it stretched full-width for what was often
   just one bar. This is a plain, readable log instead: one row per real
   API call, newest first, with a friendly description and full detail. */
.hc-call-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: 900px;
}
.hc-call-row {
    position: relative;
    display: grid;
    grid-template-columns: 90px 44px 210px 1fr;
    align-items: start;
    gap: 14px;
    background: var(--bg-panel);
    border: var(--border-width) solid var(--border);
    border-left: 4px solid var(--border);
    border-radius: 6px;
    padding: 10px 14px;
    font-size: 14px;
    overflow: hidden;
}
.hc-call-row.ok { border-left-color: #68d391; }
.hc-call-row.fail { border-left-color: #ff8888; }

/* 2026-09-21: a just-appeared row (a fresh health check / smoke test run)
   gets a one-time background flash plus a corner "NEW" ribbon, so new
   results are obviously new instead of silently blending into the list.
   Never re-flashes on a plain tab-reopen -- see seenCallTimestamps in
   monitor.js, which only marks rows new relative to the previous render. */
@keyframes hc-row-flash {
    0% { background: rgba(74, 144, 217, 0.35); }
    100% { background: var(--bg-panel); }
}
.hc-call-row-new {
    animation: hc-row-flash 2.5s ease-out;
}
.hc-call-new-badge {
    position: absolute;
    top: 0;
    right: 0;
    background: #4a90d9;
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.05em;
    padding: 2px 8px 2px 10px;
    border-bottom-left-radius: 8px;
    animation: hc-badge-fade 4s ease-out forwards;
}
@keyframes hc-badge-fade {
    0%, 60% { opacity: 1; }
    100% { opacity: 0; }
}
.hc-call-time { color: var(--text-muted); font-size: 13px; white-space: nowrap; }
.hc-call-latency { font-weight: 600; white-space: nowrap; }
.hc-call-latency .unit { font-weight: 400; color: var(--text-muted); font-size: 12px; }
.hc-call-name { font-weight: 600; display: flex; align-items: center; gap: 6px; }
.hc-call-status-icon.ok { color: #68d391; }
.hc-call-status-icon.fail { color: #ff8888; }
.hc-call-detail { color: var(--text-muted); word-break: break-word; line-height: 1.4; }

.hc-ai-smoke-results {
    font-size: 14px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* ─── Connector sub-tabs ──────────────────────────────────────── */
.c-sub-tabs {
    display: flex;
    border-bottom: var(--border-width) solid var(--border);
    background: var(--bg-panel);
    flex-shrink: 0;
}
.c-sub-tab {
    padding: 7px 18px;
    font-size: 13px;
    font-weight: 500;
    color: var(--text-muted);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}
.c-sub-tab:hover { color: var(--text-secondary); }
.c-sub-tab.active {
    color: #818cf8;
    border-bottom-color: #818cf8;
    background: var(--bg-page);
}
.c-sub-panel { display: none; flex: 1; min-height: 0; flex-direction: column; }
.c-sub-panel.active { display: flex; }

/* ─── Workflow tab scope bar ──────────────────────────────────── */
.wf-scope-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: var(--bg-nested);
    border-bottom: var(--border-width) solid var(--border);
    flex-shrink: 0;
}
.wf-scope-label {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-muted);
}
#wf-scope-select {
    font-size: 13px;
    padding: 3px 6px;
    border: var(--border-width) solid var(--border);
    border-radius: 4px;
    background: var(--bg-page);
    color: var(--text-primary);
    min-width: 180px;
    max-width: 260px;
}
.wf-scope-status {
    font-size: 12px;
    color: var(--text-muted);
    white-space: nowrap;
}
.wf-scope-reconnecting { color: var(--warning); }
.wf-scope-error { color: #f87171; }
.wf-scope-clickable { cursor: pointer; text-decoration: underline; }

/* ─── Bottom panel row (Callbacks + Custom Handlers side by side) ─── */
.wf-bottom-row {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 80px;
    border-top: 2px solid var(--border);
    background: var(--bg-panel);
}
.wf-bottom-vresize {
    position: absolute;
    top: -4px; left: 0; right: 0;
    height: 8px;
    cursor: row-resize;
    z-index: 20;
}
.wf-bottom-vresize:hover,
.wf-bottom-vresize:active { background: #818cf8; opacity: 0.6; }

.wf-bottom-inner {
    flex: 1;
    display: flex;
    flex-direction: row;
    overflow: hidden;
    min-height: 0;
}
.wf-bottom-panel {
    display: flex;
    flex-direction: column;
    flex: 1;
    overflow: hidden;
    min-width: 80px;
}
#wf-callbacks-panel { flex-basis: 50%; flex-grow: 0; flex-shrink: 0; }
.wf-bottom-panel-header {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: var(--bg-nested);
    border-bottom: var(--border-width) solid var(--border);
    flex-shrink: 0;
}
.wf-bottom-panel-body {
    flex: 1;
    overflow-y: auto;
    min-height: 0;
    padding: 6px 12px 10px;
}
/* wf-bottom-hsplit removed — replaced by single .wf-col-split overlay */

.wf-callbacks-title { font-size: 13px; font-weight: 600; color: var(--text-secondary); }
.wf-callbacks-count {
    font-size: 12px;
    color: #818cf8;
    background: #1e2060;
    border-radius: 10px;
    padding: 1px 7px;
}
.wf-cb-empty { font-size: 13px; color: var(--text-muted); }
.wf-cb-group { margin-bottom: 10px; }
.wf-cb-step {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 4px;
}
/* ── Callbacks: collapsible step groups ─────────────────────────────────── */
.wf-cb-step-toggle { cursor: pointer; user-select: none; display: flex; align-items: center; gap: 5px; }
.wf-cb-step-toggle:hover { color: var(--text-primary); }
.wf-cb-chevron { font-size: 10px; color: var(--text-faint); width: 10px; flex-shrink: 0; }
.wf-cb-group-content.hidden { display: none; }

/* ── Test payload panel ──────────────────────────────────────────────────── */
.wf-js-test-section { flex-shrink: 0; border-top: 1px solid var(--bg-nested); }
.wf-js-test-header {
    display: flex; align-items: center; gap: 5px; cursor: pointer; user-select: none;
    font-size: 11px; color: var(--text-faint); padding: 4px 10px;
    background: var(--bg-panel);
}
.wf-js-test-header:hover { color: var(--text-muted); }
.wf-js-test-body { height: 120px; }
.wf-js-test-body .CodeMirror { height: 120px; font-size: 12px; border-top: 1px solid var(--bg-nested); }
.wf-js-test-textarea { width: 100%; height: 100%; background: var(--bg-page); color: var(--text-primary); font-family: monospace; font-size: 12px; border: none; padding: 6px; box-sizing: border-box; resize: none; }
.wf-js-test-body.hidden { display: none; }

/* ── Callbacks: button header row ───────────────────────────────────────── */
.wf-cb-btn-row {
    display: flex; align-items: center; gap: 6px;
    padding: 4px 6px 1px;
    margin-top: 4px;
}
.wf-cb-elname { color: var(--text-primary); font-weight: 600; font-size: 12px; background: var(--bg-panel); border: var(--border-width) solid var(--border); border-radius: 3px; padding: 0 5px; flex-shrink: 0; }
.wf-cb-event  { color: #a78bfa; font-weight: 500; font-size: 12px; }

/* ── Callbacks: action sub-rows ─────────────────────────────────────────── */
.wf-cb-action-row {
    display: flex; align-items: center; gap: 6px;
    font-size: 12px;
    padding: 2px 6px 2px 16px;   /* indent under button header */
    border-radius: 4px;
    margin-bottom: 1px;
}
.wf-cb-action-nav    { color: var(--text-primary); }
.wf-cb-action-signal { color: var(--text-faint); }          /* muted — client-side only */
.wf-cb-row-clickable { cursor: pointer; }
.wf-cb-row-clickable:hover { background: var(--bg-nested); outline: var(--border-width) solid var(--border); }

.wf-cb-dot        { width: 7px; height: 7px; border-radius: 50%; background: var(--border); flex-shrink: 0; }
.wf-cb-dot-active { background: #58a6ff; }
.wf-cb-dot-signal { background: var(--border); opacity: 0.4; }

.wf-cb-action-label { font-family: 'Fira Mono', monospace; }
.wf-cb-arrow  { color: var(--text-muted); }
.wf-cb-src    { color: var(--text-muted); font-size: 12px; }
.wf-cb-count  {
    margin-left: auto;
    font-size: 12px;
    font-weight: 700;
    color: #fff;
    background: #d97706;
    border-radius: 3px;
    padding: 1px 4px;
    min-width: 20px;
    text-align: center;
}
.wf-cb-count.hidden { display: none; }
/* ── Custom Handler JS Panel ────────────────────────────────────────────── */
.wf-js-hint { margin-left: 8px; font-size: 12px; color: var(--text-muted); font-weight: 400; }
.wf-js-body-flex {
    padding: 0 !important;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.wf-js-tabs { display: flex; gap: 2px; padding: 5px 6px 0; flex-wrap: wrap; flex-shrink: 0; }
.wf-js-tab {
    font-size: 12px; font-weight: 600; padding: 3px 8px; border-radius: 3px 3px 0 0;
    border: var(--border-width) solid var(--border); border-bottom: none; cursor: pointer;
    background: var(--bg-nested); color: var(--text-muted);
}
.wf-js-tab.active { background: var(--bg-page); color: var(--text-primary); border-color: #4a5568; }
.wf-js-textarea {
    flex: 1; min-height: 0;
    display: block; width: 100%; box-sizing: border-box;
    font-family: 'Consolas', 'Monaco', monospace; font-size: 13px; line-height: 1.5;
    padding: 8px; border: var(--border-width) solid var(--border); border-top: none; border-left: none; border-right: none;
    background: var(--bg-page); color: var(--text-primary); resize: none; outline: none;
}
/* CodeMirror instance fills the flex slot the textarea occupied */
.wf-js-body-flex .CodeMirror {
    flex: 1;
    min-height: 0;
    height: 100%;
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 13px;
    line-height: 1.6;
    border-top: none;
}
.wf-js-body-flex .CodeMirror-scroll { min-height: 0; }
.wf-js-handler-label {
    font-size: 11px; font-family: 'Fira Mono', monospace;
    color: #58a6ff; background: var(--bg-page);
    padding: 3px 10px; border-bottom: 1px solid var(--bg-nested);
    flex-shrink: 0;
}
.wf-js-handler-label.hidden { display: none; }
.wf-js-handler-label.wf-js-placeholder-label { color: var(--text-faint); font-family: inherit; font-style: italic; }
.wf-js-script-banner {
    display: flex; align-items: center; gap: 10px; flex-shrink: 0;
    padding: 4px 10px; background: #1a2a1a; border-bottom: 1px solid #2ea043;
    font-size: 11px;
}
.wf-js-script-banner.hidden { display: none; }
#wf-js-script-banner-text { color: #56d364; font-family: 'Fira Mono', monospace; font-weight: 600; }
.wf-js-script-note { color: #6e9b6e; font-style: italic; }
.wf-js-actions { display: flex; align-items: center; gap: 8px; padding: 4px 8px 4px; flex-shrink: 0; background: var(--bg-nested); border-top: var(--border-width) solid var(--border); }
.btn-sm { font-size: 13px !important; padding: 3px 10px !important; }
.wf-js-status { font-size: 12px; color: #68d391; }

/* ── WMS Mock Responses Panel ──────────────────────────────────────────── */
.wf-mock-body { overflow-y: auto; padding: 8px 10px; display: flex; flex-direction: column; gap: 12px; }
.wf-mock-section { background: var(--bg-panel); border: var(--border-width) solid var(--border); border-radius: 6px; padding: 10px 12px; }
.wf-mock-section-title { font-size: 11px; font-weight: 600; color: #7d8590; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 8px; }
.wf-mock-row { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
.wf-mock-row:last-child { margin-bottom: 0; }
.wf-mock-label { font-size: 12px; color: var(--text-muted); width: 140px; flex-shrink: 0; }
.wf-mock-input { flex: 1; background: var(--bg-page); border: var(--border-width) solid var(--border); border-radius: 4px; color: var(--text-primary); font-size: 13px; padding: 3px 7px; font-family: 'Fira Mono', monospace; }
.wf-mock-input:focus { outline: none; border-color: #58a6ff; }
.wf-js-log {
    max-height: 100px; overflow-y: auto; margin: 0; padding: 5px 8px;
    background: var(--bg-page); border-top: 1px solid #1e293b;
    font-family: monospace; font-size: 11px; flex-shrink: 0;
    display: none;
}
.wf-js-log:not(:empty) { display: block; }
.wf-js-log-line { color: var(--text-muted); padding: 1px 0; white-space: pre-wrap; }
.wf-js-log-error { color: #fc8181; }
.wf-js-log-warn { color: #f6ad55; font-weight: 600; }

/* ── Authoring script content textarea ──────────────────────────────────── */
.at-script-content {
    font-family: monospace; font-size: 12px; line-height: 1.5;
    min-height: 220px; resize: vertical;
}

.wf-cb-asset-header {
    font-size: 12px;
    font-weight: 600;
    color: #a78bfa;
    padding: 6px 6px 2px;
    border-top: var(--border-width) solid var(--border);
    margin-top: 6px;
    font-family: monospace;
}
.wf-cb-asset-code {
    font-size: 11px;
    font-family: monospace;
    background: var(--bg-nested);
    border: var(--border-width) solid var(--border);
    border-radius: 4px;
    margin: 2px 6px 6px;
    padding: 6px;
    white-space: pre-wrap;
    word-break: break-all;
    max-height: 300px;
    overflow-y: auto;
    color: var(--text-secondary);
}

/* ─── Event type chips in feed rows ──────────────────────────── */
.evt-chip {
    display: inline-block;
    font-size: 12px;
    font-weight: 600;
    padding: 1px 5px;
    border-radius: 3px;
    white-space: nowrap;
    background: var(--border);
    color: var(--text-secondary);
    flex-shrink: 0;
}
.evt-chip-updatetask     { background: #4c1d95; color: #ddd6fe; }
.evt-chip-updatetaskdata { background: #164e4c; color: #99f6e4; }
.evt-chip-scan           { background: #1e3a5f; color: #93c5fd; }
.evt-chip-gotostep       { background: #451a03; color: #fed7aa; }
.evt-chip-script         { background: #14532d; color: #bbf7d0; }

/* ─── Connector running indicator ───────────────────────────── */
.connector-running-indicator {
    font-size: 11px;
    padding: 2px 9px;
    border-radius: 10px;
    font-weight: 600;
    letter-spacing: 0.03em;
    white-space: nowrap;
    flex-shrink: 0;
}
.connector-running-indicator.idle    { color: #4a5568; }
.connector-running-indicator.running { color: #48bb78; }

/* ─── Workflow scope bar refresh button ──────────────────────── */
.wf-refresh-btn {
    margin-left: auto;
    font-size: 13px;
    padding: 3px 12px;
    flex-shrink: 0;
}

/* ─── Workflow loading overlay ───────────────────────────────── */
.wf-loading-overlay {
    position: absolute;
    inset: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(13, 17, 23, 0.78);
    backdrop-filter: blur(2px);
}
.wf-loading-overlay.hidden { display: none; }
.wf-loading-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}
.wf-loading-spinner {
    width: 44px;
    height: 44px;
    border: 3px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: wf-spin 0.7s linear infinite;
}
@keyframes wf-spin { to { transform: rotate(360deg); } }
.wf-loading-label {
    font-size: 15px;
    color: var(--text-muted);
    font-weight: 500;
    letter-spacing: 0.01em;
}

/* ─── WMS Mock config panel ─────────────────────────────────────────────── */
.wf-wms-toggle-btn { margin-left: 6px; font-size: 11px; }
.wf-wms-toggle-btn.active { background: #1e3a5f; border-color: #3b82f6; color: #93c5fd; }
.wf-wms-panel {
    flex-shrink: 0;
    background: var(--bg-panel);
    border-bottom: var(--border-width) solid var(--border);
    padding: 8px 12px 4px;
}
.wf-wms-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    gap: 8px 12px;
}
.wf-wms-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.wf-wms-group-title {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    margin-bottom: 2px;
    border-bottom: 1px solid var(--bg-nested);
    padding-bottom: 2px;
}
.wf-wms-field {
    display: flex;
    flex-direction: column;
    gap: 1px;
    font-size: 11px;
    color: var(--text-muted);
}
.wf-wms-input {
    background: var(--bg-page);
    border: var(--border-width) solid var(--border);
    border-radius: 4px;
    color: var(--text-primary);
    font-size: 12px;
    padding: 3px 6px;
    outline: none;
}
.wf-wms-input:focus { border-color: #388bfd; }
.wf-wms-footer {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
    padding-top: 6px;
    border-top: 1px solid var(--bg-nested);
}
.wf-wms-hint {
    font-size: 10px;
    color: var(--text-faint);
    margin-left: auto;
}

/* ─── Workflow tab: panels wrapper holds both rows + the shared column split ── */
#ctab-workflow { overflow: hidden; }
.wf-panels {
    flex: 1;
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

/* Single column-split bar — absolutely positioned, spans full height of wf-panels */
.wf-col-split {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 5px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--border);
    cursor: col-resize;
    z-index: 20;
    transition: background 0.15s;
}
.wf-col-split:hover,
.wf-col-split:active { background: #818cf8; }

/* Invisible 5px spacers that keep flex-row layout intact where the bar sits */
.wf-col-spacer {
    width: 5px;
    flex-shrink: 0;
    background: transparent;
    pointer-events: none;
}

.wf-main-row {
    flex: 1;
    display: flex;
    flex-direction: row;
    overflow: hidden;
    min-height: 0;
}
.wf-main-row .net-drawer {
    flex: 1;
    min-width: 80px;
    min-height: 0;
    height: auto;
}
.wf-main-row .net-drawer.collapsed {
    flex: none;
    width: auto;
    height: 100%;
}
.wf-main-row .net-drawer-resize { display: none; }
#wf-event-drawer { height: 100% !important; }
#wf-event-drawer .net-drawer-header { cursor: default; }

/* wf-main-hsplit removed — replaced by single .wf-col-split overlay */

.wf-console-panel {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 80px;
    overflow: hidden;
    background: #0f172a;
}
.wf-console-panel .wf-bottom-panel-header {
    background: #1e293b;
    border-bottom: 1px solid #334155;
    color: #94a3b8;
}
.wf-console-panel .wf-callbacks-title { color: #94a3b8; }
.wf-console-log {
    flex: 1;
    max-height: none;
    display: block;
    overflow-y: auto;
    margin: 0;
    padding: 8px;
    border-radius: 0;
    border: none;
    background: #0f172a;
}

/* ─── All Events drawer fills its panel ──────────────────────── */
#ctab-all { overflow: hidden; }
#ctab-all .net-drawer {
    flex: 1;
    min-height: 0;
    height: auto;
}
#ctab-all .net-drawer.collapsed {
    flex: none;
    height: 36px;
}

/* ─── Service health pill ──────────────────────────────────────── */
.service-health-pill {
    font-size: 13px;
    font-weight: 600;
    padding: 3px 10px;
    border-radius: 12px;
    letter-spacing: 0.04em;
    white-space: nowrap;
    margin-left: auto;
}
.health-unknown { background: #1e293b; color: #94a3b8; }
.health-online  { background: #14532d; color: #86efac; }
.health-offline { background: #7f1d1d; color: #fca5a5; }

/* ─── Connector status pill ──────────────────────────────────── */
.connector-status-bar {
    font-size: 12px;
    font-weight: 600;
    padding: 3px 10px;
    border-radius: 12px;
    letter-spacing: 0.04em;
    white-space: nowrap;
    flex-shrink: 0;
    transition: background 0.4s, color 0.4s;
}
.connector-status-bar.status-connecting {
    background: #78350f;
    color: #fde68a;
}
.connector-status-bar.status-connected {
    background: #14532d;
    color: #86efac;
}
.connector-status-bar.status-disconnected {
    background: #7f1d1d;
    color: #fca5a5;
    animation: pulse-status 1.2s ease-in-out infinite;
}
@keyframes pulse-status {
    0%, 100% { background: #7f1d1d; }
    50%       { background: #991b1b; }
}

/* ─── Highlight row ──────────────────────────────────────────── */
.net-row-highlight {
    border-left: 3px solid var(--accent);
    padding-left: 9px;
}

/* ─── EVT badge ──────────────────────────────────────────────── */
.badge-evt { background: #1a4a3a; color: #68d391; }

/* ─── Method + status badges ──────────────────────────────────── */
.badge {
    font-size: 12px;
    font-weight: 700;
    padding: 1px 5px;
    border-radius: 3px;
    min-width: 48px;
    text-align: center;
    flex-shrink: 0;
}
.badge-get    { background: #1e3a5f; color: #93c5fd; }
.badge-post   { background: #14532d; color: #86efac; }
.badge-patch  { background: #451a03; color: #fed7aa; }
.badge-delete { background: #450a0a; color: #fca5a5; }
.badge-nats   { background: #2e1065; color: #c4b5fd; }

.badge-2xx { background: #14532d; color: #86efac; }
.badge-3xx { background: #451a03; color: #fed7aa; }
.badge-4xx { background: #450a0a; color: #fca5a5; }
.badge-5xx { background: #3b0000; color: #fca5a5; }
.badge-502 { background: #3b0000; color: #fca5a5; }

.badge-pub    { background: #164e63; color: #67e8f9; }
.badge-sub    { background: #2e1065; color: #c4b5fd; }

/* ─── NATS classified event badges ───────────────────────────── */
.badge-event  { background: #0f2e1e; color: #4ade80; }
.badge-step   { background: #1e3a5f; color: #60a5fa; }
.badge-status { background: var(--bg-nested); color: var(--text-muted); }
.badge-infra  { background: var(--bg-panel); color: var(--border); }

/* ─── Modals ──────────────────────────────────────────────────── */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
}
.modal-overlay.hidden { display: none; }

.modal {
    background: var(--bg-panel);
    border: var(--border-width) solid var(--border);
    border-radius: 10px;
    padding: 24px;
    width: 560px;
    max-height: 80vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 14px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.6);
}
.modal-title { font-size: 16px; font-weight: 600; color: var(--text-primary); }
.modal-label { font-size: 14px; color: var(--text-muted); display: flex; flex-direction: column; gap: 4px; }
.modal-label-hint { font-size: 12px; color: var(--text-muted); font-weight: 400; }
.modal-input, .modal-textarea {
    border: var(--border-width) solid var(--border);
    border-radius: 6px;
    padding: 8px 10px;
    font-size: 14px;
    font-family: 'Courier New', Courier, monospace;
    background: var(--bg-page);
    color: var(--text-primary);
}
.modal-textarea { resize: vertical; }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.modal-status { font-size: 13px; color: #f87171; min-height: 18px; }
.modal-status.error { color: #f87171; }

.modal-validate-status { padding: 4px 0 12px; }
.validate-running { font-size: 14px; color: var(--text-muted); }
.validate-ok      { font-size: 14px; color: #4ade80; font-weight: 600; }
.validate-error   { font-size: 14px; color: #f87171; font-weight: 600; }
.modal-loading { color: var(--text-muted); font-size: 14px; }
.modal-error   { color: #f87171; font-size: 14px; }
.modal-workflow-info { background: var(--bg-nested); border: var(--border-width) solid var(--border); border-radius: 6px; padding: 10px 12px; margin-bottom: 4px; font-size: 14px; }
.wf-info-row { display: flex; gap: 8px; padding: 2px 0; }
.wf-info-label { color: var(--text-muted); min-width: 72px; }
.step-list-details { margin-top: 8px; }
.step-list-details summary { cursor: pointer; color: #60a5fa; font-size: 13px; user-select: none; }
.step-list { margin: 6px 0 0 16px; padding: 0; font-size: 13px; color: var(--text-muted); }
.step-list li { padding: 1px 0; }
.step-list li.step-start { font-weight: 600; color: #4ade80; }

/* ─── Network Traffic Drawer ──────────────────────────────────── */
.net-drawer {
    flex-shrink: 0;
    background: var(--bg-chrome);
    color: var(--text-on-chrome);
    border-top: var(--border-width) solid var(--border-on-chrome);
    display: flex;
    flex-direction: column;
    transition: height 0.15s ease;
}

.net-drawer-resize {
    height: 6px;
    flex-shrink: 0;
    cursor: row-resize;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
}
.net-drawer-resize::after {
    content: "";
    width: 32px;
    height: 3px;
    border-radius: 2px;
    background: var(--border-on-chrome);
    transition: background 0.15s;
}
.net-drawer-resize:hover::after { background: #4a5568; }
.net-drawer.collapsed .net-drawer-resize { display: none; }

.net-drawer.collapsed {
    height: 36px;
    overflow: hidden;
}

.net-drawer.expanded {
    height: 30vh;
}

.net-drawer-header {
    height: 36px;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 12px;
    flex-shrink: 0;
    cursor: pointer;
    user-select: none;
}

.net-drawer-title {
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
}

.net-count {
    font-size: 12px;
    color: var(--text-muted);
    min-width: 70px;
}

.net-filter {
    flex: 1;
    max-width: 200px;
    background: var(--bg-nested);
    border: var(--border-width) solid var(--border);
    border-radius: 4px;
    color: var(--text-primary);
    font-size: 12px;
    padding: 2px 6px;
    height: 22px;
}

.net-btn {
    font-size: 12px;
    padding: 2px 8px;
    height: 22px;
}

.net-toggle-btn {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 12px;
    padding: 2px 4px;
    margin-left: auto;
}

.net-feed {
    flex: 1;
    overflow-y: auto;
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 14px;
}

.net-row {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 4px 12px;
    border-bottom: 1px solid rgba(48,54,61,0.5);
    cursor: pointer;
    white-space: nowrap;
}

.net-row:hover {
    background: rgba(48,54,61,0.5);
}

.net-row.net-expanded {
    flex-wrap: wrap;
}

.net-row.net-row-svc {
    border-left: 2px solid #667eea;
}

.net-src-badge {
    font-size: 10px;
    font-weight: 700;
    padding: 1px 4px;
    border-radius: 3px;
    background: #1e3a5f;
    color: #93c5fd;
    flex-shrink: 0;
    letter-spacing: 0.03em;
}

.net-ts {
    color: var(--text-muted);
    min-width: 88px;
    font-size: 13px;
}

.net-dir {
    font-size: 12px;
    font-weight: 700;
    min-width: 42px;
    letter-spacing: 0.02em;
    flex-shrink: 0;
}
.net-dir-in  { color: #60a5fa; }
.net-dir-out { color: #4ade80; }

.net-method {
    min-width: 46px;
    font-weight: 600;
    font-size: 13px;
}
.net-method.GET    { color: #4ade80; }
.net-method.POST   { color: #60a5fa; }
.net-method.PUT    { color: #fb923c; }
.net-method.PATCH  { color: #fb923c; }
.net-method.DELETE { color: #f87171; }

.net-status {
    min-width: 34px;
    font-weight: 600;
    font-size: 13px;
}
.net-status.s2xx { color: #4ade80; }
.net-status.s4xx { color: #fb923c; }
.net-status.s5xx { color: #f87171; }
.net-status.s0   { color: #f87171; }

.net-url {
    color: var(--text-primary);
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
}

.net-summary {
    color: var(--text-muted);
    font-size: 13px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding-right: 8px;
}

.net-duration {
    color: var(--text-muted);
    font-size: 12px;
    min-width: 50px;
    text-align: right;
}

.net-detail {
    display: none;
    width: 100%;
    white-space: pre-wrap;
    word-break: break-all;
    padding: 6px 12px;
    color: var(--text-muted);
    background: var(--bg-page);
    font-size: 14px;
    max-height: 160px;
    overflow-y: auto;
}

.net-row.net-expanded .net-detail {
    display: block;
}

/* ─── Device Client tab ───────────────────────────────────────────── */
.dc-gate {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    gap: 16px;
}
.dc-gate-hint {
    color: var(--text-muted);
    font-size: 14px;
}
.dc-gate .auth-status {
    font-size: 14px;
    color: var(--text-muted);
    min-height: 20px;
}

/* Content area */
.dc-content {
    display: flex;
    flex-direction: column;
    flex: 1;
    overflow: hidden;
    min-height: 0;
    position: relative;
}

/* Loading overlay (loadTasks / openTask) */
.dc-loading-overlay {
    position: absolute;
    inset: 0;
    z-index: 25;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(13, 17, 23, 0.78);
    backdrop-filter: blur(2px);
}
.dc-loading-overlay.hidden { display: none; }

/* Login overlay */
.dc-login-overlay {
    position: absolute;
    inset: 0;
    z-index: 20;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 20px;
    background: rgba(10, 10, 20, 0.75);
    backdrop-filter: blur(3px);
}
.dc-login-overlay.hidden { display: none; }
.dc-login-message {
    color: var(--text-primary);
    font-size: 18px;
    font-weight: 500;
}

/* ─── Authoring Tab ───────────────────────────────────────────── */
.at-body {
    display: grid;
    grid-template-columns: var(--at-w1, 240px) 6px var(--at-w2, 260px) 6px 1fr;
    flex: 1;
    overflow: hidden;
    min-height: 0;
}

#at-wf-col      { grid-column: 1; }
#at-rh-1        { grid-column: 2; }
#at-steps-panel { grid-column: 3; }
#at-flow-view   { grid-column: 3; }
#at-rh-2        { grid-column: 4; }
#at-editor-col  { grid-column: 5; }

.at-resize-h {
    background: var(--border);
    cursor: col-resize;
    transition: background 0.15s;
    z-index: 10;
    flex-shrink: 0;
}
.at-resize-h:hover, .at-resize-h.dragging { background: var(--accent); }

/* Flow mode */
.at-body-flow {
    grid-template-columns: var(--at-w1, 240px) 6px 1fr 6px var(--at-w3, 320px);
}
.at-body-flow #at-steps-panel { display: none; }
.at-body-flow #at-flow-view { display: flex; flex-direction: column; overflow: hidden; background: var(--bg-page); }
.at-body-flow .at-col-editor { border-left: none; }
.at-body-flow .at-textarea { font-size: 12px; }
.at-body-flow #at-engines-json { height: 100px; min-height: 60px; }
.at-body-flow #at-events-json { height: 56px; min-height: 40px; }
.at-body-flow #at-raw-json { height: 220px; min-height: 80px; }
.at-body-flow .at-label { font-size: 12px; }
.at-body-flow .at-input { font-size: 13px; }

.at-flow-toolbar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    background: var(--bg-chrome);
    border-bottom: var(--border-width) solid var(--border-on-chrome);
    flex-shrink: 0;
    flex-wrap: wrap;
}
.at-flow-back-btn { font-size: 13px; }
.at-flow-toolbar-sep { flex: 1; }
.at-flow-version-badge {
    font-size: 12px;
    color: var(--text-muted);
    white-space: nowrap;
}

.at-col {
    border-right: var(--border-width) solid var(--border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--bg-panel);
}

.at-col-editor {
    border-right: none;
    background: var(--bg-page);
}

.at-col-header {
    background: var(--bg-chrome);
    color: var(--text-on-chrome);
    padding: 8px 10px;
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.at-col-title {
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    flex: 1;
}

.at-header-btn {
    font-size: 12px;
    padding: 3px 8px;
}

.at-version-select {
    font-size: 13px;
    padding: 3px 6px;
    border: var(--border-width) solid var(--border-on-chrome);
    border-radius: 4px;
    background: var(--chrome-hover-bg);
    color: var(--text-on-chrome);
    cursor: pointer;
    max-width: 160px;
}

.at-readonly-notice {
    background: #2d2000;
    border-bottom: 1px solid #92400e;
    padding: 6px 10px;
    font-size: 13px;
    color: #fbd38d;
    flex-shrink: 0;
}

.at-col-actions {
    padding: 6px 10px;
    display: flex;
    gap: 4px;
    border-bottom: var(--border-width) solid var(--border);
    flex-shrink: 0;
    background: var(--bg-nested);
}

.at-search {
    width: 100%;
    padding: 7px 10px;
    border: none;
    border-bottom: var(--border-width) solid var(--border);
    font-size: 14px;
    background: var(--bg-panel);
    color: var(--text-primary);
    flex-shrink: 0;
    outline: none;
}

.at-list {
    flex: 1;
    overflow-y: auto;
}

.at-list-item {
    padding: 9px 12px;
    cursor: pointer;
    font-size: 14px;
    border-bottom: 1px solid var(--bg-nested);
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--text-primary);
}

.at-list-item:hover { background: #1c3052; }
.at-list-item.selected { background: #1e3a5f; font-weight: 600; }

.at-start-marker { color: var(--accent); font-size: 12px; flex-shrink: 0; }
.at-start-marker-empty { width: 12px; flex-shrink: 0; display: inline-block; }
.at-step-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.at-set-start-btn { font-size: 11px; padding: 1px 6px; opacity: 0; flex-shrink: 0; }
.at-list-item:hover .at-set-start-btn { opacity: 1; }

/* Flow diagram */
.at-flow-view { overflow: hidden; background: var(--bg-page); }
.at-flow-svg-wrap { flex: 1; overflow: auto; }
.at-flow-svg { display: block; }
.at-flow-edge { fill: none; stroke: #4a5568; stroke-width: 1.5; }
.at-flow-node rect { fill: var(--bg-nested); stroke: var(--border); stroke-width: 1.5; cursor: pointer; transition: stroke 0.1s; }
.at-flow-node:hover rect { stroke: var(--accent); }
.at-flow-start rect { stroke: var(--accent); stroke-width: 2; fill: #1c3052; }
.at-flow-selected rect { stroke: #2563eb; stroke-width: 2.5; fill: #1e3a5f; }
.at-flow-terminal rect { stroke-dasharray: 5 3; }
.at-fn-title { font: 600 12px system-ui, sans-serif; fill: var(--text-primary); pointer-events: none; }
.at-fn-id { font: 11px monospace; fill: var(--text-muted); pointer-events: none; }
.at-fn-badge { font: 700 9px system-ui, sans-serif; fill: #60a5fa; pointer-events: none; }
.at-fn-terminal { font: 700 10px system-ui, sans-serif; fill: #f87171; pointer-events: none; }
.at-fn-loading { font: 11px system-ui, sans-serif; fill: var(--text-muted); }

.at-placeholder {
    padding: 16px 12px;
    font-size: 14px;
    color: var(--text-muted);
}

.at-error {
    padding: 10px 12px;
    font-size: 14px;
    color: #f87171;
}

.at-reconnecting { color: var(--warning); }

/* Editor */
.at-editor {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.at-editor.hidden { display: none; }

.at-editor-tabs {
    display: flex;
    border-bottom: var(--border-width) solid var(--border);
    background: var(--bg-nested);
    flex-shrink: 0;
}

.at-editor-tab-btn {
    padding: 8px 16px;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    font-size: 14px;
    color: var(--text-muted);
    font-weight: 500;
}

.at-editor-tab-btn.active {
    border-bottom-color: var(--accent);
    color: var(--text-primary);
    font-weight: 600;
}

.at-editor-tab-panel {
    flex: 1;
    overflow-y: auto;
    padding: 12px 16px;
    background: var(--bg-page);
}

.at-editor-tab-panel.hidden { display: none; }

.at-field { margin-bottom: 14px; }

.at-label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 4px;
}

.at-step-id-display {
    font-family: 'Courier New', monospace;
    font-size: 12px;
    color: var(--text-muted);
    background: var(--bg-nested);
    padding: 4px 8px;
    border-radius: 4px;
    border: var(--border-width) solid var(--border);
    word-break: break-all;
    min-height: 22px;
}

.at-input {
    width: 100%;
    padding: 7px 9px;
    border: var(--border-width) solid var(--border);
    border-radius: 5px;
    font-size: 14px;
    background: var(--bg-page);
    color: var(--text-primary);
}

.at-input:disabled { background: var(--bg-nested); color: var(--text-muted); }

.at-textarea {
    width: 100%;
    padding: 7px 9px;
    border: var(--border-width) solid var(--border);
    border-radius: 5px;
    font-size: 13px;
    font-family: 'Courier New', Courier, monospace;
    background: var(--bg-page);
    color: var(--text-primary);
    resize: vertical;
    line-height: 1.5;
}

.at-textarea:disabled { background: var(--bg-nested); color: var(--text-muted); }
.at-textarea-tall { min-height: 420px; }

.at-editor-footer {
    padding: 10px 16px;
    border-top: var(--border-width) solid var(--border);
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--bg-nested);
    flex-shrink: 0;
}

.at-save-status { font-size: 14px; }
.at-save-status.ok { color: #4ade80; }
.at-save-status.error { color: #f87171; }

.at-script-panel {
    border-top: var(--border-width) solid var(--border);
    padding: 12px 16px 16px;
    background: var(--bg-nested);
}
.at-script-warning {
    background: #2d2000;
    border: 1px solid #92400e;
    border-radius: 6px;
    padding: 10px 12px;
    margin-bottom: 12px;
    font-size: 13px;
    line-height: 1.5;
    color: #fcd34d;
}
.at-script-warning code {
    background: #451a03;
    border-radius: 3px;
    padding: 1px 4px;
    font-family: monospace;
}
.at-script-panel-header {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 10px;
}
.at-script-footer {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
}

/* ─── Form Renderer (engine layout tree inspector) ─────────────── */
.at-field-tree { margin-bottom: 14px; }

.at-form-renderer {
    border: var(--border-width) solid var(--border);
    border-radius: 5px;
    padding: 8px;
    background: var(--bg-nested);
    font-size: 13px;
}

.fr-platform-header {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding-bottom: 6px;
    margin-bottom: 4px;
    border-bottom: var(--border-width) solid var(--border);
}

/* Node cards */
.fr-node {
    margin-top: 3px;
    border-left: 2px solid var(--border);
    padding-left: 8px;
}
.fr-node-structural { border-left-color: #4a5568; }
.fr-node-container  { border-left-color: #3b82f6; }
.fr-node-leaf       { border-left-color: #34d399; }

.fr-node-header {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 3px 0;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.fr-node-header::-webkit-details-marker { display: none; }

.fr-type-badge {
    font-size: 11px;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 10px;
    flex-shrink: 0;
}
.fr-badge-structural { background: var(--bg-nested); color: var(--text-muted); }
.fr-badge-container  { background: #1e3a5f; color: #93c5fd; }
.fr-badge-leaf       { background: #0f2e1e; color: #86efac; }

.fr-node-name {
    font-size: 12px;
    color: var(--text-muted);
    font-style: italic;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Props */
.fr-props { padding: 4px 0 4px 4px; }

.fr-prop-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 3px 0;
}

.fr-prop-label {
    font-size: 12px;
    color: var(--text-muted);
    width: 90px;
    flex-shrink: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fr-input {
    flex: 1;
    padding: 3px 7px;
    border: var(--border-width) solid var(--border);
    border-radius: 4px;
    font-size: 13px;
    background: var(--bg-page);
    color: var(--text-primary);
    min-width: 0;
}
.fr-input:disabled { background: var(--bg-nested); color: var(--text-muted); }
.fr-input:focus { outline: none; border-color: var(--accent); }

.fr-checkbox-wrap { display: flex; align-items: center; }

.fr-binding-badge {
    font-size: 12px;
    color: #60a5fa;
    background: #1e3a5f;
    padding: 1px 7px;
    border-radius: 10px;
    font-family: monospace;
}

/* Events */
.fr-events { padding: 4px 0 2px 4px; }

.fr-events-header {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 3px;
}

.fr-event-row {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 2px 0;
}

.fr-event-label {
    font-size: 11px;
    font-weight: 700;
    color: #fbbf24;
    background: #451a03;
    padding: 1px 6px;
    border-radius: 10px;
    flex-shrink: 0;
    margin-top: 1px;
}

.fr-actions { display: flex; flex-direction: column; gap: 2px; }

.fr-action-summary {
    font-size: 12px;
    color: var(--text-secondary);
    font-family: monospace;
    background: var(--bg-nested);
    padding: 1px 6px;
    border-radius: 3px;
}

/* Children indent */
.fr-children { margin-left: 0; }

/* ─── CodeMirror: Callbacks panel script asset preview ────────── */
.wf-cb-asset-cm {
    margin: 3px 6px 10px;
    border-radius: 4px;
    overflow: hidden;
}
.wf-cb-asset-cm .CodeMirror {
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 13px;
    line-height: 1.5;
    max-height: 420px;
    border: var(--border-width) solid var(--border);
    border-radius: 4px;
}

/* ─── CodeMirror: Script Asset panel (authoring tab) ──────────── */
#at-script-panel .CodeMirror {
    border: var(--border-width) solid var(--border);
    border-radius: 5px;
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 14px;
    line-height: 1.6;
    min-height: 220px;
    height: auto;
    background: #272822;   /* Monokai bg */
}
#at-script-panel .CodeMirror-scroll {
    min-height: 220px;
}

/* ─── Callbacks: combined flow-map + callback view ─────────────────── */

/* Gateway step group — purple left accent */
.wf-cb-group-gateway .wf-cb-step {
    border-left: 3px solid #a78bfa;
    background: #1e1a2e;
}
.wf-cb-group-gateway .wf-cb-step:hover { background: #252038; }

/* CONNECTOR GATEWAY badge on step heading */
.wf-cb-gateway-badge {
    margin-left: auto;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 10px;
    font-weight: 600;
    background: #2d1f4a;
    color: #d2a8ff;
    border: 1px solid #6e40c9;
    white-space: nowrap;
}

/* Background lookup step group — teal left accent (distinct from gateway
   purple: never blocks the device, no timeout, failure is silent) */
.wf-cb-group-lookup .wf-cb-step {
    border-left: 3px solid #56d4dd;
    background: #142526;
}
.wf-cb-group-lookup .wf-cb-step:hover { background: #1a2f30; }

/* BACKGROUND LOOKUP badge on step heading */
.wf-cb-lookup-badge {
    margin-left: auto;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 10px;
    font-weight: 600;
    background: #123338;
    color: #7ee8e8;
    border: 1px solid #2a7d84;
    white-space: nowrap;
}

/* "Device waits here" row inside a gateway step */
.wf-cb-wait-row {
    padding: 4px 10px;
    font-size: 11px;
    color: #a78bfa;
    font-style: italic;
    background: #1e1a2e;
    border-left: 3px solid #6e40c9;
    margin: 2px 0 4px;
}
.wf-cb-wait-row-clickable {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
}
.wf-cb-wait-row-clickable:hover {
    background: #251d3a;
    color: #c4b5fd;
}
.wf-cb-wait-edit-hint {
    font-style: normal;
    font-size: 10px;
    color: #7c3aed;
    opacity: 0.7;
    white-space: nowrap;
    margin-left: 8px;
}
.wf-cb-wait-row-clickable:hover .wf-cb-wait-edit-hint {
    opacity: 1;
    color: #a78bfa;
}

/* Tier badge: ⚡ connector  📱 local  · data */
.wf-cb-tier {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    font-size: 11px;
    flex-shrink: 0;
}
.wf-cb-tier-connector { color: #d2a8ff; }
.wf-cb-tier-local     { color: #56d364; }
.wf-cb-tier-data      { color: var(--text-faint); }

/* Connector action row — subtle purple tint */
.wf-cb-action-connector {
    background: #1e1a2e;
    border-left: 2px solid #6e40c9;
}
.wf-cb-action-connector:hover { background: #2d1f4a !important; }

/* Step name spans inside the heading */
.wf-cb-step-name { flex: 1; }

/* Separator between steps and script assets */
.wf-cb-asset-sep {
    border-top: var(--border-width) solid var(--border);
    margin: 10px 0 6px;
}

/* ═══════════════════════════════════════════════════════════════════════
   Android Device tab
   See docs/superpowers/specs/2026-07-06-android-device-tab-*.md
   ═══════════════════════════════════════════════════════════════════════ */

.ad-body {
    display: grid;
    grid-template-columns: var(--ad-w1, 320px) 6px 1fr 1fr;
    grid-template-rows: var(--ad-top-row-h, auto) 6px 1fr;
    column-gap: 0;
    row-gap: 0;
    padding: 12px;
    flex: 1;
    min-height: 0;
}

.ad-devices-panel { grid-column: 1; grid-row: 1 / 4; }
.ad-resize-h       { grid-column: 2; grid-row: 1 / 4; }
.ad-control-panel { grid-column: 3; grid-row: 1; position: relative; }
.ad-session-controls-panel { grid-column: 4; grid-row: 1; position: relative; }
.ad-top-row-resize-h { grid-column: 3 / 5; grid-row: 2; height: 6px; cursor: row-resize; border-radius: 3px; background: transparent; transition: background 0.15s; }
.ad-top-row-resize-h:hover, .ad-top-row-resize-h.dragging { background: var(--accent); }
.ad-logcat-panel  { grid-column: 3 / 5; grid-row: 3; min-height: 0; position: relative; }

.ad-subdued > *:not(.ad-select-device-overlay) {
    opacity: 0.35;
    pointer-events: none;
    user-select: none;
}
.ad-select-device-overlay {
    display: none;
    position: absolute;
    inset: 0;
    align-items: center;
    justify-content: center;
    z-index: 5;
    pointer-events: none;
}
.ad-subdued > .ad-select-device-overlay {
    display: flex;
}
.ad-select-device-overlay span {
    background: var(--bg-panel);
    border: var(--border-width) solid var(--border);
    border-radius: 8px;
    padding: 10px 18px;
    color: var(--text-primary);
    font-size: 14px;
    font-weight: 500;
    box-shadow: 0 4px 16px rgba(0,0,0,0.4);
}

.ad-resize-h {
    width: 6px;
    cursor: col-resize;
    border-radius: 3px;
    background: transparent;
    transition: background 0.15s;
    align-self: stretch;
}
.ad-resize-h:hover, .ad-resize-h.dragging { background: var(--accent); }

.ad-header-btn { margin-left: 8px; font-size: 12px; padding: 3px 8px; }

.ad-device-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    overflow-y: auto;
}

.ad-device-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px;
    border-radius: 6px;
    border: var(--border-width) solid var(--border);
    background: var(--bg-page);
    cursor: pointer;
}
.ad-device-row:hover { border-color: var(--accent); background: rgba(74,144,217,0.08); }
.ad-device-row-active {
    border-color: #2f81f7;
    background: rgba(47,129,247,0.20);
    box-shadow: 0 0 0 2px rgba(47,129,247,0.45);
}
.ad-device-row-active:hover { background: rgba(47,129,247,0.25); }
.ad-device-row-main {
    display: flex;
    align-items: center;
    gap: 8px;
}
.ad-device-name {
    flex: 1;
    font-size: 13px;
    color: var(--text-primary);
}
.ad-device-state {
    font-size: 11px;
    color: var(--text-muted);
    text-transform: uppercase;
}

.ad-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 6px 0;
}
.ad-label {
    font-size: 13px;
    color: var(--text-muted);
    min-width: 110px;
}
.ad-select, .ad-text-input {
    background: var(--bg-page);
    color: var(--text-primary);
    border: var(--border-width) solid var(--border);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 13px;
}
.ad-text-input { flex: 1; min-width: 200px; }
.ad-text-input:disabled { background: var(--bg-nested); color: var(--text-muted); }

.ad-results {
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 12px;
    white-space: pre-wrap;
    padding: 4px 0 4px 118px;
    min-height: 0;
}
.ad-result-ok { color: #7ee787; }
.ad-result-error { color: #fc8181; }

.ad-apk-info {
    padding: 4px 0 4px 118px;
    font-size: 0.9em;
    color: #7ee787;
}

.ad-device-status { font-size: 0.85em; margin-left: 8px; }
.ad-status-ok { color: #7ee787; }
.ad-status-missing { color: var(--text-muted); }
.ad-status-outdated { color: #f0c674; }
.ad-qr-value { word-break: break-all; max-width: 420px; display: inline-block; }
.ad-hint { font-size: 0.8em; opacity: 0.7; margin-left: 8px; }
.ad-status-pending { color: #58a6ff; }

/* Install & Launch / Session Controls: denser layout — these two panels
   accumulated a lot of rows over time and were running off the bottom of
   the viewport (feedback 2026-08-08). Buttons/rows scoped smaller+tighter
   here only, so the rest of the app (Connector tab, etc.) is unaffected. */
.ad-control-panel,
.ad-session-controls-panel {
    gap: 4px;
}
.ad-control-panel .ad-row,
.ad-session-controls-panel .ad-row {
    padding: 3px 0;
    gap: 6px;
}
.ad-control-panel .btn-primary,
.ad-control-panel .btn-secondary,
.ad-control-panel .btn-warning,
.ad-session-controls-panel .btn-primary,
.ad-session-controls-panel .btn-secondary,
.ad-session-controls-panel .btn-warning {
    padding: 4px 9px;
    font-size: 12px;
}
.ad-control-panel .ad-label,
.ad-session-controls-panel .ad-label {
    min-width: 90px;
    font-size: 12px;
}
.ad-control-panel .ad-results,
.ad-session-controls-panel .ad-results {
    padding-left: 0;
}
.ad-control-panel .ad-apk-info {
    padding-left: 0;
}

.ad-logcat-device-label {
    font-weight: 400;
    color: var(--text-muted);
    text-transform: none;
    letter-spacing: normal;
    margin-left: 6px;
}
.ad-logcat-filter {
    margin-left: auto;
    display: flex;
    border: var(--border-width) solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}
.ad-logcat-filter-btn {
    font-size: 12px;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text-muted);
    background: var(--bg-page);
    border: none;
    padding: 3px 10px;
    cursor: pointer;
}
.ad-logcat-filter-btn + .ad-logcat-filter-btn { border-left: var(--border-width) solid var(--border); }
.ad-logcat-filter-btn.active {
    background: var(--accent);
    color: #fff;
}
.ad-logcat-clear-result {
    font-size: 12px;
    min-height: 0;
    padding: 2px 0 6px;
}
.ad-logcat-feed {
    flex: 1;
    overflow-y: auto;
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 12px;
    background: var(--bg-page);
    border-radius: 6px;
    padding: 8px;
}
.ad-logcat-line {
    white-space: pre-wrap;
    word-break: break-all;
    border-bottom: 1px solid rgba(48,54,61,0.4);
    padding: 2px 0;
    color: var(--text-secondary);
}

/* Recording-active state for the Record Video button — red, hard to miss */
.btn-secondary.ad-recording-active {
    background: #da3633;
    color: #fff;
    border-color: #da3633;
}
.btn-secondary.ad-recording-active:hover { background: #b62324; }

.ad-sessions-resize-h {
    height: 6px;
    margin: 0 12px;
    cursor: row-resize;
    border-radius: 3px;
    background: transparent;
    transition: background 0.15s;
}
.ad-sessions-resize-h:hover, .ad-sessions-resize-h.dragging { background: var(--accent); }

.ad-sessions-panel {
    flex: 0 0 180px;
    margin: 0 12px 12px;
    min-height: 0;
}
.ad-sessions-list {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.ad-session-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 10px;
    border-radius: 6px;
    border: var(--border-width) solid var(--border);
    background: var(--bg-page);
    font-size: 12px;
}
.ad-session-name {
    font-family: 'Consolas', 'Monaco', monospace;
    color: var(--text-primary);
    min-width: 180px;
}
.ad-session-badges {
    flex: 1;
    color: var(--text-muted);
}
.ad-session-size {
    color: var(--text-muted);
    min-width: 60px;
    text-align: right;
}
.ad-session-download-btn {
    font-size: 12px;
    padding: 4px 10px;
    text-decoration: none;
    white-space: nowrap;
}

/* Real, persistent state — logs/video are still being written, so no
   Download button is offered at all for this row (see renderSessionsList).
   Pulses gently to read as "actively happening", not just a static label. */
.ad-session-row.ad-session-in-progress {
    border-color: #f0a020;
    background: rgba(240,160,32,0.08);
}
.ad-session-in-progress-badge {
    background: #f0a020;
    color: #1c1408;
    font-size: 10px;
    font-weight: 700;
    padding: 1px 7px;
    border-radius: 10px;
    letter-spacing: 0.05em;
    animation: ad-session-pulse 1.6s ease-in-out infinite;
}
@keyframes ad-session-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.55; }
}

/* Brief flash when a session just finished (Stop Testing succeeded and its
   zip is ready) — the Download button itself doesn't depend on this fading
   out, it's already showing; this is just the "hey, that one's ready now"
   notification. */
.ad-session-row.ad-session-complete {
    border-color: #7ee787;
    background: rgba(126,231,135,0.10);
    animation: ad-session-complete-fade 8s ease-out forwards;
}
@keyframes ad-session-complete-fade {
    0%, 60% { box-shadow: 0 0 0 2px rgba(126,231,135,0.5); }
    100% { box-shadow: 0 0 0 0 rgba(126,231,135,0); }
}
.ad-session-complete-badge {
    background: #7ee787;
    color: var(--bg-page);
    font-size: 10px;
    font-weight: 700;
    padding: 1px 7px;
    border-radius: 10px;
    letter-spacing: 0.05em;
}

/* Lasting (non-fading) marker for a session created earlier in this same
   browser visit, once neither of the two states above still applies — so a
   session stays identifiable as "from today's testing" indefinitely. */
.ad-session-row.ad-session-this-page { border-color: rgba(74,144,217,0.5); }
.ad-session-thispage-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
    flex-shrink: 0;
}

.ad-modal {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
}
.ad-modal.hidden { display: none; }
.ad-modal-content {
    background: var(--bg-panel);
    border-radius: 8px;
    width: 80vw;
    height: 80vh;
    display: flex;
    flex-direction: column;
    padding: 16px;
}
.ad-modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 8px;
    border-bottom: var(--border-width) solid var(--border);
    color: var(--text-muted);
    font-weight: 600;
}
.ad-ui-dump-xml {
    flex: 1;
    overflow: auto;
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 8px;
    white-space: pre-wrap;
    word-break: break-all;
}

.ad-bt-mac-qr-content {
    width: auto;
    height: auto;
}
.ad-wireless-result-content {
    width: auto;
    height: auto;
    max-width: 420px;
}
.ad-wireless-result-body {
    padding: 20px 4px 4px;
    font-size: 1.05em;
    line-height: 1.5;
}
.ad-bt-mac-qr-body {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    gap: 32px;
    padding: 24px;
}
.ad-bt-mac-code-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}
.ad-bt-mac-code-label {
    color: var(--text-muted);
    font-size: 0.9em;
    font-weight: 600;
}
.ad-bt-mac-qr-body img {
    width: 220px;
    height: 220px;
    background: #fff;
    padding: 12px;
    border-radius: 4px;
}
.ad-bt-mac-qr-body img.ad-bt-mac-code128-img {
    width: 300px;
    height: 120px;
}
#ad-bt-mac-qr-label {
    font-family: 'Consolas', 'Monaco', monospace;
    color: #7ee787;
}

/* ═══════════════════════════════════════════════════════════════════
   Inspections Tab — Project Gamma review UI
   ═══════════════════════════════════════════════════════════════════ */
.ir-body {
    display: grid;
    /* 2026-08-18: --ir-w1 drives the list panel's width, same CSS-variable technique the
       Device Client tab already uses for its resizable columns (see --dc-w1/attachColDrag
       in client.js) -- toggled discretely between the default and a collapsed rail width
       (toggleListCollapse in inspections.js), AND (2026-08-19) drag-adjustable via the
       #ir-rh-1 handle, same mechanism as the Device Client tab's own dc-rh-1/dc-rh-2.
       2026-08-19: the middle 6px column is that handle -- switched from a simple 2-column
       `gap` layout to the same gap:0 + explicit handle-column + .panel margin convention
       .app-body itself already uses (see `.app-body > .panel` below), since `gap` can't be
       selectively excluded around just the handle's own column. */
    grid-template-columns: var(--ir-w1, 320px) 6px 1fr;
    gap: 0;
    height: 100%;
    overflow: hidden;
    transition: grid-template-columns 0.15s ease;
}
.ir-header-btn { margin-left: 8px; font-size: 12px; padding: 3px 8px; }

/* 2026-08-18: collapsible task list -- lets the detail panel (and specifically Live View,
   see .ir-live-reference below) claim the freed width, e.g. so two 448px example photo
   cards can sit side by side instead of wrapping and pushing the panel's content taller
   than it needs to be. */
.ir-list-panel .panel-title { display: flex; align-items: center; gap: 8px; }
.ir-list-panel-title-text { flex: 1; }
.ir-list-collapse-btn {
    background: transparent; border: var(--border-width) solid var(--border); color: var(--text-muted);
    border-radius: 6px; width: 24px; height: 24px; font-size: 11px; line-height: 1;
    cursor: pointer; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
    padding: 0;
}
.ir-list-collapse-btn:hover { border-color: var(--accent); color: var(--text-primary); }
/* 2026-08-19: per the user, live -- a dedicated "completed work" icon for the collapsed
   rail, replacing the old plain total-count pill. Circle + checkmark (same ✓ glyph
   .ir-subtask-icon already uses elsewhere, not a new convention), with the count as a small
   bubble pinned to its bottom-right corner via position:absolute on a position:relative
   parent -- the standard "notification badge on an icon" pattern. */
.ir-list-completed-icon {
    display: none; position: relative; width: 28px; height: 28px; border-radius: 50%;
    background: var(--accent); color: #fff; font-size: 15px; font-weight: 700;
    align-items: center; justify-content: center; flex-shrink: 0;
}
.ir-list-completed-badge {
    position: absolute; bottom: -5px; right: -6px;
    min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
    background: var(--accent); color: #fff; font-size: 10px; font-weight: 700;
    display: flex; align-items: center; justify-content: center;
    border: 2px solid var(--bg-panel); /* matches .panel's own background, reads as a cutout ring */
}
.ir-list-completed-badge:empty, .ir-list-completed-badge[data-zero="true"] { display: none; }
.ir-list-panel.collapsed { padding: 14px 6px; align-items: center; }
.ir-list-panel.collapsed .panel-title {
    flex-direction: column; border-bottom: none; padding-bottom: 0; gap: 10px;
}
.ir-list-panel.collapsed .ir-list-panel-title-text,
.ir-list-panel.collapsed .ir-header-btn,
.ir-list-panel.collapsed .ir-filter-bar,
.ir-list-panel.collapsed .ir-redeploy-status,
.ir-list-panel.collapsed .ir-task-list {
    display: none;
}
.ir-list-panel.collapsed .ir-list-completed-icon { display: flex; }

.ir-redeploy-status {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px 12px;
    font-size: 12px;
}
.ir-redeploy-status.hidden { display: none; }
.ir-redeploy-line { color: var(--text-muted); }
.ir-redeploy-line.ok { color: #4caf50; }
.ir-redeploy-line.fail { color: #f87171; }

.ir-filter-bar { display: flex; gap: 6px; padding: 8px 12px; flex-wrap: wrap; }
.ir-filter-btn {
    font-size: 12px; padding: 4px 10px; border-radius: 12px;
    border: var(--border-width) solid var(--border); background: transparent; color: var(--text-muted); cursor: pointer;
}
.ir-filter-btn:hover { border-color: var(--accent); color: var(--text-primary); }
.ir-filter-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }

.ir-task-list {
    overflow-y: auto;
    padding: 4px 12px 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* 2026-08-19: per the user, live -- the default OS scrollbar here read as "ugly" next to
       the rest of this dark-themed dashboard. Thin + low-contrast, still fully functional
       (scrolling itself is unchanged, just the bar's own appearance). Firefox via the
       standard properties; Chrome/Edge (this environment) via the -webkit- pseudo-elements
       below, since scrollbar-width/-color alone have no effect there. */
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.ir-task-list::-webkit-scrollbar { width: 8px; }
.ir-task-list::-webkit-scrollbar-track { background: transparent; }
.ir-task-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.ir-task-list::-webkit-scrollbar-thumb:hover { background: var(--accent); }
/* 2026-08-19: per the user, live -- a real progress bar for the initial task-list load
   (10-15s on a real task history), so it's obviously pulling data down rather than
   possibly stuck. Width is driven from JS (updateLoadingProgress in inspections.js) off
   actual completed fetches, not a fake/looping animation. */
.ir-list-loading { padding: 24px 16px; display: flex; flex-direction: column; gap: 10px; }
.ir-list-loading-label { font-size: 13px; color: var(--text-muted); text-align: center; }
.ir-list-loading-track {
    height: 6px; border-radius: 3px; background: var(--bg-nested); overflow: hidden;
}
.ir-list-loading-fill {
    height: 100%; width: 0%; background: var(--accent); border-radius: 3px;
    transition: width 0.25s ease;
}
.ir-task-row {
    position: relative;
    padding: 10px 12px;
    border: var(--border-width) solid var(--border);
    border-radius: 8px;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.ir-task-row:hover { border-color: var(--accent); background: rgba(74,144,217,0.08); }
/* 2026-08-17: per the user, live -- "the blue color is fine but let's make it a little bit
   thicker, it's hard to see right now." Was a 1px border color swap on the same 1px border
   every row already has -- easy to miss. 3px + a stronger tint reads clearly as "selected"
   without changing the row's box size (border-box sizing, see .ir-task-row above). */
.ir-task-row.active { border: 3px solid var(--accent); background: rgba(74,144,217,0.22); }
.ir-task-title { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.ir-task-meta { font-size: 11px; color: var(--text-muted); display: flex; gap: 8px; align-items: center; }
.ir-task-status-pill {
    font-size: 10px; padding: 1px 7px; border-radius: 8px; font-weight: 600; text-transform: uppercase;
}
.ir-task-status-pill.inProgress { background: rgba(210,153,34,0.18); color: var(--warning-text); }
.ir-task-status-pill.completed { background: var(--success-bg); color: var(--success); }
.ir-task-flag-pill { font-size: 11px; color: var(--warning-text); }
/* 2026-08-19: per the user, live -- permanent per-task removal for stuck/incomplete
   "headless" test artifacts. Hidden until the row is hovered so the list doesn't read as
   cluttered with trash icons at rest -- matches this dashboard's existing convention of
   keeping chrome minimal until it's relevant (see e.g. #settingsIcon's own doc comment in
   gamma_shell.html for the same philosophy on the glasses side). */
.ir-task-delete-btn {
    position: absolute; top: 8px; right: 8px;
    background: none; border: none; cursor: pointer;
    font-size: 13px; opacity: 0; color: var(--text-muted);
    padding: 2px 5px; border-radius: 4px;
    transition: opacity 0.15s, color 0.15s, background 0.15s;
}
.ir-task-row:hover .ir-task-delete-btn { opacity: 1; }
.ir-task-delete-btn:hover { color: var(--danger); background: rgba(248,81,73,0.14); }

/* 2026-08-19: per the user -- same thin/theme-aware scrollbar treatment as .ir-task-list
   (the left panel), just applied to the right detail panel's own scroll container. */
.ir-detail-panel {
    position: relative; overflow-y: auto; padding: 4px 16px 24px;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.ir-detail-panel::-webkit-scrollbar { width: 8px; }
.ir-detail-panel::-webkit-scrollbar-track { background: transparent; }
.ir-detail-panel::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.ir-detail-panel::-webkit-scrollbar-thumb:hover { background: var(--accent); }
.ir-empty-state {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    height: 100%; gap: 6px; text-align: center;
}
.ir-empty-illustration { margin-bottom: 6px; opacity: 0.9; }
/* 2026-08-19: doubled from the original (17/13/12px), then per the user, live, brought back
   down ~10% (34/26/24 -> 30/22/22) -- and .ir-empty-listening's text explicitly matched to
   the same size as the surrounding body text (was left at its old pre-doubling 13px by
   mistake) rather than its own distinct size. Subtitle/listening/link intentionally share
   one size now -- they're all secondary/body text around the one larger title. */
.ir-empty-title { font-size: 30px; font-weight: 700; color: var(--text-secondary); }
.ir-empty-subtitle { font-size: 22px; color: var(--text-muted); margin: 0; }
.ir-empty-listening {
    display: flex; align-items: center; gap: 8px; margin-top: 14px;
    font-size: 22px; color: #58a6ff;
    /* 2026-08-19: per the user, live -- a distinct brighter blue from the standard var(--accent)
       accent used everywhere else on this page (links, .ir-live-dot, etc.), so this reads
       as its own thing. Whole row pulses as one unit (reusing ir-live-pulse, same animation
       already used for "actively live" elsewhere) on top of the dot-wave's own independent
       stagger animation on the "..." -- both run at once, not a replacement for it. */
    animation: ir-live-pulse 1.6s ease-in-out infinite;
}
/* Scoped override, not a change to the shared .ir-live-dot class (used elsewhere for the
   standard blue) -- keeps the dot matching this row's own distinct blue. */
.ir-empty-listening .ir-live-dot { background: #58a6ff; }
/* 2026-08-19: per the user, live -- toned down from the bright var(--accent) accent + full 22px
   body size, which read as too prominent next to the pulsing blue "Listening…" row above it.
   Muted gray (matching .ir-empty-subtitle's own tone) and smaller, a quiet secondary action
   rather than competing with the primary "listening" state. Still picks up the accent blue
   on hover so it's clearly still a real, clickable link. */
.ir-empty-link {
    margin-top: 10px; background: none; border: none; cursor: pointer;
    font-size: 14px; color: var(--text-faint); padding: 4px 8px;
}
.ir-empty-link:hover { color: var(--accent); text-decoration: underline; }
/* 2026-08-19: per the user, live -- animate the "…" itself, not just the dot next to it, so
   the whole line reads as actively happening rather than static text. Three separate spans
   with staggered opacity, same wave technique gamma_shell.html's #recDots/#initSpinnerDots
   already use on the glasses side (kept visually consistent across the product, even though
   this is a separate stylesheet). */
.ir-empty-dotwave span { animation: ir-empty-dotwave 1.2s ease-in-out infinite; opacity: 0.2; }
.ir-empty-dotwave span:nth-child(2) { animation-delay: 0.2s; }
.ir-empty-dotwave span:nth-child(3) { animation-delay: 0.4s; }
@keyframes ir-empty-dotwave { 0%, 60%, 100% { opacity: 0.2; } 30% { opacity: 1; } }
.ir-detail.hidden, .ir-empty-state.hidden { display: none; }

.ir-breadcrumb { font-size: 12px; color: var(--text-muted); margin: 8px 0; }

/* 2026-08-17: real-time signal from MainActivity.finishAndLoopViaVoice's uploadStatus write
   -- shown page-level (not inside a tab) since "don't power off the glasses" is safety
   information the viewer shouldn't have to go looking for. Made deliberately loud per live
   feedback ("very obvious and bold") -- bigger, bolder, a real spinner, not just an icon glyph. */
/* 2026-08-19: global stale-connection banner -- see index.html's comment on
   #stale-connection-banner for the incident this covers. Sits above every tab panel
   (sibling of .toolbar in the DOM), same warning color language as .ir-upload-banner. */
.stale-connection-banner {
    display: flex; align-items: center; justify-content: center; gap: 16px;
    background: rgba(240,136,62,0.18); border-bottom: 2px solid var(--warning-text);
    padding: 10px 18px;
    font-weight: 700; font-size: 14px; color: var(--warning-text);
}
.stale-connection-banner.hidden { display: none; }
.stale-connection-banner button {
    background: var(--warning-text); color: var(--bg-page); border: none; border-radius: 6px;
    padding: 6px 14px; font-weight: 700; font-size: 13px; cursor: pointer;
}
.stale-connection-banner button:hover { opacity: 0.85; }

.ir-upload-banner {
    display: flex; align-items: center; gap: 12px;
    background: rgba(240,136,62,0.18); border: 2px solid var(--warning-text); border-radius: 8px;
    padding: 14px 18px; margin-bottom: 12px;
    font-weight: 800; font-size: 17px; letter-spacing: 0.02em; color: var(--warning-text);
}
.ir-upload-banner.hidden { display: none; }
.ir-upload-spinner {
    width: 22px; height: 22px; flex-shrink: 0; border-radius: 50%;
    border: 3px solid rgba(240,136,62,0.3); border-top-color: var(--warning-text);
    animation: ir-upload-spin 0.8s linear infinite;
}
@keyframes ir-upload-spin {
    to { transform: rotate(360deg); }
}

.ir-detail-header { display: flex; gap: 16px; margin-bottom: 16px; flex-wrap: wrap; }
.ir-vehicle-card {
    flex: 2; min-width: 320px;
    display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap;
    border: var(--border-width) solid var(--border); border-radius: 10px; padding: 16px;
    background: var(--bg-panel);
}
.ir-vehicle-photo-placeholder {
    width: 72px; height: 72px; border-radius: 8px; background: var(--bg-nested);
    display: flex; align-items: center; justify-content: center; font-size: 30px; flex-shrink: 0;
}
.ir-vehicle-fields-wrap { flex: 1; }
/* 2026-08-19: per the user, live -- this used to be a single vertical stack of up to 7
   rows, tall enough to eat noticeably into the Live View space below it. Grid with
   grid-auto-flow:column + a fixed 2-row height reflows the same fields into a short, wide
   rail instead -- "two fields, then two more to the right, then two more" -- so it grows
   sideways (this card already had room, min-width 320px) rather than downward. */
.ir-vehicle-fields {
    display: grid; grid-auto-flow: column; grid-template-rows: repeat(2, auto);
    column-gap: 22px; row-gap: 4px;
    font-size: 12px; color: var(--text-muted); line-height: 1.6; margin-top: 4px;
}
.ir-vehicle-fields div { white-space: nowrap; }
.ir-vehicle-fields div span:first-child { color: var(--text-faint); margin-right: 6px; }

.ir-summary-card {
    flex: 1; min-width: 220px;
    border: var(--border-width) solid var(--border); border-radius: 10px; padding: 16px;
    background: var(--bg-panel);
    display: flex; align-items: center; gap: 16px;
}
.ir-summary-title { display: none; }
.ir-summary-counts { flex: 1; display: flex; flex-direction: column; gap: 6px; font-size: 12px; }
.ir-summary-counts .ir-summary-row { display: flex; justify-content: space-between; }
.ir-summary-counts .ir-summary-row .val { font-weight: 700; font-size: 15px; }
.ir-summary-counts .ir-summary-row.flagged .val { color: var(--danger); }
.ir-summary-counts .ir-summary-row.done .val { color: var(--success); }

.ir-completion-ring-wrap { position: relative; width: 80px; height: 80px; flex-shrink: 0; }
.ir-completion-ring { width: 80px; height: 80px; transform: rotate(-90deg); }
.ir-ring-track { fill: none; stroke: var(--border); stroke-width: 8; }
.ir-ring-progress {
    fill: none; stroke: var(--success); stroke-width: 8; stroke-linecap: round;
    stroke-dasharray: 213.6; /* 2*pi*34 */
    transition: stroke-dashoffset 0.3s;
}
.ir-completion-pct {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    font-size: 15px; font-weight: 700; color: var(--text-primary);
}

/* 2026-08-20: per the user, live -- the composite demo's tablet hole is short enough
   (~664px tall before the content-fit scale) that the full detail header (vehicle photo,
   order #/technician/completed fields, Download Report button, full summary card) was
   eating enough vertical space to push the checklist off the bottom of the visible frame.
   Keeps only what the user explicitly wanted -- the subject icon, title, and the
   completed/flagged/percent summary -- collapsed into one thin row instead of two full
   cards. Scoped to embedded mode only (see inspections.js's init()) -- normal full-browser
   dashboard use is untouched. */
body.embedded-mode .ir-detail-header {
    flex-wrap: nowrap; align-items: center; gap: 10px; margin-bottom: 8px;
}
body.embedded-mode .ir-vehicle-card {
    padding: 6px 10px; gap: 8px; min-width: 0; flex: 1 1 auto;
}
body.embedded-mode .ir-vehicle-photo-placeholder {
    width: 28px; height: 28px; font-size: 14px; border-radius: 6px;
}
body.embedded-mode #ir-detail-title { font-size: 15px; }
body.embedded-mode .ir-vehicle-fields,
body.embedded-mode #ir-download-report-btn {
    display: none;
}
body.embedded-mode .ir-summary-card {
    padding: 4px 12px; gap: 10px; min-width: 0; flex: 0 0 auto;
}
body.embedded-mode .ir-summary-counts {
    flex-direction: row; gap: 12px; font-size: 11px;
}
body.embedded-mode .ir-summary-counts .ir-summary-row {
    flex-direction: column; align-items: center; gap: 0;
}
body.embedded-mode .ir-summary-counts .ir-summary-row .val { font-size: 13px; }
body.embedded-mode .ir-completion-ring-wrap,
body.embedded-mode .ir-completion-ring {
    width: 34px; height: 34px;
}
body.embedded-mode .ir-ring-track,
body.embedded-mode .ir-ring-progress { stroke-width: 10; }
body.embedded-mode .ir-completion-pct { font-size: 10px; }

/* 2026-08-20: per the user, live -- My Work text "kind of small and hard to see" in the
   composite demo specifically (compounded by the tablet iframe's own 0.8x visual
   shrink-to-fit scale, see composite-demo.html) -- NOT the same request as the earlier
   3x-then-reverted pass, which was about normal full-browser use and stays reverted.
   Scoped to embedded mode only, same reasoning as the header rules above. */
body.embedded-mode .ir-checklist-row { gap: 14px; padding: 12px 14px; }
body.embedded-mode .ir-checklist-icon { width: 28px; height: 28px; }
body.embedded-mode .ir-checklist-label { font-size: 20px; }
body.embedded-mode .ir-checklist-value { font-size: 18px; padding: 5px 14px; }
body.embedded-mode #ir-checklist .ir-flag-badge { font-size: 20px; }
body.embedded-mode .ir-checklist-chevron { font-size: 16px; }
body.embedded-mode .ir-subtask-row { font-size: 17px; gap: 10px; }
body.embedded-mode .ir-subtask-icon { width: 17px; }
body.embedded-mode .ir-subtask-list,
body.embedded-mode .ir-checklist-detail {
    padding-left: 58px; /* tracks the row's new icon/gap/padding sizes above */
}

/* 2026-08-14: live reference panel — "what good looks like" guidance for whichever item is
   currently being discussed, replacing the tablet-companion task's second-device screen.
   2026-08-17: made significantly more prominent per live feedback (was too easy to miss),
   and extended with good/bad example photos + an illustrative warranty note — see
   ITEM_EXAMPLES in inspections.js. */
.ir-live-reference {
    border: 2px solid var(--accent); border-radius: 12px; padding: 18px 22px; margin-bottom: 18px;
    background: rgba(74,144,217,0.10);
}
.ir-live-reference.hidden { display: none; }

/* 2026-09-12: Multi Scan's live view -- see index.html's own comment for how this fits
   into the Live tab. Deliberately reuses --accent/--text-muted etc. rather than introducing
   new color tokens, matching every other panel in this file. */
.ir-multiscan-view.hidden { display: none; }
.ir-multiscan-batch.hidden { display: none; }
.ir-multiscan-batch { font-size: 14px; color: var(--text-muted); margin-bottom: 10px; }
.ir-multiscan-batch span { color: var(--text); font-weight: 600; font-family: monospace; }
.ir-multiscan-counts { display: flex; align-items: center; gap: 24px; margin-bottom: 16px; }
.ir-multiscan-count { display: flex; flex-direction: column; align-items: center; }
.ir-multiscan-count-value { font-size: 32px; font-weight: 700; color: var(--accent); line-height: 1; }
.ir-multiscan-count-label { font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; margin-top: 4px; }
.ir-multiscan-diagnostics {
    font-size: 12px; color: var(--text-muted); font-family: monospace; margin: 6px 0 16px;
}
.ir-multiscan-complete-badge {
    margin-left: auto; font-size: 13px; font-weight: 600; color: #68d391;
    background: rgba(104,211,145,0.12); border: 1px solid rgba(104,211,145,0.35);
    border-radius: 12px; padding: 4px 12px;
}
.ir-multiscan-complete-badge.hidden { display: none; }
.ir-multiscan-frame-wrap {
    position: relative; max-width: 480px; border-radius: 8px; overflow: hidden;
    background: var(--bg-chrome); min-height: 120px; display: flex; align-items: center; justify-content: center;
    margin-bottom: 18px;
}
.ir-multiscan-frame-img { display: block; width: 100%; height: auto; }
.ir-multiscan-frame-img:not([src]) { display: none; }
.ir-multiscan-frame-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; }
.ir-multiscan-frame-wrap .placeholder { position: absolute; margin: 0; }
.ir-multiscan-frame-wrap .ir-multiscan-frame-img[src] ~ .placeholder { display: none; }
.ir-multiscan-codes-heading { font-size: 13px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 8px; }
.ir-multiscan-codes-list { list-style: none; margin: 0; padding: 0; max-height: 240px; overflow-y: auto; }
.ir-multiscan-codes-list li {
    font-family: monospace; font-size: 13px; padding: 6px 10px; border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.08));
}
/* 2026-08-17: per the user, live -- label, "currently viewing" dot, and status/value used
   to be split across the top of the panel (label) and a separate row far below it
   (status/value) -- moved into one header row so they read as one unit. */
.ir-live-reference-label-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.ir-live-dot {
    width: 10px; height: 10px; border-radius: 50%; background: var(--accent); flex: 0 0 auto;
    animation: ir-live-pulse 1.6s ease-in-out infinite;
}
/* 2026-08-18: bumped 24px -> 30px (+25%) and text 16px -> 20px below, per the Live View
   redesign -- Live View is meant to read as the dominant, "full-screen-within-shell" view
   for an in-progress inspection, not a compact secondary tab. */
.ir-live-reference-label { font-weight: 800; color: var(--accent); font-size: 30px; letter-spacing: -0.01em; }
.ir-live-reference-status { display: flex; align-items: center; gap: 8px; }
.ir-live-status-icon { width: 20px; height: 20px; flex: 0 0 auto; }
/* 2026-08-19: per the user -- one consistent circle language everywhere: gray = pending,
   blue = in progress, green (+ checkmark, see STATUS_ICONS.done in inspections.js) = done.
   Was amber for in_progress and --text-faint for pending here specifically, out of step
   with .ir-checklist-icon's own colors just below (which already matched this scheme) --
   aligned to match. --border, not --text-faint, for pending: this is an icon fill, not
   body text, and --text-faint was just darkened toward near-black for text readability
   (see :root's own comment) -- reusing it here would make "nothing done yet" look almost
   as dark as "done", losing the muted/gray meaning entirely. */
.ir-live-status-icon.status-done, .ir-live-status-icon.status-mentioned { color: var(--success); }
.ir-live-status-icon.status-in_progress { color: var(--accent); }
.ir-live-status-icon.status-needsAttention { color: var(--danger); }
.ir-live-status-icon.status-pending { color: var(--border); }
.ir-live-status-value { font-size: 15px; font-weight: 600; color: var(--text-primary); }
.ir-live-status-value.ir-live-status-none { color: var(--success); font-style: italic; font-weight: 500; }
/* 2026-08-17: per the user, live -- referenceText is now authored as "• " bulleted lines
   joined by real newlines (see MainActivity.kt's GAMMA_REFERENCE_CONTENT), not a single
   prose paragraph. inspections.js's renderDetail sets this via .textContent (not
   innerHTML), so the newlines are already real characters; pre-line is what actually turns
   them into visible line breaks instead of collapsing to one line, while still word-wrapping
   normally within each bullet. */
.ir-live-reference-text { font-size: 20px; color: var(--text-primary); line-height: 1.6; margin: 0; white-space: pre-line; }

/* ── Good/bad example photos ─────────────────────────────────────────────── */
.ir-example-photos {
    display: flex; gap: 14px; margin-top: 16px; flex-wrap: wrap;
}
.ir-example-photos.hidden { display: none; }
.ir-example-card {
    /* 2026-08-17: went 220px+ -> 140px -> 70px on successive live feedback, then back up to
       140px ("maybe I misspoke... make them what they were before"), then doubled to 280px,
       then doubled again to 560px, all per live feedback during rack testing.
       2026-08-20: per the user, live -- "a tiny bit smaller" so two example cards (good/bad)
       can sit side by side in the Live View panel without wrapping -- at 448px, two plus the
       14px gap needed ~910px, too wide for most panel widths. 320px is a moderate trim
       (320*2+14=654px), not a return to the much-smaller sizes tried earlier in this same
       history -- adjust further if this still doesn't fit the actual panel width live. */
    flex: 0 0 320px; width: 320px; border-radius: 10px; overflow: hidden;
    background: var(--bg-panel); border: 3px solid transparent;
}
.ir-example-card.ir-example-good { border-color: var(--success); }
.ir-example-card.ir-example-bad { border-color: var(--danger); }
/* 2026-08-17: neutral reference photos (procedure steps, e.g. rack build) -- deliberately
   not green/red, there's no pass/fail framing for "here's what installing a tray looks like." */
.ir-example-card.ir-example-neutral { border-color: var(--border); }
.ir-example-card img {
    /* 2026-08-17: was a fixed 160px height against a flexible (220px+) width -- a wide,
       shallow crop that cut off most portrait-oriented reference photos. aspect-ratio keeps
       it square regardless of the card's actual rendered width, per live feedback. */
    width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; background: var(--bg-page);
    cursor: zoom-in;
}

/* 2026-08-17: full-screen reference-photo lightbox -- per the user, live: click any
   reference photo (good/bad/neutral) to see it full screen, close via the X or Escape.
   Highest z-index in the dashboard's overlay stack since nothing else should show through
   it once open. */
.ir-lightbox {
    position: fixed; inset: 0; background: rgba(0,0,0,0.9);
    display: flex; align-items: center; justify-content: center; z-index: 1000; padding: 40px;
}
.ir-lightbox.hidden { display: none; }
.ir-lightbox img {
    max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 8px;
    box-shadow: 0 10px 40px rgba(0,0,0,0.6);
}
.ir-lightbox-close {
    position: fixed; top: 20px; right: 28px; background: rgba(255,255,255,0.08);
    border: 1px solid rgba(255,255,255,0.25); color: #fff; font-size: 22px; line-height: 1;
    width: 44px; height: 44px; border-radius: 50%; cursor: pointer;
}
.ir-lightbox-close:hover { background: rgba(255,255,255,0.18); }

/* 2026-10-05, per the user, explicitly: progress/outcome modal for the single "Download &
   Email Report" button -- replaces three separate buttons with no feedback of their own.
   Same fixed/inset:0/centered pattern as .ir-lightbox above, one step down in z-index (900,
   not 1000) since the lightbox should still be able to cover it in the unlikely case both
   are ever open at once. */
.ir-report-modal {
    position: fixed; inset: 0; background: rgba(0,0,0,0.75);
    display: flex; align-items: center; justify-content: center; z-index: 900; padding: 20px;
}
.ir-report-modal.hidden { display: none; }
.ir-report-modal-box {
    background: var(--bg-panel); border: var(--border-width) solid var(--border);
    border-radius: 12px; padding: 24px 28px; min-width: 340px; max-width: 420px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.5);
}
.ir-report-modal-header { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.ir-report-modal-header h3 { margin: 0; font-size: 16px; color: var(--text-primary); }
.ir-report-modal-spinner {
    width: 20px; height: 20px; flex-shrink: 0; border-radius: 50%;
    border: 3px solid rgba(74,144,217,0.25); border-top-color: var(--accent);
    animation: ir-upload-spin 0.8s linear infinite;
}
.ir-report-modal-spinner.hidden { display: none; }
.ir-report-modal-steps { list-style: none; margin: 0 0 4px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.ir-report-modal-steps li {
    display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text-muted);
}
.ir-report-modal-steps li .ir-step-icon { flex: 0 0 auto; width: 16px; text-align: center; }
.ir-report-modal-steps li.active { color: var(--text-primary); }
.ir-report-modal-steps li.done { color: var(--text-primary); }
.ir-report-modal-steps li.done .ir-step-icon { color: var(--success); font-weight: 700; }
.ir-report-modal-steps li.warn .ir-step-icon { color: var(--warning-text); font-weight: 700; }
.ir-report-modal-steps li.active .ir-step-icon {
    display: inline-block; width: 10px; height: 10px; border-radius: 50%;
    border: 2px solid rgba(74,144,217,0.3); border-top-color: var(--accent);
    animation: ir-upload-spin 0.8s linear infinite;
}
.ir-report-modal-warning {
    margin-top: 14px; padding: 10px 12px; border-radius: 6px;
    background: rgba(240,136,62,0.14); border: 1px solid var(--warning-text);
    color: var(--warning-text); font-size: 13px; line-height: 1.5;
}
.ir-report-modal-warning.hidden { display: none; }
.ir-report-modal-error {
    margin-top: 14px; padding: 10px 12px; border-radius: 6px;
    background: rgba(248,81,73,0.14); border: 1px solid var(--danger);
    color: var(--danger); font-size: 13px; line-height: 1.5;
}
.ir-report-modal-error.hidden { display: none; }
.ir-report-modal-box .btn-secondary {
    margin-top: 18px; width: 100%;
}
.ir-report-modal-box .btn-secondary.hidden { display: none; }
.ir-example-tag {
    font-weight: 700; font-size: 13px; padding: 6px 10px;
}
.ir-example-good .ir-example-tag { color: var(--success); }
.ir-example-bad .ir-example-tag { color: var(--danger); }
.ir-example-caption { font-size: 13px; color: var(--text-secondary); padding: 0 10px 4px; }
.ir-example-credit { font-size: 10px; color: var(--text-faint); padding: 0 10px 10px; }

/* ── Illustrative warranty example ───────────────────────────────────────── */
.ir-warranty-example {
    margin-top: 16px; padding: 12px 16px; border-radius: 8px;
    background: rgba(240,136,62,0.10); border: 1px solid rgba(240,136,62,0.4);
}
.ir-warranty-example.hidden { display: none; }
.ir-warranty-tag {
    font-weight: 700; font-size: 11px; color: var(--warning-text); text-transform: uppercase;
    letter-spacing: 0.04em; margin-bottom: 6px;
}
.ir-warranty-example p { font-size: 13px; color: var(--text-secondary); line-height: 1.55; margin: 0; }

.ir-tabs { display: flex; gap: 4px; border-bottom: var(--border-width) solid var(--border); margin-bottom: 14px; }
.ir-tab-btn {
    background: none; border: none; color: var(--text-muted); padding: 8px 14px; font-size: 13px;
    cursor: pointer; border-bottom: 2px solid transparent;
}
.ir-tab-btn:hover { color: var(--text-primary); }
.ir-tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }

/* 2026-08-17: "so people are aware I'm currently in the live view for my inspection right
   now" -- green + a slow pulse on the Live View tab button itself, only while the selected
   inspection is genuinely still in progress (see renderDetail). Animates the tab's own text
   color, not the whole button, so it stays readable at every point in the cycle. */
.ir-tab-live-pulsing { color: var(--success) !important; animation: ir-live-pulse 1.6s ease-in-out infinite; }
.ir-tab-live-pulsing.active { border-bottom-color: var(--success); }
@keyframes ir-live-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.55; }
}
.ir-tab-content.hidden { display: none; }

.ir-checklist { display: flex; flex-direction: column; gap: 6px; }
.ir-checklist-item { border: var(--border-width) solid var(--border); border-radius: 6px; overflow: hidden; }
.ir-checklist-row {
    display: flex; align-items: center; gap: 10px; padding: 8px 10px;
    cursor: pointer;
}
.ir-checklist-item.flagged { border-color: rgba(240,136,62,0.5); }
.ir-checklist-row.flagged { background: rgba(240,136,62,0.08); }
.ir-checklist-row:hover { background: var(--panel-hover-bg); }
.ir-checklist-icon { width: 18px; height: 18px; flex-shrink: 0; }
.ir-checklist-icon.status-done { color: var(--success); }
.ir-checklist-icon.status-in_progress { color: var(--accent); }
.ir-checklist-icon.status-mentioned { color: var(--warning-text); }
.ir-checklist-icon.status-needsAttention { color: var(--danger); }
.ir-checklist-icon.status-pending { color: var(--border); }
.ir-checklist-label { flex: 1; font-size: 13px; color: var(--text-primary); }
.ir-checklist-value {
    font-size: 12px; font-weight: 700; color: var(--value-text); white-space: nowrap;
    background: var(--success-bg); border: 1px solid var(--success-border);
    padding: 3px 9px; border-radius: 10px;
}
/* 2026-08-17: "None" for a discussed-but-no-value item reuses .ir-checklist-value's green
   styling above (per the user, explicitly: green, not an error color) -- this just italicizes
   it to read as "confirmed nothing specific" rather than a real measurement. */
.ir-checklist-value-none { font-style: italic; opacity: 0.85; }
/* 2026-08-19: per the user -- "flagged" read as thin and too small on the My Work/completed
   section. Also fixes a real contrast bug found while checking this: var(--warning-text) computes to
   only 2.53:1 on white, failing WCAG AA outright (needs 3:1 even for bold text) -- routed
   through the existing --warning-text token (4.87:1) instead of a bare hardcoded color, so
   it's theme-aware like everything else now. */
.ir-flag-badge { font-size: 14px; font-weight: 700; color: var(--warning-text); white-space: nowrap; }
.ir-checklist-chevron {
    font-size: 10px; color: var(--text-muted); transition: transform 0.15s ease; flex-shrink: 0;
}
.ir-checklist-row.expanded .ir-checklist-chevron { transform: rotate(180deg); }

/* 2026-08-18: per-item subtasks (item{N}Sub{M}Label/Status in taskData) -- a small,
   read-only, always-visible rollup under the item's own row (not tucked inside the
   click-to-expand detail panel below), indented to roughly align under the row's label.
   No interactivity: this is a one-way render of taskData, same convention as the rest of
   this checklist (renderChecklistDetail, checklistRowInnerHtml). */
.ir-subtask-list {
    display: flex; flex-direction: column; gap: 3px;
    padding: 0 10px 8px 40px;
}
.ir-subtask-row { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.ir-subtask-row.done { color: var(--text-secondary); }
.ir-subtask-icon { flex: 0 0 auto; width: 12px; text-align: center; }
.ir-subtask-row.done .ir-subtask-icon { color: var(--success); font-weight: 700; }
/* 2026-08-19: --border, not --text-faint -- same reasoning as .ir-live-status-icon.status-
   pending's own comment above: this is an icon-ish glyph standing in for "not done yet," and
   --text-faint is now near-black (readability fix for real body text), which would make this
   look almost as dark as a completed subtask instead of clearly muted. */
.ir-subtask-row:not(.done) .ir-subtask-icon { color: var(--border); }
.ir-subtask-label { line-height: 1.4; }
/* 2026-10-05: gas MPI sub-steps' richer statuses (see renderSubtasks' own doc comment) --
   ok reuses the same green as .done; attention/immediate get the warning/danger colors
   already established for flagged items elsewhere on this page; not_applicable (a pure
   measurement, e.g. tread depth) gets a neutral dot, not a pass/fail color, since it isn't
   a pass/fail judgment at all. */
.ir-subtask-row.status-ok .ir-subtask-icon { color: var(--success); font-weight: 700; }
.ir-subtask-row.status-attention .ir-subtask-icon { color: var(--warning); font-weight: 700; }
.ir-subtask-row.status-immediate .ir-subtask-icon { color: var(--danger); font-weight: 700; }
.ir-subtask-row.status-not_applicable .ir-subtask-icon { color: var(--text-muted); }
.ir-subtask-value { color: var(--text-secondary); font-weight: 600; }

/* 2026-10-07, per the user (non-negotiable): the Vehicle Report Card tab is ONE sheet that
   matches the official Ford form. static/vehicle-card-sheet.js draws the official page (as
   an SVG background) with the answers on top; everything sits in a fixed 642.28 x 888.9
   aspect box (the form's own proportions, identical to the PDF export) so it scales as a
   unit and can never flow onto a second page. The sheet is always white "paper", in both
   themes, since the official art is black-on-white. */
.vrc-sheet-wrap { width: 100%; max-width: 900px; margin: 0 auto; container-type: inline-size; }
.vrc-sheet {
    position: relative; width: 100%; background: #fff; color: #000;
    box-shadow: 0 1px 6px rgba(0,0,0,0.35); overflow: hidden;
    container-type: inline-size;
}
.vrc-sheet-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.vrc-sheet-loading { padding: 24px; color: var(--text-secondary); text-align: center; }
/* Edit-mode hit areas / inputs: HTML laid over the svg in percentages of the sheet. */
.vrcs-hit { position: absolute; display: block; cursor: pointer; box-sizing: border-box; border-radius: 2px; }
.vrcs-hit-round { border-radius: 50%; }
.vrcs-hit:hover, .vrcs-hit:focus-visible { box-shadow: 0 0 0 1.5px rgba(47,155,255,0.9); outline: none; }
.vrcs-input {
    position: absolute; box-sizing: border-box; padding: 0 2px; margin: 0;
    font-family: Helvetica, Arial, sans-serif; line-height: 1.1; color: #0b1f73;
    background: #fffbe0; border: 1px solid rgba(47,155,255,0.7); border-radius: 2px;
    resize: none; overflow: hidden;
}
.vrcs-input:focus { outline: none; border-color: #2f9bff; background: #fffbe0; }
/* Corrected-field badge: a small black disc with a white check, laid over the form (never in
   its flow), tooltip carries "corrected by X on Y" (see vehicle-card-sheet.js editedInfo). */
.vrcs-badge {
    position: absolute; z-index: 2; box-sizing: border-box; border-radius: 50%;
    background: #000; border: 1px solid #2f9bff; pointer-events: auto;
    display: flex; align-items: center; justify-content: center;
}
.vrcs-badge::after { content: "\2713"; color: #fff; font-weight: 900; font-size: 2cqw; line-height: 1; }

/* Print: exactly one sheet. @page is the official form's own size (642.28 x 888.9pt), no
   margins. The visible tab can't be printed in place -- hidden-but-laid-out dashboard
   content still paginates -- so vehicle-card-sheet.js keeps a read-only copy of the sheet
   in #vrc-print-host (a direct child of <body>, display:none on screen). When the Vehicle
   Report Card tab is the visible tab, printing display:none's every other body child and
   shows only that host, fixed at the page's exact size with overflow clipped, so the
   browser has exactly one page's worth of content. */
@page { size: 642.28pt 888.9pt; margin: 0; }
#vrc-print-host { display: none; }
@media print {
    html:has(.ir-tab-content:not(.hidden) .vrc-sheet-wrap) body > *:not(#vrc-print-host) { display: none !important; }
    html:has(.ir-tab-content:not(.hidden) .vrc-sheet-wrap), html:has(.ir-tab-content:not(.hidden) .vrc-sheet-wrap) body {
        margin: 0 !important; padding: 0 !important; background: #fff !important;
        height: 888.9pt !important; overflow: hidden !important;
    }
    html:has(.ir-tab-content:not(.hidden) .vrc-sheet-wrap) #vrc-print-host {
        display: block !important; width: 642.28pt; height: 888.9pt; overflow: hidden;
        break-inside: avoid; page-break-after: avoid;
    }
    #vrc-print-host .vrc-sheet-wrap { width: 642.28pt; height: 888.9pt; max-width: none; margin: 0; }
    #vrc-print-host .vrc-sheet { box-shadow: none; width: 642.28pt; height: 888.9pt; }
}

/* 2026-10-06, per the user, explicitly: "if the glasses got it wrong they can make their
   own edits" -- Vehicle Report Card edit mode. ir-vehicle-card-toolbar/-edit-actions hold
   the Edit / Save Corrections / Cancel buttons above the card; vrc-dot-editable and
   vrc-edit-input are the clickable/typeable controls a row's dot/value become once edit
   mode is on (see static/inspections.js's vrcDot/vrcValue); vrc-edited-badge marks a field
   that shows up in the task's manualEditLog, so a correction stays visibly distinct from
   what the glasses' AI originally wrote, per the user's own "track editor + timestamp" ask. */
.ir-vehicle-card-toolbar {
    display: flex; justify-content: flex-end; gap: 8px; padding-bottom: 10px;
}
/* :not(.hidden), not a bare class rule -- .hidden (display:none) is declared earlier in
   this file at equal specificity, so a later plain ".ir-vehicle-card-edit-actions { display:
   flex }" rule would win the cascade and defeat .hidden when both classes are present. */
.ir-vehicle-card-edit-actions:not(.hidden) { display: flex; gap: 8px; }

.ir-checklist-detail {
    padding: 10px 12px 12px 40px; border-top: var(--border-width) solid var(--border);
    background: var(--bg-page); display: flex; flex-direction: column; gap: 10px;
}
.ir-checklist-detail.hidden { display: none; }
.ir-checklist-detail-value {
    display: flex; flex-direction: column; gap: 4px; padding: 10px 12px;
    background: var(--success-bg); border: 1px solid var(--success-border); border-radius: 6px;
}
.ir-checklist-detail-value strong {
    color: var(--text-muted); font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
}
.ir-checklist-detail-value-text { font-size: 18px; font-weight: 700; color: var(--value-text); line-height: 1.2; }
.ir-checklist-detail-transcript { display: flex; flex-direction: column; gap: 4px; }
.ir-checklist-transcript-entry {
    font-size: 12px; color: var(--text-secondary); line-height: 1.5; padding: 4px 8px;
    background: var(--bg-panel); border-radius: 4px;
}
.ir-checklist-detail-snippet { display: flex; align-items: center; gap: 10px; }
.ir-checklist-detail-snippet .ir-media-thumb { width: 120px; aspect-ratio: 16/9; border-radius: 4px; flex-shrink: 0; }
.ir-checklist-detail-empty { font-size: 12px; color: var(--text-muted); font-style: italic; }

/* 2026-08-19: per the user, live -- items gated on real-time AI visual verification need
   to read as a hard requirement on the submitted report: a bright-red badge on the
   collapsed row (checklistRowInnerHtml), and the full explanation + AI commentary log +
   the actual passing frame inside the row's own expand panel (renderChecklistDetail). */
.ir-critical-badge {
    display: inline-flex; align-items: center; gap: 4px; font-size: 10px; font-weight: 800;
    color: #fff; background: var(--danger); padding: 3px 8px; border-radius: 10px;
    text-transform: uppercase; letter-spacing: 0.03em; white-space: nowrap;
}
.ir-critical-banner {
    display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px;
    background: rgba(248,81,73,0.12); border: 1px solid var(--danger); border-radius: 6px;
}
.ir-critical-banner-icon { font-size: 18px; line-height: 1.2; flex-shrink: 0; color: var(--danger); }
.ir-critical-banner-text { font-size: 13px; color: var(--text-primary); line-height: 1.5; }
.ir-critical-banner-text strong {
    color: var(--danger); display: block; font-size: 11px; text-transform: uppercase;
    letter-spacing: 0.04em; margin-bottom: 2px;
}
.ir-verification-log {
    display: flex; flex-direction: column; gap: 4px; padding: 10px 12px;
    background: var(--bg-panel); border: 1px solid var(--border); border-radius: 6px;
}
.ir-verification-log strong {
    color: var(--text-muted); font-weight: 600; font-size: 10px; text-transform: uppercase;
    letter-spacing: 0.05em;
}
.ir-verification-log-line { font-size: 12px; color: var(--text-secondary); line-height: 1.5; }
.ir-verification-image { display: flex; flex-direction: column; gap: 6px; }
.ir-verification-image strong {
    color: var(--text-muted); font-weight: 600; font-size: 10px; text-transform: uppercase;
    letter-spacing: 0.05em;
}
.ir-verification-image-img {
    max-width: 560px; border-radius: 6px; border: var(--border-width) solid var(--border);
    cursor: zoom-in; /* 2026-08-19: per the user -- clickable to open full screen, same as reference photos */
}

.ir-cards-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px;
}
.ir-media-card {
    border: var(--border-width) solid var(--border); border-radius: 8px; overflow: hidden; background: var(--bg-panel);
}
.ir-media-thumb {
    width: 100%; aspect-ratio: 16/9; object-fit: cover; background: var(--bg-page);
    display: flex; align-items: center; justify-content: center; color: var(--border); font-size: 28px;
}
.ir-media-body { padding: 8px 10px; display: flex; flex-direction: column; gap: 4px; }
.ir-media-label { font-size: 12px; font-weight: 600; color: var(--text-primary); }
.ir-media-sub { font-size: 11px; color: var(--text-muted); }
.ir-media-download {
    display: inline-flex; align-items: center; gap: 4px; font-size: 11px; padding: 3px 8px;
    margin-top: 2px; width: fit-content;
}

.ir-notes-text { font-size: 13px; color: var(--text-primary); line-height: 1.6; white-space: pre-wrap; }
.ir-transcript-heading { font-size: 12px; font-weight: 600; color: var(--text-muted); margin-top: 20px; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.04em; }
.ir-transcript-inline {
    display: flex; flex-direction: column; gap: 4px; max-height: 320px; overflow-y: auto;
    border: var(--border-width) solid var(--border); border-radius: 6px; padding: 10px; background: var(--bg-page);
}
.ir-transcript-inline-entry { font-size: 12px; color: var(--text-secondary); line-height: 1.5; }
.ir-transcript-inline-entry .ts { color: var(--text-muted); margin-right: 6px; }
.ir-transcript-links { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; }
.ir-transcript-links a { font-size: 12px; }

/* 2026-09-01: conversational assistant — Frontline Live's long-format counterpart to the
   glasses' own short/simple dialog (see MainActivity's openAssistantDialog doc comment). */
.ir-assistant-transcript { display: flex; flex-direction: column; gap: 12px; max-height: 70vh; overflow-y: auto; }
/* 2026-09-02, per the user, live -- "round the box" (more chat-bubble-like, less flat
   card) and the text bumped to match .ir-live-reference-text's 20px (the step-instruction
   body text elsewhere in this same Live View) -- "a similar font size as the instructions
   for the steps... these are gonna be on tablets." */
.ir-assistant-turn { border-radius: 16px; padding: 12px 16px; border: var(--border-width) solid var(--border); }
.ir-assistant-turn-user { background: var(--bg-page); }
.ir-assistant-turn-assistant { background: var(--accent-bg, rgba(77, 166, 255, 0.08)); border-color: var(--accent, #4da6ff); }
.ir-assistant-turn-speaker { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }
.ir-assistant-turn-ts { font-size: 12px; color: var(--text-muted); margin-left: 8px; }
/* 2026-09-02: switched from a plain white-space:pre-wrap <p> to rendered markdown (see
   renderAssistantMarkdown in inspections.js) so a Claude answer that comes back as a
   table (common for multi-item/BOM-style questions) renders as a real table instead of
   raw pipes/dashes. Block-element spacing below replaces what pre-wrap used to give
   plain-text answers for free. */
.ir-assistant-turn-text { font-size: 20px; color: var(--text-primary); line-height: 1.6; margin: 6px 0 0; }
.ir-assistant-turn-text > *:first-child { margin-top: 0; }
.ir-assistant-turn-text > *:last-child { margin-bottom: 0; }
.ir-assistant-turn-text p, .ir-assistant-turn-text ul, .ir-assistant-turn-text ol { margin: 0.6em 0; }
.ir-assistant-turn-text ul, .ir-assistant-turn-text ol { padding-left: 1.4em; }
.ir-assistant-turn-text li { margin: 0.2em 0; }
.ir-assistant-turn-text strong { font-weight: 700; }
.ir-assistant-turn-text code { font-size: 0.85em; background: rgba(127,127,127,0.18); border-radius: 4px; padding: 0.1em 0.35em; }
.ir-assistant-turn-text table {
    width: 100%; border-collapse: collapse; margin: 0.6em 0; font-size: 0.85em;
    border: var(--border-width) solid var(--border); border-radius: 8px; overflow: hidden;
}
.ir-assistant-turn-text th, .ir-assistant-turn-text td {
    border: var(--border-width) solid var(--border); padding: 6px 10px; text-align: left;
}
.ir-assistant-turn-text th { background: rgba(127,127,127,0.12); font-weight: 700; }
.ir-assistant-turn-text tr:nth-child(even) td { background: rgba(127,127,127,0.05); }

/* 2026-09-02: conversational assistant rail -- slides out from the right over whichever
   Live View content is showing while the inspection is in progress; becomes the normal
   #ir-tab-assistant tab (above) once the task completes. See the "assistant tab
   visibility" block in inspections.js's per-task render, and setAssistantRailOpen. */
/* 2026-09-02, per the user, live -- "difficult to see... make the button a little bit
   larger... make it look like a folder or something." Substantially bigger footprint,
   bolder border/shadow, and a folder-tab silhouette (taller than it needs to be for its
   own content, rounded only on the exposed left corners) instead of reading as a plain
   small button. */
.ir-assistant-handle {
    position: fixed; top: 40%; right: 0; z-index: 400;
    display: flex; flex-direction: column; align-items: center; gap: 8px;
    background: var(--bg-panel); border: 2px solid var(--border); border-right: none;
    border-radius: 14px 0 0 14px; padding: 22px 14px; cursor: pointer;
    color: var(--text-secondary); font-size: 15px; font-weight: 700;
    box-shadow: -4px 0 14px rgba(0,0,0,0.25);
}
.ir-assistant-handle:hover { color: var(--text-primary); border-color: var(--accent); }
.ir-assistant-handle.hidden { display: none; }
.ir-assistant-handle-icon { font-size: 28px; }
.ir-assistant-handle-label { writing-mode: vertical-rl; text-orientation: mixed; letter-spacing: 0.04em; }
/* "a conversation is actually happening right now" -- reuses the Live View tab's own
   pulse animation/meaning (ir-live-pulse), toggled by the open/close lifecycle frames,
   independent of the handle's always-on in-progress visibility above. */
.ir-assistant-handle.ir-assistant-handle-active {
    color: var(--success); border-color: var(--success);
    animation: ir-live-pulse 1.6s ease-in-out infinite;
}

/* 2026-09-02, per the user, live -- "go further out, like sixty percent... this is for
   tablets" -- wider panel + a taller max-width ceiling than the original 40%/560px pass. */
.ir-assistant-rail {
    position: fixed; top: 0; bottom: 0; right: 0; width: 60%; min-width: 360px; max-width: 900px;
    background: var(--bg-panel); border-left: var(--border-width) solid var(--border);
    box-shadow: -6px 0 20px rgba(0,0,0,0.4); z-index: 410;
    display: flex; flex-direction: column;
    transform: translateX(100%); transition: transform 0.28s ease, box-shadow 0.6s ease;
}
.ir-assistant-rail.hidden { display: none; }
.ir-assistant-rail.open { transform: translateX(0); }
/* "make the whole box pulse a little bit" while a conversation is actually live -- a
   subtle glow on the panel's own edge, deliberately gentler than the handle's opacity
   pulse (an opacity pulse on a panel this large would be distracting, not just noticeable). */
.ir-assistant-rail.ir-assistant-rail-active {
    animation: ir-assistant-rail-glow 1.8s ease-in-out infinite;
}
@keyframes ir-assistant-rail-glow {
    0%, 100% { box-shadow: -6px 0 20px rgba(0,0,0,0.4), inset 3px 0 0 var(--success); }
    50% { box-shadow: -6px 0 28px rgba(63,185,80,0.35), inset 3px 0 0 var(--success); }
}
.ir-assistant-rail-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 20px; border-bottom: var(--border-width) solid var(--border);
    font-weight: 700; font-size: 16px; color: var(--text-primary); flex-shrink: 0;
}
.ir-assistant-rail-close { background: none; border: none; color: var(--text-muted); font-size: 18px; cursor: pointer; padding: 2px 8px; }
.ir-assistant-rail-close:hover { color: var(--text-primary); }
/* min-height: 0 is required here -- without it a flex child with overflow-y:auto still
   grows to fit its content instead of scrolling, since a flex item's default min-height
   is auto (content size), not 0. That's why this never scrolled: max-height:none dropped
   the base rule's scroll box and nothing replaced it. */
.ir-assistant-rail .ir-assistant-transcript { flex: 1; min-height: 0; max-height: none; overflow-y: auto; padding: 16px 20px; margin: 0; }
.ir-assistant-rail #ir-assistant-rail-empty { padding: 0 20px; }

/* 2026-09-02: one collapsible session per open/close conversation -- see renderAssistantTab
   in inspections.js. Native <details>/<summary> for free keyboard/accessibility behavior
   and to avoid a separate JS-driven expand/collapse toggle. */
.ir-assistant-session {
    /* flex-shrink: 0 is required -- .ir-assistant-transcript is itself display:flex;
       flex-direction:column (see its own rule above), so without this, the browser's
       default flex-shrink:1 on every session card COMPRESSES all of them down to fit
       inside the transcript's box instead of the box actually overflowing. That's the
       real reason scrolling never worked: scrollHeight was always being squeezed down to
       equal clientHeight, so there was never anything to scroll, live-tested and confirmed
       via a real headless-browser session (scrollHeight==clientHeight with 36 real turns
       pushed in, before this fix). */
    flex-shrink: 0;
    border: var(--border-width) solid var(--border); border-radius: 14px; overflow: hidden;
    background: var(--bg-panel);
}
.ir-assistant-session-summary {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 12px 16px; cursor: pointer; list-style: none; user-select: none;
}
.ir-assistant-session-summary::-webkit-details-marker { display: none; }
.ir-assistant-session-summary::before {
    content: "\25B8"; display: inline-block; margin-right: 10px; color: var(--text-muted);
    transition: transform 0.15s ease; flex-shrink: 0;
}
.ir-assistant-session[open] > .ir-assistant-session-summary::before { transform: rotate(90deg); }
.ir-assistant-session-summary:hover { background: rgba(127,127,127,0.08); }
.ir-assistant-session-recap { font-size: 15px; font-weight: 600; color: var(--text-primary); }
.ir-assistant-session-meta { font-size: 12px; color: var(--text-muted); white-space: nowrap; flex-shrink: 0; }
.ir-assistant-session-body {
    display: flex; flex-direction: column; gap: 12px;
    padding: 4px 16px 16px; border-top: var(--border-width) solid var(--border);
}
/* A still-open conversation gets a live accent so it reads as "in progress" even collapsed
   (rare, only if the technician manually collapses it mid-conversation). */
.ir-assistant-session-live { border-color: var(--accent, #4da6ff); }
.ir-assistant-session-live .ir-assistant-session-recap { color: var(--accent, #4da6ff); }

/* Mobile QA tab -- see docs/superpowers/specs/2026-10-01-mobile-qa-design.md */
/* .app-body is normally a 5-column CSS grid (280px/6px/1fr/6px/300px) built for the
   Device Client's 3-pane + resize-handle layout -- Mobile QA only has two plain
   .panel sections, so it must fully switch to flex (flex-direction alone does
   nothing on a grid container) or the second panel lands in the 6px resize-handle
   grid cell and gets squeezed to a sliver. */
.mqa-body { display: flex; flex-direction: column; padding: 20px; gap: 20px; overflow-y: auto; }
/* .panel's own `overflow: auto` makes its flexbox auto min-height resolve to 0, so as flex
   items both panels would fight for space and get squeezed short instead of keeping their
   natural content height -- .mqa-body already scrolls the whole tab, so neither panel here
   should shrink at all. */
.mqa-body > .panel { flex-shrink: 0; }
.mqa-blurb { padding: 0 0 10px; text-align: left; color: var(--text-muted); font-size: 13px; }
.mqa-seed-list { margin: 8px 0 0; padding-left: 18px; font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; }
.mqa-error { color: #fc8181; }
.mqa-gallery {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}
.mqa-shot {
    margin: 0;
    width: 220px;
    background: var(--bg-panel);
    border: 1px solid var(--border-color, rgba(255,255,255,0.08));
    border-radius: 8px;
    overflow: hidden;
}
.mqa-shot img {
    display: block;
    width: 100%;
    height: auto;
}
.mqa-shot figcaption {
    padding: 8px 10px;
    font-size: 12px;
    color: var(--text-muted);
    text-align: center;
}

/* 2026-10-08: combined report button's quiet status note (metadata still uploading / video
   upload state) -- deliberately unobtrusive, never a banner. */
.ir-report-status { margin-top: 6px; font-size: 12px; color: var(--text-muted); }
.ir-report-status:empty { display: none; }

/* 2026-10-08: Live View parent/child tree (same structure as My Work, live). */
/* Frontline Live redo: item list + one large active-item card (not My Work). */
#ir-live-reference, #ir-live-empty { display: none !important; }
.ir-live-tree { display: block; margin-top: 8px; }
.ir-live-tree.hidden { display: none; }
.ir-live-split.ir-live-single { grid-template-columns: 1fr; }
.ir-live-tree { position: relative; }
.ir-live-tree.syncing::before { content: ""; position: absolute; top: 14px; right: 18px; width: 16px; height: 16px; border-radius: 50%;
  background: #2f8cff; z-index: 3; animation: irRadiate 1.3s ease-out infinite; }
@keyframes irRadiate { 0% { box-shadow: 0 0 0 0 rgba(47,140,255,.75); } 100% { box-shadow: 0 0 0 24px rgba(47,140,255,0); } }
.ir-live-split { display: grid; grid-template-columns: 260px 1fr; gap: 20px; align-items: start; }
@media (max-width: 800px) { .ir-live-split { grid-template-columns: 1fr; } }
.ir-live-list { display: flex; flex-direction: column; gap: 4px; position: sticky; top: 8px; max-height: 80vh; overflow-y: auto; }
.ir-live-follow { font-size: 14px; font-weight: 700; color: var(--accent); padding: 4px 6px 8px; cursor: pointer; }
.ir-live-li { display: flex; align-items: center; gap: 10px; text-align: left; background: transparent; border: 1px solid transparent; border-radius: 8px; padding: 8px 10px; color: var(--text-primary); font-size: 15px; cursor: pointer; font-family: inherit; }
.ir-live-li:hover { background: rgba(127,127,127,0.12); }
.ir-live-li.selected { border-color: var(--accent); background: rgba(88,166,255,0.12); font-weight: 700; }
.ir-live-li-dot { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; background: var(--border); }
.ir-live-li.status-done .ir-live-li-dot, .ir-live-li.status-ok .ir-live-li-dot { background: var(--success); }
.ir-live-li.status-in_progress .ir-live-li-dot { background: var(--accent); }
.ir-live-li.flagged .ir-live-li-dot, .ir-live-li.status-needsAttention .ir-live-li-dot { background: var(--danger); }
.ir-live-li.is-active .ir-live-li-label::after { content: " \25CF"; color: var(--accent); font-size: 10px; }
.ir-live-li-label { flex: 1; }
.ir-live-li-count { font-size: 12px; color: var(--text-muted); font-weight: 700; }
.ir-live-card { border: 2px solid var(--border); border-radius: 14px; padding: 28px 32px; min-height: 60vh; }
.ir-live-card.status-in_progress { border-color: var(--accent); }
.ir-live-card.status-done { border-color: var(--success); }
.ir-live-card.flagged { border-color: var(--danger); }
.ir-live-card-title { font-size: 48px; font-weight: 800; line-height: 1.1; letter-spacing: -0.02em; color: var(--text-primary); }
.ir-live-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 14px 0 20px; font-size: 18px; }
.ir-live-card-now { display: inline-flex; align-items: center; gap: 8px; color: var(--accent); font-weight: 800; }
.ir-live-card-badge { padding: 4px 14px; border-radius: 999px; font-weight: 800; border: 2px solid var(--border); }
.ir-live-card-badge.status-done { color: var(--success); border-color: var(--success); }
.ir-live-card-badge.status-in_progress { color: var(--accent); border-color: var(--accent); }
.ir-live-card-badge.status-needsAttention { color: var(--danger); border-color: var(--danger); }
.ir-live-card-progress { color: var(--text-muted); font-weight: 700; }
.ir-live-card-value { font-weight: 700; color: var(--text-primary); }
.ir-live-card-ref { font-size: 20px; line-height: 1.6; white-space: pre-line; margin-bottom: 20px; padding: 14px 18px; border-left: 4px solid var(--accent); background: rgba(88,166,255,0.08); border-radius: 6px; }
.ir-live-card-subs { display: flex; flex-direction: column; gap: 10px; }
.ir-live-card-nosubs { font-size: 20px; color: var(--text-muted); }
.ir-live-sub { display: flex; align-items: flex-start; gap: 18px; padding: 16px 20px; border-radius: 10px; border: 1px solid var(--border); }
.ir-live-sub.done { border-color: var(--success); background: rgba(63,185,80,0.07); }
.ir-live-sub.status-needsAttention { border-color: var(--danger); background: rgba(248,81,73,0.08); }
.ir-live-sub-icon { font-size: 30px; line-height: 1; width: 34px; text-align: center; color: var(--border); }
.ir-live-sub.done .ir-live-sub-icon { color: var(--success); }
.ir-live-sub.status-needsAttention .ir-live-sub-icon { color: var(--danger); }
.ir-live-sub-main { flex: 1; display: flex; flex-direction: column; gap: 6px; }
.ir-live-sub-title { font-size: 28px; font-weight: 700; line-height: 1.2; color: var(--text-primary); }
.ir-live-sub-hint { font-size: 18px; color: var(--text-muted); line-height: 1.45; }
.ir-live-sub-state { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.ir-live-sub-badge { font-size: 16px; font-weight: 800; text-transform: uppercase; color: var(--text-muted); }
.ir-live-sub.done .ir-live-sub-badge { color: var(--success); }
.ir-live-sub.status-needsAttention .ir-live-sub-badge { color: var(--danger); }
.ir-live-sub-value { font-size: 24px; font-weight: 800; color: var(--text-primary); }

/* 2026-10-15 (user feedback 2): header buttons that are not tabs (Devices modal opener, Log out) share the
   Health/Live tab-button look. Log out was a 20x20 .theme-toggle-btn holding 7 characters of text, which
   squished and overlapped; it now sizes to its label and never shrinks. */
.toolbar-btn {
    background: transparent; color: var(--text-muted); border: none; border-radius: 4px; cursor: pointer;
    padding: 4px 8px; font-size: 12px; font-weight: 500; white-space: nowrap; flex-shrink: 0;
    transition: background 0.15s, color 0.15s;
}
.toolbar-btn:hover, .toolbar-btn.active { background: var(--chrome-hover-bg); color: var(--text-on-chrome); }
.toolbar-btn-outline { border: var(--border-width) solid var(--border-on-chrome); color: var(--text-on-chrome); padding: 4px 12px; margin-left: 6px; }
.logout-form { display: flex; align-items: center; margin: 0; flex-shrink: 0; }
.toolbar-right { flex-shrink: 0; }
.theme-toggle-btn { flex-shrink: 0; }

/* ===== 2026-10-15: list dots/badges/age groups, work-state controls, toasts, confirm dialog, N/A ===== */
.ir-task-title { display: flex; align-items: center; gap: 8px; }
.ir-task-dot { width: 11px; height: 11px; border-radius: 50%; flex: none; background: #8b949e; }
.ir-task-dot.dot-blue { background: #2f81f7; box-shadow: 0 0 0 2px rgba(47,129,247,0.25); }
.ir-task-dot.dot-green { background: #3fb950; }
.ir-task-dot.dot-grey { background: #8b949e; }
.ir-task-status-pill.state-inProgress { background: rgba(47,129,247,0.18); color: #58a6ff; }
.ir-task-status-pill.state-paused, .ir-task-status-pill.state-cancelled, .ir-task-status-pill.state-notStarted { background: rgba(139,148,158,0.2); color: var(--text-muted); }
.ir-task-status-pill.state-completed, .ir-task-status-pill.state-submitted { background: var(--success-bg); color: var(--success); }
.ir-task-group { margin-bottom: 6px; }
.ir-group-header {
    display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; cursor: pointer;
    background: #1f6feb; color: #fff; border: none; border-radius: 6px;
    padding: 8px 12px; margin: 10px 0 6px; font-size: 13px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
    box-shadow: 0 1px 3px rgba(0,0,0,0.25);
}
.ir-group-header:hover { background: #388bfd; }
.ir-group-caret { font-size: 14px; }
.ir-group-label { flex: 1; }
.ir-group-count { font-weight: 700; background: rgba(255,255,255,0.22); border-radius: 10px; padding: 1px 9px; }
.ir-task-group.collapsed .ir-group-body { display: none; }
/* work state controls */
.ir-work-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; }
.ir-work-state-badge { padding: 3px 12px; border-radius: 999px; font-size: 12px; font-weight: 700; background: rgba(139,148,158,0.2); color: var(--text-muted); }
.ir-work-state-badge.state-inProgress { background: rgba(47,129,247,0.18); color: #58a6ff; }
.ir-work-state-badge.state-completed, .ir-work-state-badge.state-submitted { background: var(--success-bg); color: var(--success); }
.ir-work-state-badge.state-submitted { border: 1px solid var(--success); }
.ir-work-buttons { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.ir-work-btn { background: transparent; color: var(--accent); border: 1px solid var(--accent); border-radius: 6px; padding: 5px 14px; font-size: 13px; font-weight: 600; cursor: pointer; }
.ir-work-btn:hover:not(:disabled) { background: rgba(74,144,217,0.15); }
.ir-work-btn.ws-submit { background: var(--accent); color: #fff; }
.ir-work-btn.danger { color: var(--danger); border-color: var(--danger); }
.ir-work-btn:disabled { opacity: 0.5; cursor: default; }
.ir-work-msg { flex-basis: 100%; color: var(--danger); font-size: 13px; }
.ir-work-msg.hidden { display: none; }
#ir-toast-host { position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%); z-index: 12000; display: flex; flex-direction: column; gap: 8px; align-items: center; max-width: 92vw; }
.ir-toast { background: #1f2937; color: #f3f4f6; border: 1px solid #374151; border-left: 4px solid var(--accent); border-radius: 8px; padding: 10px 16px; font-size: 14px; box-shadow: 0 6px 24px rgba(0,0,0,0.4); }
.ir-toast.error { border-left-color: #f85149; }
.ir-confirm-overlay { position: fixed; inset: 0; z-index: 11000; background: rgba(8,10,16,0.62); display: flex; align-items: center; justify-content: center; padding: 16px; }
.ir-confirm-box { width: min(440px, 100%); background: var(--bg-panel); color: var(--text-primary); border: 1px solid var(--border); border-radius: 14px; padding: 20px; box-shadow: 0 24px 64px rgba(0,0,0,0.5); }
.ir-confirm-title { margin: 0 0 8px; font-size: 18px; }
.ir-confirm-text { margin: 0 0 16px; line-height: 1.45; }
.ir-confirm-actions { display: flex; gap: 10px; justify-content: flex-end; }
.ir-confirm-ok { background: var(--accent); color: #fff; border: none; border-radius: 6px; padding: 8px 16px; font-weight: 700; cursor: pointer; }
.ir-confirm-ok.danger { background: #da3633; }
/* N/A is yellow, never green (item 8) */
.ir-checklist-icon.status-na, .ir-live-status-icon.status-na { color: var(--warning); }
.ir-checklist-value-na, .ir-live-status-na { color: var(--warning); font-weight: 700; }
.ir-subtask-row.status-na .ir-subtask-icon { color: var(--warning); font-weight: 700; font-size: 10px; }
.ir-live-sub.status-na { border-color: var(--warning); background: rgba(255,184,77,0.08); }
.ir-live-sub.status-na .ir-live-sub-icon, .ir-live-sub.status-na .ir-live-sub-badge { color: var(--warning); }
.ir-live-sub.done.status-na { border-color: var(--warning); }
.ir-live-card.status-na { border-color: var(--warning); }
.ir-live-card-badge.status-na { color: var(--warning); border-color: var(--warning); }
.vrcs-na { pointer-events: none; }

/* Item 18b: blue = actively worked (inProgress) only. Any other work state shows no live blue anywhere in the detail. */
.ir-inactive #ir-live-dot, .ir-inactive .ir-live-card-now, .ir-inactive .ir-live-li.is-active .ir-live-li-label::after { display: none; }
.ir-inactive .ir-checklist-icon.status-in_progress, .ir-inactive .ir-live-status-icon.status-in_progress { color: var(--text-muted); }
.ir-inactive .ir-live-li.status-in_progress .ir-live-li-dot { background: var(--border); }
.ir-inactive .ir-live-card.status-in_progress { border-color: var(--border); }
.ir-inactive .ir-live-card-badge.status-in_progress { color: var(--text-muted); border-color: var(--border); }

/* Item 18: loading banner while the work list loads. */
.ir-loading-banner { display: flex; align-items: center; gap: 12px; padding: 12px 16px; margin: 0 0 12px; border-radius: 10px;
    border: 1px solid var(--accent); background: rgba(88,166,255,0.10); color: var(--text-primary); font-weight: 700; position: relative; overflow: hidden; }
.ir-loading-banner.hidden { display: none; }
.ir-loading-spinner { width: 20px; height: 20px; border-radius: 50%; border: 3px solid rgba(127,127,127,0.3); border-top-color: var(--accent);
    animation: ir-spin 0.8s linear infinite; flex: 0 0 auto; }
.ir-loading-bar { position: absolute; left: 0; bottom: 0; height: 3px; width: 35%; background: var(--accent); animation: ir-slide 1.4s ease-in-out infinite; }
@keyframes ir-spin { to { transform: rotate(360deg); } }
@keyframes ir-slide { 0% { left: -35%; } 100% { left: 100%; } }
#ir-empty-state.ir-loading-hide { visibility: hidden; }

/* Submitted = GOLD + lock (final, read-only). Completed stays green. */
.ir-task-dot.dot-gold { background: #d4a017; box-shadow: 0 0 0 2px rgba(212,160,23,0.25); }
.ir-task-status-pill.state-submitted { background: rgba(212,160,23,0.18); color: #d4a017; }
.ir-work-state-badge.state-submitted { background: rgba(212,160,23,0.18); color: #d4a017; border: 1px solid #d4a017; }
.ir-task-lock { position: absolute; right: 8px; top: 6px; font-size: 13px; opacity: 0.85; }
.ir-task-row { position: relative; }
.ir-detail { position: relative; }
.ir-lock-icon { position: absolute; top: 6px; right: 10px; font-size: 22px; z-index: 5; color: #d4a017; }
.ir-lock-icon.hidden { display: none; }

/* selected row kept visible although it does not match the active filter */
.ir-task-row.ir-pinned { border-style: dashed; }
.ir-pinned-note { font-size: 10px; color: var(--text-muted); margin-top: 3px; font-style: italic; }
