/* ============================================================
   ArchiOSK / B-Hive — component and layout CSS

   Color, typography, and spacing are NOT defined here - see
   static/css/tokens.css (loaded before this file in base.html), the
   one controlled place for the app's visual character. Every rule
   below should reference those tokens (var(--text-secondary),
   var(--space-6), ...), never a raw hex/rem value that duplicates what
   a token already names. This file is component/layout rules only:
   what things look like structurally, not what the base palette or
   scale is.

   Page-template families: derived from actually inspecting every route's
   composition and interaction mode, not assumed up front. Two were real,
   already-duplicated geometries and are now real shared templates:
     - Dead-end (templates/errors/error.html): one message, one way out,
       no ongoing state, reachable pre- or post-auth. 403/404/500 used to
       be three near-identical files; now one parameterized template.
     - Confirm interrupt (templates/confirm_base.html, .confirm-page):
       one centered card, one question, one action set, one way back,
       always mid-flow inside the authenticated shell. Approval Gate
       actions and project deletion used to each hijack .case-workspace's
       grid via an inline style for this; now a real family with two
       members (confirm_action.html, confirm_delete_project.html).
   Others are single-instance today - named here so a second member
   inherits the grammar deliberately instead of being invented fresh, not
   built out as empty template scaffolding for a family of one:
     - Entry/gateway (login.html, gateway.html): centered card, one
       primary decision. CORRECTED: an earlier pass here called
       gateway.html dead because no template links to it - wrong,
       checked only navigation links, not redirect targets.
       routes/portal.py's login() redirects here by default whenever no
       `?next=` is present (see its own comment), and index.html's
       "Sign in to get started" link never sets one - so this is the
       actual, frequently-hit landing page for a fresh login, not an
       orphan. This makes Entry a real two-member family already
       sharing CSS (.gateway-page/.gateway-card/.gateway-brand) but
       still duplicating the brand-lockup markup between the two files
       - a genuine consolidation candidate, not yet done.
     - Single-task capture (upload.html): hero intro, one primary input,
       one submit, inline validation error.
     - Directory (projects.html): search + filterable card list.
     - Instrumented workspace (case_workspace.html, case open): three
       panes, heavy disclosure, high information density. Already
       correctly ONE template governing four behavioral states (private/
       shared/collaborative, archived read-only, derived) via data, not
       four duplicated files - the reference example other families
       should match, not a gap. Its geometry is also explicitly
       space-driven, not just state-driven - see .app-shell-body/
       .display-divisions below (CLAUDE-P40-E3A: this used to be a named-
       grid-area .case-workspace, now a flex row of Lists|Display|Toolbox
       plus a dynamic-count Display grid inside it): panel-dividers keep
       the reference/navigation panes collapsible at every width, instead
       of a single "collapse to one column" breakpoint dumping eight
       accordions above the actual conversation.
     - Hub (case_workspace.html, no case open / "Project Home"):
       single column, conversational composer, light disclosure.
   Deliberately NOT templated: the legacy dashboard (dashboard.html)
   has its own header/stats/lattice/table composition, but the product
   is actively moving traffic off it (see the "Open Case Workspace" /
   "Legacy Dashboard" cross-links in both this file and case_workspace.html)
   - investing in a family template for a surface being superseded would
     be building for the wrong direction.
   ============================================================ */
* { box-sizing: border-box; }

/* Browsers do NOT give form controls the page's font (or its colors)
   by default - they use OS UI defaults unless told otherwise. The
   font-family/font-size backstop below predates CLAUDE-P40-VW6; the
   background-color/color/border-color lines are this stage's own
   addition, for the identical reason applied to color: most buttons/
   inputs already set their own explicit colors (and those rules still
   win here on specificity - a class selector beats this bare-tag
   one), but any control that doesn't - <select> most visibly, browsers
   never theme a bare <select> from surrounding CSS at all - rendered
   with the browser's own native white-background/black-text chrome
   regardless of the page's chosen appearance mode. That is a large
   share of what CLAUDE-P40-VW6's "portions of the panel do not
   receive the Dark/Light/Tinted treatment" defect actually was:
   www.display-division-picker (the VW1/VW4 "open a Document here"
   dropdown) is exactly this case, and it is far from the only one.
   Values are the standard tokens, so this backstop automatically
   tracks whichever surface's Light/Dark/Tinted scope it renders
   inside, the same as every other component rule in this file. */
button, input, select, textarea {
    font-family: inherit;
    font-size: inherit;
    background-color: var(--surface-primary);
    color: var(--text-primary);
    border-color: var(--border);
}

/* CLAUDE-P40-VW8-QA, Section 10: the page itself never scrolls - only
   .app-shell's own children with a real bounded height do (each panel
   independently, via its own overflow-y:auto below). This is what
   makes the Menu bar "fixed" without a single position:fixed/sticky
   rule of its own: it is simply never inside anything that scrolls.
   Before this stage, html/body had no height/overflow constraint at
   all, so any page whose content grew taller than the viewport (a
   long Overview, a tall Investigation, many Project cards) scrolled
   the WHOLE page - Menu included - out of view; the panel-level sticky/
   scroll rules already on .launcher-panel/.chat-region only ever
   worked by coincidence, when nothing else on the page was tall enough
   to trigger page-level scroll first. */
html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    overflow: hidden;
    background: var(--canvas);
    color: var(--text-primary);
    font-family: var(--font-body);
    /* CLAUDE-P40-VW8-QA (Site-Wide Visual-System Consistency Addendum):
       font-stretch: condensed removed - it was never actually a no-op.
       --font-body's own stack already names the condensed variants
       explicitly ("Arial Nova Cond", "Arial Narrow") - font-family
       matching alone already selects those correctly wherever they're
       installed. The font-stretch declaration only had a real effect
       on the FALLBACK tier (plain "Arial"/sans-serif, i.e. any system
       without Arial Nova installed - not just Windows 11/365): browsers
       synthesize a horizontal squish for a static font asked to stretch
       to a width it doesn't have a real face for, which is exactly
       "unjustified synthetic font stretching" - distorted, narrower-
       than-designed text, and specifically on whichever system DIDN'T
       have the intended font, the opposite of graceful degradation.
       Removing it changes zero px of which FONT FAMILY loads (the
       fallback chain itself is untouched, per this stage's own "do not
       change the font family" instruction) - only stops the browser
       from artificially distorting the fallback face. */
    line-height: 1.55;
}

/* Light where large text stays comfortably readable at that weight;
   regular weight is the default everywhere else - see the large-heading
   overrides below (hero/entry/gateway/dashboard/project-home h1s) for
   where 300 actually gets used. Never bold-by-default the way the
   browser UA stylesheet would. */
h1, h2, h3, h4, h5, h6 { font-weight: 500; }

a { color: var(--machine-blue); text-decoration: none; }
a:hover { text-decoration: underline; }
a:focus-visible, button:focus-visible, input:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* -- blueprint grid backdrop ------------------------------------------
   Genuinely blue, not the sand --border tone: a blueprint's own defining
   feature is its cyanotype blue line, and blue sits roughly complementary
   to this app's warm ~40deg canvas hue - the one place a structural blue
   wash belongs, kept faint enough (0.3 opacity) to stay a backdrop, not a
   foreground color. */
.blueprint-grid {
    position: fixed;
    inset: 0;
    z-index: -1;
    background-image:
        linear-gradient(var(--blueprint-grid-line) 1px, transparent 1px),
        linear-gradient(90deg, var(--blueprint-grid-line) 1px, transparent 1px);
    background-size: 48px 48px;
    opacity: 0.3;
}

/* -- app shell: application-wide top bar + one left launcher panel -------
   CLAUDE-P40-E2B1: replaces the old expandable icon-only/labeled
   .side-rail (a width toggle between a narrow icon rail and a wider
   labeled panel) with a single restrained launcher panel, shown or
   hidden in full (no intermediate width state) via the top bar's own
   "Lists" toggle - see html.launcher-hidden below. .app-shell is a
   column: the top bar (full width, spans Launcher/Display/Toolbox) then
   .app-shell-body (the launcher panel beside the main content area,
   the exact same flex-row arrangement .side-rail/.app-main used before,
   just renamed and simplified). */
.app-shell {
    display: flex;
    flex-direction: column;
    /* CLAUDE-P40-VW8-QA: was min-height:100vh, letting .app-shell (Menu
       included) grow taller than the viewport and scroll with the page
       - see html/body's own comment above. Locked to the viewport
       exactly; every panel below scrolls internally instead. */
    height: 100vh;
    overflow: hidden;
    /* CLAUDE-P40-VW7A-QA2 (product-owner browser correction): a base
       canvas for anything that is shell CHROME rather than one of the 5
       independently-themed surfaces (Menu/Lists/Display/Toolbox/Chat) -
       principally the panel dividers/splitters, which sit as siblings
       of those surfaces, not descendants, and so never inherited any
       surface's own --surface-primary redefinition ("white splitter
       tracks... in the dark theme" - the actual root cause). .app-shell
       itself gets a 6th appearance class below (base.html's own inline
       scripts - piggybacked on the Menu surface's resolved mode, the
       one always-visible, always-defined surface, not a new separate
       preference), so --surface-primary here already resolves to the
       correct theme by the time any var() below reads it - this
       declaration is what actually paints it. A themed surface nested
       inside .app-shell still wins locally via normal CSS custom-
       property cascade (closer ancestor), so per-surface Appearance
       independence (Section 5's own "mixed" state) is unaffected. */
    background: var(--surface-primary);
}
.app-shell-body {
    display: flex;
    align-items: stretch;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}
/* CLAUDE-P40-VW7A-QA2 (product-owner browser correction): Lists
   (.launcher-panel) and .workspace-main-column (Display+Chat) share
   .app-shell-body's row - this is what makes Lists' own height:100%
   actually cover the SAME vertical extent as Chat's row, closing the
   "light rectangle beneath Lists in dark modes" gap that existed while
   Chat was a full-width sibling of .app-shell-body itself.
   CLAUDE-P40-EYE1: a third sibling, .workspace-right-column
   (Toolbox+Eye - see that rule below), was added for the SAME reason
   on the opposite side - it used to be Toolbox alone, a plain flex
   sibling of .app-main inside .workspace-content-row (retired: with
   Toolbox moved out, that row wrapper had only one child left,
   .app-main, so it added nothing .workspace-main-column doesn't
   already provide directly). */
.workspace-main-column {
    display: flex;
    flex-direction: column;
    flex: 1;
    /* CLAUDE-P40-EYE1 (product-owner browser correction), Section 1:
       "enforce practical minimum widths for both the centre and right
       column" - a real CSS-level floor for Display+Chat (the actual
       flex item competing for width against Lists and the right
       column), defense-in-depth alongside the drag logic's own clamp
       in base.html (which keeps the user from dragging past this in
       the first place). */
    min-width: 320px;
    min-height: 0;
    overflow: hidden;
}
/* CLAUDE-P40-VW8-QA (panel-border hierarchy correction): the desktop
   rule no longer draws its own border-right - .panel-divider's own
   ::before (below) already draws a line ~4px to the right of this
   panel's edge, so the two together were a "double line" (product-
   owner report: "the Lists-to-Display boundary" among the distracting
   areas). One line now, from the divider alone - it already carries
   the correct quiet-resting/accent-on-hover-or-focus hierarchy this
   correction asks for everywhere. The narrow-viewport drawer variant
   further below KEEPS its own border-right deliberately: at that width
   the drawer floats over content with no adjacent .panel-divider
   beside it (the divider is what collapses the panel in the first
   place), so there is no second line to double up with there. */
.launcher-panel {
    width: 240px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    background: var(--surface-primary);
    /* CLAUDE-P40-VW7A-QA2: overflow-y:auto used to live directly on this
       element (the nav scrolled as one region) - now that .lists-pane/
       .thumbnails-pane are two independently-scrolling sub-regions
       (Section 3's own "efficient rendering, independent scroll"), this
       level only clips so the draggable divider's drag range never
       spills outside the column; each pane below owns its own scroll. */
    overflow: hidden;
    /* CLAUDE-P40-VW8-QA: was height:100vh + position:sticky/top:0 - a
       workaround for the page itself scrolling (see html/body's own
       comment). Now that .app-shell is height-locked and .app-shell-
       body no longer scrolls as a whole, 100% of .app-shell-body's own
       (already well-defined) height is correct and sticky positioning
       has nothing left to stick against - simplified accordingly. */
    height: 100%;
}
/* CLAUDE-P40-LTH1 (correction): used to be flex:1 1 auto by default,
   only taking the persisted/default percentage once .launcher-panel
   got a .has-thumbnails class that static/js/pdf_viewer.js added
   solely while the active Document was a PDF - meaning Lists silently
   filled the WHOLE column, with no visible split at all, on every
   Overview/Investigation/Chat/non-PDF-Document page (a real
   product-owner-reported screenshot defect: "Project/List records
   continuing uninterrupted to the bottom edge"). Thumbnails is now a
   PERMANENT structural pane (see the template's own comment on
   .lists-pane), so this rule is unconditional - the exact same
   "outer column owns sizing" split .workspace-pane-toolbox already
   uses relative to Eye, applied here instead of the old class-gated
   version. */
.lists-pane {
    flex: 0 0 var(--lists-height, 60%);
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    /* CLAUDE-LEFTPANEL-CALM-01 / CLAUDE-PANEL-CALM-02: quiet/transparent
       by default, revealed only on :hover - a real Product Owner report
       named this panel "too agitated," then confirmed the fix and asked
       for the SAME treatment on every other panel (see the shared
       ":hover" rule and the shared WebKit block below, which now cover
       Thumbnails/Toolbox/Eye/Display/Chat/tab-strips too - this is no
       longer this ONE panel's special case). `transparent transparent`
       keeps the SAME reserved gutter width overflow-y:auto already
       allocates (no layout shift - the scrollbar still exists and still
       functions, it's simply invisible until hovered). */
    scrollbar-color: transparent transparent;
}
.lists-thumbnails-divider {
    flex-shrink: 0;
    width: 100%;
    height: 9px;
    border: none;
    padding: 0;
    cursor: row-resize;
    /* CLAUDE-P40-VW7A-QA2 (product-owner browser correction): was
       transparent - unlike .panel-divider (a sibling of the 5 themed
       surfaces), this element IS a descendant of .launcher-panel, so it
       already inherits Lists' own --surface-primary redefinition
       directly; a real background here (rather than falling through to
       whatever's behind .launcher-panel) is what actually paints it,
       merging with Lists' own theme specifically, never the shell
       fallback. */
    background: var(--surface-primary);
    position: relative;
    z-index: 1;
}
.lists-thumbnails-divider::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 4px;
    height: 1px;
    background: var(--border);
}
.lists-thumbnails-divider:hover::before,
.lists-thumbnails-divider:focus-visible::before,
.lists-thumbnails-divider.dragging::before {
    background: var(--machine-blue);
    height: 2px;
    top: 3.5px;
}
/* CLAUDE-P40-LTH1, Section 6 ("visible focus"): a real focus-visible
   outline on the divider ITSELF - the ::before accent line above only
   changes color/thickness, which is not the same as a genuine focus
   indicator for a keyboard user tabbing through the shell. Same
   treatment .toolbox-eye-divider already has. */
.lists-thumbnails-divider:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 1px;
}
.thumbnails-pane {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    border-top: 1px solid var(--border);
}
.thumbnails-pane-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0.7rem;
    flex-shrink: 0;
}
.thumbnails-pane-header h2 {
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-metadata);
    margin: 0;
}
.thumbnails-maximize-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: 0.72rem;
    padding: 0.2rem 0.4rem;
    border-radius: 4px;
}
.thumbnails-maximize-btn:hover, .thumbnails-maximize-btn:focus-visible {
    background: var(--surface-hover);
    color: var(--text-primary);
}
.thumbnails-maximize-btn[aria-pressed="true"] { color: var(--machine-blue); }
/* CLAUDE-P40-LTH1, Section 4: the pane's own "nothing to show" state -
   quiet and compact (Section 4's own explicit "do not fill the pane
   with unrelated Project records"), visible by default in the
   server-rendered markup, hidden by static/js/pdf_viewer.js the
   moment real thumbnails are built (see that file's own comment on
   buildThumbnails/clearThumbnails). Deliberately its own small rule
   rather than reusing .pane-note directly - that class' own negative
   top margin is tuned for sitting directly under a Lists tree heading,
   not this pane's padded flex layout. */
.thumbnails-empty-state {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    padding: 0.6rem;
    margin: 0;
    text-align: center;
}
.thumbnails-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.6rem;
    scrollbar-color: transparent transparent;
}
/* CLAUDE-P40-VW7A-QA2, Section 3: one real page per row - a <button>
   (not a decorative <div>) so click-to-navigate is a real activate-able
   control, aria-current="true" on whichever row matches the current
   page (kept in sync by static/js/pdf_viewer.js on every page change,
   regardless of whether that change came from scrolling, the top-menu
   controls, or a thumbnail click itself). */
.thumbnail-row {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    cursor: pointer;
    border: 2px solid transparent;
    border-radius: 4px;
    padding: 0.3rem;
    background: none;
    width: 100%;
    font-family: var(--font-body);
}
.thumbnail-row:hover { background: var(--surface-hover); }
.thumbnail-row:focus-visible { outline: 2px solid var(--machine-blue); outline-offset: 1px; }
.thumbnail-row canvas { display: block; max-width: 100%; box-shadow: 0 0 0 1px var(--border); }
.thumbnail-row[aria-current="true"] {
    border-color: var(--machine-blue);
    border-width: 3px;
    background: var(--surface-selected);
}
.thumbnail-row-label {
    font-size: 0.7rem;
    color: var(--text-metadata);
    font-variant-numeric: tabular-nums;
}
/* CLAUDE-P40-LTH1, Section 6: "selected-page indication that does not
   rely on color alone" - border-color/background above are still the
   primary cue, but border-WIDTH (2px -> 3px) and the label's own
   weight/underline are real geometry/shape cues, not color, so the
   current page still reads correctly in grayscale or for a color-
   vision-deficient reviewer. */
.thumbnail-row[aria-current="true"] .thumbnail-row-label {
    font-weight: 700;
    text-decoration: underline;
}
/* CLAUDE-P40-E3A, Section 9 (Chat is a full-width row beneath Lists/
   Display/Toolbox, sibling to .app-shell-body, not confined to the
   Display column) - CLAUDE-P40-VW8-QA: the explicit height-subtraction
   rule this comment used to document (".launcher-panel's sticky-fill
   height must stop above the sticky Chat bar") is gone, not just
   updated - .launcher-panel's own height:100% (above) is 100% of
   .app-shell-body's ACTUAL rendered height, which ordinary flexbox
   distribution already computes as "100vh minus Menu's own height
   minus .chat-region's own height" automatically (.chat-region is a
   flex-shrink:0 sibling of .app-shell-body within .app-shell, so it
   already claims its own space before .app-shell-body's flex:1 gets
   whatever's left). A second, manual height:calc(...) subtracting
   --chat-height AGAIN would double-subtract it. */

/* CLAUDE-P40-E3A, Section 7: the panel-dividing lines themselves are the
   Lists/Toolbox collapse controls (base.html's own script), replacing
   the old top-bar toggle buttons - a thin, full-height clickable seam
   between panels, not a labeled button. */
.panel-divider {
    flex-shrink: 0;
    width: 9px;
    border: none;
    padding: 0;
    cursor: pointer;
    /* CLAUDE-P40-VW7A-QA2 (product-owner browser correction): was
       transparent - a sibling of the 5 themed surfaces (never a
       descendant of any of them), so "transparent" fell through to
       .app-shell's OWN background, which now correctly resolves via
       the shell-level appearance class (see .app-shell's own comment)
       instead of the unthemed :root light default this used to expose
       as a literal white channel in every dark mode. */
    background: var(--surface-primary);
    position: relative;
    /* CLAUDE-P40-E3A-QA, Section 7: explicit low z-index (rather than
       relying on implicit stacking order) so this line can never paint
       above the top-bar menus (z-index 20), the Display context menu
       (z-index 40), or the narrow-screen Lists/Toolbox drawers (z-index
       30) even if a future change gives an ancestor of theirs its own
       stacking context - verified structurally, not just by omission. */
    z-index: 1;
}
.panel-divider::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 4px;
    width: 1px;
    background: var(--border);
}
.panel-divider:hover::before,
.panel-divider:focus-visible::before {
    background: var(--machine-blue);
    width: 2px;
    left: 3.5px;
}
.panel-divider[aria-expanded="false"] {
    width: 14px;
}
.panel-divider[aria-expanded="false"]::before {
    left: 6px;
}
/* CLAUDE-P40-EYE1 (product-owner browser correction), Section 1: the
   Toolbox/right-column divider is now ALSO a real, mouse-draggable
   width resize handle (base.html's own drag logic), not click-to-
   toggle only - .panel-divider-lists (Lists) stays click-only, so this
   modifier-scoped rather than added to the shared .panel-divider base.
   ew-resize is the standard "drag left/right" cursor affordance; the
   accent line gets the same .dragging class treatment as every other
   draggable divider in this file (:hover/:focus-visible/.dragging all
   painting the same accent, since a drag can continue after the
   pointer strays off this thin line - see .lists-thumbnails-divider's
   own comment on why :hover alone isn't enough). */
.panel-divider-toolbox {
    cursor: ew-resize;
}
.panel-divider-toolbox.dragging::before {
    background: var(--machine-blue);
    width: 2px;
    left: 3.5px;
}
/* CLAUDE-P40-E2B1, Section B: one show/hide control (the top bar's
   "Lists" button), a reviewer-wide localStorage preference (not
   per-Project like the old per-Workspace Lists toggle it replaces -
   this panel is now present on every authenticated page, not just the
   Workspace) - applied before first paint via base.html's own
   extra_head script, the same "avoid a flash of the wrong layout"
   pattern .toolbox-hidden below already established. display:none also
   satisfies "not keyboard-focusable when hidden" for free. */
html.launcher-hidden .launcher-panel { display: none; }
.launcher-panel-body {
    display: flex;
    flex-direction: column;
    padding: 0.8rem 0.7rem;
    gap: 1.1rem;
}
.launcher-section { display: flex; flex-direction: column; gap: 0.1rem; }
/* CLAUDE-P40-VW7A-QA (Clarify Project Hierarchy and Selection State):
   uppercase/letter-spaced/--text-metadata was ALREADY a distinct
   structural-title language from every other row (Section 2's own
   "dedicated structural title color for main/root headings") - the
   thing that made a root heading like PROJECTS read as "selected" was
   never its resting typography, it was sharing .active's fill with
   every genuinely selected leaf below (.launcher-link.active, same
   file). .launcher-heading.active no longer fills a background at all
   - a root heading's OWN expand/collapse state is already fully
   conveyed by aria-expanded and the caret rotation
   (.tree-toggle[aria-expanded="true"] .tree-label::before, below) and
   needs no fill-based echo of it. :hover/:focus-visible still give
   real interactive feedback - only the PERSISTENT "currently expanded"
   state stopped painting a highlight. */
