/* Logro Repricing Web UI
   Light theme, Plus Jakarta Sans, Logro navy/orange as accents */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Enable `auto` keyword interpolation so `height: 0 → auto` transitions animate
   smoothly (used by collapsible detail rows on the job page). Chrome 129+,
   Firefox 129+, Safari 17.4+. Older browsers gracefully fall back to instant. */
:root { interpolate-size: allow-keywords; }

:root {
    /* Palette -- clean light */
    --bg: #ffffff;
    --bg-alt: #f6f7f9;
    --bg-card: #ffffff;
    --bg-elevated: #f0f1f4;
    --text: #1a1d23;
    --text-secondary: #4b5060;
    --text-muted: #565a6a;
    --border: #dfe1e6;
    --border-light: #e8eaee;

    /* Brand -- Logro colors */
    --accent: #d45a33;
    --accent-hover: #bf4e29;
    --accent-light: #fdf2ee;
    --focus-color: #5b9bd5;
    --navy: #1b2438;
    --navy-light: #263352;

    /* Semantic */
    --success: #1a8a5c;
    --success-bg: #edf7f2;
    --error: #c93b3b;
    --error-bg: #fdf0f0;
    --warning: #a17216;
    --warning-bg: #fdf6e8;
    /* Caution -- distinct from --warning (used by pulsing self-healing states).
       completed_unverified is TERMINAL, not self-healing, so it gets its own
       deeper amber/orange tone -- a caution color, not an "awaiting input" one. */
    --caution: #b45309;
    --caution-bg: #fdf0dc;
    --caution-border: #f0c284;

    /* Shared */
    --radius: 10px;
    --radius-sm: 6px;
    --shadow-sm: 0 1px 2px rgba(0,0,0,.04);
    --shadow: 0 2px 6px rgba(0,0,0,.06);
    --shadow-md: 0 4px 12px rgba(0,0,0,.08);
    --savings-green: #1a8a5c;
    --savings-yellow: #a17216;
    --savings-red: #c93b3b;

    /* Type scale -- 18px base (senior-friendly), scales from root font-size */
    --text-sm: 0.833rem;     /* ~15px at 18px base */
    --text-base: 1rem;       /* 18px */
    --text-md: 1.167rem;     /* ~21px */
    --text-lg: 1.389rem;     /* ~25px */
    --text-xl: 1.667rem;     /* ~30px */
    --text-2xl: 2.111rem;    /* ~38px */

    /* Spacing */
    --sp-1: 0.25rem;
    --sp-2: 0.5rem;
    --sp-3: 0.75rem;
    --sp-4: 1rem;
    --sp-5: 1.25rem;
    --sp-6: 1.5rem;
    --sp-8: 2rem;
    --sp-10: 2.5rem;
    --sp-12: 3rem;

    /* Unified form-control heights -- inputs, selects, textareas all share these */
    --control-h: 48px;
    --control-h-sm: 40px;

    --focus-ring: 0 0 0 2px #fff, 0 0 0 4px var(--focus-color);
}

/* ─── Accessibility ────────────────────────────────── */

.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    border: 0;
}

:focus-visible {
    outline: 2px solid var(--focus-color);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(212,90,51,.2);
    border-color: var(--accent);
}

/* ─── Base ─────────────────────────────────────────── */

html { font-size: 18px; }

body {
    font-family: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    font-size: var(--text-base);
    color: var(--text);
    background: var(--bg-alt);
    line-height: 1.6;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* ─── Layout ───────────────────────────────────────── */

header {
    background: var(--navy);
    position: sticky;
    top: 0;
    z-index: 1000;
    box-shadow: 0 1px 4px rgba(0,0,0,.15);
    /* overflow-x:hidden removed -- it forced overflow-y:auto which clipped
       child dropdowns, and also constrained the stacking context so the
       notification panel (even with position:fixed) appeared behind page
       overlays. The nav's max-width:1120px already prevents horizontal bleed. */
}

nav {
    max-width: 1120px;
    margin: 0 auto;
    padding: var(--sp-4) var(--sp-6);
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.logo {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    text-decoration: none;
}

.logo img {
    height: 32px;
    width: auto;
    filter: brightness(0) invert(1);
}

.logo-text {
    font-weight: 700;
    font-size: var(--text-base);
    color: #fff;
    letter-spacing: 0.01em;
}

.logo-divider {
    width: 1px;
    height: 22px;
    background: rgba(255,255,255,.2);
}

.logo-product {
    font-weight: 600;
    font-size: var(--text-sm);
    color: rgba(255,255,255,.65);
    letter-spacing: 0.02em;
}

main {
    max-width: 1120px;
    width: 100%;
    margin: 0 auto;
    padding: var(--sp-10) var(--sp-6) var(--sp-12);
    flex: 1;
}

footer {
    border-top: 1px solid var(--border);
    background: var(--bg);
    text-align: center;
    padding: var(--sp-4) var(--sp-6);
    font-size: var(--text-sm);
    color: var(--text-muted);
}

/* ─── Typography ───────────────────────────────────── */

h1 {
    font-size: var(--text-xl);
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--navy);
    line-height: 1.3;
    margin-bottom: var(--sp-6);
}

h2 {
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--navy);
}

h3 {
    font-size: var(--text-base);
    font-weight: 700;
    margin-top: var(--sp-8);
    margin-bottom: var(--sp-3);
    color: var(--text);
}

hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: var(--sp-8) 0;
}

p.meta {
    color: var(--text-secondary);
    font-size: var(--text-sm);
    line-height: 1.5;
}

/* ─── Nav structure ────────────────────────────────── */

.nav-left {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

.nav-grid-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-sm);
    color: rgba(255,255,255,.5);
    transition: color .15s, background .15s;
}

.nav-grid-btn:hover {
    color: #fff;
    background: rgba(255,255,255,.1);
}

.nav-right {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.nav-separator {
    color: rgba(255,255,255,.25);
    font-size: var(--text-lg);
    font-weight: 300;
    margin-left: var(--sp-2);
    margin-right: var(--sp-2);
}

.nav-tool {
    color: rgba(255,255,255,.7);
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 700;
    transition: color .15s;
}

.nav-tool:hover { color: #fff; }

.nav-link {
    color: rgba(255,255,255,.7);
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 600;
    transition: color .15s;
}

.nav-link:hover { color: #fff; }

.nav-btn-ghost {
    display: inline-flex;
    align-items: center;
    color: rgba(255,255,255,.85);
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 600;
    padding: 0.4rem 0.9rem;
    border: 1px solid rgba(255,255,255,.25);
    border-radius: 6px;
    transition: background-color .15s, border-color .15s, color .15s;
}

.nav-btn-ghost:hover {
    color: #fff;
    background: rgba(255,255,255,.08);
    border-color: rgba(255,255,255,.4);
}

/* ─── Back link ────────────────────────────────────── */

.back-link {
    display: inline-block;
    color: #5b9bd5;
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 600;
    margin-bottom: var(--sp-5);
    transition: color .15s;
}

.back-link:hover { color: #73b3e1; }

/* ─── App intro ────────────────────────────────────── */

.app-intro {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-6);
    margin-bottom: var(--sp-10);
    padding-bottom: var(--sp-8);
    border-bottom: 1px solid var(--border);
}

.app-intro-text h1 {
    margin-bottom: var(--sp-2);
}

.app-intro-text p {
    color: var(--text-secondary);
    font-size: var(--text-sm);
    line-height: 1.6;
    max-width: 640px;
}

.app-intro .btn {
    flex-shrink: 0;
    margin-top: var(--sp-1);
}

/* ─── Dashboard header ─────────────────────────────── */

.dashboard-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: var(--sp-8);
}

.dashboard-header h1 { margin-bottom: 0; }

.job-count {
    font-size: var(--text-sm);
    color: var(--text-muted);
    font-weight: 600;
}

/* ─── Buttons ──────────────────────────────────────── */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: 12px 22px;
    font-size: var(--text-sm);
    font-weight: 600;
    font-family: inherit;
    color: var(--text-secondary);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    text-decoration: none;
    cursor: pointer;
    transition: all .15s;
    line-height: 1.4;
    white-space: nowrap;
    min-height: 48px;
}

.btn:hover {
    color: var(--text);
    border-color: var(--text-muted);
    background: var(--bg-alt);
}

.btn-primary {
    background: #5b9bd5;
    color: #fff;
    border-color: #5b9bd5;
    font-weight: 700;
}

.btn-primary:hover {
    background: #4d89c0;
    border-color: #4d89c0;
    color: #fff;
}

.btn-sm {
    padding: 9px 16px;
    font-size: var(--text-sm);
    min-height: 40px;
}

.btn-icon {
    padding: 0;
    width: 42px;
    height: 36px;
    min-height: 36px;
    font-size: var(--text-base);
    line-height: 1;
    border-radius: var(--radius-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bg);
    color: var(--text-secondary);
    border: 1px solid var(--border);
}

.btn-icon:hover {
    color: var(--text);
    border-color: var(--text-muted);
    background: var(--bg-alt);
}

.btn-icon svg {
    display: block;
}

.btn-danger {
    color: var(--error);
    border-color: #e8c0c0;
}

.btn-danger:hover {
    background: var(--error);
    color: #fff;
    border-color: var(--error);
}

.btn-download {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 14px 36px;
    font-size: var(--text-md);
    font-weight: 700;
    font-family: inherit;
    background: var(--accent);
    color: #fff;
    border: none;
    border-radius: var(--radius);
    text-decoration: none;
    cursor: pointer;
    transition: all .15s;
    box-shadow: 0 2px 6px rgba(212,90,51,.25);
    letter-spacing: 0.01em;
}

.btn-download:hover {
    background: var(--accent-hover);
    box-shadow: 0 4px 12px rgba(212,90,51,.3);
    transform: translateY(-1px);
}

.btn-download:active {
    transform: translateY(0);
}

.btn-upload {
    padding: 14px 30px;
    font-size: var(--text-base);
    font-weight: 700;
    min-height: 56px;
}

.btn-upload.is-processing {
    background: #e8a08a;
    color: #fff;
    pointer-events: none;
    border-color: #e8a08a;
}

.btn-upload .spinner-inline {
    display: none;
    width: 16px; height: 16px;
    border: 2px solid rgba(255,255,255,.4);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin .8s linear infinite;
    margin-right: var(--sp-2);
}

.btn-upload.is-processing .spinner-inline { display: inline-block; }

/* Generic in-button spinner for non-upload buttons */
.btn .spinner-inline {
    display: none;
    width: 14px;
    height: 14px;
    border: 2px solid rgba(255,255,255,.4);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin .8s linear infinite;
    margin-right: var(--sp-2);
    vertical-align: middle;
}

.btn.is-processing:not(.btn-upload) .spinner-inline { display: inline-block; }
.btn.is-processing:not(.btn-upload) { pointer-events: none; opacity: .8; }

/* ─── Cards ────────────────────────────────────────── */

.card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--sp-5);
    box-shadow: var(--shadow-sm);
    margin-bottom: var(--sp-6);
}

.card h3 {
    margin: 0 0 var(--sp-4);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.card h3:not(:first-child) {
    margin-top: var(--sp-6);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--border);
}

.card .summary-grid { margin-top: 0; }
.card .stat { background: var(--bg-alt); }
.card .savings-bar-container { margin-top: var(--sp-3); margin-bottom: 0; background: var(--bg-alt); }
.card .error-box { margin-top: 0; }
.card .file-list { margin: 0; }
.card .download-row { margin: 0; padding: var(--sp-8) 0; }

/* ─── Checkbox column ──────────────────────────────── */

.th-check,
.td-check {
    width: 32px;
    text-align: center;
    padding-left: 14px;
    padding-right: 8px;
}

/* ─── Batch action bar ─────────────────────────────── */

.batch-bar {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-5);
    margin-bottom: var(--sp-3);
    background: var(--navy);
    color: #fff;
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-weight: 600;
}

.batch-bar .btn {
    background: rgba(255,255,255,.12);
    color: #fff;
    border-color: rgba(255,255,255,.2);
    font-size: var(--text-sm);
    min-width: 120px;
    padding: 8px 16px;
}

.batch-bar .btn:hover {
    background: rgba(255,255,255,.22);
    border-color: rgba(255,255,255,.35);
    color: #fff;
}

/* ─── Tables ───────────────────────────────────────── */

table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
    background: var(--bg);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--border);
}

thead th {
    text-align: center;
    padding: 12px 14px;
    border-bottom: 2px solid var(--border);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--navy);
    background: #dce1e8;
}

thead th:first-child { text-align: left; }

tbody td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-light);
    vertical-align: middle;
    text-align: center;
}

tbody td:first-child { text-align: left; }

tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--bg-alt); }
tbody tr[data-href] { cursor: pointer; }

tbody td a {
    color: var(--accent);
    text-decoration: none;
    font-weight: 700;
}

tbody td a:hover { text-decoration: underline; }

table.compact { font-size: var(--text-sm); box-shadow: none; background: transparent; border: none; }
table.compact td { padding: 6px 14px 6px 0; border: none; }

/* ─── Actions cell ─────────────────────────────────── */

.actions {
    display: flex;
    gap: var(--sp-2);
    align-items: center;
    justify-content: flex-end;
}

thead th.th-actions { text-align: right; }

/* ─── Status badges ────────────────────────────────── */

.status {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 700;
    text-transform: capitalize;
    letter-spacing: 0.01em;
    line-height: 1.3;
    white-space: nowrap;
}

.status-processing { background: var(--bg-elevated); color: var(--text-secondary); }
.status-complete { background: var(--success-bg); color: var(--success); }
.status-completed { background: var(--success-bg); color: var(--success); }
.status-complete_with_errors { background: var(--warning-bg); color: var(--warning); }
.status-needs_support { background: var(--warning-bg); color: var(--warning); }
.status-needs-input { background: var(--warning-bg); color: var(--warning); font-weight: 600; }
/* completed_unverified -- terminal caution state, no pulse (not self-healing). */
.status-needs-review { background: var(--caution-bg); color: var(--caution); font-weight: 700; border: 1px solid var(--caution-border); }
.status-resolving {
    background: var(--warning-bg);
    color: var(--warning);
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
.status-resolving::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--warning);
    animation: resolving-pulse 1.4s ease-in-out infinite;
    flex-shrink: 0;
}
@keyframes resolving-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.4; transform: scale(0.75); }
}
.status-error { background: var(--error-bg); color: var(--error); }
.status-submitted { background: var(--bg-elevated); color: var(--text-secondary); }
.status-resolved { background: var(--success-bg); color: var(--success); }
.status-needs_attention { background: var(--warning, #e6a817); color: white; }
.status-in_progress { background: var(--accent); color: white; }
.status-closed { background: var(--text-muted); color: white; }
.status-open { background: var(--secondary, #6c757d); color: white; }
.status-awaiting-answer { background: var(--warning-bg); color: var(--warning); font-weight: 600; }

/* ─── Inline meta-line status (no pill) ───────────────── */

.meta-status {
    font-weight: 700;
    white-space: nowrap;
    text-transform: capitalize;
}
.meta-status-awaiting-answer { color: var(--warning); }

/* status_css_class filter returns "status-{status}" or "status-resolving" */
.meta-status-status-complete { color: var(--success); }
.meta-status-status-error { color: var(--error); }
.meta-status-status-resolving { color: var(--warning); }
.meta-status-status-needs-review { color: var(--caution); font-weight: 700; }
.meta-status-status-needs-input { color: var(--warning); font-weight: 700; }

/* ─── Savings ──────────────────────────────────────── */

.savings-green { color: var(--savings-green); font-weight: 700; }
.savings-yellow { color: var(--savings-yellow); font-weight: 700; }
.savings-red { color: var(--savings-red); font-weight: 700; }
.savings-none { color: var(--text-muted); font-style: italic; }

/* ─── Summary grid ─────────────────────────────────── */

.summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: var(--sp-2);
    margin: var(--sp-3) 0;
    align-items: stretch;
}

.stat {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: var(--sp-3);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: var(--sp-2);
    min-height: calc(var(--text-sm) * 1.4 * 2 + var(--text-base) * 1.2 + var(--sp-4) * 2 + var(--sp-3));
}

.stat .label {
    display: flex;
    align-items: flex-start;
    font-size: var(--text-sm);
    font-weight: 700;
    line-height: 1.4;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    min-height: calc(var(--text-sm) * 1.4 * 2);
}

.stat .value {
    display: block;
    font-size: var(--text-base);
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: -0.02em;
    color: var(--navy);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.stat.highlight { background: var(--success-bg); border-color: #b8dcc8; }
.stat.highlight .value { color: var(--success); }

/* completed_unverified: the highlighted savings figures must not read as a
   validated "green" result -- a screenshotted headline shouldn't be mistaken
   for a passed verification. */
.stat.highlight.is-unverified { background: var(--caution-bg); border-color: var(--caution-border); }
.stat.highlight.is-unverified .value { color: var(--caution); }
.unverified-caption {
    display: block;
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--caution);
    text-transform: none;
    letter-spacing: normal;
}

/* ─── Savings bar ──────────────────────────────────── */

.savings-bar-container {
    margin: var(--sp-2) 0;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: var(--sp-3);
}

.savings-bar-label {
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-bottom: var(--sp-3);
}

.savings-bar-track {
    height: 32px;
    background: var(--bg-elevated);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.savings-bar-fill {
    height: 100%;
    border-radius: var(--radius-sm);
    transition: width .6s ease;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-right: var(--sp-3);
    font-size: var(--text-sm);
    font-weight: 700;
    color: #fff;
    min-width: 56px;
}

.savings-bar-fill.green { background: var(--savings-green); }
.savings-bar-fill.yellow { background: var(--savings-yellow); }
.savings-bar-fill.red { background: var(--savings-red); }

.savings-bar-labels {
    display: flex;
    justify-content: space-between;
    margin-top: var(--sp-2);
    font-size: var(--text-sm);
    color: var(--text-secondary);
    font-weight: 600;
}

/* ─── Download / integrity ─────────────────────────── */

.download-row {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: var(--sp-4);
    margin: 0;
    padding: var(--sp-5) 0;
}

.btn-download-secondary {
    background: transparent;
    color: var(--accent);
    border: 1px solid var(--accent);
    box-shadow: none;
}

.btn-download-secondary:hover {
    background: var(--accent);
    color: #fff;
    box-shadow: 0 2px 6px rgba(212,90,51,.25);
}

.download-row-diagnostic {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: var(--sp-4);
    padding-bottom: var(--sp-2);
}

.link-diagnostic {
    font-size: var(--text-sm);
    color: var(--color-text-muted, #6b7280);
    text-decoration: underline;
}

.link-diagnostic:hover {
    color: var(--color-primary, #2563eb);
}

.hint {
    font-size: var(--text-xs, 0.75rem);
    color: var(--color-text-muted, #9ca3af);
    margin: var(--sp-1) 0 0;
    text-align: center;
    max-width: 480px;
}

.files-card { padding: 0; }

/* Animated collapse for <details>: keep body in layout, animate max-height */
.files-card > .files-card-body {
    display: block !important;
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    transition:
        max-height 280ms cubic-bezier(.2,.6,.2,1),
        opacity 200ms ease;
}
.files-card[open] > .files-card-body {
    max-height: 1200px;
    opacity: 1;
    transition:
        max-height 320ms cubic-bezier(.2,.6,.2,1),
        opacity 240ms ease 40ms;
}
.files-card-inner {
    padding: var(--sp-2) 0 var(--sp-4);
}
.files-card-inner .file-list,
.files-card-inner h3 {
    margin-left: var(--sp-6);
    margin-right: var(--sp-6);
}
.files-card-inner h3 { margin-top: var(--sp-5); }

.files-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-6);
    cursor: pointer;
    list-style: none;
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--text);
    border-radius: var(--radius);
    transition: background .15s;
}

.files-summary::-webkit-details-marker { display: none; }
.files-summary:hover { background: var(--bg-alt); }

.files-summary::after {
    content: "";
    width: 10px;
    height: 10px;
    border-right: 2px solid var(--text-muted);
    border-bottom: 2px solid var(--text-muted);
    transform: rotate(45deg);
    margin-right: var(--sp-1);
    transition: transform .15s;
}

.files-card[open] .files-summary::after { transform: rotate(-135deg); margin-top: 4px; }

.files-count {
    margin-left: auto;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-muted);
}

.integrity-pass {
    text-align: center;
    color: var(--success);
    font-size: var(--text-sm);
    font-weight: 600;
    margin-top: var(--sp-4);
    padding: var(--sp-3);
    background: var(--success-bg);
    border-radius: var(--radius-sm);
}

.integrity-fail {
    margin-top: var(--sp-4);
    padding: var(--sp-4);
    background: var(--error-bg);
    border: 1px solid #e8c0c0;
    border-radius: var(--radius-sm);
    color: var(--error);
    font-size: var(--text-sm);
}

.integrity-fail ul { margin: var(--sp-2) 0 0 var(--sp-5); padding: 0; }
.integrity-fail li { margin-bottom: var(--sp-1); }

/* ─── Count chip ───────────────────────────────────── */

.count-chip {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 700;
    line-height: 1.5;
    min-width: 24px;
    text-align: center;
    background: var(--bg-elevated);
    color: var(--text-secondary);
    flex-shrink: 0;
}

.count-chip.is-warning {
    background: var(--warning-bg);
    color: var(--warning);
}

.count-chip.is-error {
    background: var(--error-bg);
    color: var(--error);
}

.count-chip.is-success {
    background: var(--success-bg);
    color: var(--success);
}

.count-chip.is-muted {
    background: var(--bg-elevated);
    color: var(--text-muted);
    opacity: 0.6;
}

/* ─── Detail sections (inside Results Summary card) ── */

.detail-sections {
    border-top: 1px solid var(--border-light);
}

.detail-row {
    border-bottom: 1px solid var(--border-light);
}

.detail-row-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-1);
    cursor: pointer;
    list-style: none;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
    transition: background .15s;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    outline: none;
}

.detail-row-summary::-webkit-details-marker { display: none; }
.detail-row-summary:hover,
.detail-row[open] > .detail-row-summary { background: var(--bg-alt); }
.detail-row-summary:focus,
.detail-row-summary:focus-visible {
    outline: none;
    box-shadow: none;
}

.detail-row-summary::after {
    content: "";
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--text-muted);
    border-bottom: 2px solid var(--text-muted);
    transform: rotate(45deg);
    margin-right: var(--sp-1);
    flex-shrink: 0;
    transition: transform .15s;
}

.detail-row[open] .detail-row-summary::after {
    transform: rotate(-135deg);
    margin-top: 3px;
}

.detail-row-label {
    flex: 1;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
}

.detail-row-body {
    font-size: var(--text-sm);
    display: block;
    height: 0;
    opacity: 0;
    overflow: hidden;
    transition:
        height 280ms cubic-bezier(.2,.6,.2,1),
        opacity 220ms ease;
}

.detail-row-body > .detail-row-body-inner {
    padding: var(--sp-2) var(--sp-3) var(--sp-4);
}

.detail-row[open] > .detail-row-body {
    height: auto;
    opacity: 1;
    transition:
        height 300ms cubic-bezier(.2,.6,.2,1),
        opacity 240ms ease 30ms;
}

.detail-row-body .file-list {
    margin: 0;
}

.detail-row-intro {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin-bottom: var(--sp-3);
}

/* ─── Integrity check list ─────────────────────────── */

.integrity-check-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.integrity-check-item {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
}

.integrity-check-icon {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    margin-top: 7px;
    background: var(--success);
}

.integrity-check-item.failed .integrity-check-icon {
    background: var(--error);
}

.integrity-check-item div {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.integrity-check-item span {
    font-size: var(--text-sm);
    color: var(--text);
    line-height: 1.4;
}

.loaded-file-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.loaded-file-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    font-size: var(--text-sm);
    line-height: 1.4;
}

.anomaly-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.anomaly-item {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    font-size: var(--text-sm);
    line-height: 1.4;
}

.anomaly-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    margin-top: 7px;
    background: var(--text-muted);
}