.launcher-heading {
    font-family: var(--font-body);
    font-weight: 600;
    font-size: var(--text-sm);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-metadata);
    /* CLAUDE-LEFTPANEL-DENSITY-03: left inset only reduced (var(--tree-
       row-inset), was a symmetric 0.55rem baked into every side) - the
       right side keeps its own original 0.55rem unchanged, since
       nothing to the right (chevron/count badge) was reported too
       loose, only the left margin before a row's own content was.
       CLAUDE-LEFTPANEL-DENSITY-04 (Product Owner refinement, "denser,
       quieter, more index-like"): top/bottom went from 0.35rem to
       0.24rem - since .tree-node/.tree-children/.tree carry no margin
       or gap of their own (checked - all zero), a row's own top/bottom
       padding IS the entire "space between adjacent rows," so this one
       change is what actually tightens the whole tree, at every depth,
       for free. */
    padding: 0.24rem 0.55rem 0.24rem var(--tree-row-inset);
    border-radius: 5px;
}
.launcher-heading:hover, .launcher-heading:focus-visible { background: var(--surface-hover); color: var(--text-primary); text-decoration: none; }
.launcher-link {
    display: block;
    /* CLAUDE-LEFTPANEL-DENSITY-04: 0.45rem -> 0.3rem, same reasoning as
       .launcher-heading above. Still clears a real touch/click target
       (0.3rem*2 + var(--text-sm) line-height is comfortably above the
       usual ~24px floor) - "navigation can be dense," this is the
       navigation, not one of the spacious action controls (Send,
       checkboxes, + disclosure) that stayed untouched by this pass. */
    padding: 0.3rem 0.55rem 0.3rem var(--tree-row-inset);
    border-radius: 5px;
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.launcher-link:hover { background: var(--surface-hover); color: var(--text-primary); text-decoration: none; }
/* CLAUDE-P40-VW7A-QA: reserved for the ONE destination actually
   projected into Display (Section 1) - a Document/Case/Overview/Chats/
   Task/Tag leaf whose own href is what's currently rendered. The
   current Project's own name row (.current-project, below) no longer
   qualifies for this class at all - see templates/base.html's own
   comment on why "Chats" (or whichever child is actually open) is the
   sole thing allowed to look selected.

   CLAUDE-LEFTPANEL-DENSITY-04 (Product Owner refinement, "reduce the
   opacity/intensity of the current filled highlight; prefer a
   restrained tint, subtle edge, or slim accent rather than a large
   solid block"): the flat, fully-opaque --surface-selected fill read as
   too heavy/button-like for a navigation row. Replaced with the SAME
   translucent color-mix() idiom this stage's highlight/focus work
   already established (a low-alpha wash, not a solid block) plus a
   slim 2px left accent - distinct in BOTH weight and color from
   .current-project's own 3px, fill-less --border-strong landmark just
   below, so "hover, active, and selected states remain
   distinguishable" holds: hover is a plain --surface-hover wash with no
   border; active is a lighter tinted wash WITH a thin --machine-blue
   edge (machine/system "this is what's displayed" - a genuine semantic
   match, not --border-strong's own "structural landmark" meaning);
   current-project is border-only, no fill at all. 35% keeps this
   comfortably lighter than the already-verified 100% case (--text-
   primary was contrast-checked against the full --surface-selected
   fill; a lower-alpha version sits strictly between that and the
   panel's own resting background, so contrast can only be as good or
   better). */
.launcher-link.active {
    background: color-mix(in srgb, var(--surface-selected) 35%, transparent);
    color: var(--text-primary);
    border-left: 2px solid var(--machine-blue);
    padding-left: calc(var(--tree-row-inset) - 2px);
}
/* CLAUDE-P40-VW7A-QA: the current Project's own restrained "you are
   here" marker - Section 3's own "distinct title text... a narrow edge
   indicator... do not reuse the full selected-row fill." A left-edge
   accent (the same idiom .finding-card's own border-left already uses
   for "this is flagged/notable" elsewhere in this file) plus a bolder
   weight, never a background fill - reads as a structural landmark,
   not a second selected row. --border-strong (not --machine-blue/
   --surface-selected) keeps it quiet, matching the panel-border-
   hierarchy correction's own "reserve stronger accent color for
   meaningful states" discipline - "current Project" is a genuinely
   meaningful, but not an ACTION, state. */
.launcher-link.current-project {
    font-weight: 600;
    color: var(--text-primary);
    border-left: 3px solid var(--border-strong);
    /* CLAUDE-LEFTPANEL-DENSITY-03: compensates against the SAME
       --tree-row-inset .launcher-link's own base rule now uses (was a
       hardcoded 0.55rem) - the 3px accent border must still visually
       replace, not add to, this row's own left inset. */
    padding-left: calc(var(--tree-row-inset) - 3px);
}
.launcher-new-project { color: var(--machine-blue); }

/* CLAUDE-P40-E3A, Section 4: the recursive Lists hierarchy. .tree-toggle
   (a <button>, for parents) and .tree-leaf (an <a>, for leaves) both
   also carry .launcher-heading/.launcher-link respectively for their
   text styling (color/padding/hover/active, above) - this block only
   adds what's specific to the tree structure itself: reset, nesting
   indentation, the hover-reveal/pin-open expand indicator, and the
   count badge. Indentation is recursive and open-ended (each nested
   .tree-children adds its own left padding) rather than hardcoded per
   level, since the hierarchy's depth is not fixed. */
.tree, .tree-children {
    list-style: none;
    margin: 0;
    padding: 0;
    /* CLAUDE-LEFTPANEL-DENSITY-03: shared spacing variables, declared
       once here (inherited by every nested .tree-children) rather than
       repeating a literal value at each of the two places that used
       one - a real Product Owner report found the panel's cumulative
       indentation too wide, wasting working width. --tree-indent-step
       is the recursive per-level step (.tree-children's own padding-
       left, below); --tree-row-inset is the constant left inset of
       every row's own text (.launcher-heading/.launcher-link, further
       below) - previously 0.75rem and 0.55rem respectively, now a
       visibly tighter but still legible VS-Code-Explorer-scale step. */
    --tree-indent-step: 0.4rem;
    --tree-row-inset: 0.4rem;
}
/* CLAUDE-P40-VW7A-QA (Clarify Project Hierarchy and Selection State),
   Section 4: "the rendered hierarchy must visibly and semantically
   read as... Use consistent indentation, spacing, and a restrained
   tree guide or equivalent hierarchy cue. Do not rely on background
   highlighting to communicate nesting." A single 1px left border, the
   same quiet --border token used everywhere else in this file for
   ordinary (not accent-colored) structure, applied uniformly to every
   nested .tree-children - the classic file-tree "vertical connector"
   convention, restrained enough not to compete with row content, and
   the SAME cue at every depth (Project -> Documents/Investigations/.../
   Chats, and any further nesting below those) rather than a Project-
   specific special case. */
.tree-children {
    padding-left: var(--tree-indent-step);
    border-left: 1px solid var(--border);
}
.tree-children:not([data-tree-open]) {
    display: none;
}
.tree-node { margin: 0; }
.tree-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
    text-align: left;
}
.tree-toggle .tree-label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tree-toggle .tree-label::before {
    content: "";
    flex-shrink: 0;
    width: 0.5em;
    height: 0.5em;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(-45deg);
    transition: transform 0.12s ease;
    opacity: 0.6;
}
.tree-toggle[aria-expanded="true"] .tree-label::before {
    transform: rotate(45deg);
}
.launcher-count {
    font-variant-numeric: tabular-nums;
    font-size: 0.72rem;
    color: var(--text-metadata);
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
}
.tree-leaf.launcher-new-project { color: var(--machine-blue); }
/* CLAUDE-P40-VW8-QA (New Investigation Action in Lists): same accent
   "+ New X" already uses (.launcher-new-project, above) - a generic
   reusable modifier, not a one-off, in case a future family adopts the
   same action-row pattern (see this stage's own audit of whether other
   expandable families already have an equivalent). */
.tree-leaf.tree-leaf-action { color: var(--machine-blue); }

/* CLAUDE-P40-VW7: Tasks/Tags branches - reuse the tree idiom above as-
   is (.tree-node/.tree-toggle/.tree-children/.launcher-count already do
   the collapsing, indentation, and count-badge work); this block only
   adds what's specific to a Task/Tag row: the Open/Completed and per-
   tag sub-labels (a plain heading, not a second toggle - Tasks/Tags
   itself is the one collapsible unit per branch), the inline row that
   pairs a navigable link with its own small action form, the tag-color
   swatch dot, and the two empty/unavailable states. */
.launcher-subheading {
    font-family: var(--font-body);
    font-size: 0.76rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-metadata);
    /* CLAUDE-LEFTPANEL-DENSITY-03: same tightened left inset as every
       other tree row (.launcher-heading/.launcher-link, above).
       CLAUDE-LEFTPANEL-DENSITY-04: top/bottom tightened to match the
       same pass on .launcher-heading/.launcher-link above. */
    padding: 0.26rem 0.55rem 0.1rem var(--tree-row-inset);
    margin: 0;
    display: flex;
    align-items: center;
    gap: 0.35rem;
}
.tree-node-group { margin: 0; }
.tree-node-empty { padding: 0.16rem 0.55rem 0.16rem var(--tree-row-inset); }
.tree-node-empty .pane-note { margin: 0; font-size: var(--text-xs); }
.launcher-task-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
    min-width: 0;
}
.launcher-task-row .launcher-link {
    flex: 1;
    min-width: 0;
}
.launcher-task-completed {
    text-decoration: line-through;
    color: var(--text-metadata);
}
/* CLAUDE-CA1D-RIVER-PO-02 (Product Owner interaction correction, "task
   checkbox not a text link"): a conventional checkbox as the PRIMARY
   completion affordance, replacing the "Mark complete"/"Reopen" text
   links - restrained (thin square outline; a quiet check, not a large
   consumer-app control), matching this app's own stated "color appears
   rarely" discipline. Uses --accepted-green - already the token whose
   declared meaning in tokens.css is literally "accepted / confirmed,"
   a genuine semantic match for "this task is done," not a repurposed
   or newly-invented color. A real <input type="checkbox"> (not a div
   with aria-checked) so keyboard (Tab + Space) and screen-reader
   checked/unchecked state come from the browser itself; the visually-
   hidden label text names the specific task, and the SAME pre-existing
   complete_task_route/reopen_task_route form-POST this replaces is
   still what actually runs (on the native "change" event) - this is a
   new affordance for one existing action, not a second completion
   mechanism competing with it. */
.task-checkbox-form { flex: 0 0 auto; margin: 0; }
.task-checkbox-wrap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    cursor: pointer;
}
.task-checkbox {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    width: 0.95rem;
    height: 0.95rem;
    border: 1.5px solid var(--text-metadata);
    border-radius: 3px;
    background: transparent;
    cursor: pointer;
    position: relative;
    flex: 0 0 auto;
}
.task-checkbox:hover { border-color: var(--text-secondary); }
.task-checkbox:checked {
    border-color: var(--accepted-green);
    background: color-mix(in srgb, var(--accepted-green) 20%, transparent);
}
.task-checkbox:checked::after {
    content: "";
    position: absolute;
    left: 2px;
    top: -1px;
    width: 4px;
    height: 8px;
    border: solid var(--accepted-green);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
.launcher-link-unavailable {
    color: var(--text-disabled);
    cursor: default;
}
.launcher-link-unavailable:hover { background: none; }
.launcher-link-unavailable small { font-style: italic; }
.launcher-tag-swatch {
    display: inline-block;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
    flex-shrink: 0;
}
.conv-tag-color-yellow { background: var(--tagcolor-yellow); }
.conv-tag-color-orange { background: var(--tagcolor-orange); }
.conv-tag-color-red { background: var(--tagcolor-red); }
.conv-tag-color-green { background: var(--tagcolor-green); }
.conv-tag-color-blue { background: var(--tagcolor-blue); }
.conv-tag-color-purple { background: var(--tagcolor-purple); }

/* CLAUDE-P40-VW8-QA, Section 11: the inline tagged-text treatment - a
   real, visible consequence of "Add Tag" on the source text itself
   (app.py's own `hotlinks` filter wraps the exact tagged substring in
   this <mark>, the ONE shared primitive every tag type - Highlight/
   Important/Question/a custom color - renders through). Deliberately
   does NOT reuse --tagcolor-* as a fill background - those are raw,
   saturated swatch-dot colors, never contrast-verified against text,
   and reusing one directly here could easily fail legibility in at
   least one of Light/Dark/Tinted. Instead the FILL reuses
   --surface-selected (already contrast-verified against --text-primary
   in every mode, the same "selected/current" treatment used elsewhere
   in this app) and the per-tag color comes through as a border-bottom
   stripe only - a 2px line has no text-contrast requirement the way a
   fill does, so the raw swatch color is safe to use there directly.

   CLAUDE-CA1D-HIGHLIGHT-CONTRAST-01 (Product Owner visual-accessibility
   correction): `color` was never set here, so a real browser's own
   built-in default `<mark>` style (background: yellow; color: black -
   not a leftover from this file, an actual user-agent stylesheet rule,
   which wins over plain inheritance since inheritance only applies when
   NOTHING - including the UA sheet - already sets the property on the
   element itself) silently forced literal black text regardless of
   theme. Invisible in Light mode (--text-primary is already near-black
   there, so the wrong value looked almost like the right one) but a
   real contrast failure in Dark mode specifically: --dark-surface-
   selected is a dark warm brown and the UA default's literal black
   text against it is exactly the "dark lettering in a brownish
   block" reported live. The fix is the same token this rule's own
   comment already says was chosen for exactly this pairing -
   --text-primary was already contrast-verified against --surface-
   selected in every mode; it simply was never actually applied.

   CLAUDE-CA1D-HIGHLIGHT-CONTRAST-02 (Product Owner visual refinement,
   "translucent focus, not opaque highlight"): the fix above made text
   readable but the fill was still an OPAQUE, mode-invariant neutral
   (--surface-selected) - a solid marker block that fully replaces
   whatever was visually behind it, and looks identical no matter which
   tag color created it. Replaced with a translucent wash of the tag's
   OWN color via color-mix() against the element's own background -
   "content remains primary; highlight is an atmospheric layer behind
   it," per an editor-diff-highlighting mental model. This is a PERSISTENT
   state (the user deliberately tagged this text) so the wash does not
   animate or fade - see .conv-source-flash below for the separate,
   deliberately-animated TEMPORARY-focus sibling of this same pattern.
   22% was verified by hand (relative-luminance contrast ratio, WCAG
   formula) against this app's two extreme surfaces - --canvas (Light,
   near-white) and --dark-canvas (Dark/Tinted/Deep Forest, all a near-
   black canvas) - using the DARKEST/most saturated swatch (--tagcolor-
   red) as the worst case, and cleared 4.5:1 with a wide margin in both
   directions (>10:1 Light, ~14:1 Dark).

   CLAUDE-CA1D-HIGHLIGHT-CONTRAST-03 (Product Owner visual refinement,
   "reduce highlight strength"): 22% still read as "a block of color"
   on a live multi-line passage, not the intended "faint translucent
   tint" - lowered to 12%. Since a LOWER alpha only pulls the resulting
   background closer to the surface the CONTRAST-02 math above already
   verified, contrast can only improve further at 12% than it was at
   22% - no new verification needed, this is a strictly safer point on
   the same curve. The border-bottom stripe (full, un-mixed swatch
   color) is unchanged - it is what still signals "this passage carries
   tag X" from a glance; the fill's job is now just atmosphere, not
   identification. */
.tag-highlight-inline {
    background: color-mix(in srgb, var(--tagcolor-yellow) 12%, transparent);
    color: var(--text-primary);
    border-bottom: 2px solid var(--tagcolor-yellow);
    border-radius: 2px;
    padding: 0.05em 0.1em;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
}
.tag-highlight-inline.conv-tag-color-yellow { background: color-mix(in srgb, var(--tagcolor-yellow) 12%, transparent); border-bottom-color: var(--tagcolor-yellow); }
.tag-highlight-inline.conv-tag-color-orange { background: color-mix(in srgb, var(--tagcolor-orange) 12%, transparent); border-bottom-color: var(--tagcolor-orange); }
.tag-highlight-inline.conv-tag-color-red { background: color-mix(in srgb, var(--tagcolor-red) 12%, transparent); border-bottom-color: var(--tagcolor-red); }
.tag-highlight-inline.conv-tag-color-green { background: color-mix(in srgb, var(--tagcolor-green) 12%, transparent); border-bottom-color: var(--tagcolor-green); }
.tag-highlight-inline.conv-tag-color-blue { background: color-mix(in srgb, var(--tagcolor-blue) 12%, transparent); border-bottom-color: var(--tagcolor-blue); }
.tag-highlight-inline.conv-tag-color-purple { background: color-mix(in srgb, var(--tagcolor-purple) 12%, transparent); border-bottom-color: var(--tagcolor-purple); }

/* A small, quiet text-style action inside a Lists row (Mark complete /
   Reopen / Remove) - .btn's own padding (0.85rem 1.5rem) is sized for a
   standalone page action, far too large for an inline list row. */
.link-button {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 0.72rem;
    color: var(--machine-blue);
    text-decoration: underline;
    cursor: pointer;
    flex-shrink: 0;
}
.link-button:hover { color: var(--text-primary); }

/* Appearance menu (CLAUDE-P40-E3A Section 10; CLAUDE-P40-VW3 replaced
   the single plain/tinted checkbox with three independent modes per
   surface - Light/Dark/Tinted; CLAUDE-P40-VW6 corrected both Dark and
   Tinted's actual coverage). Light is the unmarked default - identical
   to every rule in this file already, nothing added for it. Dark and
   Tinted BOTH now REDEFINE the standard token names locally on the
   surface's own root element (see tokens.css's own comment on why
   scoping, not a file swap, is required here) - every existing
   component rule in this file that already reads
   var(--surface-primary)/var(--text-primary)/etc. repaints correctly
   for free, no per-component change needed.

   CLAUDE-P40-VW6 root cause: VW3's own Tinted implementation never did
   this - it only ever swapped ONE element's own `background` per
   surface to the existing --surface-secondary (Limestone/beige) token,
   never redefined the surface's token SCOPE. Every other element
   inside that surface reading --surface-primary/--border/--text-
   primary directly (finding cards, blank states, form controls, ...)
   kept rendering untinted Light values underneath - the product-owner
   observation "some surfaces become tinted and others do not" was
   exactly this coverage gap, and "the current tint is beige/gold" was
   --surface-secondary's own real, correct, UNRELATED meaning (Limestone
   - "nav surfaces, grouped controls") being reused as if it were a
   dedicated Tinted palette, which it never was. Tinted now uses its own
   --tint-* family (tokens.css - a light navy-blue, further lightened
   by CLAUDE-P40-VW8-QA - see that file's own header comment), the
   exact same redefinition shape Dark already used correctly.

   Menu (.workspace-topbar) is a configurable surface (CLAUDE-P40-VW3) -
   it has no background of its own in its base rule (just a border-
   bottom sitting on --canvas), so this combined rule (below, near
   .chat-region's own rules - deliberately AFTER every one of the five
   surfaces' own base component rules, so a test doing a plain textual
   "first rule whose selector contains .app-main" search still finds
   each surface's real base rule) sets one explicitly for Menu, same as
   it already did for Dark. */
.launcher-identity {
    padding: 0.6rem 0.7rem 1rem;
    border-top: 1px solid var(--border);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}
.launcher-identity-name {
    font-family: var(--font-body);
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 0.3rem 0.55rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-main {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    /* CLAUDE-P40-VW8-QA: a pure layout wrapper now - <main> below is the
       one actual scroll region, so this never becomes a second
       scrolling context of its own (no "duplicate page-level
       scrollbars" - Section 10). */
    overflow: hidden;
}

/* CLAUDE-P40-VW8-QA, Section 10: <main> is the ONE scroll region for
   every page's actual content - Menu (outside .app-main entirely,
   above it in .app-shell) never moves, because it is never an
   ancestor OR a sibling of anything that scrolls; only this element
   does. flex/min-height:0/column so a Workspace page's own
   .workspace-pane-display can, in turn, stretch to fill whatever
   height is actually available (see that rule's own comment) instead
   of shrink-wrapping its content - the direct fix for the "shallow
   white rectangle" Display-division defect, which shared this exact
   root cause (nothing in the ancestor chain ever gave the Display
   grid a real height to fill). Applies to every page sharing
   base.html's shell, not just Workspace - deliberately: the "Menu
   must stay visible while content scrolls" requirement is a property
   of this ONE shared shell, not a Workspace-specific concern (Section
   10's own "avoid... where panel-level scrolling is appropriate" -
   one central rule here, not scattered per-page overrides). Placed
   BEFORE the narrow-viewport padding override directly below, so that
   override still wins on cascade order at <=720px - both are the same
   selector specificity, and only source order decides between them. */
main {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    padding: 0 3rem;
    max-width: 1180px;
    margin: 0 auto;
    width: 100%;
    scrollbar-color: transparent transparent;
}

@media (max-width: 720px) {
    main { padding: 0 1.2rem; }
}

/* -- true zero-state entry shell (pre-authentication) ---------------------
   Deliberately minimal - no launcher panel, no top bar, no workspace
   controls exist pre-auth (see templates/base.html) - this is the entire
   identity footprint of that state, not a scaled-down copy of the app
   shell. The Archiosk wordmark is the deliberate exception to the
   UI-wide Arial Nova Cond rule below - restored to its original
   family/weight, never Arial Nova/Arial Narrow. */
.entry-shell-brand {
    padding: 1.2rem 1.5rem;
    flex-shrink: 0;
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    font-family: "Space Grotesk", sans-serif;
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--text-primary);
}

/* CLAUDE-P40-E2B1, Section G: on narrow screens the Launcher panel
   becomes a real overlay drawer rather than a permanent column -
   exactly the same idiom the Workspace-local Toolbox drawer uses (see
   main.css's own .workspace-pane-toolbox narrow-screen rule), just
   app-wide since the panel itself is now app-wide. The same
   launcher-toggle-btn/html.launcher-hidden mechanism drives this - a
   drawer is just what "shown" looks like at this width. */
@media (max-width: 640px) {
    .launcher-panel {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: min(85vw, 320px);
        z-index: 30;
        border-right: 1px solid var(--border);
    }
}

/* -- hero ---------------------------------------------------------------- */
.hero { padding: 2rem 0 1.5rem; max-width: 780px; }
.eyebrow {
    font-family: var(--font-body);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.85rem;
    color: var(--text-metadata);
    margin-bottom: 1rem;
}
.hero h1 {
    font-family: var(--font-display);
    font-size: 3rem;
    line-height: 1.12;
    margin: 0 0 1.5rem;
    font-weight: 300;
}
.hero-copy { color: var(--text-secondary); font-size: 1.05rem; max-width: 60ch; }
.hero-actions { margin-top: 2.2rem; display: flex; gap: 1rem; }
.hero-actions-center { justify-content: center; }

.upload-form { margin-top: 1.2rem; display: flex; flex-direction: column; align-items: flex-start; gap: 1rem; }
.upload-form-optional { display: flex; gap: 1rem; flex-wrap: wrap; }
/* CLAUDE-P29: Project Operating Environment selector -- deliberately
   plain (border + spacing only, no new accent color) since this is a
   structural/decision element, not a status or emphasis signal; see
   this file's own header comment on when color is/isn't appropriate. */
.operating-environment-fieldset {
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: var(--space-5) var(--space-6);
    width: 100%;
    max-width: 480px;
}
.operating-environment-option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: var(--space-3) 0;
    font-size: var(--text-sm);
}
.operating-environment-confirm {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: var(--text-sm);
    color: var(--text-secondary);
}
.text-input {
    font-family: var(--font-body);
    font-size: 0.85rem;
    padding: 0.6rem 0.8rem;
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 3px;
    color: var(--text-primary);
    width: 100%;
    max-width: 320px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.text-input::placeholder { color: var(--text-disabled); }
.text-input:focus {
    border-color: var(--machine-blue);
    box-shadow: 0 0 0 3px rgba(44, 96, 121, 0.15);
}

/* CLAUDE-CA1D-RECEPTION-FIX-01: password reveal toggle (login only). Absolute
   positioning inside a relative wrapper so it overlays the existing
   .text-input without changing .gateway-field's grid layout. */
.password-field { position: relative; display: flex; }
.password-field .text-input { flex: 1; padding-right: 2.4rem; }
.password-toggle {
    position: absolute;
    right: 0.4rem;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.3rem;
    background: none;
    border: none;
    border-radius: 3px;
    color: var(--text-metadata);
    cursor: pointer;
}
.password-toggle:hover { color: var(--text-primary); }
.password-toggle:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 1px;
}

.btn {
    font-family: var(--font-body);
    font-size: 0.85rem;
    padding: 0.85rem 1.5rem;
    border-radius: 3px;
    border: 1px solid var(--border);
    display: inline-block;
}
/* Frequent primary actions read through tonal contrast (a solid dark fill),
   not through color - see the color-scarcity rule. */
.btn-primary { background: var(--text-primary); color: var(--surface-primary); border-color: var(--text-primary); font-weight: 600; }
.btn-primary:hover { background: var(--text-secondary); text-decoration: none; }
.btn-ghost { color: var(--text-primary); }
.btn-ghost:hover { border-color: var(--border-strong); text-decoration: none; }

/* -- home / project entry (deliberately quiet, not a marketing hero) ---- */
.entry { padding: 1.5rem 0 1rem; max-width: 720px; }
.entry-copy { color: var(--text-secondary); font-size: 0.95rem; max-width: 56ch; margin: 0 0 1rem; }
.entry-actions { display: flex; gap: 1rem; margin-top: 0.8rem; margin-bottom: 1.2rem; }

.entry-recent { max-width: 900px; }
.entry-empty { color: var(--text-secondary); font-size: 0.85rem; }
.project-row-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.project-row {
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 6px;
}
.project-row-link {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    padding: 0.9rem 1.1rem;
    color: var(--text-primary);
}
.project-row-link:hover { border-color: var(--border-strong); text-decoration: none; }
.project-row-name { font-family: var(--font-display); font-size: 0.95rem; }
.project-row-meta {
    font-family: var(--font-body);
    font-size: 0.85rem;
    color: var(--text-metadata);
}
.entry-flag { white-space: nowrap; }
.entry-flag-red { color: var(--failure-red); }
.entry-flag-amber { color: var(--attention-amber); }

/* -- projects directory (cards, not a developer table) ------------------- */
.projects-controls {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin: 1rem 0 1.2rem;
    flex-wrap: wrap;
}
.projects-search { max-width: 280px; margin: 0; }
.project-card-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.7rem; }
.project-card {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}
.project-card-link {
    display: flex;
    flex: 1;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.2rem;
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    min-width: 0;
}
.project-card-link:hover { border-color: var(--border-strong); text-decoration: none; }
.project-card-main {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 0;
}
.project-card-name {
    font-family: var(--font-display);
    font-size: 1rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.project-card-id { font-size: var(--text-sm); color: var(--text-metadata); }
.project-card-meta {
    font-family: var(--font-body);
    font-size: 0.85rem;
    color: var(--text-metadata);
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-shrink: 0;
    white-space: nowrap;
}
.project-card-dot { color: var(--border-strong); }
.project-card-secondary {
    font-family: var(--font-body);
    font-size: 0.85rem;
    color: var(--text-metadata);
    padding: 0 1.2rem 0 0;
    flex-shrink: 0;
}
.project-card-secondary:hover { color: var(--text-primary); }
.projects-empty { color: var(--text-secondary); font-size: 0.9rem; padding: 1.5rem 0; }
.projects-empty .btn { margin-top: 1rem; }

/* CLAUDE-P40-VW7B, Section 4: Vestibule "Current Project" / "Available
   Projects" section labels - same small-caps metadata treatment
   .thumbnails-pane-header h2 already established for a quiet section
   heading, reused rather than a new type style. */
.gateway-vestibule-current-label,
.gateway-vestibule-available-label {
    font-family: var(--font-body);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-metadata);
    margin: 0 0 0.5rem;
}
.gateway-vestibule-current { margin-bottom: 1.2rem; }
/* A real border-WIDTH change (1px -> 2px), not color alone, so "this is
   the currently entered Project" reads even without color vision - the
   "Currently entered" badge text itself is the primary, always-
   sufficient cue (Section 13's "no color-only distinction"). */
.project-card-current .project-card-link {
    border-color: var(--machine-blue);
    border-width: 2px;
}
.project-card-current-badge {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--machine-blue);
}

@media (max-width: 640px) {
    .project-card-link { flex-direction: column; align-items: flex-start; }
    .project-card { flex-direction: column; align-items: stretch; }
    .project-card-secondary { padding: 0 1.2rem 0.9rem; }
}

/* -- chassis step cells (hexagon-clipped) -------------------------------- */
.hive-strip { padding: 3rem 0 5rem; }
.hive-strip h2 {
    font-family: var(--font-display);
    font-size: 1.1rem;
    color: var(--text-metadata);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin-bottom: 2rem;
}
.cell-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1.5rem;
}
.cell {
    background: var(--surface-primary);
    border: 1px solid var(--border);
    padding: 1.6rem 1.4rem 2rem;
    position: relative;
    clip-path: polygon(8% 0, 92% 0, 100% 8%, 100% 92%, 92% 100%, 8% 100%, 0 92%, 0 8%);
}
.cell-index {
    font-family: var(--font-body);
    color: var(--text-secondary);
    font-size: 0.8rem;
}
.cell h3 { font-family: var(--font-display); margin: 0.6rem 0 0.5rem; font-size: 1.15rem; }
.cell p { color: var(--text-secondary); font-size: 0.92rem; margin: 0; }

@media (max-width: 900px) {
    .cell-row { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 560px) {
    .cell-row { grid-template-columns: 1fr; }
    .lattice { max-width: none; }
    .dash-meta { width: 100%; justify-content: space-between; }
}

/* -- page header (dashboard, Case Workspace, Project Home - via the
   `page_header` macro in _macros.html) -------------------------------
   One shape for every page-level header: title block on the left,
   a controls slot on the right. Project Home used to have its own
   separate .project-home-header with a smaller h1 (1.5rem), top-aligned
   instead of bottom-aligned, and no divider - undocumented drift with
   no evidence it was deliberate, reconciled onto this one rule when the
   macro was introduced. */
.dash-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    padding: 1.25rem 0 0.9rem;
    border-bottom: 1px solid var(--border);
    flex-wrap: wrap;
    gap: 1.5rem;
}
.dash-head h1 { font-family: var(--font-display); font-size: 1.8rem; margin: 0.3rem 0 0; font-weight: 300; }
.dash-head-actions { display: flex; gap: 0.6rem; align-items: center; }
.mono { font-family: var(--font-body); color: var(--machine-blue); font-size: 1.1rem; }
.form-error { color: var(--failure-red); }
.dash-meta { display: flex; gap: 2.2rem; }
.meta-stat { text-align: right; }
.meta-num { display: block; font-family: var(--font-display); font-size: 1.9rem; color: var(--text-primary); }
.meta-label { font-family: var(--font-body); font-size: 0.85rem; color: var(--text-metadata); text-transform: uppercase; letter-spacing: 0.06em; }

/* -- honeycomb lattice (signature element) -------------------------------- */
.lattice-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    padding: 1.1rem 0;
    align-items: flex-start;
}
.lattice {
    /* Responsive grid instead of a fixed-width flex-wrap: no magic-number
       dependency between container width / hex width / gap to keep rows
       even, and it can't overflow the page on a narrow viewport. */
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
    gap: 10px;
    flex: 1 1 320px;
    max-width: 640px;
}
.hex {
    aspect-ratio: 92 / 80;
    clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
    background: var(--surface-primary);
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--text-metadata);
    padding: 0.4rem;
    position: relative;
}
.hex.done { background: var(--accepted-green-tint); border-color: var(--accepted-green); color: var(--text-primary); }
.hex.active { border-color: var(--machine-blue); color: var(--text-primary); animation: pulse 2.4s ease-in-out infinite; }
.hex.pending { color: var(--text-metadata); }

@keyframes pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(44, 96, 121, 0.35); }
    50% { box-shadow: 0 0 0 6px rgba(44, 96, 121, 0); }
}

.legend { font-family: var(--font-body); font-size: 0.8rem; color: var(--text-metadata); min-width: 160px; }
.legend-title { text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.85rem; margin-bottom: 0.8rem; }
.dot { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 0.5rem; }
.dot-done { background: var(--accepted-green); }
.dot-active { background: transparent; border: 1px solid var(--machine-blue); }
.dot-pending { background: transparent; border: 1px solid var(--border); }

/* -- registry table -------------------------------------------------------- */
.registry { padding: 0.6rem 0 1.25rem; }
.registry-filter { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 0.8rem 0 0.8rem; }
.chip {
    font-family: var(--font-body);
    font-size: 0.85rem;
    padding: 0.28rem 0.65rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text-metadata);
    cursor: pointer;
    background: transparent;
}
.chip.active { background: var(--surface-selected); border-color: var(--border-strong); color: var(--text-primary); }

/* Bounded, internally-scrolling region - a long registry never grows the
   page unboundedly, and a fixed height (not just max-height) means
   selecting a category never changes this box's own footprint, so
   nothing below it (Audit Trail) can shift merely because a filter
   matched fewer rows. #registry-table-scroll pins the exact height;
   this shared max-height/overflow is the general "long list" treatment
   reused for any other bounded table region (e.g. Audit Trail below). */
.table-scroll { overflow-x: auto; overflow-y: auto; max-height: 360px; }
#registry-table-scroll { height: 360px; }
.registry-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.registry-table th {
    text-align: left;
    font-family: var(--font-body);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-metadata);
    border-bottom: 1px solid var(--border);
    padding: 0.5rem 0.7rem;
    position: sticky;
    top: 0;
    background: var(--surface-primary);
}
.registry-table td { padding: 0.5rem 0.7rem; border-bottom: 1px solid var(--border); color: var(--text-primary); }
.registry-table td:last-child { font-family: var(--font-body); color: var(--machine-blue); }

/* -- governance / audit trail ---------------------------------------------- */
.governance { padding: 0.6rem 0 1.25rem; }

/* -- consistency flags ---------------------------------------------------- */
.consistency { padding: 0.6rem 0 1.25rem; }
.consistency h2 { font-family: var(--font-display); font-size: 1.05rem; margin-bottom: 0.7rem; }
.help-desk h2 { font-family: var(--font-display); font-size: 1.05rem; margin-bottom: 0.7rem; }
.consistency-note, .consistency-clean {
    font-family: var(--font-body);
    font-size: 0.85rem;
    padding: 1rem 1.2rem;
    border: 1px solid var(--border);
    border-radius: 3px;
}
.consistency-note { color: var(--text-secondary); }
.consistency-clean { color: var(--accepted-green); border-color: var(--accepted-green); }

.flag-list { display: grid; gap: 1rem; }
/* A flagged cross-requirement contradiction - genuinely the failure/
   contradiction semantic, not an amber "needs evidence" state. */
.flag-card {
    background: var(--surface-primary);
    border: 1px solid var(--failure-red);
    border-left: 4px solid var(--failure-red);
    border-radius: 3px;
    padding: 1.2rem 1.4rem;
}
.flag-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 0.8rem; }
.flag-req { font-size: var(--text-sm); color: var(--text-primary); padding: 0.6rem 0.8rem; background: var(--surface-secondary); border-radius: 3px; }
.flag-req-label {
    display: block;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--text-metadata);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 0.3rem;
}
.flag-explanation { color: var(--text-secondary); font-size: 0.9rem; margin: 0; }
.export-actions { margin-top: 1.2rem; }

/* -- gateway (login + post-login project gateway) ------------------------- */
.gateway-page { display: flex; justify-content: center; padding: 1.75rem 0; }
.gateway-card {
    width: min(480px, 100%);
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface-primary);
    box-shadow: 0 24px 60px rgba(42, 36, 30, 0.14);
    overflow: hidden;
}
.gateway-brand { display: flex; align-items: center; gap: 1.2rem; padding: 2rem 2rem 1.5rem; }
/* The application's identity mark, flat bee-yellow. */
.gateway-logo {
    display: grid;
    place-items: center;
    flex: 0 0 56px;
    width: 56px;
    height: 56px;
    border-radius: 8px;
    background: var(--bee-yellow);
    box-shadow: inset 0 0 0 1px rgba(42, 36, 30, 0.08);
    color: var(--text-primary);
    font-family: var(--font-display);
    font-size: 1.6rem;
    font-weight: 700;
}
.gateway-brand h1 { font-family: var(--font-display); font-size: 1.8rem; font-weight: 300; margin: 0; color: var(--text-primary); }
.gateway-subtitle { margin: 0.3rem 0 0; color: var(--text-secondary); font-size: var(--text-sm); }
.gateway-divider { height: 1px; margin: 0 2rem; background: var(--border); }
.gateway-section { padding: 1.6rem 2rem 2rem; }
.gateway-section-label {
    font-family: var(--font-body);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.85rem;
    color: var(--text-metadata);
    margin: 0 0 0.3rem;
}
.gateway-section h2 { font-family: var(--font-display); font-size: 1.15rem; margin: 0 0 1.2rem; color: var(--text-primary); }

.gateway-field { display: grid; gap: 0.35rem; margin-bottom: 1rem; }
.gateway-field label {
    font-family: var(--font-body);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-metadata);
}

/* auto-fit, not a fixed 2 columns: one action (a read_only session, which
   only ever sees "Open an existing project") should fill the row, not
   sit half-width with dead space beside it - composition should follow
   how many actions there actually are, not assume a fixed count. */
.gateway-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 0.8rem; }
.gateway-action {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    min-height: 82px;
    padding: 1rem;
    text-align: left;
    text-decoration: none;
    border: 1px solid var(--border);
    border-radius: 5px;
    background: var(--surface-secondary);
    color: var(--text-primary);
    transition: border-color 120ms ease, background 120ms ease, transform 120ms ease;
}
.gateway-action:hover { border-color: var(--border-strong); transform: translateY(-1px); text-decoration: none; }
.gateway-action-primary {
    border-color: var(--border-strong);
    background: var(--surface-selected);
}
.gateway-action-primary:hover { border-color: var(--border-strong); }
.gateway-action-icon {
    display: grid;
    place-items: center;
    flex: 0 0 38px;
    width: 38px;
    height: 38px;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--surface-primary);
    color: var(--text-primary);
    font-size: 1.1rem;
}
.gateway-action strong { display: block; margin-bottom: 0.25rem; font-size: 0.85rem; color: var(--text-primary); }
.gateway-action small { display: block; color: var(--text-secondary); font-size: 0.85rem; line-height: 1.4; }

/* -- gateway login card (compact) -----------------------------------------
   Geometry/spacing/background mirror the archiosk-explorer (port 5173)
   welcome/sign-in card exactly, scoped to .gateway-card-compact so the
   post-login .gateway-card (gateway.html) keeps its original spacious
   layout untouched. */
.gateway-card-compact {
    background-color: rgba(251, 248, 242, 0.75);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(42, 36, 30, 0.1);
    box-shadow: 0 24px 70px rgba(42, 36, 30, 0.16);
}
.gateway-card-compact .gateway-brand {
    gap: 9.6px;
    padding: 16px 32px 12px;
    align-items: flex-end;
}
.gateway-card-compact .gateway-brand h1 { line-height: 1; }
.gateway-card-compact .gateway-section { padding: 12.8px 32px 16px; }
.gateway-card-compact .gateway-section-label { margin-bottom: 19.2px; }
.gateway-card-compact .gateway-field { gap: 3px; margin-bottom: 14px; }
.gateway-card-compact .text-input { max-width: none; }
.gateway-card-compact form .form-error { margin: 0; }
.gateway-card-compact .gateway-signin-button {
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: 10px 16px;
    border-radius: 0;
    text-align: center;
    font-weight: 700;
    margin-top: 14px;
}

.gateway-footer {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.8rem 2rem;
    border-top: 1px solid var(--border);
    background: var(--surface-secondary);
    color: var(--text-metadata);
    font-family: var(--font-body);
    font-size: 0.8rem;
    letter-spacing: 0.02em;
}

/* CLAUDE-P40-VW5: templates/gateway_shell.html's own top-level wrapper -
   a real top bar (.workspace-topbar, reused as-is) above the centered
   action-picker card, structurally never inside .app-shell/.app-main
   (no Lists/Toolbox/Display siblings exist on this page at all - see
   that template's own comment on why). .gateway-page keeps its
   existing centering rule; flex: 1 here just lets it claim the full
   height below the top bar instead of collapsing to content height. */
.gateway-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}
.gateway-shell > .gateway-page {
    flex: 1;
    align-items: center;
}
/* Wider than the shared 480px .gateway-card default (Section 2: "must
   use the available width and remain visually centred") - scoped to
   this modifier only, so login/forgot-password/reset-password's own
   .gateway-card-compact (auth_shell.html) is completely untouched. */
.gateway-card-wide { width: min(920px, 100%); }

/* CLAUDE-P40-D1: the standalone authentication shell (auth_shell.html
   - /login, /forgot-password, /reset-password). Reuses .gateway-card
   and its children as-is for visual consistency with the post-login
   .gateway-page (gateway.html) - only the OUTER container differs,
   since this one is never inside .app-shell/.app-main (no sidebar
   column exists to center against, so it centers in the full
   viewport itself instead of relying on a flex sibling for height). */
.auth-shell-page {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 1.75rem 1rem;
}
.auth-shell-footer {
    color: var(--text-metadata);
    font-family: var(--font-body);
    font-size: 0.78rem;
    letter-spacing: 0.02em;
}

@media (max-width: 560px) {
    /* .gateway-actions no longer needs an override here - auto-fit with
       a minmax floor already collapses to one column once 240px no
       longer fits two side by side. */
    .gateway-footer { flex-direction: column; gap: 0.3rem; }
    .flag-pair { grid-template-columns: 1fr; }
}

.error-page { padding: 3rem 0; text-align: center; }
.error-page h1 { font-family: var(--font-display); font-size: 2.2rem; font-weight: 300; }

/* -- flash messages (post/redirect/get feedback) --------------------------- */
.flash-stack { padding-top: 0.8rem; display: grid; gap: 0.5rem; }
.flash-message {
    font-family: var(--font-body);
    font-size: 0.85rem;
    padding: 0.7rem 1rem;
    border-radius: 3px;
    border: 1px solid var(--border);
}
.flash-error { color: var(--failure-red); border-color: var(--failure-red); background: var(--failure-red-tint); }
.flash-success { color: var(--accepted-green); border-color: var(--accepted-green); background: var(--accepted-green-tint); }

.workspace-link { margin-top: 0.8rem; font-size: var(--text-sm); padding: 0.5rem 1rem; }

/* ============================================================
   Workspace top bar (CLAUDE-P40-E2B, Section A)
   ============================================================ */
/* Deliberately restrained - one row, plain text identity/breadcrumb,
   a handful of small buttons. Never a second "brand card": no
   background fill, no border-radius box, no shadow - the bottom
   border is the only separation from the grid below it, same
   restrained-divider language as .workspace-pane.

   CLAUDE-P40-VW8-QA (panel-border hierarchy correction): this line
   spans the ENTIRE application width, unlike every other "ordinary"
   divider in this file - product-owner report named "the divider below
   the top Menu bar" among the distracting areas. var(--border) is
   already this file's general "quiet divider" token, but at full
   viewport width even the quiet token read as too present. Switched to
   var(--divider-strong) instead - NOT because it's stronger (it isn't;
   it's the same fixed, mode-invariant, deliberately understated color
   Chat's own already-approved resize-handle divider uses, see
   .conversation-dock-resize-handle::before's own comment) but because
   it is the one token in this file proven to read calmly at every
   theme's own background rather than tracking whichever surface
   happens to render it - the same reasoning that token's own original
   comment gives, applied here to a second full-width seam instead of
   only the workspace/Chat one. */
/* CLAUDE-P40-VW7B-QA3 (real-Chromium/Playwright-verified correction):
   QA2's flex-shrink:0 fix (below, on .workspace-topbar-identity) was
   real and still correct as far as it went, but a clean-session
   real-browser reproduction showed the Project-name link still failed
   to navigate. Genuine browser evidence (Playwright against the live
   local app - getBoundingClientRect/elementFromPoint/elementsFromPoint/
   a real .click(), swept across viewport widths from 1920px down to
   600px) found the ACTUAL cause at narrow widths: both
   .launcher-panel (Lists) and .workspace-right-column (Toolbox+Eye)
   become `position: fixed; top: 0; ... z-index: 30` overlay drawers
   below the 640px breakpoint (see each one's own @media rule) - and
   since .workspace-topbar itself was plain `position: static` with no
   z-index, EITHER drawer paints over the ENTIRE topbar, including this
   link, because both drawers start at top:0 rather than below the
   topbar's own height. document.elementFromPoint at the visible
   "Project name" text returned `.tree-leaf.launcher-link.current-
   project` (Lists' own current-Project row) at 600px, not the topbar
   anchor at all - confirming the visible topbar text was being
   REACHED by clicks, just not by the element a user would expect,
   exactly the class of bug QA3 asked to rule out ("whether the visible
   text is rendered by the anchor or another overlapping element").
   Fix: .workspace-topbar gets its own stacking context
   (position:relative) and z-index:31 - one step above the drawers'
   ceiling of 30 (the same "stack higher than anything it could ever
   appear over" idiom this file already uses for
   .conv-selection-toolbar/z-index:70 relative to the 60-ceiling
   Appearance popup) - so the topbar, which is this app's "one shell
   every authenticated page shares" (this rule's own original comment,
   above), can never again be occluded by a drawer at any width,
   without touching either drawer's own top:0/z-index:30 (both still
   correctly cover Display/Chat beneath the topbar, which is the
   intended drawer behavior) and without depending on the topbar's own
   height (which varies - two-line wrap when Document controls are
   present, see QA2's own comment - so an offset like `top:
   <topbar-height>` on the drawers would have been fragile in exactly
   the way a structural fix must not be). Verified with a real
   .click(): fails at 600px before this fix (Timeout, drawer link
   receives it instead), succeeds at every width from 600px through
   1920px after it. */
.workspace-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--divider-strong);
    margin-bottom: 1rem;
    flex-wrap: wrap;
    position: relative;
    z-index: 31;
}
/* CLAUDE-P40-VW7B-QA2: flex-shrink:0 added - a real-browser check found
   that clicking the Foreground Project's own name (menu.context.switch-
   project) did not open the Vestibule. Root cause: this was the ONLY
   one of .workspace-topbar's three flex children without flex-shrink:0
   (.workspace-topbar-controls, the mirror-image region on the right,
   already has it) - #workspace-document-controls (the middle region,
   flex:1 1 auto, actively GROWS to fill space whenever Document
   controls are visible) could squeeze this region's own rendered width
   toward its min-width:0 floor, shrinking the Project-name link's
   actual clickable area toward nothing even though its DOM/href/
   aria-label were always correct - not a JS interception bug, not a
   missing anchor, a pure flex-distribution asymmetry. Now protected at
   its natural content width, exactly like .workspace-topbar-controls
   already is; .workspace-topbar's own flex-wrap:wrap is the safe
   fallback if all three regions' combined natural width ever exceeds
   the viewport (a two-line header, still fully clickable) rather than
   a one-line header with an invisible-width link. .workspace-topbar-
   context's own nested overflow:hidden/text-overflow:ellipsis (below)
   still truncates an unusually long Project+Document name WITHIN this
   now-guaranteed width, unaffected by this change. */
.workspace-topbar-identity {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    min-width: 0;
    flex-shrink: 0;
    overflow: hidden;
}
/* CLAUDE-P40-BRAND1 (product-owner correction): "Archiosk" used to be
   0.85rem/--text-metadata (a MUTED, secondary color) - smaller and
   dimmer than menu.context's own breadcrumb (0.88rem/--text-primary,
   below), so the application's own identity read as LESS prominent
   than a Project/Document breadcrumb, backwards from what identity
   branding should be. Now a real flex row (mark + wordmark, sharing
   ONE link/tab-stop/accessible-name - see the template's own comment)
   at 1.2rem/600 ("Archiosk", within the suggested 18-20px semibold
   range) - genuinely larger and richer than menu.context, which keeps
   its own EXISTING 0.88rem/normal-weight unchanged (already within the
   suggested 14-16px/normal-weight secondary range - real repository
   evidence, not a value invented for this correction). */
.workspace-topbar-brand {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    color: var(--brand-gold);
    flex-shrink: 0;
    text-decoration: none;
}
.workspace-topbar-brand:hover { text-decoration: underline; }
.workspace-topbar-brand:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 2px;
    border-radius: 3px;
}
.workspace-topbar-brand-text {
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-weight: 600;
}
/* The mark is an inline SVG (stroke="currentColor"), so it inherits
   this SAME --brand-gold color for free - one declaration drives both
   the icon and the wordmark, no separate color rule needed for either. */
.archiosk-mark {
    flex-shrink: 0;
    align-self: center;
}
/* CLAUDE-P40-BRAND1: no per-Appearance override rule here on purpose -
   .workspace-topbar is already one of the combined "owned surface
   roots" further down this file that locally redefines the standard
   token names per Appearance (the same block --text-primary/the
   semantic accents already live in); --brand-gold is redefined there
   too, so this rule's own `color: var(--brand-gold)` above already
   repaints correctly per Appearance for free, the same way every
   other token-driven rule in this file does. */
.workspace-topbar-context {
    /* CLAUDE-P40-BRAND1: deliberately kept as its own literal value, not
       var(--text-sm) - this rule's own size is verified elsewhere
       (test_p40brand1_brand_mark.py) to sit in a specific relationship
       to the brand text's own size and the 14-16px secondary-text
       range; consolidating it into the shared token would be a genuine
       (if tiny) value change to a pairing already deliberately tuned,
       not a no-op rename like the CLAUDE-POSTCAMEL-P02-ST1 consolidation
       elsewhere in this file. */
    font-size: 0.88rem;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* CLAUDE-P40-VW7B, Section 5: the Foreground Project's own breadcrumb
   segment is now a real link into the Project Vestibule (see the
   template's own comment) - same color as the plain text it replaces
   (inherits .workspace-topbar-context's --text-primary; a link here
   must not read as a DIFFERENT, more/less important piece of text than
   its neighbors), no underline at rest, real hover/focus-visible
   affordance so it still reads as interactive on inspection. */
.workspace-topbar-project {
    color: inherit;
    text-decoration: none;
}
.workspace-topbar-project:hover { text-decoration: underline; }
.workspace-topbar-project:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 2px;
    border-radius: 2px;
}
/* CLAUDE-POSTCAMEL-TOPMENU-FIX1: the link above deliberately keeps the
   SAME text color/weight as its plain-text neighbors (see that rule's
   own comment) - this chevron is the one visual signal that it's a
   control, not a second color decision. var(--text-secondary) is the
   same "less prominent than the primary reading" token .workspace-
   topbar-sep/.workspace-topbar-doc already use immediately below, not a
   new one; sized down and given breathing room so it reads as a small
   indicator, never competing with the project name itself for
   attention. */
.workspace-topbar-project-chevron {
    display: inline-block;
    margin-left: 0.3rem;
    font-size: 0.65em;
    color: var(--text-secondary);
    vertical-align: middle;
}
.workspace-topbar-sep { color: var(--text-secondary); margin: 0 0.3rem; }
.workspace-topbar-doc { color: var(--text-secondary); }
.workspace-topbar-badge {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--attention-amber);
    margin-left: 0.4rem;
}
/* CLAUDE-P40-VW7A-QA (Move Document Controls into the Top Application
   Menu): the central region between the breadcrumb and Display Layout/
   Appearance/Account - flex:1 so it claims whatever space is left
   between those two (which don't grow), and centers its own content
   within that space. Deliberately styled to "read as part of the
   application, not a bright toolbar pasted over it" - no per-button
   borders (unlike .workspace-topbar-btn above), quiet text color,
   background only on hover/focus, the same restrained language
   .conv-selection-btn already established for a comparable dense
   inline-action row. */
.workspace-topbar-document-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
}
.workspace-topbar-document-controls[hidden] { display: none; }
.doc-controls-group {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    min-width: 0;
}
.doc-control-btn {
    font-family: var(--font-body);
    font-size: 0.8rem;
    color: var(--text-secondary);
    background: none;
    border: none;
    border-radius: 3px;
    padding: 0.3rem 0.45rem;
    cursor: pointer;
    line-height: 1;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
}
.doc-control-btn:hover:not(:disabled) { background: var(--surface-hover); color: var(--text-primary); text-decoration: none; }
.doc-control-btn:focus-visible { outline: 2px solid var(--machine-blue); outline-offset: 1px; }
.doc-control-btn:disabled { color: var(--text-disabled); cursor: default; }
.doc-page-nav {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.doc-page-input {
    width: 2.6em;
    text-align: center;
    font-family: var(--font-body);
    font-size: 0.8rem;
    padding: 0.2rem 0.3rem;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--surface-primary);
    color: var(--text-primary);
}
.doc-page-total { color: var(--text-metadata); }
.doc-page-total:not(:empty)::before { content: "/ "; }
.doc-zoom-level {
    font-size: 0.78rem;
    color: var(--text-metadata);
    min-width: 3em;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.doc-controls-divider { width: 1px; height: 1.1em; background: var(--border); margin: 0 0.2rem; flex-shrink: 0; }
.doc-search-input {
    width: 9rem;
    max-width: 30vw;
    font-family: var(--font-body);
    font-size: 0.8rem;
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--surface-primary);
    color: var(--text-primary);
}
.doc-search-count { font-size: 0.75rem; color: var(--text-metadata); min-width: 2.5em; }
/* CLAUDE-P40-VW7A-QA, Section "Responsive behavior": hidden until
   static/js/pdf_viewer.js's own matchMedia(900px) listener marks it
   active (narrow viewport) and re-parents .doc-controls-secondary's
   real DOM node into #doc-controls-overflow-panel below - not a
   second, cloned copy of the same controls. */
.doc-controls-overflow { position: relative; display: none; }
.doc-controls-overflow.doc-controls-overflow-active { display: inline-flex; }
.doc-controls-overflow-summary { list-style: none; cursor: pointer; }
.doc-controls-overflow-summary::-webkit-details-marker { display: none; }
.doc-controls-overflow-panel {
    position: absolute;
    top: calc(100% + 0.3rem);
    right: 0;
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.4rem;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.15rem;
    z-index: 60;
    min-width: 170px;
    box-shadow: none;
}
.doc-controls-overflow-panel .doc-control-btn { justify-content: flex-start; }
.doc-controls-overflow-panel .doc-controls-divider { width: auto; height: 1px; margin: 0.2rem 0; }
.doc-controls-overflow-panel .doc-search-input { width: 100%; max-width: none; }

.workspace-topbar-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}
.workspace-topbar-btn {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--text-secondary);
    background: none;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 0.35rem 0.65rem;
    cursor: pointer;
    list-style: none;
    display: inline-block;
}
.workspace-topbar-btn::-webkit-details-marker { display: none; }
.workspace-topbar-btn:hover,
.workspace-topbar-btn[aria-expanded="true"] {
    color: var(--text-primary);
    border-color: var(--border-strong);
}
/* CLAUDE-CA1D-INSTRUMENT-RAIL-01: the "quiet global machine fact" line
   (Plan-Mode report, Section D.2) - deliberately NOT a peer of
   .workspace-topbar-btn above: no border/background at rest, matching
   the de-boxing discipline's "ending-line / side separation rather than
   top-and-bottom boxing" idiom already established for
   .conv-operational-actions .review-btn - a single underline appears on
   hover/focus, quiet metadata color at rest, same font-size as
   .doc-zoom-level's own plain status text. Only ever rendered for an
   admin-relevant anomaly (see base.html), so at rest this adds nothing
   to an already-busy top bar. */
.workspace-topbar-status {
    font-family: var(--font-body);
    font-size: 0.78rem;
    color: var(--text-metadata);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    padding-bottom: 0.1rem;
}
.workspace-topbar-status:hover,
.workspace-topbar-status:focus-visible {
    color: var(--text-primary);
    border-bottom-color: currentColor;
}
/* The top-bar dropdown menus (Display Layout, Appearance, Account) are
   real interactive control surfaces, not decorative Display background
   - the same exemption Section E already grants the composer/focus
   states/warnings; a bordered popover here is functional chrome, not
   the thing Section E asks to de-tint. CLAUDE-P40-E3A: generalized from
   the old two-menu (.workspace-layout-menu/.workspace-topbar-overflow)
   set to three (.workspace-layout-menu/.workspace-appearance-menu/
   .workspace-user-menu), all sharing the same popover idiom. */