.anomaly-dot-warn { background: var(--warning); }
.anomaly-dot-info { background: var(--text-muted); }
.anomaly-dot-error { background: var(--error); }

/* ─── Error file list (mirrors anomaly-list pattern) ─────────────────────── */

.error-file-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.error-file-item {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    font-size: var(--text-sm);
    line-height: 1.4;
}

.error-file-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    margin-top: 7px;
    background: var(--error);
}

.error-file-item strong {
    font-weight: 600;
    color: var(--text);
}

/* ─── Integrity check failure message (inline under failed check) ─────────── */

.integrity-check-failure-message {
    font-size: var(--text-sm);
    color: var(--error);
    line-height: 1.4;
}

.integrity-issues {
    margin-top: var(--sp-4);
    padding: var(--sp-4);
    background: var(--error-bg);
    border: 1px solid #e8c0c0;
    border-radius: var(--radius-sm);
    color: var(--error);
    font-size: var(--text-sm);
}

.integrity-issues strong {
    display: block;
    margin-bottom: var(--sp-2);
    font-weight: 700;
}

.integrity-issues ul {
    margin: 0 0 0 var(--sp-5);
    padding: 0;
}

.integrity-issues li {
    margin-bottom: var(--sp-1);
}

/* Empty / disabled rows */
.detail-row-empty {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-muted);
    cursor: default;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.detail-row-empty .detail-row-label {
    color: var(--text-muted);
}

/* All-passed integrity row gets a slightly warmer label */
.detail-row-pass .detail-row-label {
    color: var(--text);
}

/* ─── Job detail header ────────────────────────────── */

.job-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-6);
    margin-bottom: var(--sp-6);
}

.job-header h1 { margin-bottom: var(--sp-2); }

.job-actions {
    display: flex;
    gap: var(--sp-2);
    flex-wrap: wrap;
    justify-content: flex-end;
    flex-shrink: 0;
    padding-top: var(--sp-1);
}

/* ─── Needs support banner ─────────────────────────── */

.needs-support-banner {
    background: var(--warning-bg);
    border: 1px solid #dfc78a;
    border-radius: var(--radius);
    padding: var(--sp-5);
    margin-bottom: var(--sp-6);
    display: flex;
    align-items: center;
    gap: var(--sp-5);
}

.needs-support-banner .banner-icon { font-size: 1.4rem; line-height: 1; flex-shrink: 0; }
.needs-support-banner .banner-text { flex: 1; margin: 0; color: var(--text); font-size: var(--text-sm); }

/* ─── Needs input banner (password-protected files) ── */

.needs-input-banner {
    background: var(--warning-bg);
    border: 1px solid #dfc78a;
    border-radius: var(--radius);
    padding: var(--sp-5);
    margin-bottom: var(--sp-4);
    display: flex;
    align-items: flex-start;
    gap: var(--sp-5);
}

.needs-input-banner .banner-icon { font-size: 1.4rem; line-height: 1; flex-shrink: 0; }
.needs-input-banner-body { flex: 1; }
.needs-input-banner .banner-text { flex: 1; margin: 0; color: var(--text); font-size: var(--text-sm); }

.needs-input-files { margin-bottom: var(--sp-6); }

/* ─── Needs review banner (completed_unverified -- terminal, not self-healing) ── */

.needs-review-banner {
    background: var(--caution-bg);
    border: 1px solid var(--caution-border);
    border-radius: var(--radius);
    padding: var(--sp-5);
    margin-bottom: var(--sp-6);
    display: flex;
    align-items: flex-start;
    gap: var(--sp-5);
}

.needs-review-banner .banner-icon { font-size: 1.4rem; line-height: 1; flex-shrink: 0; color: var(--caution); }
.needs-review-banner-body { flex: 1; }
.needs-review-banner .banner-text { flex: 1; margin: 0; color: var(--text); font-size: var(--text-sm); }
.needs-review-banner .banner-text strong { color: var(--caution); }

/* ─── Q&A blocked / review banners (job <-> question link) ── */

.qa-blocked-banner {
    background: var(--warning-bg);
    border: 1px solid #dfc78a;
    border-radius: var(--radius);
    padding: var(--sp-5);
    margin-bottom: var(--sp-6);
    display: flex;
    align-items: flex-start;
    gap: var(--sp-5);
}
.qa-blocked-banner .banner-icon { font-size: 1.4rem; line-height: 1; flex-shrink: 0; }
.qa-blocked-body { flex: 1; }
.qa-blocked-banner .banner-text { flex: 1; margin: 0; color: var(--text); font-size: var(--text-sm); }
.qa-blocked-links { margin: var(--sp-2) 0 0; }
.qa-blocked-links a {
    color: var(--warning);
    font-weight: 600;
    font-size: var(--text-sm);
    text-decoration: none;
}
.qa-blocked-links a:hover { text-decoration: underline; }

.qa-review-banner {
    background: var(--success-bg);
    border: 1px solid var(--border-light);
    border-radius: var(--radius);
    padding: var(--sp-5);
    margin-bottom: var(--sp-6);
    display: flex;
    align-items: center;
    gap: var(--sp-5);
}
.qa-review-banner .banner-icon { font-size: 1.4rem; line-height: 1; flex-shrink: 0; color: var(--success); }
.qa-review-banner .banner-text { flex: 1; margin: 0; color: var(--text); font-size: var(--text-sm); }

.unlock-file-item {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2) 0;
    border-bottom: 1px solid var(--border-light);
}
.unlock-file-item:last-child { border-bottom: none; }
.unlock-file-item .loaded-file-name { flex: 1; }
.unlock-file-item .unlock-btn { flex-shrink: 0; }

.tag-warning {
    background: var(--warning-bg);
    color: var(--warning);
}

/* ─── Unlock modal ─────────────────────────────────── */

.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.modal-box {
    background: var(--bg-card);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    padding: var(--sp-8);
    width: 100%;
    max-width: 420px;
    display: flex;
    flex-direction: column;
    gap: var(--sp-5);
}

.modal-title {
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--text);
    margin: 0;
}

.modal-subtitle {
    font-size: var(--text-sm);
    color: var(--text-muted);
    margin: 0;
    word-break: break-all;
}

.modal-body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

.modal-label {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
}

.modal-input {
    width: 100%;
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--text-base);
    font-family: inherit;
    color: var(--text);
    background: var(--bg);
    transition: border-color .15s, box-shadow .15s;
}

.modal-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(212, 90, 51, 0.15);
}

.modal-error {
    font-size: var(--text-sm);
    color: var(--error);
    margin: 0;
    padding: var(--sp-2) var(--sp-3);
    background: var(--error-bg);
    border-radius: var(--radius-sm);
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-3);
}

.btn-secondary {
    background: var(--bg-elevated);
    color: var(--text-secondary);
    border: 1px solid var(--border);
}

.btn-secondary:hover {
    background: var(--border);
    color: var(--text);
}

.btn-primary {
    background: #5b9bd5;
    color: #fff;
    border: 1px solid transparent;
}

.btn-primary:hover {
    background: #4d89c0;
}

.btn-primary:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* ─── File counts ──────────────────────────────────── */

/* ─── Processing ───────────────────────────────────── */

.processing-time { font-size: var(--text-sm); color: var(--text-muted); margin-top: var(--sp-1); }

.spinner {
    display: inline-block;
    width: 20px; height: 20px;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin .8s linear infinite;
    margin-left: var(--sp-2);
    vertical-align: middle;
}

@keyframes spin { to { transform: rotate(360deg); } }

.processing-pulse { color: var(--text-secondary); }

/* ─── Processing banner ────────────────────────────── */

@keyframes processing-bg-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .7; }
}

.processing-banner {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    background: var(--bg);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius);
    padding: var(--sp-4) var(--sp-5);
    margin-top: var(--sp-4);
    animation: processing-bg-pulse 2.4s ease-in-out infinite;
}

.processing-banner .processing-spinner {
    width: 28px;
    height: 28px;
    border-width: 3px;
    flex-shrink: 0;
    margin-left: 0;
}

.processing-banner-text {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
}

.processing-banner-text strong {
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--text);
    line-height: 1.2;
}

.processing-banner-text span {
    font-size: var(--text-sm);
    color: var(--text-muted);
}

/* ─── Upload form ──────────────────────────────────── */

.upload-form {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--sp-8);
    margin-top: var(--sp-6);
    box-shadow: var(--shadow);
}

.field { margin-bottom: var(--sp-8); }

/* Lays a set of related fields out horizontally instead of stacking them
   full-width -- used by geo_upload.html (PCP/Specialist radius) and
   directory_search.html (specialty/taxonomy/network, state/city/zip, etc.)
   to group several ".field .field-inline" children into one responsive
   row. Mirrors the flex-wrap + fixed-gap pattern already used by
   .directory-search-facets in directory_search.css. */
.field-group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-6);
    margin-bottom: var(--sp-8);
}

/* Each field inside a .field-group also carries the base .field class;
   override its stacked margin-bottom since the group itself owns the
   bottom spacing, and let it flex-wrap at a sane minimum width. */
.field-inline {
    flex: 1 1 200px;
    min-width: 200px;
    margin-bottom: 0;
}

.field label {
    display: block;
    font-weight: 700;
    font-size: var(--text-base);
    margin-bottom: var(--sp-2);
    color: var(--text);
}

/* ─── Unified form controls ─────────────────────────
   Single source of truth for text/email/password/number/search inputs,
   textareas, and selects across .field (upload/proposal forms),
   .form-field (admin/users forms), the bare .form-input class, and
   .auth-form (login/MFA/password-reset forms). Do not reintroduce
   per-context padding/font-size -- add new contexts to this selector
   union instead. */
.field input[type="text"],
.field input[type="email"],
.field input[type="password"],
.field input[type="number"],
.field input[type="search"],
.field select,
.field textarea,
.form-field input[type="text"],
.form-field input[type="email"],
.form-field input[type="password"],
.form-field input[type="number"],
.form-field input[type="search"],
.form-field select,
.form-field textarea,
.form-field .form-input,
.form-input,
.auth-form input[type="text"],
.auth-form input[type="email"],
.auth-form input[type="password"] {
    width: 100%;
    box-sizing: border-box;
    min-height: var(--control-h);
    padding: 12px 16px;
    font-size: var(--text-base);
    font-family: inherit;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    /* background-color (not the `background` shorthand) so this rule never
       clobbers background-image -- .form-field .form-input has higher
       specificity than .form-field select and would otherwise reset the
       chevron below back to none for <select class="form-input">. */
    background-color: var(--bg);
    color: var(--text);
    transition: border-color .15s;
}

/* Custom chevron so native <select> rendering is identical across OSes.
   Stroke color is the resolved hex of --text-muted (#565a6a) -- CSS
   custom properties don't reliably resolve inside external data-URI
   SVG backgrounds, so it's hardcoded here and must be kept in sync if
   --text-muted ever changes. */
.field select,
.form-field select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 4.5L6 8L9.5 4.5' stroke='%23565a6a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    background-size: 12px;
    padding-right: 40px;
}

/* Shared focus ring for every unified control (including .select-compact) */
.field input[type="text"]:focus,
.field input[type="email"]:focus,
.field input[type="password"]:focus,
.field input[type="number"]:focus,
.field input[type="search"]:focus,
.field select:focus,
.field textarea:focus,
.form-field input:focus,
.form-field select:focus,
.form-field textarea:focus,
.form-field .form-input:focus,
.form-input:focus,
.auth-form input:focus,
.select-compact:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(212,90,51,.15);
}

/* Styled file input for tool upload forms — consistent across all tool pages */
input[type="file"] {
    display: block;
    width: 100%;
    padding: var(--sp-2) var(--sp-3);
    border: 2px dashed var(--border);
    border-radius: var(--radius);
    background: var(--bg-alt);
    color: var(--text);
    font-size: var(--text-sm);
    cursor: pointer;
    transition: border-color .15s;
    box-sizing: border-box;
}
input[type="file"]:hover {
    border-color: var(--accent);
}
input[type="file"]:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(212, 90, 51, 0.15);
}
/* Drop-zone hidden inputs: override global styles — these are invisible overlays */
.drop-zone input[type="file"],
.ws-drop-zone input[type="file"],
.ws2-dropzone input[type="file"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    border: none;
    border-radius: 0;
    background: none;
    opacity: 0;
    cursor: pointer;
    box-shadow: none;
}
/* Hidden file inputs (e.g. triggered by custom buttons) */
.file-input-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    overflow: hidden;
}
.field input[type="file"] { font-size: var(--text-sm); }

.field-error {
    color: var(--error);
    font-size: var(--text-sm);
    margin: var(--sp-1) 0 var(--sp-2);
}

.help { font-size: var(--text-sm); color: var(--text-secondary); margin-bottom: var(--sp-2); }

/* ─── Upload notice (password-prompt mode) ─────────── */

.upload-notice {
    background: var(--warning-bg);
    border: 1px solid #e8d8a0;
    border-radius: var(--radius-sm);
    padding: var(--sp-3) var(--sp-5);
    margin-top: var(--sp-4);
    font-size: var(--text-sm);
    color: var(--warning);
}

.upload-notice p { margin: 0; }

/* ─── Password show/hide toggle ─────────────────────── */

.pw-wrap {
    position: relative;
    display: flex;
    align-items: center;
}

.pw-wrap input[type="password"],
.pw-wrap input[type="text"] {
    width: 100%;
    padding-right: 4rem;
}

.pw-toggle {
    position: absolute;
    right: var(--sp-3);
    background: none;
    border: none;
    padding: var(--sp-1) var(--sp-2);
    cursor: pointer;
    color: var(--text-secondary);
    font-size: var(--text-sm);
    line-height: 1;
    user-select: none;
    white-space: nowrap;
}

.pw-toggle:hover { color: var(--text); }
.pw-toggle:focus-visible {
    outline: 2px solid var(--focus-color);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* ─── Upload help callout ──────────────────────────── */

.upload-help-callout {
    background: var(--accent-light);
    border-left: 4px solid var(--accent);
    border-radius: var(--radius-sm);
    padding: var(--sp-4) var(--sp-5);
    margin-bottom: var(--sp-5);
    display: flex;
    gap: var(--sp-4);
    align-items: flex-start;
}

.upload-help-callout.is-dismissed { display: none; }

.upload-help-callout-body {
    flex: 1;
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.6;
}

.upload-help-callout-title {
    display: block;
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--navy);
    margin-bottom: var(--sp-2);
}

.upload-help-callout ul {
    margin: var(--sp-2) 0 0 var(--sp-5);
    padding: 0;
}

.upload-help-callout ul li {
    margin-bottom: var(--sp-1);
}

.upload-help-callout-dismiss {
    flex-shrink: 0;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 1.25rem;
    line-height: 1;
    padding: 0 var(--sp-1);
    border-radius: var(--radius-sm);
    transition: color .15s;
}

.upload-help-callout-dismiss:hover { color: var(--accent); }

/* ─── Upload workflow note (below submit) ──────────── */

.upload-workflow-note {
    margin-top: var(--sp-5);
    background: var(--bg-alt);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    padding: var(--sp-4) var(--sp-5);
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.6;
}

.upload-workflow-note strong {
    color: var(--text);
}

/* ─── Help details / cheat-sheet ──────────────────── */

.help-summary {
    cursor: pointer;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--accent);
    list-style: none;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) 0;
    user-select: none;
}

.help-summary::-webkit-details-marker { display: none; }

.help-summary::before {
    content: '\25B6';
    font-size: 0.6rem;
    transition: transform .15s;
    color: var(--accent);
}

details[open] .help-summary::before { transform: rotate(90deg); }

.help-summary:hover { color: var(--accent-hover); }

.help-details {
    margin-top: var(--sp-2);
    padding: var(--sp-3) var(--sp-4);
    background: var(--bg-alt);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.6;
}

.help-details p { margin: 0 0 var(--sp-2); }
.help-details p:last-child { margin-bottom: 0; }

.help-details ul {
    margin: var(--sp-1) 0 var(--sp-2) var(--sp-5);
    padding: 0;
}

.help-details ul li { margin-bottom: var(--sp-1); }

.help-details code {
    font-family: ui-monospace, monospace;
    font-size: 0.8rem;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 1px 5px;
}

.provider-format-note { margin-top: 0; }

/* ─── Inline status help text ─────────────────────── */

.status-help-text {
    display: block;
    font-size: var(--text-sm);
    color: var(--text-muted);
    margin-top: var(--sp-2);
    line-height: 1.5;
}

.status-help-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2) var(--sp-4);
    font-size: var(--text-sm);
    color: var(--text-muted);
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--border-light);
    line-height: 1.5;
}

.status-help-legend span {
    white-space: nowrap;
}

.status-help-legend strong {
    color: var(--text-secondary);
    font-weight: 600;
}

.status-error-reasons {
    margin-top: var(--sp-4);
    padding: var(--sp-4) var(--sp-5);
    background: var(--bg-alt);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.6;
}

.status-error-reasons strong {
    display: block;
    font-weight: 700;
    color: var(--text);
    margin-bottom: var(--sp-2);
}

.status-error-reasons ul {
    margin: 0 0 var(--sp-3) var(--sp-5);
    padding: 0;
}

.status-error-reasons li {
    margin-bottom: var(--sp-1);
}

.status-error-reasons .support-link {
    color: var(--accent);
    text-decoration: none;
    font-weight: 600;
}

.status-error-reasons .support-link:hover {
    text-decoration: underline;
}

/* ─── Alert banners ────────────────────────────────── */

.alert {
    padding: var(--sp-3) var(--sp-5);
    border-radius: var(--radius-sm);
    margin: var(--sp-4) 0;
    font-size: var(--text-sm);
}

.alert-error {
    background: var(--error-bg);
    border: 1px solid #e8c0c0;
    color: var(--error);
}

/* ─── Button row ───────────────────────────────────── */

.button-row {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-top: var(--sp-2);
}

.btn-secondary {
    background: var(--bg);
    color: var(--text-secondary);
    border: 1px solid var(--border);
}

/* ─── Drop zone ────────────────────────────────────── */

.drop-zone {
    border: 2px dashed var(--border);
    border-radius: var(--radius);
    padding: var(--sp-8) var(--sp-6);
    text-align: center;
    transition: border-color .2s, background .2s;
    cursor: pointer;
    position: relative;
}

.drop-zone:hover, .drop-zone.dragover {
    border-color: var(--accent);
    background: var(--accent-light);
}

.drop-zone-text { color: var(--text-secondary); font-size: var(--text-base); }
.drop-zone-text strong { color: var(--text); }
.drop-zone-text small { font-size: var(--text-sm); }
.drop-zone input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }

.selected-files { margin-top: var(--sp-3); text-align: left; }
.selected-files ul { list-style: none; padding: 0; }

.selected-files li {
    padding: var(--sp-1) 0;
    font-size: var(--text-sm);
    color: var(--text);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.selected-files li::before {
    content: "";
    width: 6px; height: 6px;
    background: var(--success);
    border-radius: 50%;
    flex-shrink: 0;
}

.size-info { font-size: var(--text-sm); color: var(--text-secondary); margin-top: var(--sp-2); }

.size-warning {
    font-size: var(--text-sm);
    color: var(--warning);
    background: var(--warning-bg);
    border: 1px solid #dfc78a;
    border-radius: var(--radius-sm);
    padding: var(--sp-3) var(--sp-4);
    margin-top: var(--sp-2);
    font-weight: 600;
}

/* ─── Form actions ─────────────────────────────────── */

.form-actions {
    margin-top: var(--sp-4);
}

/* Generic text input matching textarea style -- sizing lives in the
   unified form-control rule above; this just sets display + placeholder. */
.form-input {
    display: block;
}

.form-input::placeholder {
    color: var(--text-muted);
}

/* Reusable field label */
.form-label {
    display: block;
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--text);
    margin-bottom: var(--sp-1);
}