.workspace-layout-menu,
.workspace-appearance-menu,
.workspace-user-menu {
    position: relative;
}
.workspace-layout-options,
.workspace-appearance-options,
.workspace-user-options {
    position: absolute;
    top: calc(100% + 0.3rem);
    right: 0;
    /* CLAUDE-P40-VW6: a solid token color (never rgba/translucent) - the
       "text beneath the Appearance popup remains visible through it"
       report was, per this stage's own diagnosis, primarily the popup
       sitting BELOW the Display context menu's z-index (40) with no
       comfortable margin (was 20) rather than a transparency defect;
       raised well above every other overlay in this file (see the
       z-index audit note - nothing else on the page exceeds 40) so this
       menu reliably paints over Toolbox/Display/Lists content
       regardless of what else is open. */
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.4rem;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    z-index: 60;
    min-width: 170px;
}
/* CLAUDE-POSTCAMEL-PROJECT-CONTEXT-01: the Project Context control joins
   the SAME popover idiom as the three menus above, but is kept as its
   own separate rule (duplicating, not extending, the shared selector
   group above) rather than folding it into that exact list - two
   existing tests (tests/test_p40e3a_qa_reconciliation.py,
   tests/test_p40vw6_theme_correction.py) assert against that precise
   3-selector string verbatim (z-index/stacking and "never rgba"
   audits), and widening it to 4 would break both for a reason
   unrelated to what either test actually checks. Same properties,
   genuinely a duplicate rule, not a divergent one. */
.workspace-project-context-menu {
    position: relative;
}
.workspace-project-context-options {
    position: absolute;
    top: calc(100% + 0.3rem);
    right: 0;
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.4rem;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    z-index: 60;
    min-width: 170px;
}
/* CLAUDE-P40-VW3: the Light/Dark/Tinted-per-surface matrix - real
   tabular data (row = surface, column = mode), not decoration, so a
   real <table> with row/col headers plus each radio's own aria-label
   (belt-and-braces: correct under table navigation AND under a plain
   linear read). Sits inside .workspace-appearance-options above, which
   already supplies this popover's own background/border/padding - this
   only lays out the grid itself, compact enough that 5 rows x 3 modes
   doesn't turn the popover into its own scrolling panel.

   CLAUDE-P40-VW8-QA (Approved Theme Set): a 4th column (Deep Forest)
   added two-word header text ("Midnight Blue") wide enough to grow the
   popover past the viewport on a narrow screen if left unconstrained -
   .workspace-appearance-options below now caps its own width, and
   header cells are left free to wrap (no white-space:nowrap - only the
   row-header/surface-name column has that, unchanged) so the table
   itself is squeezed by the popover's max-width rather than pushing it
   wider. */
.workspace-appearance-options {
    max-width: min(320px, 94vw);
}
/* CLAUDE-POSTCAMEL-PROJECT-CONTEXT-01: same shared popover shell as
   Display Layout/Appearance above, just wider (holds prose + a
   textarea, not a compact matrix) and capped in height with its own
   scroll - a long History list must never grow the popover off-screen. */
.workspace-project-context-options {
    max-width: min(360px, 94vw);
    max-height: min(480px, 80vh);
    overflow-y: auto;
}
.workspace-project-context-text {
    font-size: var(--text-sm);
    color: var(--text-primary);
    white-space: pre-wrap;
    margin: 0 0 0.2rem;
}
.workspace-project-context-subsection {
    border-top: 1px solid var(--border);
    padding-top: 0.4rem;
    margin-top: 0.3rem;
}
.workspace-project-context-subsection summary {
    cursor: pointer;
    font-size: var(--text-sm);
    color: var(--machine-blue);
}
.workspace-project-context-history {
    list-style: none;
    margin: 0.4rem 0 0;
    padding: 0;
    display: grid;
    gap: 0.5rem;
}
.workspace-project-context-history li {
    border-bottom: 1px solid var(--border);
    padding-bottom: 0.4rem;
    font-size: var(--text-sm);
}
.workspace-project-context-history li p:first-child { margin: 0 0 0.15rem; white-space: pre-wrap; }
/* CLAUDE-POSTCAMEL-PROJECT-CONTEXT-01: Document Context - a plain
   in-flow <details>, same idiom as the Files folder-row actions
   disclosure above, just not absolutely-positioned (this one sits
   directly in the Display document pane, not a narrow sidebar row). */
.document-context-panel { margin: 0.6rem 0; }
.document-context-panel summary { cursor: pointer; font-size: var(--text-sm); color: var(--machine-blue); }
.document-context-text { font-size: var(--text-sm); color: var(--text-primary); white-space: pre-wrap; margin: 0.3rem 0; }
.appearance-matrix {
    border-collapse: collapse;
    font-size: var(--text-sm);
    width: 100%;
}
.appearance-matrix th,
.appearance-matrix td {
    padding: 0.2rem 0.3rem;
    text-align: center;
}
.appearance-matrix thead th {
    color: var(--text-metadata);
    font-weight: 400;
    font-size: var(--text-xs);
    word-break: normal;
    overflow-wrap: break-word;
}
.appearance-matrix tbody th {
    text-align: left;
    font-weight: 500;
    color: var(--text-primary);
    padding-right: 0.6rem;
    white-space: nowrap;
}
.appearance-matrix input[type="radio"] {
    margin: 0;
    cursor: pointer;
}
/* CLAUDE-P40-VW8-QA, Section 5: the All row sits above the five
   per-surface rows, set apart by a divider (not a fill/box - this
   file's own "no cards/shadows" discipline) so it visibly reads as a
   universal control, not a sixth surface. */
.appearance-matrix-all-row th,
.appearance-matrix-all-row td {
    border-bottom: 1px solid var(--border);
    padding-bottom: 0.4rem;
}
.appearance-matrix tbody tr:nth-child(2) th,
.appearance-matrix tbody tr:nth-child(2) td {
    padding-top: 0.4rem;
}
.appearance-mixed-note {
    font-size: var(--text-xs);
    color: var(--text-metadata);
    margin: 0.3rem 0 0;
}
/* Standard visually-hidden pattern: present to assistive tech and
   keyboard navigation, removed from normal visual flow only - never
   `display: none`, which would also remove it from the accessibility
   tree. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
.workspace-overflow-item {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--text-primary);
    background: none;
    border: none;
    text-align: left;
    padding: 0.35rem 0.5rem;
    border-radius: 3px;
    cursor: pointer;
    text-decoration: none;
    display: block;
    width: 100%;
}
.workspace-overflow-item:hover {
    background: var(--surface-hover);
}
/* CLAUDE-P40-VW7A: the UI Reference Mode toggle is a <label> wrapping a
   checkbox, not a plain <a>/<button> like its .workspace-overflow-item
   siblings - this override keeps it visually consistent with them
   (same padding/hover/radius) while letting the checkbox sit inline. */
.workspace-overflow-checkbox {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    cursor: pointer;
}
.workspace-overflow-checkbox input { margin: 0; }
.workspace-user-name {
    font-weight: 600;
    margin-right: 0.2rem;
}

/* Display Layout menu internals (CLAUDE-P40-E3A, Section 6; CLAUDE-P40-
   VW4 replaced the old either/or orientation choice with two independent
   numeric steppers, one per axis - the old .workspace-layout-orientation/
   .workspace-layout-option radiogroup this comment used to describe is
   retired, no markup references it anymore): a numeric stepper (never a
   bare text field), Apply - nothing here re-renders on every keystroke,
   only on the explicit Apply click. The same controls are reused inside
   the per-division right-click context menu (#display-context-menu)
   below. */
.workspace-layout-quantity-label {
    display: block;
    font-size: var(--text-xs);
    color: var(--text-metadata);
    margin-bottom: 0.15rem;
}
.workspace-layout-limit-note {
    font-size: var(--text-xs);
    color: var(--text-metadata);
    margin: 0.3rem 0;
}
.workspace-layout-quantity {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 0.3rem 0;
}
.workspace-layout-stepper {
    font-family: var(--font-body);
    font-size: 0.95rem;
    width: 1.8rem;
    height: 1.8rem;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--surface-primary);
    color: var(--text-primary);
    cursor: pointer;
}
.workspace-layout-stepper:hover { background: var(--surface-hover); border-color: var(--border-strong); }
/* CLAUDE-P40-VW4, Requirement 5/6: the relevant stepper is disabled the
   moment incrementing it would exceed six Displays (or decrementing
   below one) - token-based, not a hardcoded gray, so it stays legible
   under every VW3 appearance mode. */
.workspace-layout-stepper:disabled {
    color: var(--text-disabled);
    border-color: var(--border);
    background: var(--surface-primary);
    cursor: not-allowed;
}
.workspace-layout-stepper:disabled:hover { background: var(--surface-primary); border-color: var(--border); }
.workspace-layout-quantity-value {
    font-family: var(--font-body);
    font-variant-numeric: tabular-nums;
    font-size: 0.9rem;
    min-width: 1.2rem;
    text-align: center;
}
.workspace-layout-apply {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    width: 100%;
    padding: 0.4rem 0.5rem;
    margin-top: 0.2rem;
    border: 1px solid var(--border-strong);
    border-radius: 3px;
    background: transparent;
    color: var(--text-primary);
    cursor: pointer;
}
.workspace-layout-apply:hover { background: var(--surface-hover); }

/* Appearance menu (Section 10): plain checkbox rows, one per region -
   applies the SAME existing plain/tinted presentation choice
   independently to Lists/Display/Toolbox/Chat, never a new color. */
.workspace-appearance-option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--text-primary);
    padding: 0.3rem 0.5rem;
    cursor: pointer;
}

@media (max-width: 640px) {
    .workspace-topbar-context { max-width: 40vw; }
}

/* ============================================================
   Workspace — Lists | Display | Toolbox, Chat full-width beneath
   ============================================================ */
/* CLAUDE-P40-E3A: the old .case-workspace grid (Display|Toolbox columns,
   Chat confined beneath Display only) is retired. Lists, Display and
   Toolbox are now three flex siblings inside base.html's own
   .app-shell-body row (.launcher-panel/.app-main/.workspace-pane-toolbox
   - see that rule above); Chat is a fourth, full-width flex row
   beneath .app-shell-body, inside .app-shell itself (Section 9). Flexbox
   rather than a named-area grid was chosen specifically because it makes
   "closing a Display causes the remaining Displays to expand" (Section
   6) and "Toolbox collapsing lets Display expand into the released
   space" (Section 7) automatic consequences of flex:1 on .app-main and
   display:none on a hidden sibling, rather than something that needs a
   grid-template-areas rewrite on every state change.

   Geometry reasoned from CSS's specified behavior, not confirmed against
   a real rendered browser - no browser/screenshot tool exists in this
   environment. Treat as reasoned, not proven, until someone resizes a
   real window through each state (see this stage's own completion
   report for the browser-validation limitation this carries forward). */
/* CLAUDE-P40-EYE1, Section 3: was html.toolbox-hidden .workspace-pane-
   toolbox - now targets .workspace-right-column, the new full-height
   column containing BOTH Toolbox and Eye, so hiding it removes both
   panes AND the divider between them (a descendant, no separate rule
   needed) with no leftover empty panel/gutter/reserved width, exactly
   the same display:none mechanism as before, just retargeted to the
   new outer column. */
html.toolbox-hidden .workspace-right-column {
    display: none;
}
/* CLAUDE-P40-E2B, Section E, carried forward: an explicit plain/neutral
   surface (--surface-primary, near-white), deliberately NOT the app's
   own warmer --canvas background - so an embedded Document's own
   natural white page background sits flush against Display without a
   visible color seam. No border/shadow/radius here - a plain fill only.
   CLAUDE-P40-E3A, Section 10: this IS "Default Display is plain white" -
   nothing to change here, --surface-primary already was and remains the
   untinted default; .appearance-tinted (below) is the only thing that
   ever swaps it. */
.workspace-pane-display {
    min-width: 0;
    min-height: 100%;
    flex: 1;
    display: flex;
    flex-direction: column;
    background: var(--surface-primary);
}
.app-main.appearance-tinted .workspace-pane-display,
.app-main.appearance-dark .workspace-pane-display {
    background: var(--surface-primary);
    color: var(--text-primary);
}

/* CLAUDE-P40-E3A, Section 6; CLAUDE-P40-VW4 replaced the single either/
   or orientation + one shared quantity with a genuine two-axis grid -
   Vertical divisions (--display-v, columns) and Horizontal divisions
   (--display-h, rows), independently 1-6, applied via Apply (never a
   fixed preset menu, the old [data-layout="single/side-by-side/stacked/
   grid"] system this already replaced once). A true V x H rectangle has
   14 valid combinations with V*H<=6 (not a linear 1-6 range), too many
   to enumerate as static [data-orientation][data-count] attribute
   selectors the way the single-axis version did - static/js/
   case_workspace.js's own applyLayout sets --display-v/--display-h as
   inline custom properties instead, and grid-template-columns/rows
   below reads them directly. Mobile-first: the base rule always stacks
   divisions in one column regardless of the applied V/H - the real
   multi-column/multi-row geometry only applies above the 900px
   breakpoint further down, where there's room for it (Section 11:
   Display remains usable, never forced into unreadably narrow slices).
   Divisions are separated only by a restrained 1px divider line
   (Section 5 - "no cards, shadows, rounded containers"), never a
   bordered/shadowed box per division - a `gap` the same color as
   --border, with each division painting its own --surface-primary
   background over it, is the simplest way to get a real hairline on
   BOTH axes of a true 2D grid (the old border-swaps-side-per-
   orientation technique didn't generalize past one axis). */
.display-divisions {
    display: grid;
    grid-template-columns: 1fr;
    /* CLAUDE-P40-VW8-QA: an explicit row template even at the base
       (mobile-first, single-column) width, not just at the 900px+
       breakpoint below - a 1fr row track only ever distributes real
       space if the GRID CONTAINER itself has a defined height to
       divide among them, which flex:1/min-height:100% (this rule)
       plus .workspace-pane-display's own flex:1 (above) now provide.
       Without a real height here, "1fr" silently degrades to
       content's own natural size regardless of what the row template
       says - the actual root cause of the "shallow white rectangle"/
       "small patches" Display-division defects, not a missing grid
       declaration on its own. */
    grid-template-rows: repeat(var(--display-h, 1), 1fr);
    grid-auto-flow: row;
    gap: 1px;
    background: var(--border);
    flex: 1;
    min-height: 100%;
}
.display-division {
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--surface-primary);
    /* Uniform on every division, including index 0 - a per-edge "no
       padding on whichever side touches the pane's own edge" rule
       doesn't generalize cleanly across an arbitrary V x H grid (which
       divisions sit on the top/left edge depends on both axes at once,
       not just "is this the first one"), and VW4's own scope is the
       Vertical/Horizontal split itself, not a pixel-level padding
       reconciliation. */
    padding: 1.25rem;
}
/* Only the first [data-count] divisions (always 0..count-1, in document
   order) are ever shown - divisions beyond the applied count stay in
   the DOM (their picker/content state is never lost) but are not
   displayed, same as the old [data-layout="single"] behaviour.
   [data-count] is still vertical*horizontal (set alongside --display-v/
   --display-h by the same applyLayout call) - this show/hide table
   itself is unchanged from before VW4, since which INDIVIDUAL divisions
   are visible only ever depended on the total, never on the
   arrangement. */
.display-divisions[data-count="1"] [data-division]:not([data-division="0"]) { display: none; }
.display-divisions[data-count="2"] [data-division="2"],
.display-divisions[data-count="2"] [data-division="3"],
.display-divisions[data-count="2"] [data-division="4"],
.display-divisions[data-count="2"] [data-division="5"] { display: none; }
.display-divisions[data-count="3"] [data-division="3"],
.display-divisions[data-count="3"] [data-division="4"],
.display-divisions[data-count="3"] [data-division="5"] { display: none; }
.display-divisions[data-count="4"] [data-division="4"],
.display-divisions[data-count="4"] [data-division="5"] { display: none; }
.display-divisions[data-count="5"] [data-division="5"] { display: none; }

@media (min-width: 900px) {
    .display-divisions {
        grid-template-columns: repeat(var(--display-v, 1), 1fr);
        grid-template-rows: repeat(var(--display-h, 1), 1fr);
    }
}

.display-division-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
    font-size: 0.78rem;
    color: var(--text-metadata);
    /* CLAUDE-P40-VW8-QA: .display-division is now a flex column (header
       + empty-state/content) - the header keeps its own natural size,
       never stretched or shrunk, so .display-division-content/.
       display-division-empty (both flex:1 below) get the entire
       remaining, real height to fill. */
    flex-shrink: 0;
}
.display-division-header-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* CLAUDE-P40-E3A, Section 6: "one Display is always the active target" -
   a dashed outline (functional state, not decorative framing - the same
   exemption already granted to focus rings/selected nav rows elsewhere
   in this file) marks which division the next Lists Document click will
   populate. Division 0 has no such outline: it's the default target and
   is never ambiguous about that. */
.display-division.active:not(.display-division-primary) {
    outline: 1px dashed var(--machine-blue);
    outline-offset: 4px;
}
.display-division.active .display-division-header-name {
    color: var(--machine-blue);
    font-weight: 600;
}
.display-division-close {
    font-family: var(--font-body);
    font-size: 0.9rem;
    color: var(--text-secondary);
    background: none;
    border: none;
    cursor: pointer;
    flex-shrink: 0;
    line-height: 1;
}
.display-division-close:hover { color: var(--failure-red); }

/* CLAUDE-P40-DTAB1: the Document tab strip - Documents only (Section 2's
   own scope), Division-0-only, a persistent utility above whatever
   content is currently in Display. Compact: no unnecessary height,
   .document-tab-list is the one scroll region (horizontal overflow,
   never wraps/shrinks labels below a readable width), .document-tabs-
   overflow (the "All Tabs" control) stays fixed at the strip's own
   trailing edge regardless of scroll position. */
.document-tab-strip {
    display: flex;
    align-items: flex-end;
    gap: 0.3rem;
    margin-bottom: 0.6rem;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    min-width: 0;
}
.document-tab-strip[hidden] { display: none; }
.document-tab-list {
    display: flex;
    align-items: flex-end;
    gap: 0.2rem;
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-color: transparent transparent;
}
/* CLAUDE-PANEL-CALM-02: this rail's own WebKit scrollbar rules moved
   into the shared, hover-gated block further below (with .attention-
   strip-list, which uses the identical pattern) - see that block's own
   comment. */
/* CLAUDE-P40-DTAB1, Section 3/13: a real, keyboard-operable tab, never a
   decorative div - color (data-tab-color, below) is an accent stripe
   only; the ACTIVE tab's own non-color cues (background, bottom-border
   weight/color, font-weight) are what Section 8 requires ("must also
   use shape/underline/border/weight... not color alone"). */
.document-tab {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    max-width: 190px;
    min-width: 96px;
    padding: 0.4rem 0.55rem;
    border: 1px solid transparent;
    border-bottom: none;
    border-radius: 4px 4px 0 0;
    background: none;
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-decoration: none;
    cursor: pointer;
    flex-shrink: 0;
    position: relative;
    /* the curated color accent - a 3px top stripe, present only when
       data-tab-color is set (the CSS var is undefined -> no visible
       border otherwise, no JS branching needed to omit it). */
    border-top: 3px solid var(--document-tab-accent, transparent);
}
.document-tab:hover {
    background: var(--surface-hover);
    color: var(--text-primary);
    text-decoration: none;
}
.document-tab:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: -2px;
}
.document-tab[aria-selected="true"] {
    background: var(--surface-primary);
    color: var(--text-primary);
    font-weight: 600;
    border-color: var(--border);
    border-bottom: 2px solid var(--machine-blue);
    margin-bottom: -1px;
}
.document-tab[data-tab-color="gold"] { --document-tab-accent: var(--tabcolor-gold); }
.document-tab[data-tab-color="turquoise"] { --document-tab-accent: var(--tabcolor-turquoise); }
.document-tab[data-tab-color="lapis"] { --document-tab-accent: var(--tabcolor-lapis); }
.document-tab[data-tab-color="terracotta"] { --document-tab-accent: var(--tabcolor-terracotta); }
.document-tab[data-tab-color="green"] { --document-tab-accent: var(--tabcolor-green); }
.document-tab[data-tab-color="purple"] { --document-tab-accent: var(--tabcolor-purple); }
.document-tab-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
/* CLAUDE-P40-DTAB1, Section 4: "distinguish the temporary preview tab
   visually without relying on color alone" - italic label text + a
   dashed (not solid) selected-state underline together, neither of
   which is a color cue. */
.document-tab.document-tab-preview .document-tab-label { font-style: italic; }
.document-tab.document-tab-preview[aria-selected="true"] { border-bottom-style: dashed; }
.document-tab-close {
    flex-shrink: 0;
    background: none;
    border: none;
    color: var(--text-metadata);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
    padding: 0.15rem 0.3rem;
    border-radius: 3px;
}
.document-tab-close:hover { background: var(--surface-hover); color: var(--failure-red); }
.document-tab-close:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 1px;
}
.document-tab-menu-btn {
    flex-shrink: 0;
    background: none;
    border: none;
    color: var(--text-metadata);
    cursor: pointer;
    font-size: 0.7rem;
    line-height: 1;
    padding: 0.15rem 0.2rem;
    border-radius: 3px;
}
.document-tab-menu-btn:hover { background: var(--surface-hover); color: var(--text-primary); }
.document-tab-menu-btn:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 1px;
}
/* The per-tab context menu and the All-Tabs/Hidden-Tabs overflow panel
   share the same restrained popover idiom the top-bar menus already
   established (.workspace-layout-options etc.) - a bordered, real
   interactive control surface, not decorative Display background. */
.document-tab-menu,
.document-tabs-overflow-panel {
    position: absolute;
    z-index: 40;
    background: var(--surface-primary);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
    padding: 0.4rem;
    min-width: 180px;
    font-size: var(--text-sm);
}
.document-tab-menu-item,
.document-tab-color-option,
.document-hidden-tab-item {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    color: var(--text-primary);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    padding: 0.35rem 0.5rem;
    border-radius: 4px;
    cursor: pointer;
}
.document-tab-menu-item:hover,
.document-tab-color-option:hover,
.document-hidden-tab-item:hover,
.document-tab-menu-item:focus-visible,
.document-tab-color-option:focus-visible,
.document-hidden-tab-item:focus-visible {
    background: var(--surface-hover);
}
.document-tab-color-swatch {
    display: inline-block;
    width: 0.75rem;
    height: 0.75rem;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
    flex-shrink: 0;
}
.document-tab-color-swatch[data-tab-color="gold"] { background: var(--tabcolor-gold); }
.document-tab-color-swatch[data-tab-color="turquoise"] { background: var(--tabcolor-turquoise); }
.document-tab-color-swatch[data-tab-color="lapis"] { background: var(--tabcolor-lapis); }
.document-tab-color-swatch[data-tab-color="terracotta"] { background: var(--tabcolor-terracotta); }
.document-tab-color-swatch[data-tab-color="green"] { background: var(--tabcolor-green); }
.document-tab-color-swatch[data-tab-color="purple"] { background: var(--tabcolor-purple); }
.document-tab-color-swatch[data-tab-color="none"] { background: transparent; }
.document-tab-menu-divider {
    height: 1px;
    background: var(--border);
    margin: 0.3rem 0.2rem;
}
.document-tabs-overflow { position: relative; }
.document-tabs-overflow-summary {
    list-style: none;
    background: none;
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 0.3rem 0.45rem;
    flex-shrink: 0;
    font-size: 0.75rem;
}
.document-tabs-overflow-summary::-webkit-details-marker { display: none; }
.document-tabs-overflow-summary:hover,
.document-tabs-overflow[open] .document-tabs-overflow-summary {
    color: var(--text-primary);
    border-color: var(--border-strong);
}
.document-tabs-overflow-panel {
    top: calc(100% + 0.3rem);
    right: 0;
    max-height: 60vh;
    overflow-y: auto;
    scrollbar-color: transparent transparent;
}
.document-hidden-tabs-heading {
    font-family: var(--font-body);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.7rem;
    color: var(--text-metadata);
    padding: 0.3rem 0.5rem 0.1rem;
}
.document-hidden-tab-item-original-name {
    color: var(--text-metadata);
    font-size: 0.72rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.document-tabs-empty-note {
    color: var(--text-metadata);
    font-size: 0.78rem;
    padding: 0.35rem 0.5rem;
}

/* CLAUDE-P40-VW7B, Section 8: the Investigation Attention strip - same
   compact, restrained tab-strip idiom as .document-tab-strip
   immediately above (reused deliberately, "do not introduce a
   separate visual language" - Section 13), a genuinely distinct
   control family (Investigations, not Documents) rather than a shared
   selector, since the two are never meant to merge or be
   interchangeable. Hidden entirely when attention is empty - "compact,
   visually restrained," never a permanent empty bar. */
.attention-strip {
    display: flex;
    align-items: flex-end;
    gap: 0.3rem;
    margin-bottom: 0.6rem;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    min-width: 0;
}
.attention-strip[hidden] { display: none; }
.attention-strip-list {
    display: flex;
    align-items: flex-end;
    gap: 0.2rem;
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-color: transparent transparent;
}
/* CLAUDE-PANEL-CALM-02: this rail's own WebKit scrollbar rules moved
   into the shared, hover-gated block further below (with .document-
   tab-list, which uses the identical pattern) - see that block's own
   comment. */
/* CLAUDE-INVESTIGATION-ATTENTION-02: deliberately NOT position:fixed/
   role=dialog like .attention-capacity-dialog below - this sits in
   normal document flow, right where the attention strip would have
   shown a fifth position, and never steals focus or blocks the page
   underneath it. Neutral/informational, not --failure-red or
   --attention-amber (tokens.css's own grammar: those mean a real
   contradiction/pending-evidence state, and "you have more saved work
   than fits in Attention" is neither). */
.attention-overflow-notice {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.6rem;
    font-size: var(--text-sm);
    color: var(--text-secondary);
    background: var(--surface-secondary);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.5rem 0.7rem;
    margin-bottom: 0.6rem;
}
.attention-overflow-notice[hidden] { display: none; }
.attention-overflow-notice #attention-overflow-notice-text { flex: 1 1 auto; }
.attention-overflow-notice .btn { padding: 0.3rem 0.6rem; font-size: var(--text-xs); flex-shrink: 0; }
.attention-overflow-notice-dismiss {
    background: transparent;
    border: none;
    color: var(--text-metadata);
    font-size: 1rem;
    line-height: 1;
    padding: 0.2rem 0.4rem;
    cursor: pointer;
    flex-shrink: 0;
}
/* Section 6: "selected-page indication that does not rely on color
   alone" applied here too - the focused position's real, visible
   "Focused" text tag (rendered by static/js/investigation_attention.js)
   is the non-color cue; background/border-color below are the
   additional, non-exclusive color cue on top of it. */
.attention-position {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    max-width: 210px;
    min-width: 110px;
    padding: 0.4rem 0.55rem;
    border: 1px solid transparent;
    border-bottom: none;
    border-radius: 4px 4px 0 0;
    background: none;
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-decoration: none;
    cursor: pointer;
    flex-shrink: 0;
    position: relative;
}
.attention-position:hover {
    background: var(--surface-hover);
    color: var(--text-primary);
    text-decoration: none;
}
.attention-position:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: -2px;
}
.attention-position-focused {
    background: var(--surface-primary);
    color: var(--text-primary);
    font-weight: 600;
    border-color: var(--border);
    border-bottom: 2px solid var(--machine-blue);
    margin-bottom: -1px;
}
.attention-position-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.attention-position-focused-tag {
    flex-shrink: 0;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--machine-blue);
}
/* Real text ("Archived"), not a color-only dot - a frozen Investigation
   still held in attention must read as such without relying on the
   reviewer noticing a color change. */