/* Stacked form field (label + input) with consistent bottom spacing.
   Control sizing (padding/font/border/focus) lives in the unified
   form-control rule above -- do not reimpose it here. */
.form-field {
    margin-bottom: var(--sp-4);
}

/* ─── Platform confirmation modal ─────────────────── */

.platform-modal-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 9000;
    align-items: center;
    justify-content: center;
}

.platform-modal-backdrop.is-open {
    display: flex;
}

.platform-modal {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    padding: var(--sp-6);
    max-width: 420px;
    width: calc(100% - var(--sp-8));
}

.platform-modal-title {
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--navy);
    margin-bottom: var(--sp-3);
}

.platform-modal-message {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.6;
    margin-bottom: var(--sp-6);
}

.platform-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-3);
}

/* ─── Textarea ─────────────────────────────────────── */

textarea {
    width: 100%;
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--text-base);
    font-family: inherit;
    resize: none;
    overflow: hidden;
    background: var(--bg);
    color: var(--text);
    line-height: 1.6;
    transition: border-color .15s;
}

textarea::placeholder {
    color: var(--text-muted);
    line-height: 1.6;
}

textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(212,90,51,.15);
}

/* ─── Feedback (per-job) ───────────────────────────── */

.feedback-divider {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    margin-top: var(--sp-12);
    margin-bottom: var(--sp-6);
}

.feedback-divider-label {
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--text-muted);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
}

.feedback-divider-rule {
    flex: 1;
    height: 1px;
    background: var(--border);
}

.feedback-section .feedback-form {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.feedback-section .feedback-form textarea { width: 100%; }
.feedback-section .feedback-form .btn { align-self: flex-start; }

.feedback-history-label {
    margin-top: var(--sp-8);
    padding-top: var(--sp-6);
    border-top: 1px solid var(--border);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    margin-bottom: var(--sp-3);
}

.feedback-history {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.feedback-item {
    padding: var(--sp-4) var(--sp-5);
    background: var(--bg-alt);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.feedback-item .feedback-meta {
    margin: 0;
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--border-light);
    font-size: var(--text-sm);
    color: var(--text-muted);
    display: flex;
    align-items: baseline;
    gap: var(--sp-2);
    flex-wrap: wrap;
    line-height: 1.3;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.feedback-item .feedback-status {
    font-weight: 700;
    white-space: nowrap;
}

.feedback-item .feedback-status-submitted { color: var(--text-secondary); }
.feedback-item .feedback-status-resolved { color: var(--success); }

.feedback-item .feedback-meta-sep { color: var(--border); }
.feedback-item .feedback-meta-date { font-variant-numeric: tabular-nums; }

.feedback-item .feedback-auto-badge {
    display: inline-block;
    padding: 1px 6px;
    margin-left: 2px;
    border-radius: 4px;
    background: var(--bg-elevated);
    color: var(--text-muted);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    line-height: 1.4;
}

.feedback-item .feedback-text {
    margin: 0;
    font-size: var(--text-base);
    line-height: 1.55;
    color: var(--text);
}

.resolution {
    color: var(--success);
    font-style: italic;
    font-size: var(--text-sm);
    margin: 0;
}

/* ─── Feedback resolution card & reply thread ─────── */

.fb-resolution-card {
    margin-top: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    background: rgba(34, 160, 98, 0.07);
    border-left: 3px solid var(--success);
    border-radius: var(--radius-sm);
}

.fb-resolution-header {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-2);
}

.fb-resolution-icon {
    color: var(--success);
    font-weight: 700;
    font-size: var(--text-sm);
}

.fb-resolution-label {
    font-weight: 700;
    font-size: var(--text-sm);
    color: var(--success);
}

.fb-resolution-date {
    font-size: var(--text-sm);
    color: var(--text-muted);
    margin-left: auto;
    white-space: nowrap;
}

.fb-resolution-text {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.6;
    margin: 0 0 var(--sp-2) 0;
}

.fb-download-btn {
    margin-top: var(--sp-1);
}

.fb-thread {
    margin-top: var(--sp-3);
}

/* Team messages: warm accent tint (matches admin styling convention) */
.thread-team {
    background: rgba(212, 90, 51, 0.05);
}

/* Client messages: neutral alt-bg (same as thread-user default) */
.thread-client {
    background: var(--bg-alt);
}

.thread-author-team {
    color: var(--accent);
}

.thread-author-client {
    color: var(--success);
}

.fb-reply-section {
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--border-light);
}

.fb-reply-prompt {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin: 0 0 var(--sp-2) 0;
}

.fb-reply-form textarea {
    width: 100%;
    box-sizing: border-box;
}

.fb-reply-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-top: var(--sp-2);
    flex-wrap: wrap;
}

/* ─── Feedback (global page) ──────────────────────── */

.feedback-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    margin-top: var(--sp-8);
}

.feedback-ticket {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: var(--sp-5);
}

.ticket-header {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-3);
}

.ticket-source { color: var(--text-secondary); font-size: var(--text-sm); }

.ticket-source-link {
    color: var(--accent);
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 700;
}

.ticket-source-link:hover { text-decoration: underline; }

.ticket-date {
    color: var(--text-muted);
    font-size: var(--text-sm);
    margin-left: auto;
    white-space: nowrap;
}

.ticket-body {
    font-size: var(--text-sm);
    line-height: 1.6;
    white-space: pre-line;
    color: var(--text);
}

.ticket-body + .resolution { margin-top: var(--sp-2); }

.ticket-meta {
    color: var(--text-muted);
    font-size: var(--text-sm);
    margin: var(--sp-2) 0 0;
}

.feedback-category {
    display: flex;
    gap: var(--sp-4);
    margin-bottom: var(--sp-4);
}

.category-option {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--text-sm);
    color: var(--text-secondary);
    cursor: pointer;
    font-weight: 600;
}

.category-option input[type="radio"] { accent-color: var(--accent); }
.category-option:has(input:checked) span { color: var(--text); }

/* ─── Questions ──────────────────────────────── */

.section-heading {
    margin-top: var(--sp-10);
    margin-bottom: var(--sp-4);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

.count-badge {
    background: var(--accent);
    color: white;
    font-size: 11px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 10px;
    letter-spacing: 0;
    text-transform: none;
}

.count-badge.count-muted {
    background: var(--text-muted);
}

.count-badge.count-attention {
    background: var(--warning, #e6a817);
}

.form-hint {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin-bottom: var(--sp-4);
    line-height: 1.5;
}

.questions-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.question-card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: var(--sp-5);
}

.question-open {
    border-left: 3px solid var(--accent);
}

.question-answered {
    border-left: 3px solid var(--success);
}

.question-needs_attention {
    border-left: 3px solid var(--warning, #e6a817);
}

.question-in_progress {
    border-left: 3px solid var(--accent);
}

.question-closed {
    border-left: 3px solid var(--text-muted);
    opacity: 0.7;
}

.question-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-3);
    row-gap: var(--sp-2);
    margin-bottom: var(--sp-3);
}

.question-asker {
    font-weight: 700;
    font-size: var(--text-sm);
    color: var(--text);
}

.question-text {
    font-size: var(--text-sm);
    line-height: 1.6;
    white-space: pre-line;
    color: var(--text);
    margin-bottom: var(--sp-3);
}

.answer-form textarea {
    font-size: var(--text-sm);
}

.answer-block {
    background: var(--bg-alt);
    border-radius: var(--radius-sm);
    padding: var(--sp-4);
    margin-top: var(--sp-2);
}

.answer-by {
    font-weight: 700;
    font-size: var(--text-sm);
    color: var(--success);
}

.answer-block .ticket-date {
    font-size: var(--text-xs, 0.75rem);
    margin-left: var(--sp-2);
}

.answer-text {
    font-size: var(--text-sm);
    line-height: 1.6;
    white-space: pre-line;
    color: var(--text);
    margin-top: var(--sp-2);
}

/* ─── Thread ─────────────────────────────────── */

.thread {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    margin: var(--sp-3) 0;
    padding-left: var(--sp-4);
    border-left: 2px solid var(--border-light);
}

.thread-message {
    padding: var(--sp-3);
    border-radius: var(--radius-sm);
    background: var(--bg-alt);
}

.thread-admin {
    background: rgba(212, 90, 51, 0.05);
}

.thread-msg-header {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-1);
}

.thread-author {
    font-weight: 700;
    font-size: var(--text-sm);
}

.thread-author-admin {
    color: var(--accent);
}

.thread-author-user {
    color: var(--success);
}

.thread-msg-text {
    font-size: var(--text-sm);
    line-height: 1.6;
    white-space: pre-line;
    color: var(--text);
}

/* Markdown-rendered Q&A message bodies (question body + thread messages).
   white-space: normal so <p> tags don't create extra gaps;
   p margins give the breathing room that pre-line used to provide. */
.qa-msg-body {
    font-size: var(--text-sm);
    line-height: 1.6;
    white-space: normal;
    color: var(--text);
    margin-bottom: var(--sp-3);
}
.qa-msg-body p {
    margin: 0 0 var(--sp-2) 0;
}
.qa-msg-body p:last-child {
    margin-bottom: 0;
}
.qa-msg-body strong {
    font-weight: 600;
}
.qa-msg-body em {
    font-style: italic;
}
.qa-msg-body code {
    font-family: monospace;
    background: var(--bg-alt);
    padding: 0.1em 0.3em;
    border-radius: 2px;
    font-size: 0.9em;
}
.qa-msg-body ul,
.qa-msg-body ol {
    padding-left: var(--sp-4);
    margin: 0 0 var(--sp-2) 0;
}
.qa-msg-body a {
    color: var(--accent);
    text-decoration: underline;
}

.reply-form {
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--border-light);
}

.reply-form textarea {
    font-size: var(--text-sm);
}

.status-controls {
    display: flex;
    gap: var(--sp-2);
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--border-light);
}

.answer-form-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-top: var(--sp-2);
}

.answer-form-actions .btn:last-child {
    margin-left: auto;
}

.file-input-hidden {
    display: none;
}

.btn-outline {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-secondary);
}

.btn-outline:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.file-upload-names {
    font-size: var(--text-xs, 0.75rem);
    color: var(--text-muted);
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.answer-header {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-2);
}

.answer-attachments {
    margin-top: var(--sp-3);
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
}

.attachment-link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    font-size: var(--text-sm);
    color: var(--accent);
    text-decoration: none;
    padding: var(--sp-1) var(--sp-3);
    background: var(--bg);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
}

.attachment-link:hover {
    border-color: var(--accent);
    text-decoration: underline;
}

.section-divider {
    border: none;
    border-top: 1px solid var(--border-light);
    margin: var(--sp-10) 0;
}

.section-title {
    font-size: var(--text-lg, 1.125rem);
    font-weight: 700;
    color: var(--text);
    margin-bottom: var(--sp-5);
}

/* ─── Error / file lists ──────────────────────────── */

.error-box {
    background: var(--error-bg);
    border: 1px solid #e8c0c0;
    border-radius: var(--radius-sm);
    padding: var(--sp-4) var(--sp-5);
    margin: var(--sp-4) 0;
    color: var(--error);
    font-size: var(--text-sm);
}

.success-box {
    background: var(--success-bg);
    border: 1px solid #b3dfc9;
    border-radius: var(--radius-sm);
    padding: var(--sp-4) var(--sp-5);
    margin: var(--sp-4) 0;
    color: var(--success);
    font-size: var(--text-sm);
}

.dev-notice {
    background: rgba(200, 100, 50, 0.12);
    border: 1px solid rgba(200, 100, 50, 0.25);
    border-left: 4px solid #d45a33;
    padding: var(--sp-4);
    border-radius: var(--radius);
    color: #d45a33;
    font-size: var(--text-sm);
    font-weight: 500;
    margin: var(--sp-4) 0;
    display: block;
}

.error-list li { color: var(--error); margin-left: var(--sp-6); margin-bottom: var(--sp-1); }

.file-list { list-style: none; }
.file-list li {
    padding: var(--sp-2) 0;
    font-size: var(--text-sm);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}
.file-list li + li { border-top: 1px solid var(--border-light); }
.file-list.muted li { color: var(--text-muted); }

.tag {
    display: inline-block;
    padding: 4px 10px;
    background: var(--bg-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin-left: auto;
    vertical-align: middle;
    flex-shrink: 0;
    font-weight: 600;
}

.question-context {
    max-width: 20rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-left: 0;
}

.tag-linked-job {
    background: var(--accent-light);
    border-color: var(--accent);
    color: var(--accent);
    text-decoration: none;
    cursor: pointer;
}
.tag-linked-job:hover {
    background: var(--accent);
    color: white;
    text-decoration: none;
}

/* ─── Empty state ──────────────────────────────────── */

.empty-state {
    text-align: center;
    padding: var(--sp-12) var(--sp-6);
    color: var(--text-secondary);
    font-size: var(--text-md);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

.empty-state a { color: var(--accent); font-weight: 700; }

/* ─── Dashboard footer link ───────────────────────────
   Content-area link (light background) -- NOT the dark-header
   .nav-link, which is styled for the navy nav bar and is nearly
   invisible (near-white text) when placed on the page body. */
.dashboard-footer-link {
    color: var(--accent);
    font-weight: 700;
    text-decoration: none;
    transition: color .15s;
}

.dashboard-footer-link:hover {
    color: var(--accent-hover);
    text-decoration: underline;
}

/* ─── Info box ─────────────────────────────────────── */

.info-box {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--sp-6);
    margin-top: var(--sp-8);
    box-shadow: var(--shadow-sm);
}

.info-box h3 {
    margin: 0 0 var(--sp-4);
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
}

/* ─── Agent message ────────────────────────────────── */

.agent-message {
    background: var(--bg-alt);
    border-left: 3px solid var(--accent);
    padding: var(--sp-4) var(--sp-5);
    margin-top: var(--sp-4);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.agent-message h4 { margin-bottom: var(--sp-1); color: var(--text); font-size: var(--text-base); }

/* ─── Hub page ─────────────────────────────────────── */

.hub-header {
    margin-bottom: var(--sp-10);
}

.hub-subtitle {
    color: var(--text-secondary);
    font-size: var(--text-md);
    margin-top: var(--sp-2);
}

.tool-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: var(--sp-5);
}

.tool-card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
    padding: var(--sp-6);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    color: var(--text);
    transition: border-color .15s, box-shadow .15s;
}

a.tool-card:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow);
}

.tool-card-upcoming {
    border-style: dashed;
}

.tool-icon {
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-alt);
    border-radius: var(--radius-sm);
    color: var(--accent);
}

.tool-card-upcoming .tool-icon {
    color: var(--text-muted);
}

.tool-info h2 {
    font-size: var(--text-md);
    font-weight: 700;
    color: var(--navy);
    margin-bottom: var(--sp-1);
}

.tool-card-upcoming .tool-info h2 {
    color: var(--text-muted);
}

.tool-info p {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.5;
}

.tool-card-upcoming .tool-info p {
    color: var(--text-muted);
}

.tool-status {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 700;
    width: fit-content;
}

.tool-status-active {
    background: var(--success-bg);
    color: var(--success);
}

.tool-status-planned {
    background: var(--bg-elevated);
    color: var(--text-muted);
}

/* ─── Print ────────────────────────────────────────── */

@media print {
    header, footer, nav, .btn, .btn-download, .download-row,
    .back-link, form, .actions, .feedback-history, .agent-message, .btn-danger {
        display: none !important;
    }
    body { background: #fff; color: #222; font-size: 11pt; }
    main { max-width: 100%; padding: 0; margin: 0; }
    .summary-grid { grid-template-columns: repeat(3, 1fr); }
    .stat, .card, .savings-bar-container, .info-box, table { box-shadow: none; border: 1px solid #ddd; }
    .needs-support-banner { border: 2px solid #b8860b; }
    h1, h2 { color: #222; }
    a { color: #222 !important; text-decoration: none !important; }
}

/* ─── Responsive ───────────────────────────────────── */

@media (max-width: 640px) {
    main { padding: var(--sp-6) var(--sp-4) var(--sp-8); }
    nav { padding: var(--sp-3) var(--sp-4); }
    .summary-grid { grid-template-columns: repeat(2, 1fr); }
    table { font-size: var(--text-sm); }
    thead th, tbody td { padding: 12px 10px; }
    .upload-form { padding: var(--sp-5); }
    .dashboard-header { flex-direction: column; gap: var(--sp-2); }
    .drop-zone { padding: var(--sp-6) var(--sp-4); }
    .stat .value { font-size: var(--text-md); }
    .btn-download { padding: 12px 20px; font-size: var(--text-base); width: 100%; justify-content: center; }
    .job-header { flex-direction: column; gap: var(--sp-3); }
    .job-actions { justify-content: flex-start; }
    .logo-divider, .logo-product { display: none; }
    .cost-summary-grid { grid-template-columns: 1fr 1fr; }
    .admin-charts .card canvas { height: 200px !important; }
}

/* ─── Admin nav link ──────────────────────────────── */

.nav-link-admin {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0.4;
    color: rgba(255,255,255,.7);
    transition: opacity .15s;
    padding: 4px;
}

.nav-link-admin:hover { opacity: 0.8; }
.nav-link-admin svg { display: block; }

/* ─── Admin Dashboard ─────────────────────────────── */

.admin-header {
    margin-bottom: var(--sp-8);
}

.admin-header h1 {
    margin-bottom: var(--sp-2);
}

.admin-header-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-4);
    margin-bottom: var(--sp-8);
}

.admin-header-row h1 {
    margin-bottom: 0;
}

/* Inline status text (not badges) */
.text-success { color: var(--success); font-weight: 600; }
.text-warning { color: var(--warning); font-weight: 600; }
.text-error   { color: var(--error);   font-weight: 600; }

/* Compact inline role/action form in table cells */
.table-action-form {
    display: flex;
    gap: var(--sp-2);
    align-items: center;
}

/* Smaller sibling of the unified control system (inline table-row selects) --
   shares border/radius/chevron/focus with .field/.form-field selects, just
   at --control-h-sm instead of --control-h. */
.select-compact {
    min-height: var(--control-h-sm);
    font-size: var(--text-sm);
    padding: 9px 36px 9px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
    color: var(--text);
    font-family: inherit;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 4.5L6 8L9.5 4.5' stroke='%23565a6a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 10px;
}

.admin-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-8);
}

.admin-card {
    text-decoration: none;
    display: block;
    padding: var(--sp-5);
    transition: border-color .15s, box-shadow .15s;
}

.admin-card h3 {
    margin-top: 0;
}

.admin-card:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow);
}

.admin-section-heading {
    margin-top: var(--sp-2);
    margin-bottom: var(--sp-4);
}

.cost-summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-8);
}

.cost-card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--sp-5) var(--sp-6);
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    box-shadow: var(--shadow-sm);
}

.cost-card-label {
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.cost-card-value {
    font-size: var(--text-2xl);
    font-weight: 800;
    color: var(--navy);
    letter-spacing: -0.02em;
    line-height: 1.2;
}

.cost-card-sub {
    font-size: var(--text-sm);
    color: var(--text-secondary);
}

.admin-charts {
    display: flex;
    flex-direction: column;
    gap: var(--sp-6);
}

.admin-charts .card canvas {
    max-height: 280px;
    margin-bottom: var(--sp-4);
}

.admin-cost-table {
    margin-top: var(--sp-4);
}

.admin-cost-table .total-row td {
    border-top: 2px solid var(--border);
    padding-top: var(--sp-3);
}

/* ─── Telemetry banner ────────────────────────────── */

.telemetry-banner {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 8000;
    background: var(--bg-elevated);
    border-top: 1px solid var(--border-light);
    padding: var(--sp-2) var(--sp-6);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-4);
    font-size: 0.8125rem; /* 13px */
    color: var(--text-muted);
    line-height: 1.4;
}

.telemetry-banner-close {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 1rem;
    line-height: 1;
    padding: 0 var(--sp-1);
    flex-shrink: 0;
    opacity: 0.7;
    transition: opacity 0.15s;
}

.telemetry-banner-close:hover { opacity: 1; }

/* ─── Telemetry admin ─────────────────────────────── */

.telemetry-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-8);
}

.telemetry-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
    margin-top: var(--sp-4);
}

.telemetry-table th,
.telemetry-table td {
    text-align: left;
    padding: var(--sp-2) var(--sp-3);
    border-bottom: 1px solid var(--border-light);
}

.telemetry-table th {
    font-weight: 600;
    color: var(--text-secondary);
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: var(--bg-alt);
}

.telemetry-table tbody tr:hover { background: var(--bg-alt); }

.telemetry-bar {
    display: inline-block;
    height: 10px;
    border-radius: 3px;
    background: var(--accent);
    min-width: 2px;
    vertical-align: middle;
}

.telemetry-count {
    font-weight: 600;
    color: var(--navy);
    min-width: 3rem;
    display: inline-block;
}

/* ─── Auth pages ─────────────────────────────────── */

/* ─── Error page ────────────────────────────────── */

.error-page {
    max-width: 560px;
    margin: 60px auto;
    text-align: center;
    padding: 0 var(--sp-4);
}

.error-page-code {
    font-size: 3.5rem;
    font-weight: 800;
    color: var(--text-muted);
    line-height: 1;
    margin-bottom: var(--sp-3);
    letter-spacing: -2px;
}

.error-page-title {
    font-size: var(--text-xl);
    font-weight: 700;
    margin: 0 0 var(--sp-2);
}

.error-page-message {
    color: var(--text-secondary);
    font-size: var(--text-sm);
    margin: 0 0 var(--sp-6);
    line-height: 1.65;
}

.error-page-actions {
    display: flex;
    gap: var(--sp-3);
    justify-content: center;
    flex-wrap: wrap;
}

.error-support-box {
    background: var(--success-bg);
    border: 1px solid rgba(26,138,92,.2);
    border-radius: var(--radius-sm);
    padding: var(--sp-4) var(--sp-5);
    margin-bottom: var(--sp-6);
    text-align: left;
}

.error-support-box p {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--success);
    line-height: 1.55;
}

.error-support-box code {
    font-family: ui-monospace, SFMono-Regular, monospace;
    font-weight: 600;
    background: rgba(26,138,92,.08);
    padding: 1px 5px;
    border-radius: 3px;
}

/* ─── Auth ──────────────────────────────────────── */

.auth-wrap {
    display: flex;
    justify-content: center;
    padding: var(--sp-12) var(--sp-4);
}

.auth-card {
    background: var(--bg-card);
    border: 1px solid var(--border-light);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: var(--sp-10) var(--sp-8);
    width: 100%;
    max-width: 420px;
}

.auth-card h1 {
    font-size: var(--text-xl);
    font-weight: 700;
    margin-bottom: var(--sp-2);
}

.auth-card .auth-intro {
    color: var(--text-secondary);
    margin-bottom: var(--sp-6);
    font-size: var(--text-sm);
}

.auth-form {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

.auth-form label {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
}

/* Control sizing (padding/font/border/focus) for .auth-form inputs lives
   in the unified form-control rule above -- do not reimpose it here. */

.auth-form .btn-primary {
    width: 100%;
    margin-top: var(--sp-2);
}

.auth-error {
    background: var(--error-bg);
    color: var(--error);
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-weight: 500;
    border: 1px solid rgba(201,59,59,.2);
    margin-bottom: var(--sp-4);
}

.auth-info {
    background: var(--success-bg);
    color: var(--success);
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    border: 1px solid rgba(26,138,92,.2);
    margin-bottom: var(--sp-4);
}

.auth-footer-links {
    margin-top: var(--sp-6);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--border-light);
    text-align: center;
    font-size: var(--text-sm);
}

.auth-footer-links a {
    color: var(--accent);
    text-decoration: none;
    font-weight: 600;
}

.auth-footer-links a:hover { text-decoration: underline; }

.auth-mfa-code {
    font-size: var(--text-lg);
    letter-spacing: 0.3em;
    text-align: center;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Courier New", monospace;
}

.auth-totp-secret {
    background: var(--bg-elevated);
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius-sm);
    font-family: ui-monospace, monospace;
    font-size: var(--text-sm);
    word-break: break-all;
    user-select: all;
}

.auth-qr {
    display: block;
    margin: var(--sp-4) auto;
    width: 200px;
    height: 200px;
    background: #fff;
    padding: var(--sp-2);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
}

/* ─── Secure handoff link ───────────────────────────── */

.secure-link-card-wide {
    max-width: 680px;
}

.secure-link-card h1 {
    text-align: center;
}

.secure-link-card .auth-intro {
    text-align: center;
}

.secure-link-secret {
    background: var(--bg-elevated);
    color: var(--text);
    padding: var(--sp-4);
    border-radius: var(--radius-sm);
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Courier New", monospace;
    font-size: var(--text-sm);
    white-space: pre-wrap;
    word-break: break-word;
    user-select: all;
}

.secure-link-note {
    color: var(--text-secondary);
    font-size: var(--text-sm);
    text-align: center;
    margin-top: var(--sp-4);
}

.secure-link-card .btn-primary {
    display: flex;
    width: 100%;
    margin-top: var(--sp-4);
}

/* ─── Secure handoff link — structured fields ───────── */

.secure-field-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
    margin: 0 0 var(--sp-6);
}

.secure-field-row {
    background: var(--bg-elevated);
    border: 1px solid var(--border-light);
    border-radius: var(--radius-sm);
    padding: var(--sp-3) var(--sp-4);
}

.secure-field-row-sensitive {
    border-left: 3px solid var(--accent);
}

.secure-field-label {
    display: flex;
    align-items: center;
    gap: var(--sp-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
    margin: 0 0 var(--sp-2);
}

.secure-field-value-row {
    display: flex;
    align-items: stretch;
    gap: var(--sp-3);
    margin: 0;
}

.secure-field-value {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: var(--sp-2) var(--sp-3);
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Courier New", monospace;
    font-size: var(--text-base);
    white-space: pre-wrap;
    word-break: break-word;
    user-select: all;
    cursor: pointer;
}

.secure-field-value:hover {
    border-color: var(--accent);
}

.secure-field-actions {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.secure-field-toggle-btn,
.secure-field-copy-btn {
    flex-shrink: 0;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-size: var(--text-sm);
    font-weight: 600;
    padding: 0.5rem 0.85rem;
    cursor: pointer;
    white-space: nowrap;
    min-width: 5.5rem;
}

.secure-field-toggle-btn:hover,
.secure-field-copy-btn:hover {
    background: var(--bg-alt);
    border-color: var(--accent);
    color: var(--accent);
}

.secure-field-copy-btn-success {
    background: var(--success-bg);
    border-color: var(--success);
    color: var(--success);
}

.secure-tooltip {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.secure-tooltip-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    color: var(--text-muted);
    font-size: 0.7rem;
    font-weight: 700;
    cursor: help;
}

.secure-tooltip-text {
    position: absolute;
    bottom: calc(100% + var(--sp-2));
    left: 50%;
    transform: translateX(-50%);
    width: 240px;
    background: var(--text);
    color: var(--bg);
    font-size: var(--text-sm);
    font-weight: 400;
    line-height: 1.4;
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius-sm);
    opacity: 0;
    visibility: hidden;
    transition: opacity .15s ease;
    z-index: 10;
    pointer-events: none;
}

.secure-tooltip:hover .secure-tooltip-text,
.secure-tooltip:focus .secure-tooltip-text,
.secure-tooltip:focus-within .secure-tooltip-text {
    opacity: 1;
    visibility: visible;
}

.secure-qr-block {
    text-align: center;
    margin-bottom: var(--sp-6);
}

.secure-qr-manual {
    margin-top: var(--sp-3);
    font-size: var(--text-sm);
}

.secure-qr-manual summary {
    cursor: pointer;
    color: var(--accent);
    font-weight: 600;
}

/* ─── User menu dropdown ────────────────────────────── */

.user-menu {
    position: relative;
}

.user-menu-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    background: transparent;
    border: 1px solid rgba(255,255,255,.25);
    border-radius: var(--radius-sm);
    color: rgba(255,255,255,.85);
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    padding: 0.4rem 0.75rem;
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s;
    white-space: nowrap;
    user-select: none;
}

.user-menu-btn:hover,
.user-menu-btn[aria-expanded="true"] {
    color: #fff;
    background: rgba(255,255,255,.1);
    border-color: rgba(255,255,255,.4);
}

.user-menu-btn:focus-visible {
    outline: 2px solid var(--focus-color);
    outline-offset: 2px;
}

.user-menu-label {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user-menu-chevron {
    flex-shrink: 0;
    transition: transform .15s;
}

.user-menu-btn[aria-expanded="true"] .user-menu-chevron {
    transform: rotate(180deg);
}

.user-menu-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 100;
    min-width: 220px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-sm);
    padding: var(--sp-1) 0;
    outline: none;
}

.user-menu-panel[hidden] { display: none; }

.user-menu-identity {
    padding: var(--sp-3) var(--sp-4) var(--sp-2);
    display: flex;
    flex-direction: column;
    gap: 2px;
    border-bottom: 1px solid var(--border-light);
    margin-bottom: var(--sp-1);
}

.user-menu-name {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
    line-height: 1.4;
}

.user-menu-email {
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: 1.4;
    word-break: break-all;
}

.user-menu-role-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 4px;
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: capitalize;
    letter-spacing: 0.02em;
    align-self: flex-start;
}

.user-menu-divider {
    display: none;
}

.user-menu-item {
    display: block;
    width: 100%;
    padding: var(--sp-2) var(--sp-4);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 500;
    text-decoration: none;
    text-align: left;
    background: transparent;
    border: none;
    cursor: pointer;
    transition: background .12s, color .12s;
    white-space: nowrap;
}

.user-menu-item:hover,
.user-menu-item:focus-visible {
    background: var(--bg-alt);
    color: var(--text);
    outline: none;
}

.user-menu-logout-form {
    margin: 0;
    padding: 0;
}

/* Mobile: keep panel within viewport */
@media (max-width: 640px) {
    .user-menu-panel {
        right: 0;
        left: auto;
        min-width: 190px;
    }

    .user-menu-label {
        max-width: 120px;
    }
}

/* ─── Notification bell ─────────────────────────────── */

.notif-bell {
    position: relative;
}

.notif-bell-wrap {
    position: relative;
}

.notif-bell-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: relative;
    background: transparent;
    border: 1px solid rgba(255,255,255,.25);
    border-radius: var(--radius-sm);
    color: rgba(255,255,255,.75);
    padding: 0.4rem 0.55rem;
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s;
    line-height: 1;
}

.notif-bell-btn:hover,
.notif-bell-btn[aria-expanded="true"] {
    color: #fff;
    background: rgba(255,255,255,.1);
    border-color: rgba(255,255,255,.4);
}

.notif-bell-btn:focus-visible {
    outline: 2px solid var(--focus-color);
    outline-offset: 2px;
}

.notif-badge {
    position: absolute;
    top: -5px;
    right: -5px;
    min-width: 16px;
    height: 16px;
    background: var(--error);
    color: #fff;
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    border-radius: 8px;
    padding: 0 3px;
    pointer-events: none;
}

.notif-panel {
    /* Fixed (not absolute, and portaled to body via JS in base.html) so it
       escapes the sticky header's stacking context entirely. Positioned
       under the bell via positionNotifPanel() in base.html, which runs
       before every paint where this panel could be visible -- the top/right
       below are a no-JS fallback only and are intentionally >= the header's
       current rendered height (~72px) plus margin so they never overlap it.
       Keep in sync with header height (nav padding + content) if that grows. */
    position: fixed;
    top: 80px;
    right: 16px;
    z-index: 1001;
    width: 320px;
    max-width: calc(100vw - 16px);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    overflow: hidden;
}

.notif-panel[hidden] { display: none; }

.notif-panel-header {
    padding: var(--sp-3) var(--sp-4);
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--text);
    border-bottom: 1px solid var(--border-light);
}

.notif-list {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 380px;
    overflow-y: auto;
}

.notif-item {
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--border-light);
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.notif-item:last-child { border-bottom: none; }

.notif-item-title {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
    line-height: 1.4;
}

.notif-item-age {
    font-size: 0.75rem;
    color: var(--text-muted);
}

.notif-item-link {
    font-size: 0.75rem;
    font-weight: 600;
    color: #5b9bd5;
    text-decoration: none;
    align-self: flex-start;
    margin-top: 2px;
    transition: color .15s;
}

.notif-item-link:hover { color: #73b3e1; }

.notif-empty {
    padding: var(--sp-5) var(--sp-4);
    text-align: center;
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.notif-panel-footer-link {
    display: block;
    padding: var(--sp-2) var(--sp-4);
    text-align: center;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--accent);
    text-decoration: none;
    border-top: 1px solid var(--border-light);
    transition: color .15s, background .15s;
}

.notif-panel-footer-link:hover {
    color: var(--accent-hover);
    background: var(--bg-hover, rgba(0,0,0,.02));
}

/* ─── Stale banner ──────────────────────────────────── */

.notif-stale-banner {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    background: var(--warning-bg);
    color: var(--warning);
    padding: var(--sp-2) var(--sp-5);
    font-size: var(--text-sm);
    font-weight: 500;
    border-bottom: 1px solid rgba(161,114,22,.2);
}

.notif-stale-banner[hidden] { display: none; }

.notif-stale-link {
    font-weight: 700;
    color: var(--warning);
    text-decoration: underline;
    cursor: pointer;
    white-space: nowrap;
    background: none;
    border: none;
    padding: 0;
    font-size: inherit;
}

.notif-stale-dismiss {
    margin-left: auto;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--warning);
    font-size: 1rem;
    line-height: 1;
    padding: 0 var(--sp-1);
    opacity: 0.7;
    transition: opacity .15s;
    flex-shrink: 0;
}

.notif-stale-dismiss:hover { opacity: 1; }

/* Mobile: full-width panel below header */
@media (max-width: 600px) {
    .notif-panel {
        position: fixed;
        top: auto;
        left: 0;
        right: 0;
        width: 100%;
        border-radius: 0;
        border-left: none;
        border-right: none;
        max-height: 60vh;
        overflow-y: auto;
    }

    /* Compact nav on narrow screens to prevent horizontal overflow. */
    nav {
        padding-left: var(--sp-3);
        padding-right: var(--sp-3);
    }

    /* Hide the text "Feedback" nav link -- accessible via notification panel. */
    nav .nav-link {
        display: none;
    }

    /* Hide the nav separator (| between logo and tool name) to save space. */
    .nav-separator {
        display: none;
    }

    /* Truncate user name label to prevent overflow. */
    .user-menu-label {
        max-width: 72px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* ─── Nav count badge (Questions link) ──────────────── */

.nav-count-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--warning, #e6a817);
    color: white;
    font-size: 0.6875rem; /* 11px */
    font-weight: 700;
    line-height: 1;
    margin-left: var(--sp-1);
    vertical-align: middle;
}

/* ─── Client Questions page ─────────────────────────── */

.questions-page {
    max-width: 780px;
    margin: 0 auto;
    padding: var(--sp-8) var(--sp-4);
}

.questions-page-header {
    margin-bottom: var(--sp-8);
}

.questions-page-title {
    font-size: 1.75rem;
    font-weight: 700;
    margin-bottom: var(--sp-2);
    color: var(--text-primary);
}

.questions-page-subtitle {
    font-size: 1rem;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.questions-section-note {
    font-size: 0.875rem;
    color: var(--text-muted);
    margin-bottom: var(--sp-4);
}

.questions-in-our-court .question-card {
    opacity: 0.8;
}

.question-card-passive {
    border-left-color: var(--border);
}

.question-passive-note {
    font-size: 0.8125rem;
    color: var(--text-muted);
    margin-top: var(--sp-3);
    font-style: italic;
}

/* Closed questions section toggle */

.closed-questions-section {
    margin-top: var(--sp-8);
}

.closed-toggle-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    background: none;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--sp-2) var(--sp-3);
    font-size: 0.875rem;
    color: var(--text-muted);
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
    margin-bottom: var(--sp-4);
}

.closed-toggle-btn:hover {
    border-color: var(--text-secondary);
    color: var(--text-primary);
}

.closed-toggle-icon {
    flex-shrink: 0;
    transition: transform 0.2s;
}

.closed-toggle-icon-open {
    transform: rotate(180deg);
}

.questions-closed-list .question-card {
    opacity: 0.65;
}

/* Questions tile on apps grid -- distinct treatment as an inbox, not a tool */

.tool-card-questions {
    border-left: 4px solid var(--border, #e5e7eb);
}

.tool-card-questions--alert {
    border-left: 4px solid var(--accent);
}


/* ─── Dedicated notifications page ──────────────────────────────────
   Gated behind LOGRO_NOTIF_PAGE -- these rules only ever apply to the
   .notifications-page container, which only renders when the flag is on,
   so this block cannot affect any flag-off page. */

.notifications-page {
    max-width: 780px;
    margin: 0 auto;
    padding: var(--sp-8) var(--sp-4);
}

.notifications-page-header {
    margin-bottom: var(--sp-8);
}

.notifications-page-title {
    font-size: 1.75rem;
    font-weight: 700;
    margin-bottom: var(--sp-2);
    color: var(--text-primary);
}

.notifications-page-subtitle {
    font-size: 1rem;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.notifications-section {
    margin-top: var(--sp-8);
}

.notifications-section:first-of-type {
    margin-top: 0;
}

.notif-page-empty {
    padding: var(--sp-5) var(--sp-4);
    text-align: center;
    font-size: var(--text-sm);
    color: var(--text-muted);
    background: var(--bg-card);
    border: 1px solid var(--border-light);
    border-radius: var(--radius);
}

.notifications-active-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

.notif-page-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    background: var(--bg-card);
    border: 1px solid var(--border-light);
    border-radius: var(--radius);
}

.notif-page-item-main {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.notif-page-item-title {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
}

.notif-page-item-age {
    font-size: 0.75rem;
    color: var(--text-muted);
}

.notif-page-item-link {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--accent);
    text-decoration: none;
    white-space: nowrap;
    flex-shrink: 0;
    transition: color .15s;
}

.notif-page-item-link:hover { color: var(--accent-hover); }

.notifications-history-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.notif-history-item {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-2);
    border-bottom: 1px solid var(--border-light);
}

.notif-history-item:last-child { border-bottom: none; }

.notif-history-icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--bg-muted, #f3f4f6);
    color: var(--text-muted);
    margin-top: 2px;
}

.notif-history-item-qa .notif-history-icon {
    color: var(--accent);
}

.notif-history-item-feedback .notif-history-icon {
    color: var(--warning, #e6a817);
}

.notif-history-body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.notif-history-title {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text);
    text-decoration: none;
}

.notif-history-title:hover { color: var(--accent); }

.notif-history-age {
    font-size: 0.75rem;
    color: var(--text-muted);
}


/* ─── Hub onboarding UX ─────────────────────────────── */

/* Intro banner */
.hub-intro-banner {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-4);
    background: var(--accent-light);
    border-left: 4px solid var(--accent);
    border-radius: var(--radius);
    padding: var(--sp-5) var(--sp-6);
    margin-bottom: var(--sp-6);
}

.hub-intro-banner-body {
    flex: 1;
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.6;
}

.hub-intro-banner-headline {
    display: block;
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--navy);
    margin-bottom: var(--sp-1);
}

.hub-intro-banner-body p {
    margin: 0;
}

.hub-intro-banner-dismiss {
    flex-shrink: 0;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 1.25rem;
    line-height: 1;
    padding: 0 var(--sp-1);
    border-radius: var(--radius-sm);
    transition: color .15s;
}

.hub-intro-banner-dismiss:hover {
    color: var(--accent);
}

/* Tool card restructured as div with click-via-JS */
div.tool-card {
    position: relative;
    cursor: pointer;
}

div.tool-card:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow);
}

div.tool-card:focus {
    outline: 2px solid var(--focus-color);
    outline-offset: 2px;
}

/* (?) help button -- click to reveal, no hover-only info */
.tool-help-btn {
    position: absolute;
    top: var(--sp-3);
    right: var(--sp-3);
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text-muted);
    font-size: 0.833rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: color .15s, border-color .15s, background .15s;
    z-index: 1;
    min-width: 28px;
}

.tool-help-btn:hover,
.tool-help-btn[aria-expanded="true"] {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-light);
}

/* Click-reveal help panel (replaces hover-only tooltip) */
.tool-help-panel {
    display: none;
    position: absolute;
    top: calc(var(--sp-3) + 34px);
    right: var(--sp-3);
    width: 240px;
    background: var(--navy);
    color: #fff;
    font-size: var(--text-sm);
    font-weight: 400;
    line-height: 1.5;
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    white-space: normal;
    z-index: 100;
    text-align: left;
}

.tool-help-panel.is-open {
    display: block;
}

/* How it works details block */
.tool-how-details {
    margin-top: var(--sp-3);
    border-top: 1px solid var(--border-light);
    padding-top: var(--sp-3);
}

.tool-how-details summary {
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--accent);
    cursor: pointer;
    user-select: none;
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-1) 0;
    transition: color .15s;
}

.tool-how-details summary::-webkit-details-marker {
    display: none;
}

.tool-how-details summary::before {
    content: '\25B6';
    font-size: 0.6rem;
    transition: transform .15s;
    display: inline-block;
}

.tool-how-details[open] summary::before {
    transform: rotate(90deg);
}

.tool-how-details summary:hover {
    color: var(--accent);
}

.tool-how-list {
    margin: var(--sp-2) 0 0 var(--sp-4);
    padding: 0;
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.6;
}

.tool-how-list li {
    margin-bottom: var(--sp-1);
}

.tool-how-list li:last-child {
    margin-bottom: 0;
}

/* ─── Upload steps (numbered flow) ─────────────────── */

.upload-steps {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--sp-6) 0;
    display: flex;
    flex-direction: column;
    gap: 0;
    counter-reset: upload-step;
}

.upload-step {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-4);
    padding: var(--sp-4) 0;
    border-bottom: 1px solid var(--border-light);
}

.upload-step:last-child {
    border-bottom: none;
}

.upload-step-num {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--navy);
    color: #fff;
    font-size: var(--text-base);
    font-weight: 800;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 2px;
}

.upload-step-body {
    flex: 1;
}

.upload-step-label {
    display: block;
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--navy);
    margin-bottom: var(--sp-1);
}

.upload-step-hint {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.5;
    margin: 0;
}

/* Active/current step highlight */
.upload-step-active .upload-step-num {
    background: #5b9bd5;
}

/* Form control that lives directly inside a step body */
.upload-step-field {
    margin-top: var(--sp-4);
    margin-bottom: 0;
}

/* Give steps more breathing room now that each holds an input */
.upload-form .upload-steps {
    margin: 0;
}

.upload-form .upload-step {
    padding: var(--sp-5) 0;
}

.upload-form .upload-step:first-child {
    padding-top: 0;
}

.upload-form .upload-step:last-child {
    padding-bottom: 0;
}

/* ─── Hub tour button ───────────────────────────────── */

.hub-tour-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-6);
    background: var(--accent);
    border: 2px solid var(--accent);
    border-radius: var(--radius-sm);
    color: #fff;
    font-size: var(--text-md);
    font-weight: 700;
    font-family: inherit;
    cursor: pointer;
    text-decoration: none;
    transition: background .15s, border-color .15s;
    min-height: 52px;
    white-space: nowrap;
    box-shadow: var(--shadow);
}

.hub-tour-btn:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
}

.hub-header-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-4);
    flex-wrap: wrap;
    margin-bottom: var(--sp-10);
}

.hub-header-text { flex: 1; }