.attention-position-archived-tag {
    flex-shrink: 0;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-metadata);
}
.attention-position-release {
    flex-shrink: 0;
    background: none;
    border: none;
    color: var(--text-metadata);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
    padding: 0.15rem 0.3rem;
    border-radius: 3px;
}
.attention-position-release:hover { background: var(--surface-hover); color: var(--failure-red); }
.attention-position-release:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 1px;
}

/* CLAUDE-P40-VW7B, Section 9: the fifth-Investigation capacity dialog's
   own list of currently-attended positions - reuses the SAME
   .attention-capacity-dialog* family (itself the renamed, reused
   CLAUDE-P40-VW8 Project-switching dialog CSS - see that rule's own
   comment) for the dialog shell; this is only the per-position row
   inside .attention-capacity-dialog-list. */
.attention-capacity-dialog-list {
    list-style: none;
    margin: 0 0 0.7rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    max-height: 40vh;
    overflow-y: auto;
}
.attention-capacity-dialog-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.4rem 0.5rem;
    background: var(--surface-secondary);
    border-radius: 4px;
}
.attention-capacity-dialog-item-name {
    font-size: var(--text-sm);
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.attention-capacity-dialog-item .btn { padding: 0.3rem 0.6rem; font-size: 0.78rem; flex-shrink: 0; }
.attention-capacity-conclude-form { display: none; }

/* CLAUDE-P40-E3A, Section 6: the shared right-click context menu -
   repositioned (left/top set inline by JS) to whichever division was
   clicked, the same popover idiom as the top-bar menus above. */
.display-context-menu {
    position: fixed;
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.4rem;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    z-index: 40;
    min-width: 190px;
}
/* CLAUDE-P40-VW1: an author-origin class selector of equal specificity
   to the UA stylesheet's `[hidden] { display: none }` always wins the
   cascade regardless of source order, so `display: flex` above silently
   defeated the JS-toggled `hidden` attribute and left the menu
   permanently visible. The top-bar menus (.workspace-layout-menu etc.)
   never hit this because they're native <details> disclosure widgets,
   not a plain hidden-attribute toggle. */
.display-context-menu[hidden] {
    display: none;
}
.display-context-item {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--text-primary);
    background: none;
    border: none;
    text-align: left;
    padding: 0.35rem 0.5rem;
    border-radius: 3px;
    cursor: pointer;
    display: block;
    width: 100%;
}
.display-context-item:hover { background: var(--surface-hover); }
.display-context-divide {
    padding: 0.3rem 0.5rem;
    border-top: 1px solid var(--border);
    margin-top: 0.2rem;
    padding-top: 0.5rem;
}

/* CLAUDE-P40-VW8-QA, Section 9: "empty-state content is positioned
   coherently inside the division" - centered within the division's
   own real, now-full-height area (flex:1 on the empty state itself,
   inside .display-division's own flex column) rather than left
   stranded at the top of a tall, mostly-blank box. */
.display-division-empty {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 0.4rem;
    padding: 1.5rem 0;
    color: var(--text-secondary);
    font-size: 0.85rem;
}
.display-division-picker {
    width: 100%;
    max-width: 320px;
    margin-top: 0.5rem;
}
.display-division.display-division-populated .display-division-empty { display: none; }
/* CLAUDE-P40-VW8-QA: fills the division's real available height
   (flex:1 within .display-division's own column) instead of shrink-
   wrapping to nothing when empty, or a content-blind height:50vh
   guess when populated - both were instances of the same "shallow
   rectangle" root cause the container-level fix above addresses. */
.display-division-content {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.display-division-content iframe,
.display-division-content img {
    width: 100%;
    border: 1px solid var(--border);
}
.display-division-content iframe { flex: 1; min-height: 0; height: 100%; background: var(--surface-primary); }
.display-division-content img { max-width: 100%; max-height: 100%; display: block; margin: 0 auto; object-fit: contain; }

/* CLAUDE-P40-EYE1, Section 1: the full-height right column itself -
   Toolbox (upper) and Eye (lower), mirroring .launcher-panel's own role
   on the left (CLAUDE-P40-VW7A-QA2's Lists/Thumbnails split). Owns the
   width/background/flex-shrink that used to live directly on
   .workspace-pane-toolbox (below) - a sibling of .launcher-panel AND
   .workspace-main-column inside .app-shell-body, so it spans the SAME
   full vertical extent Chat's row occupies (never stopping at the
   Display/Chat divider - Section 1's own explicit requirement), the
   same "one shared painted background, transparent panes on top of it"
   split .lists-pane/.thumbnails-pane already established. */
/* CLAUDE-P40-EYE1 (product-owner browser correction): width is now a
   real, draggable dimension (--right-column-width, set by the new
   toolbox-divider drag logic in base.html), not a fixed value - the
   min(340px, 30vw) default becomes the STARTING value instead
   (fallback for the var()), so an unvisited browser/reset state still
   renders identically to before this correction. */
.workspace-right-column {
    width: var(--right-column-width, min(340px, 30vw));
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
    background: var(--surface-primary);
}
/* CLAUDE-P40-E2: the Toolbox itself - a flex stack of .workspace-pane
   sections (Investigation/Document/Project tools, contextual; Removed
   Items and admin-only Project Data Management, always visible - see
   case_workspace.html), not a single pane of its own.
   CLAUDE-P40-EYE1: no longer owns width/flex-shrink/background of its
   own (moved to .workspace-right-column, above) - just the upper pane
   inside that column, sized by --toolbox-height (the Toolbox/Eye
   divider's own live value) and independently scrollable, the same
   "outer column owns sizing, inner pane owns its own scroll" split
   .lists-pane already established. */
.workspace-pane-toolbox {
    flex: 0 0 var(--toolbox-height, 60%);
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    scrollbar-color: transparent transparent;
    /* CLAUDE-P40-EYE1: positioning context for .toolbox-maximize-btn
       (below), which floats over this pane's own top-right corner
       rather than a dedicated header row. */
    position: relative;
    padding-top: 2.2rem;
}
/* CLAUDE-P40-EYE1, Section 2: "clear collapse and restore controls" for
   Toolbox - floats rather than a new header row, since case_workspace.
   html's own {% block toolbox %} already renders a real Toolbox
   heading as its first child; padding-top on the pane itself (above)
   reserves room so this never overlaps that heading's own text. */
.toolbox-maximize-btn {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: 0.72rem;
    padding: 0.2rem 0.4rem;
    border-radius: 4px;
    z-index: 2;
}
.toolbox-maximize-btn:hover, .toolbox-maximize-btn:focus-visible {
    background: var(--surface-hover);
    color: var(--text-primary);
}
.toolbox-maximize-btn[aria-pressed="true"] { color: var(--machine-blue); }
/* CLAUDE-P40-VW6: the old .workspace-pane-toolbox.appearance-tinted
   single-property rule that used to live here is gone - Toolbox's own
   root used to BE its painted surface (unlike Display/Chat, which paint
   a descendant), so the combined .appearance-tinted/.appearance-dark
   rule below (near .chat-region's own rules) already covered it
   directly via its own background/color declarations, the same way
   .appearance-dark always did.
   CLAUDE-P40-EYE1: that combined rule's own selector now names
   .workspace-right-column instead - the new full-height right column
   (Toolbox above Eye) is the painted root today, so BOTH panes inherit
   the theme via ordinary CSS custom-property cascade; .workspace-pane-
   toolbox itself paints nothing of its own anymore (mirrors .lists-pane
   inside .launcher-panel). */
.workspace-pane-toolbox > h2 {
    font-family: var(--font-display);
    font-size: 0.95rem;
    margin: 0;
    color: var(--text-primary);
}

/* Narrow: Toolbox becomes a real overlay drawer rather than a
   permanent column competing with Display for width - Display is the
   one thing always on screen without having to scroll past it. The
   same toolbox-divider/html.toolbox-hidden class drives this (Section
   7) - a drawer is just what "shown" looks like at this width, not a
   second mechanism. Closing is via the same divider (already reachable,
   already keyboard-operable) or Escape (base.html's own script) -
   deliberately no separate click-outside-to-close backdrop element,
   which would need its own focus-trap/hit-testing machinery this pass
   doesn't otherwise need. The Launcher panel's own equivalent narrow-
   screen drawer lives in base.html's own media query, alongside the
   panel itself - "only one overlay should obstruct Display at a time"
   (Section 11) is enforced in that script, not here. */
/* CLAUDE-P40-EYE1: was .workspace-pane-toolbox - now the WHOLE right
   column becomes the overlay drawer (Toolbox and Eye both, stacked
   exactly as they are at desktop widths via the base .workspace-right-
   column rule's own display:flex/flex-direction:column, unchanged
   here), not Toolbox alone. .workspace-pane-toolbox's own padding:1rem
   moves to this element too - it used to double as both the drawer's
   outer padding AND (implicitly) Toolbox's own content inset, since
   Toolbox was the only thing in it; now .eye-pane needs the same
   drawer-edge breathing room, so the padding lives one level up. */
@media (max-width: 640px) {
    .workspace-right-column {
        position: fixed;
        top: 0;
        bottom: 0;
        right: 0;
        width: min(85vw, 320px);
        z-index: 30;
        padding: 1rem;
        border: 1px solid var(--border);
    }
}

/* CLAUDE-P40-EYE1, Section 2: draggable divider between Toolbox and
   Eye - same visual/interaction grammar as .lists-thumbnails-divider
   (CLAUDE-P40-VW7A-QA2): quiet resting line (var(--border), a
   descendant of .workspace-right-column so it inherits that column's
   own theme directly, never the shell fallback), --machine-blue accent
   on hover/focus/active-drag only, transparent hit-target background
   inheriting the column's own (no white/beige gutter in dark modes),
   thin line with a comfortable invisible hit target. Never [hidden] -
   unlike Lists/Thumbnails, Eye is a permanent pane from this stage on
   (Section 4), only its SIZE is adjustable. */
.toolbox-eye-divider {
    flex-shrink: 0;
    width: 100%;
    height: 9px;
    border: none;
    padding: 0;
    cursor: row-resize;
    background: var(--surface-primary);
    position: relative;
    z-index: 1;
}
.toolbox-eye-divider::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 4px;
    height: 1px;
    background: var(--border);
}
.toolbox-eye-divider:hover::before,
.toolbox-eye-divider:focus-visible::before,
.toolbox-eye-divider.dragging::before {
    background: var(--machine-blue);
    height: 2px;
    top: 3.5px;
}
.toolbox-eye-divider:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 1px;
}

/* CLAUDE-P40-EYE1, Section 4: the Eye pane itself - a structural
   scaffold, not a completed tool. Takes whatever height Toolbox's own
   flex-basis (--toolbox-height) doesn't use, the same "remaining space"
   idiom .thumbnails-pane already established relative to .lists-pane. */
.eye-pane {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    border-top: 1px solid var(--border);
}
.eye-pane-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0.7rem;
    flex-shrink: 0;
}
.eye-maximize-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: 0.72rem;
    padding: 0.2rem 0.4rem;
    border-radius: 4px;
}
.eye-maximize-btn:hover, .eye-maximize-btn:focus-visible {
    background: var(--surface-hover);
    color: var(--text-primary);
}
.eye-maximize-btn[aria-pressed="true"] { color: var(--machine-blue); }
.eye-pane-header h2 {
    font-family: var(--font-display);
    font-size: 0.95rem;
    margin: 0;
    color: var(--text-primary);
}
.eye-pane-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    padding: 0 0.7rem 0.7rem;
    scrollbar-color: transparent transparent;
}
/* CLAUDE-P40-EYE1, Section 4: a real (not decorative) drop target - a
   dashed border reads as "things go here" without implying a filled/
   bordered "card" the CLAUDE-P40-E1A-VISUAL de-boxing pass deliberately
   removed elsewhere (this is a genuinely functional boundary - Section
   4's own "select this to paste/drop" affordance - not a decorative
   container, so it is exempt from that pass the same way .finding-card/
   .delegation-choice already are). --surface-secondary (a step above
   the pane's own --surface-primary, the same "grouped/interactive
   sub-region" meaning it already carries elsewhere in this file) marks
   it as its own distinct drop zone within the pane, not a repaint of
   the whole pane. static/js/eye_pane.js toggles .eye-drop-target-active
   during a real dragover/dragenter (Section 4's own "visually reacts to
   drag-over"). */
.eye-drop-target {
    flex: 1 1 auto;
    min-height: 120px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    text-align: center;
    padding: 1rem;
    border: 2px dashed var(--border-strong);
    border-radius: 6px;
    background: var(--surface-secondary);
    cursor: pointer;
}
.eye-drop-target:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 2px;
}
.eye-drop-target.eye-drop-target-active {
    border-color: var(--machine-blue);
    background: var(--surface-hover);
}
.eye-drop-target-empty {
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin: 0;
}
.eye-drop-target-note {
    color: var(--text-metadata);
    font-size: 0.72rem;
    margin: 0;
    max-width: 24rem;
}
.eye-drop-target-error {
    color: var(--failure-red);
    font-size: 0.78rem;
    margin: 0;
}
/* CLAUDE-P40-EYE1 (product-owner browser correction), Section 3: a real
   responsive viewing canvas replacing the old small fixed-size preview
   - align-self:stretch/flex:1 override .eye-drop-target's own
   align-items:center/justify-content:center (correct for the EMPTY
   state's centered message, wrong for a canvas that should fill the
   available area) so the canvas genuinely uses the pane's available
   space instead of shrink-wrapping to the image's own natural size. */
.eye-canvas {
    align-self: stretch;
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.eye-canvas[hidden] { display: none; }
.eye-canvas-toolbar {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.3rem;
    flex-shrink: 0;
}
.eye-canvas-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-secondary);
    font-family: var(--font-body);
    font-size: 0.78rem;
    padding: 0.3rem 0.55rem;
    border-radius: 4px;
}
.eye-canvas-btn:hover, .eye-canvas-btn:focus-visible {
    background: var(--surface-hover);
    color: var(--text-primary);
}
.eye-canvas-zoom-level {
    font-size: 0.75rem;
    color: var(--text-metadata);
    font-variant-numeric: tabular-nums;
    min-width: 3.2em;
    text-align: center;
}
.eye-canvas-divider {
    width: 1px;
    height: 1.1rem;
    background: var(--border);
}
/* CLAUDE-P40-EYE1 (product-owner browser correction), Section 3: native
   scroll IS the pan mechanism - #eye-canvas-image is sized to its real
   scaled pixel dimensions (static/js/eye_pane.js sets width/height
   directly from naturalWidth/naturalHeight * scale, never CSS max-
   width/height percentages, so there is no stretching or distortion at
   any zoom level), and overflow:auto lets the browser's own scrollbars/
   touch/trackpad panning take over once the image exceeds the viewport
   - real keyboard accessibility (Page Up/Down, arrow keys) and touch
   support for free, no hand-rolled pointer-drag panning needed.
   display:flex + align-items/justify-content:center is what keeps a
   smaller-than-viewport image centered rather than pinned top-left. */
.eye-canvas-viewport {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--surface-primary);
    border-radius: 4px;
    scrollbar-color: transparent transparent;
}
.eye-canvas-viewport:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: -2px;
}
.eye-canvas-image {
    display: block;
    flex-shrink: 0;
}
/* CLAUDE-MM5: orientation status, save bar, and the post-save handoff
   view - additive to CLAUDE-P40-EYE1's own canvas layout above, same
   visual language (--text-secondary/--text-metadata, .eye-canvas-btn's
   own button styling reused for #eye-save-btn). */
.eye-orientation-status {
    font-size: 0.72rem;
    color: var(--text-metadata);
    text-align: center;
    flex-shrink: 0;
}
.eye-save-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    flex-shrink: 0;
    padding-top: 0.3rem;
    border-top: 1px solid var(--border);
}
.eye-save-status {
    font-size: 0.78rem;
    color: var(--text-secondary);
    flex: 1 1 auto;
}
.eye-save-description {
    flex: 1 1 12rem;
    min-width: 8rem;
    font-family: var(--font-body);
    font-size: 0.78rem;
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--surface-primary);
    color: var(--text-primary);
}
/* Reuses .btn-primary's own neutral (--text-primary-on-surface) emphasis
   convention rather than introducing a new blue-background button -
   --machine-blue is reserved for machine/system/reference accents
   (focus rings, links - tokens.css's own header comment), not primary
   actions. */
.eye-save-btn {
    background: var(--text-primary);
    color: var(--surface-primary);
    font-weight: 600;
}
.eye-save-btn:hover, .eye-save-btn:focus-visible {
    background: var(--text-secondary);
}
.eye-saved-view {
    align-self: stretch;
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
}
.eye-saved-view[hidden] { display: none; }

/* CLAUDE-P40-EYE1 (product-owner browser correction): "one nested
   scrollbar in the upper-right Toolbox/Findings region remains
   unthemed" - every scroll container above already had `scrollbar-
   color` (the standards-track property, Firefox always, Chromium only
   since v121/Jan-2024) but NOTHING using the older, still very widely
   deployed WebKit/Chromium `::-webkit-scrollbar` pseudo-element API -
   on any Chromium build older than 121, `scrollbar-color` is silently
   ignored entirely and the browser falls back to its own default
   white-track/gray-thumb rendering, exactly matching the report. Both
   are now declared together on every real scroll container this app
   has (Lists, Thumbnails, Toolbox, Eye's own body AND its image-canvas
   viewport, Display's <main> AND its PDF canvas container, Chat's
   message thread) - not just the one specifically reported, per this
   correction's own "check all nested... scroll containers" instruction.
   background-clip:padding-box + a transparent border is what gives the
   thumb its visible inset from the track edges without a hard-coded
   pixel gap. :hover/:active on the thumb are WebKit's own equivalent of
   "visible hover/active scrolling states" - :focus has no dedicated
   scrollbar-part pseudo-class, so the CONTAINER's own :focus-visible
   outline (already present on the keyboard-focusable ones, e.g.
   .eye-canvas-viewport) is what covers focus instead. */
/* CLAUDE-PANEL-CALM-02: every panel-scale scroll container (Lists,
   Thumbnails, Toolbox, Eye's own body and its image-canvas viewport,
   Display's <main>, its PDF canvas container, Chat's message thread)
   shares ONE quiet-by-default/hover-reveal treatment now -
   CLAUDE-LEFTPANEL-CALM-01 built this first for Lists alone after a
   real Product Owner report named it "too agitated"; the same report
   then confirmed that fix and asked for it everywhere. Width/height
   stay unconditional (always reserved, regardless of hover) - that is
   what guarantees no layout shift when track/thumb color fades in or
   out. See the separate combined block further below for the two
   horizontal overflow rails (document/attention tab strips), which
   share this exact pattern but their own, smaller 8px sizing. */
.lists-pane::-webkit-scrollbar,
.thumbnails-list::-webkit-scrollbar,
.workspace-pane-toolbox::-webkit-scrollbar,
.eye-pane-body::-webkit-scrollbar,
.eye-canvas-viewport::-webkit-scrollbar,
main::-webkit-scrollbar,
.document-viewer-canvas-container::-webkit-scrollbar,
.conversation-thread::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
.lists-pane::-webkit-scrollbar-track,
.thumbnails-list::-webkit-scrollbar-track,
.workspace-pane-toolbox::-webkit-scrollbar-track,
.eye-pane-body::-webkit-scrollbar-track,
.eye-canvas-viewport::-webkit-scrollbar-track,
main::-webkit-scrollbar-track,
.document-viewer-canvas-container::-webkit-scrollbar-track,
.conversation-thread::-webkit-scrollbar-track {
    background: transparent;
}
.lists-pane::-webkit-scrollbar-thumb,
.thumbnails-list::-webkit-scrollbar-thumb,
.workspace-pane-toolbox::-webkit-scrollbar-thumb,
.eye-pane-body::-webkit-scrollbar-thumb,
.eye-canvas-viewport::-webkit-scrollbar-thumb,
main::-webkit-scrollbar-thumb,
.document-viewer-canvas-container::-webkit-scrollbar-thumb,
.conversation-thread::-webkit-scrollbar-thumb {
    background-color: transparent;
    border-radius: 6px;
    border: 2px solid transparent;
    background-clip: padding-box;
    transition: background-color 0.15s ease;
}
.lists-pane:hover::-webkit-scrollbar-track,
.thumbnails-list:hover::-webkit-scrollbar-track,
.workspace-pane-toolbox:hover::-webkit-scrollbar-track,
.eye-pane-body:hover::-webkit-scrollbar-track,
.eye-canvas-viewport:hover::-webkit-scrollbar-track,
main:hover::-webkit-scrollbar-track,
.document-viewer-canvas-container:hover::-webkit-scrollbar-track,
.conversation-thread:hover::-webkit-scrollbar-track {
    background: var(--surface-primary);
}
.lists-pane:hover::-webkit-scrollbar-thumb,
.thumbnails-list:hover::-webkit-scrollbar-thumb,
.workspace-pane-toolbox:hover::-webkit-scrollbar-thumb,
.eye-pane-body:hover::-webkit-scrollbar-thumb,
.eye-canvas-viewport:hover::-webkit-scrollbar-thumb,
main:hover::-webkit-scrollbar-thumb,
.document-viewer-canvas-container:hover::-webkit-scrollbar-thumb,
.conversation-thread:hover::-webkit-scrollbar-thumb {
    background-color: var(--border-strong);
}
.lists-pane::-webkit-scrollbar-thumb:hover,
.thumbnails-list::-webkit-scrollbar-thumb:hover,
.workspace-pane-toolbox::-webkit-scrollbar-thumb:hover,
.eye-pane-body::-webkit-scrollbar-thumb:hover,
.eye-canvas-viewport::-webkit-scrollbar-thumb:hover,
main::-webkit-scrollbar-thumb:hover,
.document-viewer-canvas-container::-webkit-scrollbar-thumb:hover,
.conversation-thread::-webkit-scrollbar-thumb:hover,
.lists-pane::-webkit-scrollbar-thumb:active,
.thumbnails-list::-webkit-scrollbar-thumb:active,
.workspace-pane-toolbox::-webkit-scrollbar-thumb:active,
.eye-pane-body::-webkit-scrollbar-thumb:active,
.eye-canvas-viewport::-webkit-scrollbar-thumb:active,
main::-webkit-scrollbar-thumb:active,
.document-viewer-canvas-container::-webkit-scrollbar-thumb:active,
.conversation-thread::-webkit-scrollbar-thumb:active {
    background-color: var(--machine-blue);
    background-clip: padding-box;
}
.lists-pane::-webkit-scrollbar-corner,
.thumbnails-list::-webkit-scrollbar-corner,
.workspace-pane-toolbox::-webkit-scrollbar-corner,
.eye-pane-body::-webkit-scrollbar-corner,
.eye-canvas-viewport::-webkit-scrollbar-corner,
main::-webkit-scrollbar-corner,
.document-viewer-canvas-container::-webkit-scrollbar-corner,
.conversation-thread::-webkit-scrollbar-corner {
    background: transparent;
}
/* CLAUDE-PANEL-CALM-02: the standards-track scrollbar-color property
   (Firefox) gets the identical hover-reveal treatment, for every
   container above PLUS the two horizontal overflow rails (their own
   WebKit sizing stays separate, below, but scrollbar-color doesn't
   carry a size - one shared rule covers all of them). */
.lists-pane:hover,
.thumbnails-list:hover,
.workspace-pane-toolbox:hover,
.eye-pane-body:hover,
.eye-canvas-viewport:hover,
main:hover,
.document-viewer-canvas-container:hover,
.conversation-thread:hover,
.document-tab-list:hover,
.attention-strip-list:hover,
.document-tabs-overflow-panel:hover {
    scrollbar-color: var(--border-strong) var(--surface-primary);
}
/* CLAUDE-PANEL-CALM-02: the two horizontal overflow rails (document/
   attention tab strips) - same quiet-by-default/hover-reveal pattern as
   the panel group above, kept in their own block because their WebKit
   sizing (8px height, 1px thumb inset) has always been smaller/thinner
   than the 10px/2px panel scrollbars, not because the underlying
   behavior differs. */
.document-tab-list::-webkit-scrollbar,
.attention-strip-list::-webkit-scrollbar {
    height: 8px;
}
.document-tab-list::-webkit-scrollbar-track,
.attention-strip-list::-webkit-scrollbar-track {
    background: transparent;
}
.document-tab-list::-webkit-scrollbar-thumb,
.attention-strip-list::-webkit-scrollbar-thumb {
    background-color: transparent;
    border-radius: 6px;
    border: 1px solid transparent;
    background-clip: padding-box;
    transition: background-color 0.15s ease;
}
.document-tab-list:hover::-webkit-scrollbar-track,
.attention-strip-list:hover::-webkit-scrollbar-track {
    background: var(--surface-primary);
}
.document-tab-list:hover::-webkit-scrollbar-thumb,
.attention-strip-list:hover::-webkit-scrollbar-thumb {
    background-color: var(--border-strong);
}
.document-tab-list::-webkit-scrollbar-thumb:hover,
.attention-strip-list::-webkit-scrollbar-thumb:hover,
.document-tab-list::-webkit-scrollbar-thumb:active,
.attention-strip-list::-webkit-scrollbar-thumb:active {
    background-color: var(--machine-blue);
    background-clip: padding-box;
}