/* ─── Unified job-status colors (platform-wide) ─────────────────────────
   The repricing tool uses status values complete/error/needs_input; the
   other tools (benchmark/directory/geo/disruption/proposal) use
   completed/failed/queued/running/pending_phase1. Map those to the same
   semantic meta-line colors so a finished job reads green and a failed job
   reads red everywhere, matching the repricing gold standard. */
.meta-status-status-completed { color: var(--success); }
.meta-status-status-failed { color: var(--error); }
.meta-status-status-queued,
.meta-status-status-running,
.meta-status-status-processing,
.meta-status-status-pending_phase1 { color: var(--text-secondary); }

/* Stat-grid value colors: raise specificity above `.stat .value` so semantic
   savings colors actually render inside a summary grid (pass=green, fail=red,
   caution=amber) — used by directory QA, geo anomalies, disruption. */
.stat .value.savings-green { color: var(--savings-green); }
.stat .value.savings-yellow { color: var(--savings-yellow); }
.stat .value.savings-red { color: var(--savings-red); }

/* ─── Sortable tables ───────────────────────────────────────────── */
th.th-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.th-sortable:hover { color: var(--accent); }
th.th-sortable::after { content: '\2195'; opacity: 0.3; margin-left: 0.35em; font-size: 0.85em; font-weight: 400; }
th.th-sortable[aria-sort="ascending"]::after { content: '\2191'; opacity: 1; color: var(--accent); }
th.th-sortable[aria-sort="descending"]::after { content: '\2193'; opacity: 1; color: var(--accent); }
th.th-sortable:focus-visible { outline: 2px solid var(--focus-color); outline-offset: -2px; }

/* ─── Sidebar Navigation ─────────────────────────────
   Everything below is scoped under body.has-sidebar so flag-OFF pages
   (LOGRO_SIDEBAR_NAV unset/false) are completely unaffected -- no existing
   rule above this point is modified. */

:root {
    --sidebar-width: 240px;
    --sidebar-width-collapsed: 64px;
}

/* NOTE: body keeps its base flex column layout (display:flex; min-height:100vh
   with main{flex:1}) so the sticky footer still pins to the viewport bottom on
   short pages. The sidebar rail is position:fixed, so it's out of flow and does
   not participate in the body flex layout; the margin-left shifts on
   main/footer below handle the horizontal offset. */

/* Slim top bar replacing the old full header when the sidebar is active. */
body.has-sidebar .topbar-slim {
    background: var(--navy);
    position: sticky;
    top: 0;
    z-index: 900;
    box-shadow: 0 1px 4px rgba(0,0,0,.15);
    margin-left: var(--sidebar-width);
    transition: margin-left .18s ease;
}

html.sidebar-collapsed body.has-sidebar .topbar-slim {
    margin-left: var(--sidebar-width-collapsed);
}

body.has-sidebar .topbar-slim nav {
    max-width: none;
    padding: var(--sp-3) var(--sp-6);
}

body.has-sidebar .sidebar-hamburger {
    display: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-sm);
    color: rgba(255,255,255,.85);
    background: transparent;
    border: none;
    cursor: pointer;
    transition: background .15s, color .15s;
}

body.has-sidebar .sidebar-hamburger:hover {
    color: #fff;
    background: rgba(255,255,255,.1);
}

body.has-sidebar .nav-tool-label {
    color: rgba(255,255,255,.85);
    font-size: var(--text-sm);
    font-weight: 700;
    margin-left: var(--sp-2);
}

/* Shift page content to make room for the fixed sidebar rail. `main` sets an
   explicit `width: 100%` in the base rules above (for the flag-OFF centered
   layout) -- combined with a fixed margin-left that's a SPECIFIED (not auto)
   width, the browser doesn't shrink the box to compensate, so the two
   together overflow the viewport by exactly the sidebar's width. `footer`
   has no explicit width in the base rules (default auto), so margin-left
   alone is safe there and needs no width override. This only bites between
   the mobile breakpoint (640px, where margin-left resets to 0 below) and
   roughly max-width + sidebar-width (~1360px, where 1120px's own cap already
   leaves enough room) -- i.e. tablet-ish widths -- which is exactly the gap
   that surfaced it. */
body.has-sidebar main,
body.has-sidebar footer {
    margin-left: var(--sidebar-width);
    transition: margin-left .18s ease;
}

body.has-sidebar main {
    width: calc(100% - var(--sidebar-width));
}

html.sidebar-collapsed body.has-sidebar main,
html.sidebar-collapsed body.has-sidebar footer {
    margin-left: var(--sidebar-width-collapsed);
}

html.sidebar-collapsed body.has-sidebar main {
    width: calc(100% - var(--sidebar-width-collapsed));
}

/* Sidebar rail itself. */
body.has-sidebar .app-sidebar {
    /* Width is intentionally fit-content (not 100%/inset:0) -- this wrapper
       must NOT intercept pointer events across the whole viewport when the
       rail is transformed off-screen (mobile, closed drawer). Only the
       .sidebar-backdrop child (itself position:fixed + inset:0, shown only
       while .is-open) is allowed to cover the full viewport. */
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1000;
    width: fit-content;
    height: 100vh;
    pointer-events: none;
}

body.has-sidebar .sidebar-rail,
body.has-sidebar .sidebar-backdrop {
    pointer-events: auto;
}

body.has-sidebar .sidebar-rail {
    position: relative;
    z-index: 1001;
    width: var(--sidebar-width);
    height: 100%;
    background: var(--navy);
    display: flex;
    flex-direction: column;
    transition: width .18s ease;
    overflow-x: hidden;
}

html.sidebar-collapsed body.has-sidebar .sidebar-rail {
    width: var(--sidebar-width-collapsed);
}

body.has-sidebar .sidebar-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,.4);
    z-index: 999;
}

body.has-sidebar .sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--sp-4);
    gap: var(--sp-2);
}

body.has-sidebar .sidebar-logo {
    display: flex;
    align-items: center;
    min-width: 0;
}

body.has-sidebar .sidebar-logo img {
    height: 28px;
    width: auto;
    filter: brightness(0) invert(1);
}

body.has-sidebar .sidebar-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border-radius: var(--radius-sm);
    color: rgba(255,255,255,.6);
    background: transparent;
    border: none;
    cursor: pointer;
    transition: color .15s, background .15s, transform .18s;
}

body.has-sidebar .sidebar-toggle:hover {
    color: #fff;
    background: rgba(255,255,255,.1);
}

html.sidebar-collapsed body.has-sidebar .sidebar-toggle svg {
    transform: rotate(180deg);
}

/* Collapsed rail (64px): the wide wordmark overflows and would push the
   collapse/expand chevron out of the overflow-x:hidden rail, leaving a
   collapsed user with no visible way to expand. Hide the wordmark and center
   the toggle so the (now right-pointing) chevron is the top affordance. */
html.sidebar-collapsed body.has-sidebar .sidebar-logo {
    display: none;
}

html.sidebar-collapsed body.has-sidebar .sidebar-header {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
}

body.has-sidebar .sidebar-tools {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--sp-2);
    min-width: 0;
    /* This <nav> also matches the global bare `nav { margin: 0 auto;
       max-width: 1120px; align-items: center; ... }` rule further up this
       file (written for the old centered topbar nav). That rule's
       properties aren't overridden here just by being more specific unless
       explicitly re-declared, and margin:auto on the cross axis of a column
       flex item disables align-items:stretch entirely (per the flexbox
       spec) -- so without this reset, the nav shrink-to-fits around its
       longest link's content instead of filling the 240px rail, and gets
       centered inside it besides. That's what let the min-width:auto trap
       on .sidebar-link below go unnoticed: the active/hover row highlight
       was itself shrink-wrapped and inset from both edges rather than
       spanning the full rail width. */
    margin: 0;
    max-width: none;
    align-items: stretch;
    justify-content: flex-start;
}

body.has-sidebar .sidebar-tools-secondary {
    padding-bottom: var(--sp-2);
}

body.has-sidebar .sidebar-divider {
    height: 1px;
    margin: var(--sp-2) var(--sp-4);
    background: rgba(255,255,255,.12);
}

body.has-sidebar .sidebar-link {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius-sm);
    color: rgba(255,255,255,.7);
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 600;
    white-space: nowrap;
    border-left: 3px solid transparent;
    transition: color .15s, background .15s, border-color .15s;
    /* A flex item's default min-width is auto (content-based), not 0 -- so
       without this, an unusually long tool name won't respect the rail's
       240px width at all; the whole row grows to fit the text and gets
       silently hard-clipped by .sidebar-rail's overflow-x:hidden instead of
       ever reaching the label's ellipsis below. min-width:0 here (and on
       .sidebar-link-label) lets the row actually shrink to the rail's width
       so truncation can kick in. */
    min-width: 0;
}

body.has-sidebar .sidebar-link:hover {
    color: #fff;
    background: rgba(255,255,255,.08);
}

body.has-sidebar .sidebar-link.is-active,
body.has-sidebar .sidebar-link[aria-current="page"] {
    color: #fff;
    background: var(--navy-light);
    border-left-color: var(--accent);
}

body.has-sidebar .sidebar-link-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

body.has-sidebar .sidebar-link-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Collapsed: icons only, centered, labels hidden via CSS (kept in DOM for a11y). */
html.sidebar-collapsed body.has-sidebar .sidebar-link {
    justify-content: center;
    padding: var(--sp-2);
}

html.sidebar-collapsed body.has-sidebar .sidebar-link-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    border: 0;
}

/* Collapsed-rail tooltip: a single shared floating element, shown/positioned
   by JS in base.html on hover/focus of a .sidebar-link (see
   '#sidebar-tooltip' there). It can't be a CSS ::after on the link itself --
   .sidebar-rail has overflow-x:hidden (needed to clip the wordmark during
   the collapse-width transition above), and overflow clips ALL descendants
   regardless of position, so a pseudo-element tooltip positioned outside the
   64px rail would just get cut off. Living outside .sidebar-rail (as a
   position:fixed sibling inside #app-sidebar, which has no overflow rule)
   sidesteps that entirely. Desktop only in practice -- the JS only shows it
   when collapsed AND above the mobile breakpoint, since on mobile the drawer
   always shows full labels (see the mobile media query below). */
.sidebar-tooltip {
    position: fixed;
    z-index: 1005;
    background: var(--navy);
    color: #fff;
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-weight: 600;
    white-space: nowrap;
    box-shadow: var(--shadow-md);
    pointer-events: none;
}

body.has-sidebar .sidebar-user {
    margin-top: auto;
    padding: var(--sp-3);
    border-top: 1px solid rgba(255,255,255,.12);
}

body.has-sidebar .sidebar-user-summary {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    width: 100%;
    padding: var(--sp-2);
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    color: #fff;
    cursor: pointer;
    text-align: left;
    transition: background .15s;
}

body.has-sidebar .sidebar-user-summary:hover {
    background: rgba(255,255,255,.08);
}

body.has-sidebar .sidebar-user-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--accent);
    color: #fff;
    font-size: var(--text-sm);
    font-weight: 700;
}

body.has-sidebar .sidebar-user-info {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    overflow: hidden;
}

body.has-sidebar .sidebar-user-name {
    font-size: var(--text-sm);
    font-weight: 600;
    color: #fff;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

body.has-sidebar .sidebar-user-email {
    font-size: 0.75rem;
    color: rgba(255,255,255,.6);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

body.has-sidebar .sidebar-user-actions {
    display: none;
    flex-direction: column;
    gap: 2px;
    margin-top: var(--sp-2);
}

body.has-sidebar .sidebar-user-open .sidebar-user-actions {
    display: flex;
}

body.has-sidebar .sidebar-link-logout {
    width: 100%;
    background: transparent;
    border: none;
    font-family: inherit;
    cursor: pointer;
}

/* Collapsed: show just an avatar/initial; hide name/email/actions. */
html.sidebar-collapsed body.has-sidebar .sidebar-user-summary {
    justify-content: center;
    padding: var(--sp-2) 0;
}

html.sidebar-collapsed body.has-sidebar .sidebar-user-info {
    display: none;
}

html.sidebar-collapsed body.has-sidebar .sidebar-user-actions {
    display: none;
}

/* Desktop: backdrop and off-canvas transform are mobile-only; keep the rail
   permanently visible and non-transformed above 640px. */
@media (min-width: 641px) {
    body.has-sidebar .sidebar-backdrop {
        display: none;
    }
}

/* Mobile: sidebar becomes an off-canvas drawer. */
@media (max-width: 640px) {
    body.has-sidebar .sidebar-hamburger {
        display: inline-flex;
    }

    body.has-sidebar .topbar-slim,
    body.has-sidebar main,
    body.has-sidebar footer {
        margin-left: 0;
    }

    /* Mobile drawer is off-canvas (transformed out of view, see below), so
       main shouldn't reserve any width for it -- undo the calc() width
       override above or content would sit 240px narrower than the viewport
       for no reason. */
    body.has-sidebar main {
        width: 100%;
    }

    body.has-sidebar .sidebar-rail {
        width: 260px;
        transform: translateX(-100%);
        transition: transform .2s ease;
    }

    html.sidebar-collapsed body.has-sidebar .sidebar-rail {
        width: 260px;
    }

    body.has-sidebar .app-sidebar.is-open .sidebar-rail {
        transform: translateX(0);
    }

    body.has-sidebar .sidebar-backdrop {
        display: none;
    }

    body.has-sidebar .app-sidebar.is-open .sidebar-backdrop {
        display: block;
    }

    html.sidebar-collapsed body.has-sidebar .sidebar-link-label {
        position: static;
        width: auto;
        height: auto;
        padding: 0;
        margin: 0;
        overflow: visible;
        clip: auto;
        white-space: nowrap;
    }

    html.sidebar-collapsed body.has-sidebar .sidebar-link {
        justify-content: flex-start;
        padding: var(--sp-2) var(--sp-3);
    }

    html.sidebar-collapsed body.has-sidebar .sidebar-user-info {
        display: flex;
    }

    html.sidebar-collapsed body.has-sidebar .sidebar-user-open .sidebar-user-actions {
        display: flex;
    }

    /* The desktop rail-collapse concept (icons-only, ~64px) doesn't exist on
       mobile -- the drawer is always full-width and open/closed via the
       hamburger + backdrop + Escape below, not "collapsed". A collapsed
       state persisted in localStorage from a prior desktop session (or the
       chevron below, were it visible) would otherwise strand the drawer with
       its logo hidden and no corresponding visual change, since the desktop
       collapse rules for the logo aren't scoped away from mobile. Force the
       logo back on and hide the now-meaningless collapse toggle so there's
       no dead control offering a broken state. */
    html.sidebar-collapsed body.has-sidebar .sidebar-logo {
        display: flex;
    }

    body.has-sidebar .sidebar-toggle {
        display: none;
    }

    body.has-sidebar .sidebar-header {
        justify-content: flex-start;
    }
}

/* =========================================================
   Workspace — client conversation surface (Story 2)
   ========================================================= */

/* Thread cards (list page) */
.ws-thread-card {
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 12px;
  display: flex;
  gap: 12px;
  transition: border-color 0.15s, background 0.15s;
}
.ws-thread-card:hover {
  border-color: #d1d5db;
  background: #f9fafb;
}
.ws-thread-card-bar {
  width: 4px;
  border-radius: 2px;
  flex-shrink: 0;
  align-self: stretch;
}
.ws-thread-card-bar.received    { background: #9ca3af; }
.ws-thread-card-bar.in-progress { background: #3b82f6; }
.ws-thread-card-bar.awaiting-you { background: #f59e0b; }
.ws-thread-card-bar.responded   { background: #10b981; }
.ws-thread-card-bar.resolved    { background: #d1d5db; }

/* Message bubbles (thread detail) */
.ws-message {
  margin-bottom: 20px;
}
.ws-message-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.ws-message-time {
  color: #9ca3af;
  font-size: 0.8rem;
}
.ws-message-client .ws-message-body {
  background: #f0f9ff;
  border-radius: 0 8px 8px 8px;
  padding: 12px 16px;
  font-size: 0.95rem;
  line-height: 1.6;
}
.ws-message-team .ws-message-body {
  background: #f9fafb;
  border: 1px solid #f3f4f6;
  border-radius: 8px 0 8px 8px;
  padding: 12px 16px;
  font-size: 0.95rem;
  line-height: 1.6;
}
.ws-message-attachments {
  margin-top: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ws-attachment-link {
  font-size: 0.85rem;
  color: #2563eb;
  text-decoration: none;
  padding: 4px 10px;
  background: #eff6ff;
  border-radius: 4px;
  border: 1px solid #bfdbfe;
  transition: background 0.12s;
}
.ws-attachment-link:hover {
  background: #dbeafe;
}

/* Timeline events (status transitions) */
.ws-timeline-event {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 16px 0;
  color: #6b7280;
  font-size: 0.85rem;
}
.ws-timeline-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #d1d5db;
  flex-shrink: 0;
}
.ws-timeline-label { flex: 1; }
.ws-timeline-time  { color: #9ca3af; white-space: nowrap; }

/* Awaiting-you amber banner */
.ws-awaiting-banner {
  background: #fef3c7;
  border: 1px solid #f59e0b;
  border-radius: 8px;
  padding: 12px 16px;
  margin-bottom: 20px;
  color: #92400e;
  font-weight: 500;
  font-size: 0.95rem;
}

/* Session-expired banner (composer draft preservation) */
.ws-session-banner {
  background: #fef2f2;
  border: 1px solid #fca5a5;
  border-radius: 8px;
  padding: 12px 16px;
  margin-bottom: 14px;
  color: #991b1b;
  font-weight: 500;
  font-size: 0.9rem;
}
.ws-session-banner a { color: #991b1b; text-decoration: underline; font-weight: 600; }

/* "New" chip — team has replied since the client last viewed the thread */
.ws-new-chip {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #92400e;
  background: #fef3c7;
  border: 1px solid #f59e0b;
  border-radius: 10px;
  padding: 1px 8px;
  margin-left: 4px;
  vertical-align: middle;
}

/* =========================================================
   Workspace V2 -- three-panel thread-native shell (WS-A)
   Flag: LOGRO_WORKSPACE_V2. New surface; reuses the .ws-* rules
   above by class name (message bubbles, timeline, attachment
   links) but introduces its own .ws2-* namespace for panel
   chrome so nothing above is touched or overridden. The
   conversation's ticket-shaped status (received/in_progress/
   awaiting_you/responded/resolved) is intentionally not shown
   as a pill or stepper here -- see .ws2-canvas-state-chip below
   for the 3-state indicator that replaced it on the Canvas panel.
   ========================================================= */

/* Registers --ws2-canvas-w as a typed <length> custom property with a sane
   initial value. inherits:true so a value written on the root element (by
   the no-flash inline script, before .ws2-shell exists in the DOM) still
   reaches .ws2-shell once it renders. Chrome 85+, Safari 15.4+, Firefox 128+. */
@property --ws2-canvas-w {
  syntax: '<length>';
  inherits: true;
  initial-value: 260px;
}

.ws2-shell-wrap {
  width: 100%;
}

.ws2-shell {
  display: grid;
  /* Chat defaults much wider than the thread list here too (was 520px) --
     matches fullpage mode's "chat is the star" treatment (see the
     body.ws2-fullpage .ws2-shell rule below) even though this non-fullpage
     grid has no resize handle wired to --ws2-mid-w yet. */
  grid-template-columns: var(--ws2-left-w, 220px) var(--ws2-mid-w, 760px) minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
}

.ws2-panel {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.ws2-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border);
  font-weight: 700;
  font-size: var(--text-sm);
  color: var(--navy);
}

.ws2-panel-body {
  padding: var(--sp-3);
  overflow-y: auto;
  max-height: 70vh;
}

.ws2-empty-note {
  color: var(--text-muted);
  font-size: var(--text-sm);
  padding: var(--sp-4) var(--sp-2);
  text-align: center;
}

/* Utility classes (2026-08-25 design-system audit, POLISH finding #11):
   replace one-off `style="margin-top: 1rem;"` / `style="display:inline;"`
   attributes in _workspace_v2_conversation.html with named classes -- same
   visual result, but themeable/reusable/greppable instead of baked-in
   inline CSS. */
.ws2-mt-card {
  margin-top: var(--sp-4); /* 1rem, matches the spacing scale */
}

.ws2-inline {
  display: inline;
}

/* Modifier for the conversation panel's "nothing selected" empty state --
   by far the largest empty column in the shell (the whole middle panel),
   so it gets true both-axes centering and a bigger note instead of the
   compact top-padded treatment the smaller thread-list/canvas empty states
   use. Scoped to its own class rather than changing the shared
   .ws2-panel-body / .ws2-empty-note rules above, which the other (smaller)
   empty states also rely on. */
.ws2-conversation-empty-body {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 240px;
}

.ws2-conversation-empty-note {
  font-size: 15px;
  padding: 0;
}

/* --- Left panel: thread list --- */

.ws2-thread-items {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.ws2-thread-item {
  display: flex;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
  transition: background .12s;
}

.ws2-thread-item:hover {
  background: var(--bg-alt);
}

.ws2-thread-item-active {
  background: var(--bg-alt);
  box-shadow: inset 2px 0 0 var(--accent);
}

.ws2-thread-item-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ws2-thread-item-title {
  font-weight: 600;
  font-size: var(--text-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ws2-thread-item-cat-icon {
  margin-right: 4px;
}

.ws2-thread-item-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

/* --- WS-E: Q&A/feedback flagged-thread additions --- */

/* Left panel: conversation search box (fixed above the scrolling list). */
.ws2-thread-search {
  position: relative;
  padding: var(--sp-2) var(--sp-3);
}

.ws2-thread-search-icon {
  position: absolute;
  left: calc(var(--sp-3) + 8px);
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  pointer-events: none;
}

.ws2-thread-search-input {
  width: 100%;
  box-sizing: border-box;
  padding: var(--sp-2) var(--sp-2) var(--sp-2) 30px;
  font-size: var(--text-sm);
  color: var(--navy);
  background: var(--bg-alt);
  border: none;
  border-radius: var(--radius-sm);
  outline: none;
}

.ws2-thread-search-input::placeholder {
  color: var(--text-muted);
}

/* Search filter hides non-matching items. .ws2-thread-item sets display:flex,
   which overrides the UA [hidden] rule, so make [hidden] authoritative here. */
.ws2-thread-item[hidden] {
  display: none;
}

.ws2-thread-list-filter {
  padding: 0 0 var(--sp-2);
  margin-bottom: var(--sp-2);
}

.ws2-filter-link {
  font-size: var(--text-sm);
  font-weight: 600;
  color: #5b9bd5;
  text-decoration: none;
}

.ws2-filter-link:hover {
  text-decoration: none;
}

.ws2-flag-badge {
  margin-right: 4px;
}

/* Icon inside the badge (2026-08-25 design-system audit, POLISH finding
   #12): the "Show flagged" filter-link icon previously inline-styled this
   same alignment directly on its <svg> instead of using .ws2-flag-badge
   like the per-row flagged icon does -- unify on the class. */
.ws2-flag-badge svg {
  vertical-align: text-top;
  flex-shrink: 0;
}

.ws2-legacy-qa-chip {
  display: inline-block;
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  background: var(--surface-alt, #eef1f5);
  color: var(--text-muted);
}

/* Sidebar per-row tool-tag chip (LOGRO_WS_TOOL_CHIPS) -- reuses the
   .ws2-tool-badge visual language (muted pill) at a more compact size so it
   reads as a secondary label next to the status pill. */
.ws2-thread-tool-chip {
  display: inline-block;
  flex-shrink: 0;
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  background: var(--surface-alt, #eef1f5);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Sidebar tool-tag filter bar (LOGRO_WS_TOOL_CHIPS) -- row of toggle chips
   beneath the search box, above the thread list. */
.ws2-tool-filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1, 4px);
  padding: 0 var(--sp-2, 8px) var(--sp-2, 8px);
}

.ws2-tool-filter-chip {
  display: inline-block;
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-alt, #eef1f5);
  border: 1px solid transparent;
  color: var(--text-muted);
  cursor: pointer;
  white-space: nowrap;
}

.ws2-tool-filter-chip:hover {
  background: var(--bg-alt);
}

.ws2-tool-filter-chip-active {
  background: var(--navy);
  color: #fff;
}

.ws2-tool-filter-chip-active:hover {
  background: var(--navy);
}

.ws2-pending-approval-section {
  padding: 0 var(--sp-2, 8px) var(--sp-2, 8px);
  margin-bottom: var(--sp-2, 8px);
  border-bottom: 1px solid var(--border, rgba(0, 0, 0, 0.08));
}

.ws2-pending-approval-header {
  font-size: var(--text-xs, 0.75rem);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--warning, #d9a441);
  padding: var(--sp-1, 4px) var(--sp-1, 4px) var(--sp-2, 8px);
}

.ws2-pending-thread-item {
  background: var(--warning-bg, #fff8e6);
  border-radius: var(--radius-sm);
}

.ws2-pending-publish-form { margin: 0; }

.ws2-pending-publish-btn {
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}

.ws2-pending-publish-btn:hover { opacity: 0.9; }

/* Thread-detail publish control (bug fix, 2026-09): the Pending Approval
   section above previously rendered ONLY on the workspace list sidebar --
   the detail page (this panel) had no equivalent, so a platform_admin
   deep-linked here from a notification/reminder could read pending
   content but not publish it. Reuses .ws2-pending-publish-form /
   .ws2-pending-publish-btn for the form/button so the action itself is
   visually and functionally identical to the sidebar's; this banner is
   just the detail-page wrapper around it. */
.ws2-detail-pending-approval-banner {
  display: flex;
  align-items: center;
  gap: var(--sp-3, 12px);
  background: var(--warning-bg, #fff8e6);
  border: 1px solid var(--warning, #d9a441);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
  font-size: var(--text-sm);
}

.ws2-detail-pending-approval-icon {
  flex: none;
  color: var(--warning, #d9a441);
}

.ws2-detail-pending-approval-text {
  flex: 1;
}

.ws2-detail-publish-btn {
  flex: none;
}

.ws2-flagged-banner {
  background: var(--warning-bg, #fff8e6);
  border: 1px solid var(--warning, #d9a441);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
  font-weight: 600;
  font-size: var(--text-sm);
}

.ws2-legacy-qa-banner {
  background: var(--surface-alt, #eef1f5);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.ws2-feedback-tag {
  display: inline-block;
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  padding: 1px 6px;
  margin-left: var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--surface-alt, #eef1f5);
  color: var(--text-muted);
}

/* P2 (ws-usefulness): mirrors .ws2-feedback-tag exactly -- a small,
   non-visual-redesign tag identifying a legacy-QA opening message as the
   original question, since question_messages() now tags it
   kind: "question" instead of the generic "message". */
.ws2-question-tag {
  display: inline-block;
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  padding: 1px 6px;
  margin-left: var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--surface-alt, #eef1f5);
  color: var(--text-muted);
}

/* Client message integrity review (POST .../messages/{seq}/amend): mirrors
   .ws2-feedback-tag/.ws2-question-tag exactly, but on the --warning/
   --warning-bg pair already used for "needs attention"/caution semantics
   elsewhere (.status-needs_attention, .status-awaiting-answer) -- a
   corrected message is exactly that kind of signal. .ws2-corrected-tag
   marks the ORIGINAL (now-superseded) message; .ws2-correction-tag marks
   the NEW kind="correction" message that replaces it. Neither ever renders
   amend_reason or a guard's detail/excerpt -- both are internal-only (see
   client_message_review.py's module docstring). */
.ws2-corrected-tag,
.ws2-correction-tag {
  display: inline-block;
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  padding: 1px 6px;
  margin-left: var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--warning-bg);
  color: var(--warning);
}

/* P2 (ws-usefulness): the question's free-text "context" label
   (question_to_virtual_thread's qa_context), shown under the conversation
   title for a legacy-QA thread. */
.ws2-qa-context-subtitle {
  margin: 2px 0 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* --- Middle panel: conversation --- */

.ws2-conversation-panel {
  /* Header + scrollable body + reply bar stack vertically inside the panel. */
  max-height: calc(70vh + 96px);
}

.ws2-conversation-title {
  /* Renders as an h1 for document heading structure (a11y hardening) --
     reset all UA heading defaults so it stays visually identical to the
     prior span. */
  margin: 0;
  font: inherit;
  font-weight: inherit;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ws2-conversation-body {
  flex: 1;
}

.ws2-inline-error {
  background: var(--error-bg);
  border: 1px solid var(--error);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
  color: var(--error);
  font-size: var(--text-sm);
}

.ws2-reply-bar {
  border-top: 1px solid var(--border);
  padding: var(--sp-3);
}

.ws2-reply-bar form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.ws2-reply-textarea {
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-family: inherit;
  resize: vertical;
}

.ws2-reply-submit {
  align-self: flex-end;
}

/* Busy state while a reply is in flight -- dims the button and swaps the
   cursor without touching the SVG send icon or its aria-label markup, so
   the icon never gets clobbered and a stuck-disabled button never loses
   its visual affordance (see ws2-reply-form onsubmit). */
.ws2-reply-submit-busy,
.ws2-reply-submit:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Decision #7 (LOGRO_WS_ENTER_SEND): persistent drag-and-drop zone rendered
   below the submit/attach buttons in the reply composer. Reuses the shared
   .ws-drop-zone dashed-box look; this modifier just trims the padding/font
   so it reads as a compact affordance rather than the larger new-thread
   compose dropzone it's visually based on. */
.ws2-reply-drop-zone {
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--text-sm);
}

/* --- Right panel: canvas --- */

.ws2-canvas-slot {
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  margin-bottom: var(--sp-4);
}

.ws2-canvas-slot:last-child {
  margin-bottom: 0;
}

.ws2-canvas-slot-label {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: var(--sp-2);
}

.ws2-canvas-placeholder {
  color: var(--text-muted);
  font-size: var(--text-sm);
  margin: 0;
}

/* Thread-owns-the-canvas: a slot with nothing relevant to show (e.g. the
   downloads slot before any job has produced an output) renders with no
   label and no placeholder text at all -- see
   _workspace_v2_canvas_downloads.html. Hidden, not removed: the element
   keeps its id and (when applicable) its polling hx-* attributes, so htmx
   can still swap it back in once there's something to show. */
.ws2-canvas-slot-empty {
  display: none;
}

/* Inline one-click tool picker rendered by the "Next step" card's
   confirm_tool state (_workspace_v2_canvas_job_status.html) -- one submit
   button per workspace_utils.TOOL_TAGS entry, posting straight to
   POST /{thread_id}/canvas/tool-tag via htmx. Buttons wrap onto multiple
   lines in the narrow canvas sidebar rather than overflowing. */
.ws2-canvas-tool-picker {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}

/* Role-assignment / job-picker forms rendered in the empty-state canvas
   slot (geo census/provider-roster picks, multi-file disruption
   claims/proposed/current-network picks, proposal source-job picks). These
   reuse .field select's existing chevron/padding/focus-ring styling (see
   the "Unified form controls" block above) but need a much tighter
   margin-bottom than that block's full-page-form default so several stacked
   fields fit the compact canvas sidebar without excess whitespace. */
.ws2-canvas-role-form .field {
  margin-bottom: var(--sp-3);
}

.ws2-canvas-role-form .field label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: var(--sp-1);
}

/* "Already ran this outside a conversation?" link-job form. Deliberately
   its own class (not .ws2-canvas-slot-label) -- that shared class forces
   uppercase, which read as a shouty section header on this plain question.
   The input+button row: both controls share one height so they read as a
   single aligned control, matching the 38px min-height the fullpage-glass
   override already sets on the input (see workspace_glass.css) -- picked
   up here as the row's shared height so the button matches without a
   fullpage-only special case. */
.ws2-canvas-link-job-label {
  display: block;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin-bottom: var(--sp-2);
}

.ws2-canvas-link-job-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.ws2-canvas-link-job-row input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  height: 38px;
  box-sizing: border-box;
}

.ws2-canvas-link-job-row button {
  /* .btn-sm sets min-height:40px, which -- combined with height -- would
     win over this 38px per the CSS height/min-height precedence rule and
     leave the button 2px taller than the input. Override min-height too so
     they actually match. */
  height: 38px;
  min-height: 38px;
  box-sizing: border-box;
  flex-shrink: 0;
}

.ws2-canvas-job-status,
.ws2-canvas-downloads-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.ws2-canvas-job-name {
  font-weight: 600;
  font-size: var(--text-sm);
}

.ws2-canvas-job-state {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.ws2-canvas-job-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.ws2-canvas-job-spinner {
  display: inline-block;
  margin-right: var(--sp-1);
  vertical-align: middle;
}

.ws2-canvas-job-message {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin: 0;
}

.ws2-canvas-job-meta {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin: 0;
}

.ws2-canvas-download-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.ws2-canvas-download-meta {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin: 0;
}

/* --- Repricing canvas cards: results summary, Q&A banner, feedback --- */

.ws2-canvas-repricing-summary-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}

.ws2-canvas-repricing-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--bg-alt);
}

.ws2-canvas-repricing-stat-highlight {
  border: 1px solid var(--border);
}

.ws2-canvas-repricing-stat-highlight.is-unverified {
  border-color: var(--savings-yellow);
}

.ws2-canvas-repricing-stat-label {
  font-size: 0.7rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .03em;
}

.ws2-canvas-repricing-stat-value {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--text);
}

.ws2-canvas-repricing-unverified-caption {
  font-size: 0.7rem;
  color: var(--savings-yellow);
}

.ws2-canvas-repricing-savings-green { color: var(--savings-green); }
.ws2-canvas-repricing-savings-yellow { color: var(--savings-yellow); }
.ws2-canvas-repricing-savings-red { color: var(--savings-red); }

.ws2-canvas-repricing-summary-download {
  margin-bottom: var(--sp-3);
}

.ws2-canvas-repricing-detail-row {
  border-top: 1px solid var(--border);
  padding-top: var(--sp-2);
  margin-top: var(--sp-2);
}

.ws2-canvas-repricing-detail-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
  list-style: none;
}

.ws2-canvas-repricing-detail-summary::-webkit-details-marker {
  display: none;
}

.ws2-canvas-repricing-count-chip {
  font-size: 0.7rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--bg-alt);
  color: var(--text-secondary);
}

.ws2-canvas-repricing-count-chip.is-error {
  background: var(--savings-red);
  color: #fff;
}

.ws2-canvas-repricing-count-chip.is-success {
  background: var(--savings-green);
  color: #fff;
}

.ws2-canvas-repricing-anomaly-list,
.ws2-canvas-repricing-integrity-list {
  list-style: none;
  margin: var(--sp-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.ws2-canvas-repricing-anomaly-item,
.ws2-canvas-repricing-integrity-item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.ws2-canvas-repricing-anomaly-dot,
.ws2-canvas-repricing-integrity-icon {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 5px;
  background: var(--text-muted);
}

.ws2-canvas-repricing-anomaly-dot-critical,
.ws2-canvas-repricing-anomaly-dot-error {
  background: var(--savings-red);
}

.ws2-canvas-repricing-anomaly-dot-warning {
  background: var(--savings-yellow);
}

.ws2-canvas-repricing-anomaly-dot-info {
  background: var(--text-muted);
}

.ws2-canvas-repricing-integrity-item.passed .ws2-canvas-repricing-integrity-icon {
  background: var(--savings-green);
}

.ws2-canvas-repricing-integrity-item.failed .ws2-canvas-repricing-integrity-icon {
  background: var(--savings-red);
}

.ws2-canvas-repricing-integrity-failure {
  display: block;
  font-size: 0.75rem;
  color: var(--savings-red);
  margin-top: 2px;
}

.ws2-canvas-repricing-integrity-issues {
  margin-top: var(--sp-2);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.ws2-canvas-repricing-integrity-issues ul {
  margin: var(--sp-1) 0 0;
  padding-left: var(--sp-3);
}

/* Q&A banner */

.ws2-canvas-repricing-qa-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}

.ws2-canvas-repricing-qa-blocked {
  background: color-mix(in srgb, var(--savings-yellow) 12%, transparent);
  border: 1px solid var(--savings-yellow);
}

.ws2-canvas-repricing-qa-review {
  background: color-mix(in srgb, var(--savings-green) 10%, transparent);
  border: 1px solid var(--savings-green);
}

.ws2-canvas-repricing-qa-icon {
  flex: 0 0 auto;
}

.ws2-canvas-repricing-qa-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.ws2-canvas-repricing-qa-text {
  margin: 0;
  color: var(--text);
}

.ws2-canvas-repricing-qa-links a {
  color: var(--text);
  font-weight: 600;
}

/* Feedback card */

.ws2-canvas-repricing-fb-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}

.ws2-canvas-repricing-fb-form textarea {
  width: 100%;
  resize: vertical;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-2);
  font: inherit;
  color: var(--text);
  background: var(--bg-alt);
}

.ws2-canvas-repricing-fb-file-label {
  font-size: 0.75rem;
  color: var(--text-muted);
}

.ws2-canvas-repricing-fb-history-label {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: var(--sp-2);
}

.ws2-canvas-repricing-fb-history {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.ws2-canvas-repricing-fb-item {
  border-top: 1px solid var(--border);
  padding-top: var(--sp-2);
}

.ws2-canvas-repricing-fb-meta {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  margin: 0 0 var(--sp-1);
  font-size: 0.75rem;
}

.ws2-canvas-repricing-fb-status {
  font-weight: 700;
  text-transform: capitalize;
  color: var(--text-secondary);
}

.ws2-canvas-repricing-fb-status-resolved,
.ws2-canvas-repricing-fb-status-addressed {
  color: var(--savings-green);
}

.ws2-canvas-repricing-fb-status-reopened {
  color: var(--savings-yellow);
}

.ws2-canvas-repricing-fb-auto-badge {
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--bg-alt);
  color: var(--text-muted);
}

.ws2-canvas-repricing-fb-meta-sep {
  color: var(--text-muted);
}

.ws2-canvas-repricing-fb-meta-date {
  color: var(--text-muted);
}

.ws2-canvas-repricing-fb-text {
  margin: 0 0 var(--sp-1);
  font-size: var(--text-sm);
  color: var(--text);
}

.ws2-canvas-repricing-fb-attachments {
  margin: 0 0 var(--sp-1);
  font-size: 0.75rem;
  color: var(--text-muted);
}

.ws2-canvas-repricing-fb-resolution {
  margin: var(--sp-1) 0 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.ws2-canvas-repricing-fb-resolution-card {
  margin-top: var(--sp-2);
  padding: var(--sp-2);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--savings-green) 8%, transparent);
  border: 1px solid var(--savings-green);
}

.ws2-canvas-repricing-fb-resolution-header {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  font-weight: 700;
  font-size: 0.75rem;
  color: var(--savings-green);
  margin-bottom: var(--sp-1);
}

.ws2-canvas-repricing-fb-resolution-date {
  margin-left: auto;
  font-weight: 400;
  color: var(--text-muted);
}

.ws2-canvas-repricing-fb-resolution-text {
  margin: 0 0 var(--sp-2);
  font-size: var(--text-sm);
  color: var(--text);
}

.ws2-canvas-repricing-fb-thread {
  margin-top: var(--sp-2);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.ws2-canvas-repricing-fb-thread-message {
  padding: var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--bg-alt);
}

.ws2-canvas-repricing-fb-thread-msg-header {
  display: flex;
  justify-content: space-between;
  font-size: 0.7rem;
  color: var(--text-muted);
  margin-bottom: 2px;
}

.ws2-canvas-repricing-fb-thread-author {
  font-weight: 700;
  color: var(--text-secondary);
}

.ws2-canvas-repricing-fb-thread-text {
  font-size: var(--text-sm);
  color: var(--text);
}

.ws2-canvas-repricing-fb-thread-attachments {
  margin-top: var(--sp-1);
  font-size: 0.75rem;
  color: var(--text-muted);
}

.ws2-canvas-repricing-fb-reply-section {
  margin-top: var(--sp-2);
}

.ws2-canvas-repricing-fb-reply-prompt {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin: 0 0 var(--sp-1);
}

.ws2-canvas-repricing-fb-reply-form textarea {
  width: 100%;
  resize: vertical;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-2);
  font: inherit;
  color: var(--text);
  background: var(--bg-alt);
}

.ws2-canvas-repricing-fb-reply-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-1);
}

.ws2-canvas-repricing-fb-file-input-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
}

.ws2-canvas-repricing-fb-file-upload-label {
  position: relative;
  cursor: pointer;
}

.ws2-canvas-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  background: transparent;
  border: none;
  cursor: pointer;
  transition: color .15s, background .15s, transform .18s;
}

.ws2-canvas-toggle:hover {
  color: var(--text);
  background: var(--bg-alt);
}

/* In fullpage dark mode the toggle needs dark-adapted colors */
body.ws2-fullpage .ws2-canvas-toggle {
  color: rgba(240,240,245,0.4);
}
body.ws2-fullpage .ws2-canvas-toggle:hover {
  background: rgba(255,255,255,0.06);
  color: rgba(240,240,245,0.8);
}

/* Resize handles: hidden in non-fullpage card layout; shown in fullpage mode. */
.ws2-resize-handle {
  display: none;
}

/* Collapsed canvas: shrink the right column to a slim rail with just the
   toggle button, hide its body and title text. Mirrors the sidebar-nav
   collapse pattern (html.sidebar-collapsed) but scoped to this shell only. */
body.ws2-canvas-collapsed .ws2-shell {
  grid-template-columns: 220px minmax(0, 1fr) 44px;
}

body.ws2-canvas-collapsed .ws2-canvas-panel .ws2-panel-body,
body.ws2-canvas-collapsed .ws2-canvas-panel-title-text {
  display: none;
}

body.ws2-canvas-collapsed .ws2-canvas-toggle svg {
  transform: rotate(180deg);
}

body.ws2-canvas-collapsed .ws2-canvas-panel .ws2-panel-header {
  justify-content: center;
}

/* Responsive: stack panels on narrow screens instead of squeezing 3 columns.
   Canvas panel becomes a collapsed-by-default section the client can expand;
   thread list gets a fixed short height so the conversation stays reachable
   without excessive scrolling.
   NOTE (2026-08-25 design-system audit): this breakpoint is intentionally
   900px, not the platform's usual 640px -- a 3-column shell needs to
   collapse to single-column earlier than a single-column page does. Do not
   "fix" this to match 640px. */
@media (max-width: 900px) {
  .ws2-shell,
  body.ws2-canvas-collapsed .ws2-shell {
    grid-template-columns: 1fr;
  }

  .ws2-thread-list-panel .ws2-panel-body {
    max-height: 220px;
  }

  .ws2-conversation-panel {
    max-height: none;
  }

  .ws2-conversation-body {
    max-height: 50vh;
  }

  .ws2-canvas-panel .ws2-panel-body {
    max-height: 50vh;
  }

  body.ws2-canvas-collapsed .ws2-canvas-panel .ws2-panel-body,
  body.ws2-canvas-collapsed .ws2-canvas-panel-title-text {
    display: none;
  }
}

/* =========================================================
   WS2 FULLPAGE MODE
   body.ws2-fullpage: workspace takes over the entire viewport.
   Hides global sidebar + topbar; resets main's margin/width.
   Three seamless columns with Apple system-UI aesthetic.
   All rules are scoped under body.ws2-fullpage so they cannot
   bleed into any other page.
   ========================================================= */

/* --- Custom properties scoped to the ws2 fullpage shell --- */
body.ws2-fullpage {
  /* Apple dark-mode hierarchy: sidebars recede, content panel pops forward */
  --ws2-bg-sidebar:   #1e1e2c;
  --ws2-bg-content:   #2b2b3d;
  --ws2-bg-canvas:    #232332;
  --ws2-bg-glass:     rgba(30,30,44,0.98);
  --ws2-bg-glass-w:   rgba(43,43,61,0.98);
  --ws2-border:       rgba(255,255,255,0.18);
  --ws2-text-primary:   #ececf1;
  --ws2-text-secondary: rgba(236,236,241,0.65);
  --ws2-text-tertiary:  rgba(236,236,241,0.4);
  /* Indigo accent - Logro brand */
  --ws2-accent:       #6366f1;
  --ws2-accent-warm:  #818cf8;
  --ws2-hover:        rgba(99,102,241,0.14);
  --ws2-active:       rgba(99,102,241,0.22);

  background: #1a1a28;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* 1. Suppress global chrome */
body.ws2-fullpage .app-sidebar,
body.ws2-fullpage .sidebar-rail,
body.ws2-fullpage .sidebar-backdrop,
body.ws2-fullpage .topbar-slim {
  display: none !important;
}
body.ws2-fullpage > header,
body.ws2-fullpage > footer {
  display: none !important;
}
/* The global stale-notifications banner is a body child (base.html) meant
   to float above the normal page chrome -- it bleeds into the fullpage
   shell (z-index 200) and gets covered by it, so it must be suppressed
   here alongside the rest of the global chrome. */
body.ws2-fullpage .notif-stale-banner {
  display: none !important;
}
body.ws2-fullpage {
  overflow: hidden; /* prevent body scroll — only ws2 panels scroll internally */
}
body.ws2-fullpage main {
  margin-left: 0 !important;
  width: 100% !important;
  max-width: none !important;
  padding: 0 !important;
}

/* 2. Shell: fixed full-viewport grid, zero gap; resize handles occupy 4px columns */
body.ws2-fullpage .ws2-shell {
  position: fixed;
  inset: 0;
  height: 100vh;
  /* Chat is the star: it gets flexible 1fr space (bounded by a 360px floor
     via minmax so it can never be crushed). Thread list is fixed via
     --ws2-left-w, canvas is fixed via --ws2-canvas-w. Left handle resizes
     the thread list; right handle resizes the canvas (drag left grows it,
     drag right shrinks it back toward chat). */
  grid-template-columns: var(--ws2-left-w, 320px) 4px minmax(360px, 1fr) 4px var(--ws2-canvas-w, 420px);
  gap: 0;
  align-items: stretch;
  /* No font-family override here -- this used to hardcode a system-font
     stack, which silently dropped the brand font ("Plus Jakarta Sans", set
     on body) the instant fullpage mode kicked in. Inherit from body instead;
     letter-spacing stays as a deliberate fullpage-only tightening. */
  letter-spacing: -0.01em;
  z-index: 200;
  /* No transition here: --ws2-canvas-w now drives a live grid track during
     pointer drag, and animating it would make every drag frame lag behind
     the cursor. The toggle collapse/expand still reads as instant, which
     matches the left handle's (already transition-less) behavior. */
}


/* 2a. Session-expiry banner must float above the fixed full-viewport shell
   (z-index 200) or it renders behind it and the user never sees the
   "your draft was saved" message when their session times out mid-compose. */
body.ws2-fullpage .ws-session-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 300;
  border-radius: 0;
  margin-bottom: 0;
}
/* Collapsed: the canvas rail pins to the far right edge and the CHAT absorbs
   all the reclaimed space. The 360px floor matches the expanded grid's chat
   track (and MIN_MID in the drag script) so the column has one consistent
   minimum in both states. */
body.ws2-fullpage.ws2-canvas-collapsed .ws2-shell {
  grid-template-columns: var(--ws2-left-w, 320px) 4px minmax(360px, 1fr) 48px;
}
body.ws2-fullpage.ws2-canvas-collapsed .ws2-resize-right {
  display: none;
}

/* 2b. Resize handles: visible in fullpage mode as 4px drag zones. The grid
   track itself stays 4px (keeps column math simple) but position:relative
   plus a ::before that overhangs a few px on each side widens the actual
   grabbable/hoverable area — a bare 4px target is hard to hit with a mouse.
   The highlight background stays on the handle itself so it still reads as
   a thin 4px line rather than the wider invisible hit zone. */
body.ws2-fullpage .ws2-resize-handle {
  display: block;
  position: relative;
  height: 100%;
  cursor: col-resize;
  background: transparent;
  transition: background 0.15s;
  z-index: 10;
  user-select: none;
}
body.ws2-fullpage .ws2-resize-handle::before {
  content: '';
  position: absolute;
  inset: 0 -3px;
  cursor: col-resize;
}
body.ws2-fullpage .ws2-resize-handle:hover,
body.ws2-fullpage .ws2-resize-handle.dragging {
  background: rgba(99,102,241,0.5);
}

/* Applied to <body> for the duration of a fullpage drag so text selection
   doesn't fire mid-drag and the cursor stays col-resize even when the
   pointer strays off the (now widened) handle hit area. */
body.ws2-resizing {
  user-select: none;
  cursor: col-resize;
}

/* 3. Remove card chrome; make each panel a flex column that fills height */
body.ws2-fullpage .ws2-panel {
  border: none;
  border-radius: 0;
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: none;
}

/* 4. Column dividers + panel background colors */
body.ws2-fullpage .ws2-thread-list-panel {
  background: var(--ws2-bg-sidebar);
  border-right: 1px solid var(--ws2-border);
  box-shadow: 2px 0 16px rgba(0,0,0,0.4);
}
body.ws2-fullpage .ws2-canvas-panel {
  border-left: 1px solid var(--ws2-border);
  background: var(--ws2-bg-canvas);
  box-shadow: -2px 0 16px rgba(0,0,0,0.4);
}
body.ws2-fullpage .ws2-conversation-panel {
  background: var(--ws2-bg-content);
  /* Reset the base .ws2-conversation-panel max-height clamp (calc(70vh +
     96px)) -- in fullpage mode the panel is already a flex column with
     .ws2-conversation-body flex:1 and .ws2-reply-bar flex-shrink:0, so it
     should fill the full column height instead of stopping short and
     leaving dead space with the composer hidden below the fold. */
  max-height: none;
}

/* 5. Panel header: frosted glass, minimal, Apple-style */
body.ws2-fullpage .ws2-panel-header {
  flex-shrink: 0;
  padding: 0 16px;
  height: 52px;
  border-bottom: 1px solid var(--ws2-border);
  border-radius: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ws2-text-primary);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
body.ws2-fullpage .ws2-thread-list-panel .ws2-panel-header,
body.ws2-fullpage .ws2-canvas-panel .ws2-panel-header {
  background: var(--ws2-bg-glass);  /* sidebar/canvas glass = darker */
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
}
body.ws2-fullpage .ws2-conversation-panel .ws2-panel-header {
  background: var(--ws2-bg-glass-w);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
}

/* Left panel brand + tenant (workspace) switcher, top-left.
   The switcher trigger renders identically for single- and multi-tenant
   users: today it opens a menu that confirms the current workspace; when
   cross-tenant membership ships the same markup handles real switching. */
body.ws2-fullpage .ws2-brand-header {
  justify-content: space-between;
}

/* Wrapper element that positions the floating menu. */
body.ws2-fullpage .ws2-tenant {
  position: relative;
  min-width: 0;
}

/* Single-tenant static brand (no interaction). */
body.ws2-fullpage .ws2-tenant-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

/* Trigger button: looks like a plain brand label until hovered/active. */
body.ws2-fullpage .ws2-tenant-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 4px 6px;
  margin: -4px -6px;
  background: none;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  color: var(--ws2-text-primary);
  font-family: inherit;
  transition: background 0.12s;
}
body.ws2-fullpage .ws2-tenant-trigger:hover {
  background: var(--ws2-hover);
}
body.ws2-fullpage .ws2-tenant-trigger:focus-visible {
  outline: 2px solid var(--ws2-accent);
  outline-offset: 1px;
}

body.ws2-fullpage .ws2-brand-mark {
  display: flex;
  flex-shrink: 0;
  line-height: 0;
  border-radius: 7px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.28);
}
body.ws2-fullpage .ws2-brand-name {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ws2-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Chevron: always visible (affordance), dims at rest. */
body.ws2-fullpage .ws2-tenant-chevron {
  flex-shrink: 0;
  color: var(--ws2-text-tertiary);
  transition: transform 0.15s, color 0.12s;
}
body.ws2-fullpage .ws2-tenant-trigger[aria-expanded="true"] .ws2-tenant-chevron {
  transform: rotate(180deg);
  color: var(--ws2-text-secondary);
}

/* Dropdown menu */
body.ws2-fullpage .ws2-tenant-menu {
  position: absolute;
  top: calc(100% + 10px);
  left: -6px;
  z-index: 120;
  min-width: 200px;
  background: rgba(40, 40, 48, 0.92);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid var(--ws2-border);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.36), var(--ws2-specular);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
body.ws2-fullpage .ws2-tenant-menu-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ws2-text-tertiary);
  padding: 4px 8px 6px;
}
body.ws2-fullpage .ws2-tenant-option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  border: none;
  background: none;
  color: var(--ws2-text-primary);
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
  transition: background 0.1s;
}
body.ws2-fullpage .ws2-tenant-option:hover {
  background: var(--ws2-hover);
}
body.ws2-fullpage .ws2-tenant-option.is-current {
  background: var(--ws2-active);
}
body.ws2-fullpage .ws2-tenant-option:focus-visible {
  outline: 2px solid var(--ws2-accent);
  outline-offset: -2px;
}
body.ws2-fullpage .ws2-tenant-option-mark {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  background: #1a3a5c;
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 800;
  color: var(--ws2-accent);
  line-height: 1;
}
body.ws2-fullpage .ws2-tenant-option-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.ws2-fullpage .ws2-tenant-check {
  flex-shrink: 0;
  color: var(--ws2-accent);
}

body.ws2-fullpage .ws2-brand-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* Header left side: title stacked over the (optional) Q&A context subtitle. */
.ws2-header-titlewrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

/* Header right side: tool badge / poll-trouble indicator / status pill,
   kept from being squeezed by the title's ellipsis overflow. */
.ws2-header-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* Conversation panel header: bigger title -- stronger hierarchy against the
   15px/400 message body so the two are no longer easy to confuse. */
body.ws2-fullpage .ws2-conversation-panel .ws2-panel-header .ws2-conversation-title {
  font-size: 16px;
  font-weight: 650;
  color: var(--ws2-text-primary);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Quiet subtitle under the title in the dark glass shell -- left-aligned,
   not the centered flex-sibling layout the base rule above uses. */
body.ws2-fullpage .ws2-qa-context-subtitle {
  font-size: 12px;
  color: var(--ws2-text-secondary);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 6. Panel body: fills remaining height, scrolls internally */
body.ws2-fullpage .ws2-panel-body {
  flex: 1;
  max-height: none;
  overflow-y: auto;
  padding: 16px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.15) transparent;
}

/* Thin webkit scrollbars -- light on dark */
body.ws2-fullpage ::-webkit-scrollbar { width: 5px; height: 5px; }
body.ws2-fullpage ::-webkit-scrollbar-track { background: transparent; }
body.ws2-fullpage ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.15); border-radius: 999px; }
body.ws2-fullpage ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.25); }