/* CLAUDE-P40-E1A-VISUAL: was a filled/bordered/rounded "card"
   (background + border + border-radius + padding) around every major
   section - Project information, an Investigation's own content, the
   Findings area, an opened document, Project Briefing, Project State.
   Visual de-boxing addendum: decorative containers removed: sections
   now separate from each other with a restrained bottom divider and
   spacing only - hierarchy comes from headings/.workspace-pane-label
   typography and whitespace, not a filled box. Functional boundaries
   (the composer, real controls, focus states, selected nav rows,
   warnings, confirmations - .delegation-choice/.rfi-preview/
   .revision-notice/.finding-card, all still fully bordered/filled)
   are deliberately untouched - this rule only ever provided decorative
   framing, never a functional one. */
.workspace-pane {
    padding-bottom: 1.5rem;
    margin-bottom: 1.5rem;
    border-bottom: 1px solid var(--border);
}
.workspace-pane-display > .workspace-pane:last-child,
.workspace-pane-toolbox > .workspace-pane:last-child {
    border-bottom: none;
    margin-bottom: 0;
    padding-bottom: 0;
}
.workspace-pane h2,
.workspace-pane h3 {
    font-family: var(--font-display);
    font-size: 0.95rem;
    margin: 0 0 0.6rem;
    color: var(--text-primary);
}
.workspace-pane-label {
    font-family: var(--font-body);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-size: var(--text-xs);
    color: var(--text-metadata);
    margin: 0 0 var(--space-2);
}

/* CLAUDE-P40-E: an opened document/drawing (?source=), inside the
   Workspace pane rather than a new tab. A generic best-effort embed
   (browser-native PDF/text rendering via iframe, or a plain image) -
   no per-format viewer of this project's own; see the pane-note this
   section itself already renders about page/clause navigation not
   being available.
   CLAUDE-P40-E2B, Section E: was background: var(--surface-secondary)
   (Limestone, the same tinted/beige surface token main.css's own
   header comment reserves for nav/grouped-control surfaces, never the
   Display) plus border-radius - a rounded, filled "card" around the
   embed. Now a plain, neutral surface (--surface-primary, the same
   near-white token the rest of the de-boxed Workspace already uses for
   functional-not-decorative backgrounds) with square corners - no
   rounded container. The 1px border is kept, deliberately: a
   functional boundary marking where the embedded content starts (the
   same "real controls/boundaries stay bordered" exemption the P40-
   E1A-VISUAL de-boxing pass already established), not decorative
   framing - without it a white-background PDF embedded against this
   same near-white page would have no visible edge at all. */
.document-viewer-frame {
    width: 100%;
    height: 70vh;
    border: 1px solid var(--border);
    background: var(--surface-primary);
}
.document-viewer-image {
    max-width: 100%;
    border: 1px solid var(--border);
    display: block;
}
/* CLAUDE-CA1D-RIVER-PO-02 CONSOLIDATION (Section B, "internal-first
   document opening"): a format with no in-app renderer (.docx/.txt/
   anything without its own branch above) used to fall back to the
   SAME .document-viewer-frame iframe as PDF/XLSX - which those two
   formats' own browser-native handling can actually render, but this
   catch-all case cannot, so the iframe silently triggered an OS
   download the instant the Source was selected. This calm card
   replaces that: the same bordered "real boundary" idiom as
   .document-viewer-frame (a genuine functional edge, not decoration),
   holding an honest explanation plus the two explicit secondary
   actions that are now the ONLY way this reaches OS-level open/
   download behavior. */
.document-unavailable-preview {
    border: 1px solid var(--border);
    background: var(--surface-primary);
    border-radius: 4px;
    padding: 1.2rem;
}
.document-unavailable-preview-actions {
    display: flex;
    gap: 0.6rem;
    margin-top: 0.8rem;
}
/* CLAUDE-P40-VW7A-QA (Move Document Controls into the Top Application
   Menu): PDF Sources render here instead of .document-viewer-frame -
   same box (width/height/border/background all unchanged from the old
   iframe's own), but with NO competing native browser toolbar chrome
   inside it, since a <canvas> has none - the "reclaimed vertical
   height" this stage's own requirement asks for happens automatically
   inside this same 70vh box, not by growing the box itself. Centers
   the rendered page horizontally when it's narrower than the
   container (fit-page/a low zoom level) and scrolls when taller
   (a tall page at fit-width, or zoomed in). */
.document-viewer-canvas-container {
    width: 100%;
    height: 70vh;
    border: 1px solid var(--border);
    background: var(--surface-primary);
    overflow: auto;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    scrollbar-color: transparent transparent;
}
.document-viewer-canvas { display: block; }
.document-viewer-load-error {
    margin: auto;
    padding: 1rem;
    max-width: 28rem;
    text-align: center;
    color: var(--failure-red);
    font-size: 0.85rem;
}
/* CLAUDE-P40-VW7A-QA2, Section 4: the page canvas and its transparent
   annotation overlay are stacked in one positioning wrapper - the wrap
   sizes to the page canvas (the only child in normal flow; the overlay
   is position:absolute and contributes no size of its own), so this
   never changes the rendered box size .document-viewer-canvas-container
   already centers/scrolls, only adds a second painted layer on top. */
.document-viewer-page-wrap {
    position: relative;
    display: inline-block;
}
.document-viewer-annotation-layer {
    position: absolute;
    top: 0;
    left: 0;
}
/* CLAUDE-P40-VW7A-QA2, Section 4: the one text-annotation input surface -
   a real, focusable <input> positioned at the click point (static/js/
   pdf_viewer.js's own openTextAnnotationInput), not a canvas-drawn fake
   text box - so typing, IME, and screen readers all work exactly like
   any other form field, right up until Enter/blur commits it into the
   canvas-drawn annotation and removes this element. */
.document-viewer-annotation-text-input {
    position: absolute;
    z-index: 5;
    font-size: 13px;
    padding: 2px 4px;
    border: 1px solid var(--machine-blue);
    border-radius: 2px;
    background: var(--surface-primary);
    color: var(--text-primary);
    min-width: 120px;
}
/* CLAUDE-MM5: the one marker-note input drawing_image_viewer.js creates -
   same shape as .document-viewer-annotation-text-input above, kept as
   its own class since it lives inside .drawing-region-overlay's own
   pointer-events:none layer (needs pointer-events re-enabled locally). */
.drawing-marker-note-input {
    position: absolute;
    z-index: 5;
    font-size: 13px;
    padding: 2px 4px;
    border: 1px solid var(--machine-blue);
    border-radius: 2px;
    background: var(--surface-primary);
    color: var(--text-primary);
    min-width: 140px;
    pointer-events: auto;
}
.doc-annotation-tool[aria-pressed="true"] {
    background: var(--surface-selected);
    color: var(--machine-blue);
}
.doc-annotation-status {
    font-size: 0.72rem;
    color: var(--text-metadata);
    white-space: nowrap;
}
/* CLAUDE-MM4: the in-pane drawing toolbar/viewport - lives DIRECTLY in
   the document pane (case_workspace.html's own kind == 'drawing' branch,
   and every 'source'-kind Display division static/js/case_workspace.js
   inserts), never the top application menu bar, so it renders
   identically for the primary document AND any comparison Display
   (Section 8) with no dependency on #workspace-document-controls. */
.drawing-viewer {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.drawing-viewer-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.15rem;
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--surface-secondary);
}
.doc-orientation-status,
.doc-region-status {
    font-size: 0.72rem;
    color: var(--text-metadata);
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}
.drawing-viewport {
    position: relative;
    width: 100%;
    height: 70vh;
    border: 1px solid var(--border);
    background: var(--surface-primary);
    overflow: hidden;
    touch-action: none;
    display: flex;
    align-items: center;
    justify-content: center;
}
.drawing-pan-zoom {
    /* JS (drawing_image_viewer.js's own applyPanZoomTransform) sets
       `transform: translate(panX,panY) scale(zoom)` here - flexbox
       centering above gives pan=0/zoom=1 a sensible starting position,
       panning/zooming is layered on top of that via the transform. */
    display: flex;
    align-items: center;
    justify-content: center;
}
.drawing-pan-zoom .document-viewer-image {
    display: block;
    max-width: none;
    max-height: 68vh;
    border: none;
    /* transform-origin defaults to "center" - never overwritten by JS
       (only .style.transform is set, never .style.transformOrigin) - so
       every rotate()/scaleX()/scaleY() JS applies always pivots around
       the drawing's own visual center, matching this stage's own
       transform_point_to_display/original convention. */
}
.drawing-region-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}
.drawing-region-box {
    position: absolute;
    border: 2px dashed var(--machine-blue);
    background: rgba(79, 169, 162, 0.15);
}
.drawing-sheet-metadata {
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--surface-secondary);
    font-size: 0.78rem;
}
.drawing-sheet-metadata-list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.15rem 0.6rem;
    margin: 0 0 0.4rem;
}
.drawing-sheet-metadata-list dt { color: var(--text-metadata); }
.drawing-sheet-metadata-list dd { margin: 0; color: var(--text-primary); }
.drawing-sheet-metadata-unavailable { color: var(--text-disabled); font-style: italic; }
.drawing-scale-warning {
    margin: 0;
    color: var(--attention-amber);
    font-size: 0.74rem;
}

/* -- CLAUDE-MM6: bounded river relationship viewer -------------------------
   Section 19's own "NOT a large free-form graph canvas" - a small panel
   attached to the existing evidence surface (drawing_image_viewer.js),
   listing an evidence item's own relationships, its Trustworthy Answer
   Contract summary, and a bounded create-relationship form. Status colors
   reuse tokens.css's own existing semantic meanings rather than minting
   new ones: confirmed=accepted-green, proposed/stale=attention-amber
   (pending/needs re-verification), disputed/rejected/broken=failure-red
   (a concluded contradiction or a broken anchor), superseded/unresolved
   stay tonal - neither a success nor a failure, just historical/unknown. */
.relationship-river-panel {
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--surface-secondary);
    font-size: 0.78rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.relationship-river-panel h4 { margin: 0; font-size: var(--text-sm); color: var(--text-primary); }
.relationship-trust-summary { margin: 0; color: var(--text-secondary); }
.relationship-river-empty { margin: 0; color: var(--text-disabled); font-style: italic; }
.relationship-river-list { display: flex; flex-direction: column; gap: 0.4rem; }
.relationship-river-row {
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--surface-primary);
}
.relationship-river-row-head { display: flex; align-items: center; gap: 0.4rem; color: var(--text-primary); }
.relationship-river-reason { margin: 0.2rem 0 0; color: var(--text-metadata); }
.relationship-river-row-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem; margin-top: 0.3rem; }
.relationship-river-claim-case-input {
    width: 6rem;
    padding: 0.15rem 0.3rem;
    border: 1px solid var(--border);
    border-radius: 3px;
    font-size: 0.76rem;
}
.relationship-status-badge {
    display: inline-block;
    padding: 0.05rem 0.4rem;
    border-radius: 3px;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}
.relationship-status-proposed,
.relationship-status-stale { background: var(--attention-amber-tint); color: var(--attention-amber); }
.relationship-status-confirmed { background: var(--accepted-green-tint); color: var(--accepted-green); }
.relationship-status-disputed,
.relationship-status-rejected,
.relationship-status-broken { background: var(--failure-red-tint); color: var(--failure-red); }
.relationship-status-superseded,
.relationship-status-unresolved { background: var(--surface-hover); color: var(--text-metadata); }
.relationship-river-create {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem;
    padding-top: 0.4rem;
    border-top: 1px solid var(--border);
}
.relationship-river-create input[type="text"] {
    flex: 1 1 8rem;
    min-width: 6rem;
    padding: 0.15rem 0.3rem;
    border: 1px solid var(--border);
    border-radius: 3px;
    font-size: 0.76rem;
}
.relationship-river-create select {
    padding: 0.15rem 0.3rem;
    border: 1px solid var(--border);
    border-radius: 3px;
    font-size: 0.76rem;
}
.relationship-river-create-status { font-size: 0.72rem; color: var(--text-metadata); }

/* -- shared text utilities ------------------------------------------------
   Consolidates inline style="" patterns that had drifted into
   near-duplicates across templates (font-size:0.85rem vs 0.82rem vs
   0.88rem all meaning "small secondary text", margin -0.6rem vs -0.4rem
   both meaning "pull this note up under the section title") - now one
   canonical value each, referencing tokens.css. Prefer these classes
   over a new inline style="" for anything this general; keep inline
   styles for genuinely one-off, non-reusable positioning only. */
.text-muted { color: var(--text-secondary); }
.pane-note {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin: calc(-1 * var(--space-5)) 0 var(--space-6);
}
.history-entry {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin: var(--space-3) 0;
    border-left: 3px solid var(--border-strong);
    padding-left: var(--space-6);
}

/* Visual pressure - see tokens.css's own comment on --pressure-quiet-text
   for the token-level rule. Apply only to neutral text nodes (a
   statement, a metadata line) - NEVER to a .review-state-badge or any
   other semantic-colored element, and never via `opacity` on a shared
   ancestor (opacity composites the whole subtree, including badges,
   toward the background - it cannot be selectively "restored" on a
   child). This is a color swap on plain text only, so a badge sitting
   next to quieted text is completely unaffected by construction. */
.pressure-quiet-text { color: var(--pressure-quiet-text); }

/* -- left: project navigation ------------------------------------------------ */
.lifecycle-strip { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 0.8rem; }
.lifecycle-stage {
    font-family: var(--font-body);
    font-size: 0.8rem;
    color: var(--text-metadata);
    padding: 0.2rem 0.45rem;
    border: 1px solid var(--border);
    border-radius: 999px;
}
/* Deliberately the one place ordinary list/nav "selected" tone (Warm
   Stone) is replaced with real color: a project's current lifecycle
   position is a singular, rare fact worth a dedicated highlight, not
   just another selected-row state - see --highlight-orange above. */
.lifecycle-stage.current {
    color: var(--surface-primary);
    background: var(--highlight-orange);
    border-color: var(--highlight-orange);
    font-weight: 600;
}

/* CLAUDE-P40-E1A-VISUAL: was a filled beige (--surface-secondary,
   Limestone) card per row, bordered and rounded - a "box around
   Investigation/Source listings" the de-boxing addendum specifically
   names. Now a plain row, separated by a restrained divider
   (border-bottom, last row excepted) instead of a filled card -
   selection/hover are still real, visible state changes (addendum:
   "retain boundaries for... selected navigation rows"), just via a
   background tint on that one row rather than every row getting a
   permanent box. */
.source-list, .case-list { list-style: none; margin: 0 0 0.7rem; padding: 0; display: grid; }
.source-item, .case-item {
    display: block;
    font-size: var(--text-sm);
    padding: 0.45rem 0.1rem;
    color: var(--text-primary);
    border-bottom: 1px solid var(--border);
}
.source-list li:last-child .source-item,
.case-list li:last-child .case-item { border-bottom: none; }
.case-item:hover { color: var(--machine-blue); text-decoration: none; }
.case-item.active { background: var(--surface-selected); border-radius: 4px; padding-left: 0.5rem; }
.source-kind-badge, .case-status-badge {
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-metadata);
    display: block;
    margin-bottom: 0.2rem;
}

.workspace-form { display: grid; gap: 0.5rem; margin-top: 0.5rem; }
.workspace-form input[type="text"],
.workspace-form select,
.workspace-form textarea {
    font-family: var(--font-body);
    font-size: 0.8rem;
    padding: 0.5rem 0.6rem;
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 3px;
    color: var(--text-primary);
    width: 100%;
}
.workspace-form button {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    padding: 0.5rem 0.8rem;
    border-radius: 3px;
    border: 1px solid var(--border-strong);
    background: transparent;
    color: var(--text-primary);
    cursor: pointer;
}
.workspace-form button:hover { background: var(--surface-hover); }

/* -- the ONE physical conversation dock, now full application width
   (CLAUDE-P40-E3A, Section 9 - was CLAUDE-P40-E2B, Section C, before
   that CLAUDE-P40-E1A, Section A) ---------------------------------------
   #conversation-dock is the single html_id macros.conversation_dock
   always renders, whether it's targeting the Project conversation or
   an open Investigation's own - the two are mutually exclusive Jinja
   branches (see case_workspace.html), never both on screen, so one id/
   one set of rules is genuinely one dock, not a shared style applied
   to two different elements.

   CLAUDE-P40-E3A: Chat is no longer grid-area: chat inside the retired
   .case-workspace grid, confined to the Display column - it's now
   base.html's own .chat-region, a full-width flex row beneath
   .app-shell-body (Lists|Display|Toolbox), sticky at the viewport
   bottom itself (see .chat-region below) so THIS panel no longer needs
   its own position:sticky/bottom/z-index - one sticky ancestor is
   enough, and stacking two independently sticky boxes here would only
   reintroduce the exact Lists/Chat overlap problem .launcher-panel's
   own :has(> .chat-region) rule above was written to avoid. height:
   100% fills .chat-region's own --chat-height; a flex column
   internally, so the resize handle/header/note stay a fixed size,
   .conversation-thread (history) takes the remaining space and scrolls
   internally, and the composer stays pinned at the panel's OWN bottom
   edge via flex. */
/* CLAUDE-P40-VW7A-QA: ONE shared horizontal inset, applied to every
   piece of Chat content (message text/role-labels via .conversation-
   thread's own padding below, and the composer via .conversation-
   input-form's own padding) rather than the PREVIOUS scheme's
   per-role, per-side asymmetric margins (.conversation-message.human
   had margin-left:1.5rem/margin-right:0, .system had the opposite) -
   product-owner report: "inconsistent horizontal alignment... left
   edges must align... right margin must visually balance the left
   margin." Declared once here (a local custom property, inherited by
   every descendant) so both consuming rules reference the SAME value
   instead of two separately hardcoded 1.5rem literals that could drift
   apart. Deliberately NOT applied to .conversation-dock-resize-handle
   (a direct sibling-in-spirit, not a padded-content child) - that
   divider line must stay full-width, unaffected by this inset. */
.conversation-dock-panel {
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--surface-primary);
    min-height: 0;
    --conversation-inset: 1.5rem;
    /* CLAUDE-P40-E3A-QA, Section 10 fix: .accordion-section (a class this
       element also carries - see the macro's own comment on reusing its
       visual treatment) sets border-top/margin-top/padding-top by
       default. CLAUDE-P40-E2B already intended the resize handle's own
       divider line to be THE one divider ("the handle IS the divider,
       not a separate invisible hit-target floating over a decorative
       one") but never actually zeroed these out here, leaving a second,
       redundant border+gap stacked directly above the handle's own -
       exactly the "visually heavy separators" the product owner flagged.
       Zeroed here, not by editing .accordion-section itself (still
       correct for its many other, actually-nested, callers). */
    border-top: none;
    margin-top: 0;
    padding-top: 0;
}
/* CLAUDE-P40-E3A, Section 9: the shell-level Chat row itself - "remains
   at the bottom... can be raised or lowered" (the existing resize
   handle/presets, unchanged internally). Sticky at the viewport bottom
   so it "remains reachable" while scrolling a long Document/
   Investigation in Display, exactly the guarantee the old
   .conversation-dock-panel sticky rule provided before Chat became a
   full-width row. 220px matches case_workspace.js's own
   COMPACT_HEIGHT default (see .launcher-panel's own note above on why).
   CLAUDE-P40-VW7A-QA2 (product-owner browser correction): this no
   longer spans the entire application width - a real-browser check
   found Chat extending underneath the full-height Lists column, and an
   earlier fix attempt (margin-left, since reverted) offsetting Chat's
   own box instead of moving it left a strip beneath Lists unpainted by
   anything, reading as a light rectangle in dark Appearance modes. The
   actual, structural fix: .chat-region is now nested inside
   templates/base.html's own .workspace-main-column, alongside .app-main
   (Display), both children of a column that is itself Lists' own
   sibling inside .app-shell-body - so Chat's box starts at the correct
   horizontal position automatically (never needing a margin-left kept
   in sync with Lists' own width/collapsed state), while Lists' own
   height:100% now genuinely covers the same vertical extent Chat's row
   occupies. CLAUDE-P40-EYE1 later moved Toolbox out of this column
   entirely (into its own .workspace-right-column, alongside a new Eye
   pane) - Chat's own width here is therefore Display's alone, not
   Display+Toolbox as it briefly was for one stage. */
.chat-region {
    flex-shrink: 0;
    position: sticky;
    bottom: 0;
    z-index: 10;
    height: var(--chat-height, 220px);
    background: var(--surface-primary);
}
/* CLAUDE-P40-E3A-QA, Section 10 fix: no border-top here - product-owner
   browser observation named "visually heavy separators", and this rule
   was stacking a second divider line directly above
   .conversation-dock-resize-handle's own (its ::before below is already
   documented, since CLAUDE-P40-E2B, as THE one visual divider handle
   reviewers see - "the handle IS the divider"). One line, not two. */
/* CLAUDE-P40-VW3/VW6: the shared Dark- and Tinted-mode rules,
   positioned here deliberately - AFTER every one of the five surfaces'
   own base component rules (.launcher-panel, .app-main,
   .workspace-topbar, .workspace-pane-toolbox, and .chat-region's own
   rule directly above), so a plain textual "first rule whose selector
   contains .app-main" search (an existing test-helper convention - see
   tests/test_p40e2b_flexible_workspace_frame.py's own _rule_body)
   still finds each surface's real base rule first, not this one, even
   though this rule's own selector list also names each of them as
   part of a compound selector. See the Appearance-menu comment above
   (near .launcher-count) for the full VW6 rationale - BOTH rules
   REDEFINE the standard token names locally on whichever surface's own
   root carries the class, so every existing rule in this file already
   written as var(--surface-primary)/var(--text-primary)/etc. repaints
   correctly for free. Tinted uses its own --tint-* family (tokens.css)
   - a real light navy-blue palette, not --surface-secondary borrowed
   from its own unrelated "grouped content" meaning (VW3's own defect,
   corrected here). */
.app-shell.appearance-dark,
.workspace-topbar.appearance-dark,
.launcher-panel.appearance-dark,
.app-main.appearance-dark,
.workspace-right-column.appearance-dark,
.chat-region.appearance-dark {
    --canvas: var(--dark-canvas);
    --surface-primary: var(--dark-surface-primary);
    --surface-secondary: var(--dark-surface-secondary);
    --surface-hover: var(--dark-surface-hover);
    --surface-selected: var(--dark-surface-selected);
    --border: var(--dark-border);
    --border-strong: var(--dark-border-strong);
    --text-primary: var(--dark-text-primary);
    --text-secondary: var(--dark-text-secondary);
    --text-metadata: var(--dark-text-metadata);
    --text-disabled: var(--dark-text-disabled);
    --seal-red: var(--dark-seal-red);
    --seal-red-tint: var(--dark-seal-red-tint);
    --machine-blue: var(--dark-machine-blue);
    --machine-blue-tint: var(--dark-machine-blue-tint);
    --highlight-orange: var(--dark-highlight-orange);
    --highlight-orange-tint: var(--dark-highlight-orange-tint);
    --accepted-green: var(--dark-accepted-green);
    --accepted-green-tint: var(--dark-accepted-green-tint);
    --attention-amber: var(--dark-attention-amber);
    --attention-amber-tint: var(--dark-attention-amber-tint);
    --failure-red: var(--dark-failure-red);
    --failure-red-tint: var(--dark-failure-red-tint);
    --risk-red: var(--dark-risk-red);
    --risk-red-tint: var(--dark-risk-red-tint);
    --brand-gold: var(--dark-brand-gold);
    background: var(--surface-primary);
    color: var(--text-primary);
}
.app-shell.appearance-tinted,
.workspace-topbar.appearance-tinted,
.launcher-panel.appearance-tinted,
.app-main.appearance-tinted,
.workspace-right-column.appearance-tinted,
.chat-region.appearance-tinted {
    --canvas: var(--tint-canvas);
    --surface-primary: var(--tint-surface-primary);
    --surface-secondary: var(--tint-surface-secondary);
    --surface-hover: var(--tint-surface-hover);
    --surface-selected: var(--tint-surface-selected);
    --border: var(--tint-border);
    --border-strong: var(--tint-border-strong);
    --text-primary: var(--tint-text-primary);
    --text-secondary: var(--tint-text-secondary);
    --text-metadata: var(--tint-text-metadata);
    --text-disabled: var(--tint-text-disabled);
    --seal-red: var(--tint-seal-red);
    --seal-red-tint: var(--tint-seal-red-tint);
    --machine-blue: var(--tint-machine-blue);
    --machine-blue-tint: var(--tint-machine-blue-tint);
    --highlight-orange: var(--tint-highlight-orange);
    --highlight-orange-tint: var(--tint-highlight-orange-tint);
    --accepted-green: var(--tint-accepted-green);
    --accepted-green-tint: var(--tint-accepted-green-tint);
    --attention-amber: var(--tint-attention-amber);
    --attention-amber-tint: var(--tint-attention-amber-tint);
    --failure-red: var(--tint-failure-red);
    --failure-red-tint: var(--tint-failure-red-tint);
    --risk-red: var(--tint-risk-red);
    --risk-red-tint: var(--tint-risk-red-tint);
    --brand-gold: var(--tint-brand-gold);
    background: var(--surface-primary);
    color: var(--text-primary);
}
/* "Deep Forest" (CLAUDE-P40-VW8-QA, Approved Theme Set) - third dark
   appearance choice, same redefinition pattern as .appearance-dark
   ("Graphite") and .appearance-tinted ("Midnight Blue") directly
   above, reading from the new --forest-* token family
   (static/css/tokens.css's own comment there has the full derivation
   and contrast-verification story). */
.app-shell.appearance-deep-forest,
.workspace-topbar.appearance-deep-forest,
.launcher-panel.appearance-deep-forest,
.app-main.appearance-deep-forest,
.workspace-right-column.appearance-deep-forest,
.chat-region.appearance-deep-forest {
    --canvas: var(--forest-canvas);
    --surface-primary: var(--forest-surface-primary);
    --surface-secondary: var(--forest-surface-secondary);
    --surface-hover: var(--forest-surface-hover);
    --surface-selected: var(--forest-surface-selected);
    --border: var(--forest-border);
    --border-strong: var(--forest-border-strong);
    --text-primary: var(--forest-text-primary);
    --text-secondary: var(--forest-text-secondary);
    --text-metadata: var(--forest-text-metadata);
    --text-disabled: var(--forest-text-disabled);
    --seal-red: var(--forest-seal-red);
    --seal-red-tint: var(--forest-seal-red-tint);
    --machine-blue: var(--forest-machine-blue);
    --machine-blue-tint: var(--forest-machine-blue-tint);
    --highlight-orange: var(--forest-highlight-orange);
    --highlight-orange-tint: var(--forest-highlight-orange-tint);
    --accepted-green: var(--forest-accepted-green);
    --accepted-green-tint: var(--forest-accepted-green-tint);
    --attention-amber: var(--forest-attention-amber);
    --attention-amber-tint: var(--forest-attention-amber-tint);
    --failure-red: var(--forest-failure-red);
    --failure-red-tint: var(--forest-failure-red-tint);
    --risk-red: var(--forest-risk-red);
    --risk-red-tint: var(--forest-risk-red-tint);
    --brand-gold: var(--forest-brand-gold);
    background: var(--surface-primary);
    color: var(--text-primary);
}
.chat-region.appearance-tinted,
.chat-region.appearance-tinted .conversation-dock-panel,
.chat-region.appearance-dark,
.chat-region.appearance-dark .conversation-dock-panel,
.chat-region.appearance-deep-forest,
.chat-region.appearance-deep-forest .conversation-dock-panel {
    background: var(--surface-primary);
    color: var(--text-primary);
}
/* CLAUDE-P40-E2B: the drag/keyboard-operable divider between Display
   and Chat - a real ARIA separator (draggable via
   static/js/case_workspace.js's pointer handlers, and keyboard-
   operable via ArrowUp/ArrowDown/Home/End when focused), not a purely
   decorative line. The visual accordion-section top border moves here
   (from the panel itself) so the handle IS the divider reviewers see,
   not a separate invisible hit-target floating over a decorative one. */
.conversation-dock-resize-handle {
    flex-shrink: 0;
    height: 10px;
    margin: -0.6rem 0 0.2rem;
    cursor: ns-resize;
    position: relative;
    /* CLAUDE-P40-VW7A-QA2 (product-owner browser correction): was
       unset/transparent - a descendant of .chat-region, so a real
       background here (rather than relying on whatever shows through)
       merges this splitter's own channel with Chat's own theme, the
       same "Appearance All must govern... the surrounding channel"
       requirement every other divider now satisfies. */
    background: var(--surface-primary);
}
.conversation-dock-resize-handle::before {
    content: "";
    position: absolute;
    top: 4px;
    left: 0;
    right: 0;
    height: 1px;
    /* CLAUDE-P40-VW6: --divider-strong (tokens.css), not --border - the
       upper workspace and Chat are independently-themed surfaces (VW3),
       so --border here would resolve to whichever mode CHAT ITSELF is
       in, with no guarantee the workspace surface directly above is
       different enough to still show a line (Dark workspace above Dark
       Chat was exactly the reported "the divider... disappears" case -
       two very-low-contrast dark-on-dark borders, technically present,
       not perceptible). --divider-strong is fixed and never redefined
       by .appearance-dark/.appearance-tinted, so it stays visible
       against light, dark, AND tinted alike, on either side, in any
       combination. */
    background: var(--divider-strong);
}
.conversation-dock-resize-handle:hover::before,
.conversation-dock-resize-handle:focus-visible::before,
.conversation-dock-resize-handle.dragging::before {
    background: var(--machine-blue);
}
.conversation-dock-resize-handle:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 2px;
}
/* CLAUDE-P40-VW8-QA: was justify-content:space-between, spreading the
   old heading text (removed - see _macros.html's own comment) and this
   toggle to opposite ends. With only the toggle left, flex-end keeps it
   in its prior top-right position rather than letting a single flex
   item collapse to flex-start under the old rule. */
.conversation-dock-header {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.6rem;
    font-family: var(--font-body);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-size: 0.8rem;
    color: var(--text-metadata);
    flex-shrink: 0;
    margin-bottom: 0.5rem;
}
/* CLAUDE-P40-E3A-QA, Section 10: one size toggle, replacing the old
   two-button .conversation-dock-presets/.conversation-preset-btn pair -
   its own label already names the action ("Expand"/"Compact"), so no
   aria-pressed-driven color distinction between two buttons is needed
   anymore. */
.conversation-size-toggle {
    font-family: var(--font-body);
    font-size: 0.78rem;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text-secondary);
    background: none;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 0.15rem 0.5rem;
    cursor: pointer;
}
.conversation-size-toggle:hover {
    color: var(--text-primary);
    border-color: var(--border-strong);
}

/* -- center: conversation ----------------------------------------------------- */
.conversation-thread {
    display: grid;
    align-content: start;
    gap: 0.7rem;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    margin-bottom: 1rem;
    scrollbar-color: transparent transparent;
    /* CLAUDE-P40-VW7A-QA: the shared --conversation-inset (declared on
       .conversation-dock-panel above) on both sides, superseding the
       old right-only 0.3rem scrollbar-clearance padding - comfortably
       larger than a scrollbar needs, so that purpose is still served
       for free. */
    padding-left: var(--conversation-inset);
    padding-right: var(--conversation-inset);
    scroll-behavior: smooth;
}
/* CLAUDE-P40-E1A-VISUAL: was a filled beige bubble (human) and a
   bordered card (system) per message - the de-boxing addendum names
   this directly ("remove borders and filled cards around ordinary
   user and Archiosk messages"). CLAUDE-P40-VW7A-QA removed the
   per-role asymmetric indent (.human had margin-left:1.5rem/.system
   had margin-right:1.5rem instead - two different left edges,
   "inconsistent horizontal alignment" per that stage's own report) -
   role is now distinguished by the existing .role-label alone (already
   uppercase/letter-spaced/colored differently per role), not
   indentation; every message now starts at the SAME left edge, set by
   .conversation-thread's own shared inset above. */
.conversation-message {
    padding: 0.3rem 0;
    font-size: var(--text-sm);
    line-height: 1.45;
    color: var(--text-primary);
}
/* CLAUDE-POSTCAMEL-CA1C (Section 6/7): a real ConversationMessage reply
   can now contain deliberate embedded line breaks (a vertical, copy-
   paste-ready structure proposal) - the default browser white-space
   behavior collapses them to a single line, which would otherwise
   silently defeat the entire point of proposing a structure "vertically
   and hierarchically, not buried in prose". pre-wrap preserves both
   line breaks and indentation while still wrapping long lines (never
   forcing horizontal scroll) - every existing single-line reply is
   visually unaffected. */
.conv-message-text {
    white-space: pre-wrap;
}
.conversation-message .role-label {
    display: block;
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-metadata);
    margin-bottom: 0.3rem;
}
.conversation-message.system .role-label { color: var(--machine-blue); }
.conversation-empty { color: var(--text-secondary); font-size: 0.85rem; }
/* CLAUDE-P40-E3A-QA, Section 10: product-owner browser observation named
   an "oversized empty-history area" - .conversation-thread is flex:1
   (fills whatever Chat height is currently set, by design, so continuous
   resize has somewhere to put the extra space), which pinned a single
   empty-state line to the top and left a large bare gap beneath it.
   Centering only the genuinely-empty case (the message is the thread's
   only child) fills that same space on purpose instead of leaving it
   looking like an accident - a real conversation with messages keeps
   align-content: start (top-packed, scrollable) unaffected. */
.conversation-thread:has(> .conversation-empty:only-child) {
    align-content: center;
    justify-items: center;
}
.conversation-thread .conversation-empty { text-align: center; }

/* CLAUDE-P40-VW7A-QA: padding-left/right use the SAME --conversation-
   inset .conversation-thread uses above (declared once, on their
   shared ancestor .conversation-dock-panel) - the composer's own left/
   right edges now line up with the message thread's, and the input
   itself (flex:1) simply fills whatever width remains inside that
   inset, which grew once the old Chat (N) footer label was removed
   (CLAUDE-P40-VW7A-QA) - nothing here needs to know that label ever
   existed; it just fills available space, same as before. */
.conversation-input-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    flex-shrink: 0;
    padding-left: var(--conversation-inset);
    padding-right: var(--conversation-inset);
    /* CLAUDE-P40-VW7A-QA2 (product-owner browser correction): a real-
       browser check found the composer row (input + Send) touching the
       application frame/viewport edge - this element had left/right
       inset (above) but no bottom spacing at all, since it is the last
       child of .conversation-dock-panel, itself the last child of
       .chat-region (position:sticky; bottom:0). The SAME
       --conversation-inset token used for left/right, reused rather
       than a new one-off value, so left/right/bottom read as one
       consistent, balanced inset - not page overflow or an external
       blank strip, just intrinsic padding on a flex-shrink:0 item, so
       it survives every --chat-height value (resize/collapse/expand)
       and the narrow-viewport layout unchanged. */
    padding-bottom: var(--conversation-inset);
}
/* CLAUDE-P40-E1: the "Re: <anchored object>" badge a "Discuss this X"
   click (macros.aperture) sets on the ONE dock composer - flex-basis
   100% forces it onto its own line above the input/button when shown,
   rather than cramming into the same row. */
.dock-composer-anchor-label {
    flex-basis: 100%;
    font-family: var(--font-body);
    font-size: 0.78rem;
    color: var(--text-metadata);
    background: var(--surface-secondary);
    border-radius: 4px;
    padding: 0.25rem 0.5rem;
    width: fit-content;
}
.conversation-input-form input[type="text"] {
    flex: 1;
    font-family: var(--font-body);
    font-size: 0.9rem;
    /* CLAUDE-P40-VW7A-QA: back to symmetric internal padding - the
       form's own padding-left (above) is what now aligns the input's
       text with the message thread's own left edge, so the input no
       longer needs its own asymmetric compensation (CLAUDE-P40-VW8-QA's
       left:1.5rem special case is superseded, not layered on top of,
       the new shared inset - two overlapping fixes for the same
       alignment would just be a different inconsistency).

       CLAUDE-CA1D-RIVER-PO-02 (Section 18, "composer visual chrome"):
       a full border+radius+filled-surface box beside a filled Send
       button read as one heavy search-bar widget, not "a disciplined
       lane." Replaced the all-around border with a single bottom rule
       - "input area as a disciplined lane, not a boxed widget," the
       same parallel-horizontal-structure principle as the operational-
       action controls above, applied to the one remaining boxed
       control in this row. Background stays transparent (the panel's
       own surface shows through) rather than a separate lighter/darker
       fill, so there is nothing left reading as an enclosure. The
       clear-editable-region requirement is met by the bottom rule plus
       the existing global input:focus-visible outline (unchanged) -
       both survive dark/tinted/forest since --border already carries
       per-theme contrast the same as every other divider in this
       file.

       CLAUDE-CA1D-COMPOSER-LINE-01: a live product-owner refinement -
       the lane's top and bottom rules now reuse --machine-blue (the
       SAME token already used, conditionally, for this exact input's
       own :focus state below, and permanently for this same Chat
       surface's .conversation-message.system .role-label - i.e.
       already ARCHIOSK's chat/machine identity color, not a new one).
       Only these two hairlines change color; surface stays
       transparent, placeholder/mic/Send are untouched, so this reads
       as the lane's own quiet identity marker, never a tinted
       composer. Kept thin (1px, unchanged weight) and theme-aware for
       free, since --machine-blue is already redefined per Appearance
       mode (dark/tinted/forest) elsewhere in this file.

       CLAUDE-CA1D-COMPOSER-CONTEXT-LABEL-01: the top rule moved OFF this
       element onto .composer-context-rule directly below (an <input>
       cannot contain the embedded work-context label's child markup) -
       this input keeps only its own bottom rule, completely unchanged. */
    padding: 0.7rem 0.2rem;
    background: transparent;
    border: none;
    border-bottom: 1px solid var(--machine-blue);
    border-radius: 0;
    color: var(--text-primary);
}
/* CLAUDE-CA1D-COMPOSER-CONTEXT-LABEL-01: "blue upper rule -> embedded
   context label -> blue upper rule" - the composer's own upper line,
   now hosting the repositioned work-context indicator (formerly a
   separate `context_indicator` macro/div rendered above the whole
   composer). Two flex:1 line segments carry the actual --machine-blue
   rule; with no current_context they sit directly adjacent (gap: 0),
   reading as ONE continuous line - the exact same "uninterrupted when
   empty" behavior the lower rule already has, just applied to the
   upper one now that it can host content. */
.composer-context-rule {
    display: flex;
    align-items: center;
    gap: 0;
}
.composer-context-rule-line {
    flex: 1 1 auto;
    height: 0;
    border-top: 1px solid var(--machine-blue);
}
/* The label itself: text only, --attention-amber (ARCHIOSK's existing
   restrained amber/orange accent - "needs evidence / pending attention"
   per tokens.css's own semantic grammar, reused here for "this is the
   active work lane," not a new color). Deliberately no background/fill/
   radius - reads as a tab/folder name cut directly into the rule, not a
   pill or badge; its own left/right padding is what pushes the two rule
   segments apart, so the "gap" is real spacing, not a background-
   masking trick that would need to match every theme's own surface
   color to look right. */
.composer-context-label {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0 0.5rem;
    min-width: 0;
    flex: 0 1 auto;
    font-family: var(--font-body);
    font-size: 0.72rem;
    color: var(--attention-amber);
    background: transparent;
    white-space: nowrap;
}
.composer-context-label-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 220px;
}
.composer-context-label-text strong {
    font-weight: 600;
}
/* A real, focusable, keyboard-operable <button> (not a link styled to
   look like one) - reuses the existing supported clear-context route
   via `formaction`, no new switching/navigation mechanism introduced.
   Deliberately quiet/subordinate to the label text itself. */
.composer-context-clear {
    font-family: var(--font-body);
    font-size: 0.85rem;
    line-height: 1;
    color: var(--attention-amber);
    background: transparent;
    border: none;
    padding: 0 0.1rem;
    cursor: pointer;
    opacity: 0.75;
}
.composer-context-clear:hover,
.composer-context-clear:focus-visible {
    opacity: 1;
}
.composer-context-clear:focus-visible {
    outline: 2px solid var(--machine-blue);
    outline-offset: 1px;
}
.conversation-input-form button {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    padding: 0.7rem 1.1rem;
    border-radius: 4px;
    border: 1px solid var(--text-primary);
    background: var(--text-primary);
    color: var(--surface-primary);
    font-weight: 600;
    cursor: pointer;
}
/* CLAUDE-POSTCAMEL-VOICE1-PRE: a secondary, visually distinct control
   from Send (outline, not filled) - it never submits the form, so it
   must never look like the primary action. voice-input-listening is
   the ONLY visual state change while capturing - no separate "recording
   timer" or waveform UI, matching this stage's own "no audio permanence,
   no new conversation system" minimalism. */
.voice-input-button {
    background: transparent !important;
    color: var(--text-primary) !important;
    padding: 0.7rem 0.9rem !important;
}
.voice-input-button.voice-input-listening {
    background: var(--attention-amber) !important;
    color: var(--surface-primary) !important;
    border-color: var(--attention-amber) !important;
}
/* CLAUDE-VOICE1-LIVE-FIX-01: the one visible outcome surface for voice
   input - flex-basis:100% (same pattern as .dock-composer-anchor-label
   above) drops it onto its own line below input/mic/Send rather than
   cramming into that row or reflowing it. Empty and invisible via :empty
   whenever voice input is idle - never a permanent reserved-space line. */
.voice-input-status {
    flex-basis: 100%;
    font-family: var(--font-body);
    font-size: 0.78rem;
    color: var(--text-metadata);
}
.voice-input-status:empty {
    display: none;
}
/* CLAUDE-CA1D-INSTRUMENT-RAIL-01: the composer-adjacent execution strip
   proof (Plan-Mode report, Section D.3) - identical shape to
   .voice-input-status directly above (same flex-basis/font/color/:empty
   idiom), deliberately not a new visual pattern. static/js/case_workspace.js
   sets this text right before the composer's own classic form-POST fires
   and never clears it client-side - the next page load starts empty, so
   :empty below hides it again with no extra code. */
.composer-execution-status {
    flex-basis: 100%;
    font-family: var(--font-body);
    font-size: 0.78rem;
    color: var(--text-metadata);
}
.composer-execution-status:empty {
    display: none;
}
/* --failure-red per tokens.css's own grammar: "contradiction / failure" -
   a denied permission, missing microphone, or unavailable recognition
   service are real failures, not neutral status text like "Listening…". */
.voice-input-status[data-state="error"] {
    color: var(--failure-red);
}

/* CLAUDE-P40-VW7: OneNote-style selection toolbar for Project
   Conversation text -> Tags/Highlights/Tasks (static/js/case_workspace.js
   positions/shows/hides this; hidden by default via the [hidden]
   attribute, never a permanent floating toolbar - Section 10's own
   explicit "avoid adding" instruction). position:fixed because
   positionToolbar() computes against getBoundingClientRect(), viewport-
   relative coordinates. Solid token background (never rgba/translucent)
   and a z-index above every other overlay in this file, same fix and
   same reasoning as the Appearance popup's own comment above
   (.workspace-appearance-options, z-index 60) - "text beneath the popup
   remains visible through it" is a stacking defect, not a transparency
   one, so the fix here is identical: paint solid, stack higher than
   anything it could ever appear over (70, one step above the existing
   ceiling of 60). */
.conv-selection-toolbar {
    position: fixed;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.05rem;
    background: var(--surface-primary);
    border: 1px solid var(--border-strong);
    border-radius: 5px;
    padding: 0.25rem;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
    z-index: 70;
}
/* The [hidden] attribute alone does not hide the toolbar: this class
   selector's own `display: flex` and the UA default `[hidden]{display:
   none}` are equal specificity (0,1,0 each), and this rule is declared
   later in the cascade, so it silently won - the toolbar rendered
   permanently regardless of `toolbar.hidden` being set correctly by
   JS. Same bug CLASS as the tokens.css comment-boundary regression
   (CLAUDE-P40-VW8-QA-R3): logic was correct, a cascade/specificity
   detail made it invisible in its effect. */
.conv-selection-toolbar[hidden] {
    display: none;
}
.conv-selection-btn {
    font-family: var(--font-body);
    font-size: 0.76rem;
    padding: 0.35rem 0.55rem;
    border-radius: 4px;
    border: none;
    background: none;
    color: var(--text-primary);
    cursor: pointer;
    white-space: nowrap;
    text-align: left;
}
.conv-selection-btn:hover:not(:disabled) { background: var(--surface-hover); }
.conv-selection-btn:disabled { color: var(--text-disabled); cursor: default; }
.conv-selection-status {
    position: fixed;
    z-index: 70;
    font-size: var(--text-xs);
    color: var(--text-metadata);
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.3rem 0.5rem;
    bottom: 1rem;
    right: 1rem;
    max-width: 320px;
}
/* CLAUDE-P40-VW8-QA (reversibility correction): the short-lived Undo
   affordance for a Tag/Highlight/Important/Question removal - sits
   immediately left of .conv-selection-status (same fixed bottom-right
   corner, same z-index/solid-background/border treatment) so the
   result message and the way to reverse it read as one unit. Written
   with its own [hidden] override from the start (learned directly from
   .conv-selection-toolbar's own bug above - display declared on the
   base rule always needs one, not just when a report catches its
   absence). */
.conv-selection-undo {
    position: fixed;
    z-index: 70;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--machine-blue);
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.3rem 0.6rem;
    bottom: 1rem;
    right: 340px;
    cursor: pointer;
}
.conv-selection-undo[hidden] { display: none; }
.conv-selection-undo:hover { border-color: var(--border-strong); }
.conv-selection-undo:focus-visible { outline: 2px solid var(--machine-blue); outline-offset: 2px; }

/* The Remove Tag dialog's own applied-Tags list - reuses .conv-dialog's
   shared modal chrome (background/border/z-index/centering, above),
   this only lays out the rows themselves. Each row identifies its Tag
   by NAME (text), not the color swatch alone - "do not rely on color
   alone" for state identification. */
.conv-remove-tag-list {
    list-style: none;
    margin: 0.5rem 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}
.conv-remove-tag-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3rem 0;
}
.conv-remove-tag-name {
    flex: 1;
    font-size: 0.85rem;
    color: var(--text-primary);
}

/* Add Tag / Make Task - small, compact dialogs (Section 10: "don't
   cover most of the selection", "avoid heavy shadows/filled cards"), a
   fixed-position centered card rather than a full-screen modal takeover
   - the conversation stays visible around it. Same solid-background/
   raised-z-index treatment as the selection toolbar above, one step
   higher again (80) so a dialog always paints over a still-visible
   toolbar rather than the two fighting for stacking order. */
.conv-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 80;
    width: min(360px, calc(100vw - 2rem));
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    background: var(--surface-primary);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    padding: 0.9rem;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
}
.conv-dialog form { display: flex; flex-direction: column; gap: 0.5rem; }
.conv-dialog-heading {
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 1rem;
    margin: 0 0 0.2rem;
    color: var(--text-primary);
}
.conv-dialog-error {
    font-size: var(--text-sm);
    color: var(--failure-red);
    background: var(--failure-red-tint);
    border-radius: 4px;
    padding: 0.35rem 0.5rem;
    margin: 0;
}
.conv-dialog-quote {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    font-style: italic;
    border-left: 3px solid var(--border-strong);
    padding-left: 0.6rem;
    margin: 0 0 0.3rem;
}
.conv-dialog-or {
    font-size: var(--text-xs);
    color: var(--text-metadata);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 0.2rem 0 0;
}
.conv-dialog label {
    font-size: var(--text-xs);
    color: var(--text-metadata);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.conv-dialog select,
.conv-dialog input[type="text"] {
    font-family: var(--font-body);
    font-size: 0.9rem;
    padding: 0.5rem 0.6rem;
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-primary);
}
.conv-tag-color-picker {
    border: none;
    padding: 0;
    margin: 0.2rem 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.conv-tag-color-picker legend {
    font-size: var(--text-xs);
    color: var(--text-metadata);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0;
    width: 100%;
}
.conv-tag-color-option {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    font-size: var(--text-xs);
    text-transform: capitalize;
    color: var(--text-secondary);
    cursor: pointer;
}
.conv-tag-color-swatch {
    display: inline-block;
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
}
.conv-dialog-actions {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.3rem;
}
.conv-dialog-actions .btn { padding: 0.5rem 1rem; font-size: var(--text-sm); }

/* CLAUDE-P40-VW8, renamed and reused CLAUDE-P40-VW7B: the same fixed/
   centered/solid-background/high-z-index dialog idiom .conv-dialog
   already established (CLAUDE-P40-VW7) - this used to be the Project-
   switching interruption dialog, retired in CLAUDE-P40-VW7B once its
   only trigger (a different Project's own Lists row, clickable while
   a Project was open) stopped existing at all (Section 3's own
   removal of the portfolio from the opened workspace). Renamed rather
   than deleted-then-recreated for the NEW fifth-Investigation capacity
   dialog (Section 9) - "do not introduce a separate visual language"
   (Section 13) - same markup shape (heading/body/actions/note),
   different content and trigger. */
.attention-capacity-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 80;
    width: min(380px, calc(100vw - 2rem));
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    background: var(--surface-primary);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    padding: 0.9rem;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
}
.attention-capacity-dialog-heading {
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 1rem;
    margin: 0 0 0.4rem;
    color: var(--text-primary);
}
.attention-capacity-dialog-body {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    margin: 0 0 0.7rem;
}
.attention-capacity-dialog-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.attention-capacity-dialog-actions .btn { padding: 0.5rem 0.8rem; font-size: var(--text-sm); }
.attention-capacity-dialog-note {
    font-size: var(--text-xs);
    color: var(--attention-amber);
    margin: 0.6rem 0 0;
}

/* Navigate-to-source (Section 4): a temporary, animated flash - never a
   permanent border/fill (CLAUDE-P40-E1A-VISUAL's own "remove borders and
   filled cards around ordinary...messages" de-boxing rule above still
   applies to a message's RESTING appearance; this is time-boxed feedback
   that JS removes 2.5s after applying it, not a redesign of that
   resting state). Built on --highlight-orange - already means "the one
   current/active position in a sequence," a genuine semantic match for
   "this is what you navigated to," not a repurposing.

   CLAUDE-CA1D-HIGHLIGHT-CONTRAST-02 (Product Owner visual refinement,
   "translucent focus, not opaque highlight"): originally an opaque flat
   --highlight-orange-tint wash - readable, but a solid block that hid
   the surrounding cockpit rather than sitting as a layer behind it, and
   visually indistinguishable in KIND from .tag-highlight-inline's own
   PERSISTENT state above (same flat fill, just a different hue) even
   though the two mean different things: this one is a few seconds of
   "you just arrived here," that one is "the user chose to mark this."
   Replaced with an actual glow - a translucent color-mix() background
   wash plus a soft blurred box-shadow aura, both fading to nothing -
   using the same low-alpha reasoning verified above, so legibility
   holds at every animation frame, not just at rest.

   CLAUDE-CA1D-HIGHLIGHT-CONTRAST-03 (Product Owner visual refinement,
   "reduce highlight strength" - explicitly "temporary source-return
   focus should fade quickly and never resemble a persistent selected
   block"): the original 22%/35% peak still read as a block on a real
   multi-line message, the opposite of what a glancing "you arrived
   here" cue should feel like. Lowered the background peak to 10% (below
   even the persistent-highlight's own 12%, since this state should
   read as the quieter of the two - a flash, not a mark) and moved most
   of the visible effect onto the blurred box-shadow (18% peak, spread
   over a wide 24px blur so no single pixel is anywhere near that
   opacity) - an edge glow around the message rather than a fill across
   it, matching "text -> faint translucent tint -> subtle edge/glow."
   Both keyframe stops are far below the already-verified 22% case, so
   contrast only improves further. Reduced-motion keeps a single static
   low-alpha wash (no shadow, no keyframes) rather than a hard opaque
   block, so the "soft, restrained" character survives even without
   animation. */
.conv-source-flash {
    animation: conv-source-flash-fade 2.5s ease-out;
    border-radius: 6px;
}
@keyframes conv-source-flash-fade {
    0% {
        background: color-mix(in srgb, var(--highlight-orange) 10%, transparent);
        box-shadow: 0 0 24px 0 color-mix(in srgb, var(--highlight-orange) 18%, transparent);
    }
    100% {
        background: transparent;
        box-shadow: 0 0 24px 0 transparent;
    }
}
@media (prefers-reduced-motion: reduce) {
    .conv-source-flash {
        animation: none;
        background: color-mix(in srgb, var(--highlight-orange) 8%, transparent);
        box-shadow: none;
    }
}

/* -- disclosure grammar (application-wide) ---------------------------------
   ONE mechanism for every collapse/expand control, whatever <details> it
   decorates - a bare "+"-prefixed nested affordance (.add-source-details)
   or a labeled section header (.accordion-summary). Never a native
   OS-drawn triangle, never a mix of unrelated arrow glyphs - the shape
   and motion always mean "this expands," full stop. */