/* 7. Conversation body: fills between header and composer */
body.ws2-fullpage .ws2-conversation-body {
  flex: 1;
  max-height: none;
  overflow-y: auto;
  padding: 24px 28px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ws2-text-primary);
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.15) transparent;
}

/* Round 2 fix: a short thread otherwise renders its messages pinned to the
   TOP of .ws2-conversation-body, leaving a large dead gap above the
   composer -- standard chat behavior anchors the transcript to the BOTTOM
   so the newest message sits just above the input. `.ws-timeline` becomes
   the flex container that packs its message/event children against its own
   bottom edge; `min-height: 100%` (of the scrollable `.ws2-conversation-body`
   ancestor above, which has a definite height via flex:1) gives
   justify-content:flex-end room to operate when there are only a few
   messages -- without it, `.ws-timeline`'s box would just be exactly as
   tall as its content and there'd be no free space left to pack against.
   Overflow/scrolling itself stays on the non-flex `.ws2-conversation-body`
   ancestor (not on `.ws-timeline` itself), which is the safe pattern for
   this trick -- putting overflow and justify-content:flex-end on the SAME
   flex container is the version with a known top-content-clipping bug in
   some engines when content overflows. A long thread's `.ws-timeline` just
   grows past 100% naturally (min-height is a floor, not a cap) and scrolls
   normally, oldest message at the top. */
body.ws2-fullpage .ws-timeline {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 100%;
}

/* 8. Message bubbles: Claude.ai-style chat */
body.ws2-fullpage .ws-message {
  margin-bottom: 20px;
}
body.ws2-fullpage .ws-message-header {
  display: flex;
  align-items: baseline;
  /* flex-start so author + kind-tag group left; time gets margin-left:auto
     to anchor to the right. Overrides base `justify-content: space-between`
     which scattered middle children (e.g. the Question tag) to mid-row. */
  justify-content: flex-start;
  gap: 8px;
  margin-bottom: 4px;
  font-size: 11px;
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws-message-header strong {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws-message-time {
  font-size: 11px;
  color: var(--ws2-text-tertiary);
  /* Anchor time to the right regardless of how many items precede it
     (author name alone, or author + Question/kind tag). */
  margin-left: auto;
}
/* Client/user messages: right-leaning with subtle bg
   background + border-radius removed (2026-08-25 design-system audit,
   finding #5): both were fully shadowed by workspace_glass.css:127-134
   (identical selector, later load order, same specificity) and dead code.
   `border` is ALSO shadowed there but is deliberately left in place
   (out of scope for this fix) as a fallback if workspace_glass.css is ever
   rolled back per that file's own header comment -- padding/max-width/
   float/clear/font-size/color below are genuinely load-bearing (not
   redeclared in workspace_glass.css at all). */
body.ws2-fullpage .ws-message-client .ws-message-body,
body.ws2-fullpage .ws-message-user .ws-message-body {
  border: 1px solid rgba(255,255,255,0.08);
  padding: 10px 14px;
  display: inline-block;
  /* 85% of the column, but never past a readable measure -- with the canvas
     collapsed the chat column is ~1500px wide and a bare 85% ran single lines
     past 1200px. */
  max-width: min(85%, 78ch);
  float: right;
  clear: both;
  font-size: 15px;
  color: var(--ws2-text-primary);
  /* A long unbroken token (URL, long filename, no-spaces word) has no break
     opportunity by default, so it overflows the bubble's max-width and can
     blow out the whole message column. overflow-wrap is the standard
     property; word-break is kept alongside it (matching the fallback
     pairing already used for the same problem elsewhere, e.g.
     .secure-link-secret / .secure-field-value above) for older engines. */
  overflow-wrap: break-word;
  word-break: break-word;
}
/* Client/user header: right-align to match the right-floating bubble.
   `row-reverse` + `flex-end` was previously used but placed items at the
   visual left (flex-end in a reversed row = pack at the reversed start =
   visual left). Plain `justify-content: flex-end` in the default row
   direction achieves the correct visual-right alignment. */
body.ws2-fullpage .ws-message-client .ws-message-header,
body.ws2-fullpage .ws-message-user .ws-message-header {
  justify-content: flex-end;
}
/* Round 2 fix: `.ws-message-time` unconditionally sets margin-left:auto
   (below) so the timestamp right-anchors for TEAM/ADMIN headers -- correct
   there, since those headers are left-aligned and need the trailing
   auto-margin to push time to the right edge. But that same auto margin
   also fires here and eats ALL the row's free space, which defeats this
   rule's justify-content:flex-end (an auto margin always wins over
   justify-content) -- the two fought and the author name ended up pinned
   far left while the bubble floats right. Zeroing it here lets
   justify-content:flex-end actually pack author + time together, right
   above the bubble they belong to. */
body.ws2-fullpage .ws-message-client .ws-message-time,
body.ws2-fullpage .ws-message-user .ws-message-time {
  margin-left: 0;
}
/* Team/admin messages: left-aligned.
   background + border-radius removed (2026-08-25 design-system audit,
   finding #5): both were fully shadowed by workspace_glass.css:117-125
   (identical selector, later load order, same specificity) and dead code
   -- background here still carried the pre-rebrand indigo tint. `border`
   is ALSO shadowed there but is deliberately left in place (out of scope
   for this fix) as a fallback if workspace_glass.css is ever rolled back
   per that file's own header comment -- padding/max-width/float/clear/
   font-size/color below are genuinely load-bearing (not redeclared in
   workspace_glass.css at all). */
body.ws2-fullpage .ws-message-team .ws-message-body,
body.ws2-fullpage .ws-message-admin .ws-message-body {
  border: 1px solid rgba(99,102,241,0.18);
  padding: 10px 14px;
  display: inline-block;
  max-width: min(85%, 78ch);
  float: left;
  clear: both;
  font-size: 15px;
  color: var(--ws2-text-primary);
  /* Same wrap fix as the client/user bubble above -- see that rule's comment. */
  overflow-wrap: break-word;
  word-break: break-word;
}
/* Attachment row: the message body above it floats (right for client/user,
   left for team/admin, see the two rules above). Without `clear: both` the
   attachments div top-aligns beside/behind the floated bubble instead of
   dropping below it, letting the translucent bubble paint over the
   attachment cards. Clearing plus matching justify-content keeps the row
   below the bubble and aligned to the same side it floats to. */
body.ws2-fullpage .ws-message-attachments {
  clear: both;
}
body.ws2-fullpage .ws-message-client .ws-message-attachments,
body.ws2-fullpage .ws-message-user .ws-message-attachments {
  justify-content: flex-end;
}
body.ws2-fullpage .ws-message-team .ws-message-attachments,
body.ws2-fullpage .ws-message-admin .ws-message-attachments {
  justify-content: flex-start;
}
/* Attachment cards: base theme's light blue chip is illegible on the dark
   fullpage canvas. Match the message-bubble dark-theme tokens, and cap
   width so a long filename doesn't force a full-bleed slab -- overflow
   ellipsizes (trailing size suffix goes first) rather than wrapping the
   size onto its own line. */
body.ws2-fullpage .ws-attachment-link {
  display: inline-block;
  max-width: 320px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--ws2-text-primary);
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.14);
}
body.ws2-fullpage .ws-attachment-link:hover {
  background: rgba(255,255,255,0.1);
}
body.ws2-fullpage .ws-message::after {
  content: '';
  display: table;
  clear: both;
}
/* Rendered markdown content inside chat bubbles (global reset zeros ol/ul padding). */
body.ws2-fullpage .ws-message-body p {
  margin: 0 0 8px 0;
}
body.ws2-fullpage .ws-message-body p:last-child {
  margin-bottom: 0;
}
body.ws2-fullpage .ws-message-body ol,
body.ws2-fullpage .ws-message-body ul {
  padding-left: 22px;
  margin: 0 0 8px 0;
}
body.ws2-fullpage .ws-message-body li {
  margin-bottom: 4px;
}
body.ws2-fullpage .ws-message-body li:last-child {
  margin-bottom: 0;
}
body.ws2-fullpage .ws-message-body strong { font-weight: 600; }
body.ws2-fullpage .ws-message-body em { font-style: italic; }
body.ws2-fullpage .ws-message-body code {
  font-family: ui-monospace, monospace;
  font-size: 0.88em;
  background: rgba(255,255,255,0.08);
  padding: 0.1em 0.35em;
  border-radius: 3px;
}
body.ws2-fullpage .ws-message-body a {
  color: var(--ws2-accent, #5b9bd5);
  text-decoration: underline;
}
body.ws2-fullpage .ws-message-body blockquote {
  border-left: 3px solid rgba(255,255,255,0.15);
  padding-left: 10px;
  margin: 0 0 8px 0;
  color: var(--ws2-text-secondary);
}
/* Markdown tables inside chat bubbles. Borders/cell padding/header weight
   already come from the existing generic `table`/`thead th`/`tbody td`
   rules above (light theme) plus `body.ws2-fullpage table` in
   workspace_glass.css (dark-theme override) -- no need to duplicate those
   here. The one gap: the bubble itself is `display: inline-block; max-width:
   min(85%, 78ch)` (see .ws-message-client/.ws-message-team .ws-message-body
   above), and a table with several columns can need more width than that to
   render without cramming, which would blow out the bubble/column. `display:
   block` on the table (its table-row-group/row/cell children keep their own
   table-* display values via the CSS anonymous-table-box fixup, so the grid
   still renders correctly) turns the table into a normal block box that
   respects max-width and can scroll its own overflow horizontally, instead
   of forcing the whole bubble wider than the chat column. `white-space:
   nowrap` on the cells is required alongside `overflow-x: auto`, not
   optional -- table auto-layout treats a wrapped word as an acceptable
   minimum column width, so without it the browser crams every column down
   to single-character width (verified visually: at a narrow viewport the
   table wrapped every cell letter-by-letter instead of scrolling). nowrap
   forces cells to keep their natural width, which is what actually makes
   the container overflow and the scrollbar appear. */
body.ws2-fullpage .ws-message-body table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  margin: 0 0 8px 0;
}
body.ws2-fullpage .ws-message-body table th,
body.ws2-fullpage .ws-message-body table td {
  white-space: nowrap;
}
/* Timeline events */
body.ws2-fullpage .ws-timeline-event {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0;
  font-size: 12px;
  color: var(--ws2-text-tertiary);
  justify-content: center;
}
body.ws2-fullpage .ws-timeline-label { color: var(--ws2-text-secondary); }
body.ws2-fullpage .ws-timeline-time { font-size: 11px; color: var(--ws2-text-tertiary); }