.add-source-details { margin-top: 0.6rem; }
.add-source-details summary {
    display: flex;
    align-items: center;
    font-family: var(--font-body);
    font-size: 0.85rem;
    color: var(--text-metadata);
    cursor: pointer;
    margin-bottom: 0.4rem;
    list-style: none;
}
.add-source-details summary::-webkit-details-marker { display: none; }
.add-source-details summary::before {
    content: "\25B8";
    display: inline-block;
    margin-right: 0.5rem;
    color: var(--text-secondary);
    font-size: 0.72rem;
    flex-shrink: 0;
    transition: transform 0.12s ease;
}
.add-source-details[open] > summary::before { transform: rotate(90deg); }

/* CLAUDE-CA1D-RIVER-PO-01 (River Action Stack): each item reuses
   .add-source-details itself (subdisclosure, above) for its own
   independent expand/collapse - the SAME rotating-triangle disclosure
   grammar every other collapsible surface in this app already uses, per
   that rule's own "never a mix of unrelated arrow glyphs" comment. This
   block only styles the list container and the item's own expanded
   content, never a second disclosure mechanism. */
.conv-river-action-stack {
    list-style: none;
    margin: 0.5rem 0 0;
    padding: 0;
}
.conv-river-action + .conv-river-action { margin-top: 0.4rem; }
.conv-river-action-detail {
    padding-left: 1.2rem;
    font-size: var(--text-sm);
    color: var(--text-secondary);
}
.conv-river-action-detail p { margin: 0.3rem 0; }
.conv-river-action-uncertainty { color: var(--attention-amber); }
.conv-river-action-evidence-label {
    font-size: var(--text-xs);
    color: var(--text-metadata);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* -- Case Workspace accordion/focus sections ------------------------------- */
.accordion-section {
    border-top: 1px solid var(--border);
    margin-top: 0.6rem;
    padding-top: 0.6rem;
}
.workspace-pane > .accordion-section:first-of-type,
.workspace-pane > h2 + .accordion-section {
    border-top: none;
    margin-top: 0;
    padding-top: 0;
}
.accordion-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    font-family: var(--font-body);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-size: 0.8rem;
    color: var(--text-metadata);
    cursor: pointer;
    list-style: none;
}
.accordion-summary::-webkit-details-marker { display: none; }
.accordion-summary::before {
    content: "\25B8";
    display: inline-block;
    margin-right: 0.5rem;
    color: var(--text-secondary);
    font-size: 0.72rem;
    transition: transform 0.12s ease;
}
.accordion-section[open] > .accordion-summary::before { transform: rotate(90deg); }
.accordion-summary-text { flex: 1; }
.accordion-summary-status {
    color: var(--text-metadata);
    font-size: 0.8rem;
    text-transform: none;
    letter-spacing: normal;
    white-space: nowrap;
}
.accordion-section[open] > .accordion-summary { margin-bottom: 0.5rem; }
.collapse-all-btn {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--text-metadata);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.35rem 0.65rem;
    cursor: pointer;
}
.collapse-all-btn:hover { color: var(--text-primary); border-color: var(--border-strong); }

/* -- Project Home (calm, single-purpose project entry - Prompt 3) --------- */
/* CLAUDE-P40-E2B: rendered inside .workspace-pane-display now (that
   wrapper carries the plain/neutral Display surface - see its own
   comment above), inside division 0's own .display-division-content. */
.project-home { max-width: 760px; padding: 0.25rem 0 1.5rem; }
.project-home-back { font-size: var(--text-sm); color: var(--text-secondary); margin: 0 0 0.6rem; }
.project-home-back a { color: var(--text-secondary); }
.project-home-back a:hover { color: var(--text-primary); }

/* CLAUDE-P40-VW8-QA (New Investigation Action in Lists): the focused
   create-form panel projected into Display - reuses .project-home's own
   max-width/padding (class list is "project-home new-case-form-panel"),
   these two rules are the only genuinely new geometry needed. */
.new-case-form-heading { font-family: var(--font-display); font-size: 1.3rem; font-weight: 500; margin: 0 0 0.8rem; }
.new-case-form-actions { display: flex; gap: 0.6rem; align-items: center; margin-top: 0.3rem; }

/* CLAUDE-POSTCAMEL-INVESTIGATION-AR1: "Continue from Archive" chooser -
   reuses .project-home/.new-case-form-panel/.source-list/.source-item/
   .pane-note/.link-button/.btn wholesale (same panel this stage's
   "focused form/chooser, never a management page" precedent already
   established for New Investigation); only the row's own internal
   layout (header + trailing actions + an initially-hidden Snapshot
   output) is genuinely new geometry. */
.archive-chooser-row { display: grid; gap: 0.35rem; }
.archive-chooser-row-header { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.archive-chooser-row-actions { display: flex; align-items: center; gap: 0.8rem; }
.archive-chooser-continue-form { display: inline; }
.archive-chooser-snapshot { border-left: 2px solid var(--border); padding-left: 0.6rem; margin-top: 0.2rem; }

/* CLAUDE-P40-VW9 (Governed Files Display and Project File Architecture):
   the two governed sibling roots read as different GOVERNANCE SPACES
   without inventing a new color distinction (this file's own header
   comment: color is used rarely, only for the fixed semantic meanings
   above - Data Room/Design-Builder are not one of them). The
   differentiation is structural/neutral instead: Data Room gets the
   quieter --surface-secondary + --border-strong treatment ("controlled,
   structural"); Design-Builder Workspace gets --surface-primary + the
   ordinary --border ("open, editable") - the same two-tier surface
   language main.css already uses elsewhere (nav vs. panel), reused, not
   a new one invented for this stage. .files-surface widens past
   .project-home's own 760px max-width since two side-by-side roots need
   more room; narrows to one stacked column under the existing 900px
   breakpoint (see main.css's own responsive rules), never a second,
   parallel breakpoint system. */
.files-surface { max-width: 1100px; }
.files-roots { display: grid; grid-template-columns: 1fr 1fr; gap: 1.2rem; margin-top: 1rem; }
@media (max-width: 900px) {
    .files-roots { grid-template-columns: 1fr; }
}
.files-root {
    border-radius: 6px;
    padding: 1rem 1.1rem;
}
.files-root-data-room { background: var(--surface-secondary); border: 1px solid var(--border-strong); }
.files-root-design-builder { background: var(--surface-primary); border: 1px solid var(--border); }
.files-breadcrumb { font-size: 0.85rem; color: var(--text-secondary); margin: 0.6rem 0; }
.files-breadcrumb a { color: var(--text-secondary); }
.files-breadcrumb a:hover { color: var(--text-primary); }
.files-folder-list { list-style: none; margin: 0.6rem 0 0; padding: 0; display: grid; gap: 0.25rem; }
.files-folder-row {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    padding: 0.35rem 0.5rem; border-radius: 4px;
}
.files-folder-row:hover { background: var(--surface-hover); }
.files-folder-link { color: var(--text-primary); font-size: 0.92rem; }
.files-folder-actions { position: relative; flex-shrink: 0; }
.files-folder-actions summary {
    list-style: none; cursor: pointer; color: var(--text-metadata);
    padding: 0.1rem 0.4rem; border-radius: 4px;
}
.files-folder-actions summary::-webkit-details-marker { display: none; }
.files-folder-actions summary:hover { color: var(--text-primary); background: var(--surface-hover); }
/* CLAUDE-P40-VW9A (Files Cockpit Close-Out, A1/A3): the panel renders
   IN-FLOW, never as a floating absolute overlay. It used to be
   position:absolute/right:0 against .files-folder-actions itself (the
   small "..." trigger near the row's own right edge) - real testing
   this stage found the SAME underlying problem at two different
   widths: at the realistic ~300-400px a multi-Display division
   actually renders at (A3's own ask), the panel genuinely extended
   past the iframe body's own left edge; and, independently, at
   ORDINARY full desktop width, a panel tall enough to hold three
   stacked forms could visually cover several folder rows below it,
   taking THEIR triggers physically out of reach too - not a
   narrow-viewport-only problem after all (confirmed directly by a
   10-folder real-browser regression test, not assumed). :has()
   (already used elsewhere in this file - see
   .conversation-thread:has(...) above) switches the ROW itself to a
   column layout only while its OWN menu is open, so the expanding
   panel pushes later rows down instead of floating over them -
   applied unconditionally rather than gated behind a width
   breakpoint, since the reachability problem it fixes was never
   actually width-specific. A bounded, in-flow variant reusing
   already-tested styling, not a redesign of the page. */
.files-folder-row:has(.files-folder-actions[open]) { flex-direction: column; align-items: stretch; }
.files-folder-actions-panel {
    background: var(--surface-primary); border: 1px solid var(--border-strong);
    border-radius: 6px; padding: 0.6rem; display: grid; gap: 0.5rem;
    margin-top: 0.4rem; width: 100%; box-sizing: border-box;
}
.files-folder-actions-panel form { display: flex; gap: 0.35rem; align-items: center; flex-wrap: wrap; }
@media (max-width: 480px) {
    /* The realistic ~300-400px multi-Display division case: even a
       wrapped horizontal form (select + button) can feel cramped -
       stack its own fields vertically too, at that width only. */
    .files-folder-actions-panel form { flex-direction: column; align-items: stretch; }
}

/* Project Home's title/actions row is now the shared .dash-head (see
   above) instead of its own parallel rule. */
.project-home-subtitle { color: var(--text-secondary); font-size: 0.85rem; margin: 0.35rem 0 0; max-width: 56ch; }

.project-home-controls { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }
.project-home-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 4px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-metadata);
    cursor: pointer;
    font-size: 1rem;
    list-style: none;
}
.project-home-icon-btn::-webkit-details-marker { display: none; }
.project-home-icon-btn:hover { color: var(--text-primary); border-color: var(--border-strong); }
/* Star is a personal bookmark, not a governance or identity signal - tonal
   only, never bee-yellow (reserved) or seal-red (not consequential). */
.project-home-icon-btn.active { color: var(--text-primary); border-color: var(--border-strong); background: var(--surface-selected); }
.project-home-overflow { position: relative; }
.project-home-overflow-panel {
    margin-top: 0.6rem;
    padding: 0.9rem;
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 6px;
    max-width: 320px;
}

.project-home-composer { margin: 0 0 0.5rem; }
.composer-plus { margin-top: 0.5rem; }
.composer-plus summary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 4px;
    border: 1px solid var(--border);
    color: var(--text-metadata);
    cursor: pointer;
    font-size: 0.9rem;
    list-style: none;
}
.composer-plus summary::-webkit-details-marker { display: none; }
.composer-plus summary:hover { color: var(--text-primary); border-color: var(--border-strong); }
.composer-plus-links { font-size: 0.85rem; color: var(--text-secondary); margin: 0.5rem 0 0; display: flex; gap: 0.9rem; flex-wrap: wrap; }
.composer-plus-links a { color: var(--machine-blue); }

.project-home-state-message {
    color: var(--text-secondary);
    font-size: 0.8rem;
    line-height: 1.5;
    max-width: 62ch;
    margin: 0.3rem 0 1rem;
}

/* -- left: unpromoted (machine-extracted) Requirements ---------------------
   Same signal as .finding-card's left border below - this is
   machine-produced, provisional-by-nature content too, and previously had
   no visual distinction from ordinary governed text at all (visual
   language review finding: the one concrete gap on a near-empty Project
   Home). Lighter-weight than a full card since this sits inside an
   already-nested accordion, not the main Artifact Workspace list - same
   signal, proportionate to context. */
.unpromoted-requirement {
    border-left: 3px solid var(--machine-blue);
    padding: 0.3rem 0 0.3rem 0.6rem;
    margin: 0.3rem 0;
}
.unpromoted-requirement small { color: var(--machine-blue); }

/* -- right: artifact workspace -------------------------------------------- */
.finding-list { display: grid; gap: 1rem; }
/* The left border marks this as a machine-produced Finding - a genuine,
   restrained use of the machine/reference signal (Prompt: BEEHIVE Visual
   Color System #6), not decoration. */
.finding-card {
    background: var(--surface-secondary);
    border: 1px solid var(--border);
    border-left: 4px solid var(--machine-blue);
    border-radius: 4px;
    padding: 1rem 1.1rem;
}
.finding-card.focused { border-left-color: var(--border-strong); box-shadow: 0 0 0 1px var(--border-strong); }
.finding-statement { font-size: 0.9rem; color: var(--text-primary); margin: 0 0 0.5rem; }
.finding-confidence {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--machine-blue);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.finding-artifact-thumb {
    display: block;
    max-width: 100%;
    border-radius: 3px;
    margin: 0.7rem 0;
    border: 1px solid var(--machine-blue);
}

.finding-provenance {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    color: var(--text-metadata);
    background: var(--surface-primary);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 0.5rem 0.6rem;
    margin-bottom: 0.7rem;
    line-height: 1.6;
    word-break: break-all;
}
.finding-provenance span { color: var(--text-metadata); }
.finding-provenance strong { color: var(--text-primary); font-weight: 500; }

.snapshot-detail {
    background: var(--surface-secondary);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.7rem 0.9rem;
    margin: 0.6rem 0;
}
.snapshot-detail p:first-child { margin-top: 0; }
.snapshot-detail .source-list { margin-top: 0.4rem; }

.finding-review-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.6rem; }
.review-btn {
    font-family: var(--font-body);
    font-size: 0.85rem;
    padding: 0.4rem 0.7rem;
    border-radius: 999px;
    cursor: pointer;
    background: transparent;
}
.review-btn.accept { border: 1px solid var(--accepted-green); color: var(--accepted-green); }
.review-btn.accept:hover { background: var(--accepted-green-tint); }
.review-btn.reject { border: 1px solid var(--failure-red); color: var(--failure-red); }
.review-btn.reject:hover { background: var(--failure-red-tint); }
.review-btn.needs_evidence { border: 1px solid var(--attention-amber); color: var(--attention-amber); }
.review-btn.needs_evidence:hover { background: var(--attention-amber-tint); }
.review-btn.correction { border: 1px solid var(--text-metadata); color: var(--text-metadata); }
.review-btn.correction:hover { border-color: var(--text-primary); color: var(--text-primary); }
/* Human authority / deliberate commitment (Approval Gate "Yes") - the
   sealing-wax accent, used only here, extremely sparingly. */
.review-btn.seal { border: 1px solid var(--seal-red); color: var(--seal-red); }
.review-btn.seal:hover { background: var(--seal-red-tint); }
/* CLAUDE-CA1D-RIVER-01 (the "fourth beat"): each real action is its own
   <form> (create_task_route/add_tag_occurrence_route both require a
   real POST, unlike .conv-next-steps' plain <a> navigation links) - a
   compact horizontal row, same idiom as this stage's own Section 3
   example ("Prepare deadlines · Make tasks · Check conflict"), not a
   stacked list. */
.conv-operational-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.5rem;
}
.conv-operational-action-form { display: inline-flex; }
.conv-operational-action-form button[disabled] { opacity: 0.6; cursor: default; }
/* CLAUDE-CA1D-RIVER-PO-02 (Section 17, "action control visual chrome"):
   these two buttons shared .review-btn.needs_evidence wholesale with
   Finding review's accept/reject/needs_evidence/correction/seal pills -
   fine for a deliberate review decision, but the Product Owner found it
   read as a full enclosed capsule for what is really a light, casual
   offer ("Make a Task from this"). Scoped to THIS container only (base
   .review-btn is untouched - Finding review keeps its own pill) so the
   correction cannot bleed into an unrelated, already-working control.
   "Ending-line / side separation rather than top-and-bottom boxing":
   no border/background/radius at rest, a single underline that appears
   on hover/focus (interactivity is still obvious, just not a standing
   box), and a hairline left-rule between adjacent actions instead of
   gap alone - separation without a second enclosure per action. Padding
   keeps the click/tap target close to .review-btn's own original
   height even though the visible box is gone. */
.conv-operational-actions .review-btn {
    border: none;
    border-radius: 0;
    background: transparent;
    padding: 0.35rem 0.1rem;
    border-bottom: 1px solid transparent;
}
.conv-operational-actions .review-btn:hover {
    background: transparent;
    border-bottom-color: currentColor;
}
.conv-operational-action-form:not(:first-child) {
    border-left: 1px solid var(--border);
    padding-left: 0.5rem;
}
/* CLAUDE-CA1D-RIVER-03: a quiet, one-time teaching line, not a second
   toolbar - deliberately plain text (no border/background/icon), the
   same restraint .conv-next-steps's own plain <a> row already uses.
   [hidden] (native, not a class) is the actual on/off switch - this
   rule only styles it for the one time it IS shown. */
.conv-selection-hint {
    font-size: var(--text-xs);
    color: var(--text-metadata);
    font-style: italic;
    margin: 0.3rem 0 0;
}

.review-decision-badge {
    display: inline-block;
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 0.25rem 0.55rem;
    border-radius: 999px;
    margin-top: 0.5rem;
}
.review-decision-badge.accept { color: var(--accepted-green); border: 1px solid var(--accepted-green); background: var(--accepted-green-tint); }
.review-decision-badge.reject { color: var(--failure-red); border: 1px solid var(--failure-red); background: var(--failure-red-tint); }
.review-decision-badge.needs_evidence { color: var(--attention-amber); border: 1px solid var(--attention-amber); background: var(--attention-amber-tint); }
.review-decision-badge.correction { color: var(--text-metadata); border: 1px solid var(--text-metadata); }

.applied-badge {
    display: inline-block;
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 0.3rem 0.6rem;
    border-radius: 3px;
    color: var(--surface-primary);
    background: var(--accepted-green);
    font-weight: 700;
}

.correction-note {
    font-size: var(--text-sm);
    color: var(--text-primary);
    background: var(--surface-secondary);
    border-left: 3px solid var(--text-metadata);
    padding: 0.5rem 0.7rem;
    margin-top: 0.5rem;
}

.apply-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-top: 1.4rem;
    padding-top: 1.2rem;
    border-top: 1px solid var(--border);
}
.apply-bar p { margin: 0; font-size: 0.8rem; color: var(--text-secondary); }
/* Apply Confirmed Findings / Issue RFI: a consequential, approval-gated,
   irreversible commitment - the moment BEEHIVE's own vocabulary calls
   sealing/formal decision. See the color-scarcity rule: this is one of
   the few buttons in the whole application that earns seal-red. */
.apply-button {
    font-family: var(--font-body);
    font-size: 0.85rem;
    padding: 0.7rem 1.2rem;
    border-radius: 4px;
    border: 1px solid var(--seal-red);
    background: var(--seal-red);
    color: var(--surface-primary);
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
}
.apply-button:disabled { background: transparent; color: var(--text-disabled); border-color: var(--border); cursor: not-allowed; }

.findings-empty { color: var(--text-secondary); font-size: var(--text-sm); padding: 2rem 0; text-align: center; }

/* -- Reviewer Validation / Disposition / review_state badges --------------
   Three separate concepts, three separate badge families - never merged
   into one color/label so the distinction stays visible in the UI, not
   just in the data model. */
.review-state-badge {
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.15rem 0.45rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    color: var(--text-metadata);
}
.review-state-badge.review-state-verified { color: var(--accepted-green); border-color: var(--accepted-green); }
.review-state-badge.review-state-not-verified { color: var(--failure-red); border-color: var(--failure-red); }
.review-state-badge.review-state-unverified { color: var(--text-metadata); border-color: var(--border); }
/* TemporalObligation's derived condition (evaluate_temporal_condition) -
   only the two states someone actually needs to notice get color;
   not-yet-due and the terminal statuses (completed/cancelled/superseded)
   stay the neutral default pill, same "color is rare, only where it
   carries real information" rule as everywhere else in this file. */
.review-state-badge.review-state-overdue { color: var(--failure-red); border-color: var(--failure-red); }
.review-state-badge.review-state-due, .review-state-badge.review-state-due-soon { color: var(--attention-amber); border-color: var(--attention-amber); }
/* CLAUDE-P13: PerspectiveAssessment polarity, reusing the same badge
   component - "risk"/"opportunity" are just two more states in the same
   vocabulary as verified/overdue/etc., not a new visual component. */
.review-state-badge.review-state-risk { color: var(--risk-red); border-color: var(--risk-red); }
.review-state-badge.review-state-opportunity { color: var(--accepted-green); border-color: var(--accepted-green); }

/* CLAUDE-P13: navigation-membrane layer toggle. Layer annotations
   (currently just the risk/opportunity badge below) render into the
   page unconditionally - cheap, they're small badges - and are shown or
   hidden by one class on <html>, exactly like launcher-hidden above. No
   server round-trip to toggle; nothing changes until a reviewer
   explicitly turns a layer on, and the governed content underneath
   (the Requirement's own text, its Perspective disclosure) is completely
   unaffected either way - the map, not the terrain. */
[data-layer] { display: none; }
.layer-risk-active [data-layer="risk"] { display: inline; }

/* CLAUDE-P38 (OBS-12): History defaults to a compact summary; "Show
   full history" flips one class on <html>, same client-side-only
   pattern as the risk layer toggle above - the complete audit record
   (services/governance.py's GovernanceLog) is unaffected either way,
   only what's rendered by default changes. */
.history-full { display: none; }
.history-full-active .history-full { display: block; }
.history-full-active .history-summary { display: none; }

/* Requirement-evidence explainability (Connect Accepted Knowledge to
   Requirement Impact tranche) - maps the existing Relationship.
   relationship_type vocabulary onto the same semantic language already
   used above, not a new truth-status vocabulary. */
.evidence-badge {
    font-family: var(--font-body);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.15rem 0.45rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    color: var(--text-metadata);
}
.evidence-badge.evidence-green { color: var(--accepted-green); border-color: var(--accepted-green); }
.evidence-badge.evidence-red { color: var(--failure-red); border-color: var(--failure-red); }
.evidence-badge.evidence-amber { color: var(--attention-amber); border-color: var(--attention-amber); }
.evidence-badge.evidence-cyan { color: var(--machine-blue); border-color: var(--machine-blue); }

.review-decision-badge.validation-correct { color: var(--accepted-green); border: 1px solid var(--accepted-green); background: var(--accepted-green-tint); }
.review-decision-badge.validation-incorrect { color: var(--failure-red); border: 1px solid var(--failure-red); background: var(--failure-red-tint); }
.review-decision-badge.validation-partial,
.review-decision-badge.validation-needs_evidence { color: var(--attention-amber); border: 1px solid var(--attention-amber); background: var(--attention-amber-tint); }
.review-decision-badge.validation-not_applicable { color: var(--text-metadata); border: 1px solid var(--text-metadata); }

.review-decision-badge.disposition-confirmed,
.review-decision-badge.disposition-known_accepted { color: var(--accepted-green); border: 1px solid var(--accepted-green); background: var(--accepted-green-tint); }
.review-decision-badge.disposition-rejected { color: var(--failure-red); border: 1px solid var(--failure-red); background: var(--failure-red-tint); }
.review-decision-badge.disposition-deferred,
.review-decision-badge.disposition-known_pending_acceptance { color: var(--attention-amber); border: 1px solid var(--attention-amber); background: var(--attention-amber-tint); }

/* -- Revision-awareness ---------------------------------------------------- */
.revision-notice {
    background: var(--attention-amber-tint);
    border: 1px solid var(--attention-amber);
    border-left: 4px solid var(--attention-amber);
    border-radius: 4px;
    padding: 0.9rem 1.1rem;
    margin-bottom: 1rem;
}
.revision-notice strong { color: var(--attention-amber); text-transform: uppercase; font-family: var(--font-body); font-size: var(--text-sm); letter-spacing: 0.05em; }
.revision-notice p { color: var(--text-primary); font-size: 0.85rem; margin: 0.4rem 0 0.6rem; }
.region-status { font-family: var(--font-mono); }
.region-status-unchanged { color: var(--accepted-green); }
.region-status-changed { color: var(--failure-red); }
.region-status-unable_to_determine { color: var(--text-metadata); }

/* -- Delegation Choice / RFI preview & draft -------------------------------- */
.delegation-choice, .rfi-preview, .rfi-draft-card {
    background: var(--surface-secondary);
    border: 1px solid var(--machine-blue);
    border-radius: 4px;
    padding: 0.9rem 1.1rem;
    margin: 1rem 0;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.delegation-choice form, .rfi-preview form, .rfi-draft-card form { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }

/* -- Confirm page family (templates/confirm_base.html) -----------------------
   The one-decision interrupt: Approval Gate actions and project deletion
   both need a single centered card, no page header, no nav-adjacent chrome
   - a real, named geometry now, not two copies of an inline-styled
   .case-workspace grid override repurposed for one column. */
.confirm-page { max-width: 560px; margin: 3rem auto; padding: 0 1rem; }

/* -- Approval Gate ----------------------------------------------------------- */
.approval-gate h2 { font-family: var(--font-display); font-size: 1.1rem; margin: 0.4rem 0 1rem; }
.approval-gate-actions { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 1.2rem; align-items: flex-start; }
.approval-gate-actions button { width: 100%; text-align: left; padding: 0.7rem 1rem; }

/* CLAUDE-P40-VW7A: UI Reference Mode - a developer/QA overlay only (the
   "UI Reference Mode" checkbox in the Account menu), never rendered by
   default. Every [data-ui-ref] element gets a small monospace badge via
   ::after and attr(data-ui-ref) - zero JS beyond the toggle itself needed
   to read the value, since CSS's own attr() function renders it
   directly. position:relative is scoped to when the mode is ACTIVE
   only (never applied at rest) so this has zero layout effect on the
   ordinary rendered page - the entire point of a reference registry is
   that consulting it never changes what a reviewer normally sees.
   High z-index (100, one step above every other overlay this app
   defines - see .conv-dialog's own 80) so the badge is never hidden
   behind a popup/dialog while inspecting one. pointer-events:none so
   the badge itself is never a click target, and pre-wrap/monospace so
   a longer dot-path id never gets silently clipped. */
.ui-reference-mode-active [data-ui-ref] {
    position: relative;
    outline: 1px dashed var(--machine-blue);
    outline-offset: 1px;
}
.ui-reference-mode-active [data-ui-ref]::after {
    content: attr(data-ui-ref);
    position: absolute;
    top: -0.05rem;
    left: -0.05rem;
    transform: translateY(-100%);
    z-index: 100;
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    line-height: 1.3;
    color: var(--surface-primary);
    background: var(--machine-blue);
    padding: 0.05rem 0.3rem;
    border-radius: 2px;
    white-space: pre;
    pointer-events: none;
}