/* 9. Composer: floating dark card, pinned to bottom */
body.ws2-fullpage .ws2-reply-bar {
  flex-shrink: 0;
  position: relative; /* anchors the transient drag-drop overlay */
  border-top: 1px solid var(--ws2-border);
  padding: 12px 16px 14px 16px;
  background: rgba(15,15,22,0.95);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
/* Round 2 fix: the textarea no longer draws its own rounded box -- that box
   moved up to `.ws2-reply-input-row` (below) so attach + textarea + send
   read as ONE pill-shaped input, not a boxed textarea with a disconnected
   button stack floating outside it. The textarea keeps a matching
   transparent border (not `border: none`) so the existing focus-visible
   rule in workspace_glass.css still has a border to color for keyboard
   users -- see that file's "Keyboard-only focus indicators" block. */
body.ws2-fullpage .ws2-reply-textarea {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 6px 4px;
  font-size: 15px;
  resize: none;
  min-height: 22px;
  max-height: 140px;
  /* The global `textarea` rule sets overflow:hidden -- re-enable vertical
     scroll here so a long reply scrolls within the 140px cap instead of
     being clipped with no scrollbar. */
  overflow-y: auto;
  /* flex-grow within `.ws2-reply-input-row`, not just width:100% -- with
     the attach/send buttons as flex siblings, width:100% would overflow the
     row; flex:1 with min-width:0 lets it shrink/grow correctly beside them. */
  flex: 1 1 auto;
  min-width: 0;
  box-sizing: border-box;
  font-family: inherit;
  color: var(--ws2-text-primary);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
  box-shadow: none;
}
body.ws2-fullpage .ws2-reply-textarea:focus {
  /* No focus highlight -- keep the input identical focused or not (simple UI).
     Matches the resting (now transparent/borderless) state; no accent ring. */
  outline: none;
  border-color: transparent;
  box-shadow: none;
}
body.ws2-fullpage .ws2-reply-textarea::placeholder { color: var(--ws2-text-tertiary); }
body.ws2-fullpage .ws-drop-zone.ws2-dropzone {
  border: 1.5px dashed rgba(255,255,255,0.12);
  border-radius: 12px;
  font-size: 12px;
  color: var(--ws2-text-tertiary);
  padding: 10px 16px;
  margin-top: 8px;
  text-align: center;
  cursor: pointer;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.12s ease, background 0.12s ease;
}
body.ws2-fullpage .ws-drop-zone.ws2-dropzone:hover,
body.ws2-fullpage .ws-drop-zone.ws2-dropzone.ws-drag-over {
  border-color: var(--ws2-accent);
  background: rgba(99,102,241,0.08);
}
body.ws2-fullpage .ws2-reply-bar form {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* Round 2 fix: single-row chat input. `.ws2-reply-input-row` is now ONE
   rounded container -- attach button, flex-grow textarea, send button, left
   to right -- instead of a boxed textarea with a separate right-hand button
   column outside it (the old `.ws2-reply-actions` vertical stack, removed
   below). `align-items: flex-end` keeps both circular buttons anchored to
   the textarea's LAST line as it auto-grows, instead of drifting to the
   vertical center of a tall multi-line textarea. */
body.ws2-fullpage .ws2-reply-input-row {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 20px;
  padding: 5px 6px 5px 12px;
  box-shadow: inset 0 1px 4px rgba(0,0,0,0.3);
}
body.ws2-fullpage .ws2-reply-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 34px;
  height: 34px;
  /* Neutralize the base .btn padding (12px 22px) + min-height (48px): on a
     34px circle that side-padding exceeds the width and clips the SVG to
     nothing, and min-height forces it taller than the 34px attach button. */
  padding: 0;
  min-height: 0;
  border-radius: 50%;
  background: var(--ws2-accent-warm);
  border: none;
  color: #fff;
  font-size: 16px;
  line-height: 0;
  cursor: pointer;
  transition: background 0.12s ease;
  float: none;
  flex-shrink: 0;
}
body.ws2-fullpage .ws2-reply-submit:hover {
  background: #4f46e5;
}
body.ws2-fullpage form.ws2-reply-form::after { display: none; }

/* Attach button: ghost/quiet at rest (no fill, no border) so it never
   competes with the accent-filled send button -- a faint background only
   appears on hover to signal it's interactive. */
body.ws2-fullpage .ws2-reply-attach-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: transparent;
  border: none;
  color: var(--ws2-text-tertiary);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
  flex-shrink: 0;
}
body.ws2-fullpage .ws2-reply-attach-btn:hover {
  background: rgba(255,255,255,0.1);
  color: var(--ws2-text-secondary);
}

/* Decision #7 (LOGRO_WS_ENTER_SEND): persistent drag-and-drop zone below the
   submit/attach buttons, dark-glass variant. Mirrors the compact dashed-box
   look already defined for body.ws2-fullpage .ws-drop-zone.ws2-dropzone
   above (same family of composer dropzone), just under its own selector
   since ws2-reply-drop-zone is additive (flag-gated), not a rename.
   Round 2 fix: kept always-visible (product decision -- not removed) but
   slimmed from ~46px to ~30px tall (explicit height + trimmed vertical
   padding/margin) so it reads as a quiet affordance on every thread instead
   of eating real estate like a second input. */
body.ws2-fullpage .ws2-reply-drop-zone {
  border: 1.5px dashed rgba(255,255,255,0.12);
  border-radius: 8px;
  font-size: 12px;
  color: var(--ws2-text-tertiary);
  height: 30px;
  padding: 0 16px;
  margin-top: 6px;
  text-align: center;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.12s ease, background 0.12s ease;
}
body.ws2-fullpage .ws2-reply-drop-zone:hover,
body.ws2-fullpage .ws2-reply-drop-zone.ws-drag-over {
  border-color: var(--ws2-accent);
  background: rgba(99,102,241,0.08);
}

/* Transient drag-drop overlay -- hidden by default (inline style), shown by
   JS only while a file drag is over the reply bar. Not part of static
   layout flow, so it never reserves space the way the old always-visible
   dashed dropzone did. */
body.ws2-fullpage .ws2-reply-drop-overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  margin: 6px;
  border: 2px dashed var(--ws2-accent);
  border-radius: 12px;
  background: rgba(99,102,241,0.10);
  color: var(--ws2-text-primary);
  font-size: 13px;
  font-weight: 600;
}

/* 10. Thread list: spaced items with rounded corners */
body.ws2-fullpage .ws2-thread-items { gap: 2px; }

body.ws2-fullpage .ws2-thread-item {
  min-height: 60px;
  padding: 12px 12px;
  border-radius: 6px;
  /* flex-start (not center): the title can now wrap to 2 lines (see
     .ws2-thread-item-title below), and centering would float the avatar
     away from the first line whenever a row wraps. */
  align-items: flex-start;
  gap: 10px;
  transition: background 0.15s ease;
}
body.ws2-fullpage .ws2-thread-item:hover { background: var(--ws2-hover); }
body.ws2-fullpage .ws2-thread-item-active {
  background: var(--ws2-active);
  box-shadow: inset 3px 0 0 var(--ws2-accent);
  border-radius: 6px;
}

/* Avatar circle */
.ws2-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 600;
  flex-shrink: 0;
  background: rgba(255,255,255,0.08);
  color: rgba(240,240,245,0.5);
  text-transform: uppercase;
}
.ws2-avatar-in-progress  { background: rgba(99,102,241,0.15); color: #818cf8; }
.ws2-avatar-awaiting-you { background: rgba(251,146,60,0.12); color: #fb923c; }
.ws2-avatar-responded    { background: rgba(16,185,129,0.12); color: #34d399; }
.ws2-avatar-resolved     { background: rgba(255,255,255,0.05); color: rgba(240,240,245,0.3); }
.ws2-avatar-received     { background: rgba(255,255,255,0.06); color: rgba(240,240,245,0.4); }

/* Two-row thread item layout */
body.ws2-fullpage .ws2-thread-item-body {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.ws2-thread-item-row-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
  flex: 1;
}
.ws2-thread-item-row-bottom {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  overflow: hidden;
}
body.ws2-fullpage .ws2-thread-item-title {
  font-size: 14px;
  font-weight: 500;
  color: var(--ws2-text-primary, #1c1c1e);
  /* 2-line clamp instead of single-line ellipsis -- a one-line cutoff was
     truncating most real thread titles down to a handful of characters.
     -webkit-line-clamp is still the only cross-browser-reliable way to do
     multi-line ellipsis; the standard `line-clamp` is added alongside it
     for forward compat as browser support lands. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  line-height: 1.35;
  overflow: hidden;
  min-width: 0;
  flex: 1;
  /* The base (non-fullpage) .ws2-thread-item-title rule sets
     white-space:nowrap + text-overflow:ellipsis for single-line truncation;
     this rule only wins the cascade on the properties it declares, so
     without an explicit reset here the inherited nowrap silently blocks the
     -webkit-box from ever wrapping to a second line. */
  white-space: normal;
  text-overflow: clip;
}
.ws2-thread-item-ts {
  font-size: 11px;
  color: var(--ws2-text-tertiary, #aeaeb2);
  white-space: nowrap;
  /* Lives in .ws2-thread-item-row-bottom now (moved out of row-top so it no
     longer competes with the title for width -- see
     _workspace_v2_thread_list.html). margin-left:auto right-anchors it past
     the left-packed chips; still shrinkable with ellipsis as a safety net
     for very narrow sidebar widths, but no fixed max-width cap. */
  flex-shrink: 1;
  min-width: 0;
  margin-left: auto;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Fullpage overrides: make badge pills feel dark-glass, not loud. */
body.ws2-fullpage .ws-new-chip {
  /* Muted "unread" indicator — soft background, no loud border, toned text. */
  background: rgba(255,255,255,0.06);
  color: rgba(240,240,245,0.5);
  border: none;
  text-transform: none;  /* lowercase "new" instead of uppercase "NEW" */
  font-weight: 500;
  font-size: 10px;
  padding: 1px 6px;
  letter-spacing: 0;
}
body.ws2-fullpage .ws2-legacy-qa-chip {
  /* Match the dark-glass palette instead of the light surface-alt. */
  background: rgba(255,255,255,0.06);
  color: rgba(240,240,245,0.5);
}
body.ws2-fullpage .ws2-thread-tool-chip {
  background: rgba(255,255,255,0.06);
  color: var(--ws2-text-tertiary);
  font-size: 10px;
}

/* 11. New conversation button in left panel header */
.ws2-new-thread-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: rgba(99,102,241,0.15);
  color: #818cf8;
  text-decoration: none;
  flex-shrink: 0;
  transition: background 0.12s ease, color 0.12s ease;
}
.ws2-new-thread-btn:hover {
  background: #6366f1;
  color: #ffffff;
}

/* 12. Canvas panel: job status cards + download items */
body.ws2-fullpage .ws2-canvas-slot {
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 12px;
}
body.ws2-fullpage .ws2-canvas-slot:last-child { margin-bottom: 0; }
body.ws2-fullpage .ws2-canvas-slot-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ws2-text-tertiary);
  margin-bottom: 10px;
}
body.ws2-fullpage .ws2-canvas-placeholder {
  font-size: 13px;
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws2-canvas-link-job-label {
  font-size: 13px;
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws2-canvas-download-item {
  height: 44px;
  display: flex;
  align-items: center;
  gap: 8px;
  border-radius: 8px;
  padding: 0 8px;
  transition: background 0.12s ease;
}
body.ws2-fullpage .ws2-canvas-download-item:hover { background: rgba(255,255,255,0.05); }
body.ws2-fullpage .ws2-canvas-download-item a {
  color: var(--ws2-accent);
  text-decoration: none;
  font-size: 13px;
}
body.ws2-fullpage .ws2-canvas-download-item a:hover { text-decoration: underline; }

/* Repricing canvas cards (dark) */
body.ws2-fullpage .ws2-canvas-repricing-stat {
  background: rgba(255,255,255,0.04);
}
body.ws2-fullpage .ws2-canvas-repricing-stat-highlight {
  border: 1px solid var(--ws2-border);
}
body.ws2-fullpage .ws2-canvas-repricing-stat-label {
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-canvas-repricing-stat-value {
  color: var(--ws2-text-primary);
}
body.ws2-fullpage .ws2-canvas-repricing-detail-row {
  border-top: 1px solid var(--ws2-border);
}
body.ws2-fullpage .ws2-canvas-repricing-detail-summary {
  color: var(--ws2-text-primary);
}
body.ws2-fullpage .ws2-canvas-repricing-count-chip {
  background: rgba(255,255,255,0.08);
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws2-canvas-repricing-anomaly-item,
body.ws2-fullpage .ws2-canvas-repricing-integrity-item {
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws2-canvas-repricing-integrity-issues {
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws2-canvas-repricing-qa-text {
  color: var(--ws2-text-primary);
}
body.ws2-fullpage .ws2-canvas-repricing-qa-links a {
  color: var(--ws2-accent-warm);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-form textarea,
body.ws2-fullpage .ws2-canvas-repricing-fb-reply-form textarea {
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--ws2-border);
  color: var(--ws2-text-primary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-file-label,
body.ws2-fullpage .ws2-canvas-repricing-fb-history-label {
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-item {
  border-top: 1px solid var(--ws2-border);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-status {
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-auto-badge {
  background: rgba(255,255,255,0.08);
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-meta-sep,
body.ws2-fullpage .ws2-canvas-repricing-fb-meta-date {
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-text {
  color: var(--ws2-text-primary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-attachments {
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-resolution {
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-resolution-date {
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-resolution-text {
  color: var(--ws2-text-primary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-thread-message {
  background: rgba(255,255,255,0.04);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-thread-msg-header {
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-thread-author {
  color: var(--ws2-text-secondary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-thread-text {
  color: var(--ws2-text-primary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-thread-attachments {
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-canvas-repricing-fb-reply-prompt {
  color: var(--ws2-text-tertiary);
}

/* Thread list filter link */
body.ws2-fullpage .ws2-thread-list-filter {
  padding: 8px 12px;
  margin-bottom: 4px;
}
body.ws2-fullpage .ws2-filter-link {
  font-size: 12px;
  color: var(--ws2-accent);
  text-decoration: none;
}
body.ws2-fullpage .ws2-filter-link:hover { color: var(--ws2-accent-warm); text-decoration: none; }

/* Tool-tag filter bar: dark-glass toggle chips. */
body.ws2-fullpage .ws2-tool-filter-chip {
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.08);
  color: var(--ws2-text-tertiary);
}
body.ws2-fullpage .ws2-tool-filter-chip:hover {
  background: rgba(255,255,255,0.1);
  color: rgba(240,240,245,0.7);
}
body.ws2-fullpage .ws2-tool-filter-chip-active {
  background: rgba(99,102,241,0.18);
  border-color: var(--ws2-accent);
  color: #c7d2fe;
}
body.ws2-fullpage .ws2-tool-filter-chip-active:hover {
  background: rgba(99,102,241,0.25);
  color: #c7d2fe;
}

/* Empty notes */
body.ws2-fullpage .ws2-empty-note {
  font-size: 14px;
  color: var(--ws2-text-secondary);
  padding: 32px 16px;
  text-align: center;
}
body.ws2-fullpage .ws2-empty-note a {
  color: var(--ws2-accent);
  text-decoration: none;
}
body.ws2-fullpage .ws2-empty-note a:hover {
  color: rgba(91, 155, 213, 0.8);
  text-decoration: underline;
}
/* Conversation panel's own empty state: centered both axes in the large
   middle column, not just top-padded like the smaller sidebar/canvas empty
   notes. See the base .ws2-conversation-empty-body/-note rules above for
   why this is its own class instead of a change to .ws2-panel-body /
   .ws2-empty-note directly. */
body.ws2-fullpage .ws2-conversation-empty-body {
  display: flex;
  align-items: center;
  justify-content: center;
}
body.ws2-fullpage .ws2-conversation-empty-note {
  font-size: 15px;
  padding: 0;
}

/* Inline error / flagged / pushback banners */
body.ws2-fullpage .ws2-inline-error {
  background: rgba(239,68,68,0.08);
  border: 1px solid rgba(239,68,68,0.2);
  border-radius: 10px;
  color: #dc2626;
  font-size: 14px;
  padding: 10px 14px;
  margin-bottom: 16px;
}
body.ws2-fullpage .ws2-flagged-banner {
  background: rgba(212,90,51,0.08);
  border: 1px solid rgba(212,90,51,0.15);
  border-radius: 10px;
  color: var(--accent, #d45a33);
  font-size: 13px;
  padding: 8px 14px;
  margin-bottom: 16px;
}
body.ws2-fullpage .ws2-detail-pending-approval-banner {
  background: rgba(251,146,60,0.10);
  border: 1px solid rgba(251,146,60,0.22);
  color: #fb923c;
  border-radius: 10px;
  font-size: 13px;
  padding: 10px 14px;
  margin-bottom: 16px;
}
body.ws2-fullpage .ws2-detail-pending-approval-icon {
  color: #fb923c;
}
body.ws2-fullpage .ws2-pushback-banner {
  background: rgba(99,102,241,0.06);
  border: 1px solid rgba(99,102,241,0.18);
  border-radius: 10px;
  font-size: 13px;
  padding: 10px 14px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* The base .ws2-pending-thread-item rule uses a solid light --warning-bg
   card, which is correct for the light theme but illegible in fullpage dark
   mode: body.ws2-fullpage .ws2-thread-item-title forces --ws2-text-primary
   (a light color) onto the title, and a light card underneath it makes the
   title nearly invisible. Swap to a translucent amber tint (same hue as
   .ws2-avatar-awaiting-you) so the dark-mode ambient light text stays
   legible, matching the .ws2-pushback-banner/.ws2-flagged-banner pattern
   above. */
body.ws2-fullpage .ws2-pending-thread-item {
  background: rgba(251,146,60,0.10);
  border: 1px solid rgba(251,146,60,0.22);
}

/* 13. Responsive override: below 900px, stack normally (not fixed)
   NOTE (2026-08-25 design-system audit): 900px is intentional here too,
   same rationale as the earlier ws2 breakpoint above -- the 3-column shell
   collapses earlier than the platform's normal 640px single-column
   breakpoint. Do not change it to 640px. */
@media (max-width: 900px) {
  body.ws2-fullpage .ws2-shell {
    position: static;
    height: auto;
    grid-template-columns: 1fr;
  }
  body.ws2-fullpage.ws2-canvas-collapsed .ws2-shell {
    grid-template-columns: 1fr;
  }
  body.ws2-fullpage .ws2-panel {
    height: auto;
  }
  body.ws2-fullpage .ws2-conversation-body {
    max-height: 50vh;
  }
  body.ws2-fullpage main {
    padding: 0 !important;
  }
}

/* =========================================================
   Workspace V2 -- tool-tag chips + deterministic pushback (WS-B)
   Flag: LOGRO_WORKSPACE_V2. Composer chip row (new-thread page) and the
   conversation-panel tool badge + pushback banner share this block.
   ========================================================= */

.ws2-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.ws2-chip {
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}

.ws2-chip:hover {
  background: var(--bg-alt);
}

.ws2-chip-selected {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Reuses the drop-zone visuals originally inline in workspace_new.html,
   promoted here so the v2 reply composer (_workspace_v2_conversation.html)
   can share them without duplicating a <style> block per template. */
.ws-drop-zone,
.ws2-dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-4) var(--sp-3);
  text-align: center;
  cursor: pointer;
  color: var(--text-muted);
  font-size: var(--text-sm);
  transition: border-color .15s, background .15s;
}

.ws-drop-zone.ws-drag-over,
.ws2-dropzone.ws-drag-over {
  border-color: var(--accent);
  background: var(--bg-alt);
}

.ws-file-list {
  margin-top: var(--sp-2);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ws-file-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  background: var(--bg-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px var(--sp-2);
  font-size: 0.85rem;
}

.ws-file-item-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ws-file-item-size {
  color: var(--text-muted);
  white-space: nowrap;
}

.ws-file-remove {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-muted);
  font-size: 1rem;
  padding: 0 2px;
  line-height: 1;
}

.ws-file-remove:hover {
  color: var(--error);
}

.ws2-tool-badge {
  background: var(--bg-alt);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px var(--sp-2);
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--navy);
  white-space: nowrap;
}

/* _workspace_v2_thread_tool_badge.html always renders the
   #ws2-thread-tool-badge element (an htmx OOB swap needs an existing
   element with a matching id to replace -- see that partial's docstring),
   including for a thread with no tool_tag yet. The [hidden] attribute
   already suppresses rendering per HTML semantics; this rule just also
   strips the badge's own border/padding/background so no empty pill-shaped
   gap is reserved in the header layout while it's hidden. */
.ws2-tool-badge-empty {
  display: none;
  border: none;
  padding: 0;
  background: none;
}

/* Canvas job-status chip: the linked job's 3-state indicator (In Progress /
   Needs Input / Resolved) -- see
   workspace_v2_routes.py::_canvas_state_for_job_state for the vocabulary
   this collapses down from. Modeled on .ws2-tool-badge's small-rounded-label
   shape; color semantics match the rest of the app (green=resolved, blue
   accent=in-progress, amber=needs input). */
.ws2-canvas-state-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 10px;
  border-radius: 12px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.ws2-canvas-state-chip-in-progress {
  background: #dbeafe;
  color: #1e40af;
}
.ws2-canvas-state-chip-needs-input {
  background: var(--warning-bg);
  color: var(--warning);
}
.ws2-canvas-state-chip-resolved {
  background: var(--success-bg);
  color: var(--success);
}

/* Subtle, non-intrusive live-poll trouble indicator -- shown after a few
   consecutive poll failures, hidden again on recovery. Deliberately quiet
   (small, muted) since it's a background-retry notice, not an error. */
.ws2-poll-trouble {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
body.ws2-fullpage .ws2-poll-trouble {
  color: var(--ws2-text-tertiary);
  font-size: 11px;
  font-weight: 500;
}

.ws2-pushback-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  background: var(--warning-bg);
  border: 1px solid var(--warning);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  margin-bottom: var(--sp-3);
  color: var(--warning);
  font-size: var(--text-sm);
}

.ws2-pushback-actions {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.ws2-pushback-btn {
  font-size: 0.8rem;
  padding: 6px var(--sp-3);
  white-space: nowrap;
}

.ws2-pushback-btn-secondary {
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
}
