/* ============================================================================
 * Unified Media Modal — Single modal for all media viewing contexts
 * Replaces: .mdm-* (browse), .smc-* (curator), .mi-* (presentation inspect)
 * ============================================================================ */

/* ── Panel accent — Archive Dusk, panel-wide (hardening-vault-faculties S6) ──
 *
 * Joe's S0 ruling: retire the hard-coded green PANEL-WIDE, not at the three
 * sites the plan happened to name. There were TWELVE `#16a34a` occurrences in
 * this file plus two of its `#15803d` hover partner — section labels, the type
 * badge, the analysis rule, the spinner, the active-button state, quote rules,
 * the expand link, the commentary box and its send button — and a panel that
 * re-themes eleven-fourteenths of the way is a panel that looks broken.
 *
 * `--ffa-active-base` is the Archive Dusk active-tier token (archive-dusk.css):
 * it is set by whatever `.ffa-tier-N` / `.ffa-theme-<category>` ancestor the
 * panel is opened inside, so a UMI opened from a themed story picks up that
 * story's tier. Indigo (`--ffa-tier-1-base`) is the documented fallback and is
 * what an unthemed panel renders today — the UMI overlay mounts on
 * `document.body`, so nothing sets the token until a call site passes a theme.
 * That call-site wiring is a one-line change in files outside S6's scope and
 * is carried to SR rather than reached for here.
 *
 * `.ffvc-framed` (the desktop Archivist's Light Table) overrides the label
 * colour to bronze further down and is unaffected by construction.
 */
.um-overlay,
.um-modal {
    --um-accent: var(--ffa-active-base, var(--ffa-tier-1-base, #4338CA));
    --um-accent-deep: var(--ffa-active-deep, var(--ffa-tier-1-deep, #312E81));
    --um-accent-wash: color-mix(in srgb, var(--um-accent) 12%, transparent);
}

/* ── Overlay: fills entire App Pane ── */
.um-overlay {
    position: fixed;
    top: var(--nav-height, 60px);
    left: var(--side-nav-width, 60px);
    right: 0;
    bottom: 0;
    background: transparent;
    z-index: var(--z-modal-umi); /* modal-integrity-scan S4: was 10400 literal */
    display: none;
    pointer-events: none;
}
.um-overlay.visible {
    display: block;
    pointer-events: auto;
}

/* fixing-about-again S3 (A2 — exit-trap fix). On the standalone /about/
   surface (`body.presentation-root`, no SPA top-nav / left-sidebar), raise
   UMI's overlay to cover the full viewport. The `.pres-header` chapter-
   timeline strip (z-index:10) carries the story-exit × at its right edge;
   absent this rule UMI's overlay starts at the 60px/220px fallback inset,
   leaving that × visible AND clickable above UMI's own ×. Joe's
   walkthrough cue A2: he was reaching for UMI's × and closing the story
   instead. With `inset:0` on /about/, UMI's overlay (z 10400, pointer-
   events:auto when visible) paints over the .pres-header and blocks hit-
   testing through to its exit button — UMI's × becomes the only upper-
   right exit control while UMI is open. The SPA-embedded UMI context
   (where --nav-height / --side-nav-width are load-bearing) is untouched.
   Reconciled in `Z_INDEX_HIERARCHY.md` — no z-index change required; the
   missing piece was geometric coverage, not stacking order. */
body.presentation-root .um-overlay {
    top: 0;
    left: 0;
}

/* ── Modal shell: fills entire App Pane like face tagging ── */
.um-modal {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: row;
    overflow: hidden;
    background: #1a1f2e;
    border: none;
    border-radius: 0;
    box-shadow: none;
    transform: none;
    transition: none;
}
.um-overlay.visible .um-modal {
    transform: none;
}

/* ── Left pane: media display ── */
.um-media-pane {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #141824;
    overflow: hidden;
    min-width: 0;
    position: relative;
}
.um-media-pane img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
/* Video CLAIMS the pane; it does not merely fit inside it.
   directing-canvas-situations S2, Issue 11 / Joe ruling R-S0.1 (2026-07-31):
   "The video in a UMI should be sized to the available panel space."

   `max-*` was the defect: a ceiling shrinks oversized content and never grows
   undersized content. A scanned photo is thousands of pixels wide so the
   ceiling engaged; digitized 8mm footage is ~640x480, far under the ~1450x1230
   pane, so nothing ever bound and the <video> painted at native size — a
   postage stamp in a dark room, on every low-resolution archival reel in the
   vault. `width/height: 100%` claims the panel and `object-fit: contain`
   keeps the aspect ratio, so the fill NEVER crops the frame; the pane's flex
   centering still letterboxes whatever is left over.

   The stated tradeoff, so a later reader does not "fix" it back: upscaling a
   640x480 source looks softer. Joe ruled for size over sharpness — the
   smallness was hiding the source resolution, not honouring it. The images
   rule above deliberately KEEPS `max-*`: a still is a print, and a print is
   allowed to be smaller than its frame. */
.um-media-pane video {
    width: 100%;
    height: 100%;
    object-fit: contain;
}
.um-media-pane audio {
    width: 80%;
    max-width: 400px;
}
.um-media-pane iframe {
    width: 100%;
    height: 100%;
    border: none;
}
.um-media-pane .um-yt-frame {
    width: 100%;
    height: 100%;
    border: none;
}

/* Face-bbox overlay (normalized 0-1 svg sized to rendered image rect) */
.um-face-overlay {
    position: absolute;
    pointer-events: none;
    display: none;
}
.um-face-svg {
    width: 100%;
    height: 100%;
    overflow: visible;
}
.um-face-bbox rect {
    fill: none;
    stroke: rgba(108, 158, 248, 0.85);
    stroke-width: 2;
    rx: 2;
    ry: 2;
}
.um-face-bbox.is-unidentified rect {
    stroke: rgba(255, 255, 255, 0.55);
    stroke-dasharray: 4 3;
}
.um-face-bbox.is-focus rect {
    stroke: #fbbf24;
    stroke-width: 3;
    animation: umFacePulse 1.6s ease-in-out 2;
}
@keyframes umFacePulse {
    0%   { stroke: #fbbf24; filter: drop-shadow(0 0 0 rgba(251, 191, 36, 0)); }
    50%  { stroke: #fde68a; filter: drop-shadow(0 0 6px rgba(251, 191, 36, 0.9)); }
    100% { stroke: #fbbf24; filter: drop-shadow(0 0 0 rgba(251, 191, 36, 0)); }
}
.um-face-label-wrap {
    /* HTML beside the SVG (not a foreignObject: iOS WebKit drew those at the corner — Greg 2026-10-18);
       left/top are set inline as percentages of the rendered image, at the face box's bottom-left. */
    position: absolute;
    white-space: nowrap;
    pointer-events: none;
}
.um-face-label {
    display: inline-block;
    margin-top: 4px;
    padding: 2px 6px;
    background: rgba(108, 158, 248, 0.92);
    color: #fff;
    font-family: 'Inter', sans-serif;
    font-size: calc(11px * var(--type-scale, 1));
    font-weight: 500;
    border-radius: 4px;
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
}
.um-face-bbox.is-focus .um-face-label,
.um-face-label-wrap.is-focus .um-face-label {
    background: #fbbf24;
    color: #1a1d2b;
    font-weight: 600;
}
.um-face-bbox.is-unidentified .um-face-label,
.um-face-label-wrap.is-unidentified .um-face-label {
    background: rgba(255, 255, 255, 0.75);
    color: #1a1d2b;
}

/* PDF / Document preview */
.um-doc-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    gap: 12px;
    overflow: hidden;
    padding: 16px;
    box-sizing: border-box;
}
.um-pdf-poster {
    max-width: 100%;
    /* S37/L71 (hardening-triptych-templates S2): the cover poster must show
       the WHOLE first page on landing, never a clipped tall/skinny column.
       max-height + contain letterbox the cover inside the pane (a portrait
       8.5×11 scan no longer overflows the flex column and gets bottom-chopped
       — Joe 2026-06-13 "U.S. Securities thumbnail bottom-half chopped"). */
    max-height: 100%;
    object-fit: contain;
    display: block;
    margin: 0 auto;
    min-height: 0;
    flex: 1 1 auto;
}
/* In-modal readable PDF viewer (UMI Heart / X3 — view, not just download).
   Scoped to .um-media-pane so it beats the generic `.um-media-pane iframe`
   {height:100%} rule (which would push the actions row out of the column). */
.um-doc-container--viewing {
    align-items: stretch;
    justify-content: flex-start;
    padding: 0;
    gap: 0;
    /* The pane is a centered flex row; without an explicit width the container
       shrinks to its content and the reader iframe's width:100% resolves against
       a content-sized box → it collapses to the iframe intrinsic ~300px (Joe's
       "very narrow column", 2026-07-01). Fill the pane so width:100% is anchored. */
    width: 100%;
    height: 100%;
}
/* ⛔ BOTH ANCESTORS, OR THE POCKET GETS A BLACK PANE (Joe, mobile QA 2026-08-29:
   "the mobile UMI for documents does not present the documents. Other media
   types are properly presented.")

   The desktop pane carries the CLASS (`unified-media-modal.js:733`,
   mediaPane.className = 'um-media-pane'). The mobile scaffold carries only the
   ID — `mobile-umi.js:364`, focalEl.id = 'umMediaPane' — because its comment
   withheld `.um-media-pane-mobile` so the scaffold's own letterbox rule could
   size images and video. But that withheld a DIFFERENT class than the one these
   document rules are scoped to, and nothing noticed: photos and video are styled
   directly by `.msp-focal-content > img|video`, so only DOCUMENTS fell through.
   The reader div got no height and rendered as a black rectangle — on every
   document, for every member, on the surface the family actually uses.

   Matching `.msp-focal-content` too is deliberately narrower than adding the
   class to the mobile pane: it fixes documents without letting every other
   `.um-media-pane …` desktop rule reach the pocket scaffold. */
.um-media-pane .um-doc-viewer,
.msp-focal-content .um-doc-viewer {
    flex: 1 1 auto;
    width: 100%;
    /* S8 (unifying-triptych-stagecraft W1, Joe ×3: 09:54 / 12:43 / 46:38):
       the first page must FILL the display pane and scroll — height:auto on
       an iframe collapses to intrinsic size and produced the tall/skinny
       column Joe flagged. 100% + flex:1 fills the pane; the PDF viewer
       inside the iframe provides the scroll. */
    height: 100%;
    min-height: 0;
    border: none;
    background: #fff;
    display: block;
}
/* pdf.js page column. S20 (converging-triptych-encore) rendered each page at
   pane WIDTH — but a portrait 8.5×11 page at pane width is TALLER than the
   pane, so the landing showed only the top of page 1 (Joe 2026-06-13, S37/
   L69/A120: still "tall and skinny… the WHOLE first page must fit, then
   scroll within"). S2 (hardening-triptych-templates) lands the whole-page
   form factor: each page is one scroll-snap section that fills the pane, with
   the page CONTAINED inside it (scaled by the binding dimension — height for a
   portrait page), so the whole first page fits on landing and scrolling reads
   page-by-page. The JS computes the fit so the canvas is crisp at that size. */
/* Same both-ancestors rule as .um-doc-viewer above — without this the page
   column has no scroll context on mobile even once the viewer has height. */
.um-media-pane .um-doc-pages,
.msp-focal-content .um-doc-pages {
    display: block;
    overflow-y: auto;
    overflow-x: hidden;
    background: #141824;
    padding: 0;
    scroll-snap-type: y proximity;
}
.um-doc-pages .um-doc-page {
    min-height: 100%;        /* one page per pane-height on landing */
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 12px;
    margin: 0;
    background: transparent;  /* the page sits on the dark pane */
    scroll-snap-align: center;
}
.um-doc-pages .um-doc-page canvas {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    display: block;
    background: #fff;
    box-shadow: 0 2px 22px rgba(0, 0, 0, 0.55);
}
/* placeholder (pre-render) keeps a page-shaped footprint so lazy pages reserve
   roughly one screen each as they scroll into view */
.um-doc-pages .um-doc-page:empty {
    aspect-ratio: 17 / 22;
    max-height: 100%;
}
/* blocking-pocket-geometry S6 (#3). This rule carried `order: -1` — "document
   controls form a TOP bar above the page, never below" — which was the SECOND of
   Joe's two 2026-08-28 symptoms: it hoisted the action row to the top of a
   container filling `height:100%` of `.msp-top`, where the mobile scaffold's
   `.msp-float-controls` is `position:absolute` and reserves nothing. Nothing owned
   that ~52px band, so the row landed on the header and the page canvas below it
   was sized to zero — the black viewport.
   The row is no longer a controls bar. Its four mobile buttons are gone (see the
   block comment in unified-media-modal.js); what remains is at most one inbound
   external-source reference, which has no claim on the top of the reading surface
   and which the JS now appends only when it is occupied. So it sits BELOW the
   pages, in flow, and cannot reach the header band from there. */
.um-doc-container--viewing .um-doc-actions {
    padding: 8px 12px;
    background: #141824;
    flex-shrink: 0;
    justify-content: flex-start;
    /* The row must never overflow its line the way the four-button row did.
       Not a repair of that row — it is deleted — but the property whose ABSENCE
       let a flex line grow past a 390pt stage and clip its own left edge
       unreachably. Declared so the next occupant inherits the constraint. */
    flex-wrap: wrap;
}
.um-doc-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    color: var(--color-text-light, #6b7280);
    font-size: calc(14px * var(--type-scale, 1));
    padding: 40px;
}
.um-doc-icon {
    font-size: calc(64px * var(--type-scale, 1));
    opacity: 0.5;
}
.um-doc-actions {
    display: flex;
    gap: 10px;
    justify-content: center;
    flex-shrink: 0;
    padding: 8px 12px;
    /* S6 (#3): `flex-wrap` and horizontal padding were BOTH absent, and that pair
       is the whole of Joe's first symptom — a centre-justified flex line that
       overflows does so symmetrically, and the left overflow inside
       `.um-doc-container`'s `overflow:hidden` is unreachable, not merely ugly. */
    flex-wrap: wrap;
}
.um-pdf-view-btn {
    display: inline-block;
    padding: 8px 24px;
    background: var(--color-primary, #3b82f6);
    color: white;
    border: none;
    border-radius: 6px;
    font-size: calc(14px * var(--type-scale, 1));
    cursor: pointer;
    transition: background 0.2s;
    text-decoration: none;
    text-align: center;
}
.um-pdf-view-btn:hover {
    background: #2563eb;
}
/* S6 (#3): `.um-pdf-download-btn` was here — the legacy in-pane mobile Download,
   retired with the rest of the bespoke document row. Its replacement is the
   audited egress (umDownloadCurrentMedia) on the scaffold header and the State-4
   TabBar. No rule is left behind: a style for a button nothing renders is how the
   row grew from two controls to four without anyone noticing it had. */
/* External-source INBOUND hot-link (clearing-release-runway S4, C6-a/c).
   Distinct amber "inbound reference" affordance — consistent with the
   by-reference citation aesthetic (FFACitationExamine) — so the family can tell
   a followable public-source link from the in-vault Open/Download actions at a
   glance. "no data OUT of the vault ≠ no inbound reference links." */
.um-doc-source-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: rgba(232, 160, 64, 0.12);
    color: #b7791f;
    border: 1px solid rgba(232, 160, 64, 0.55);
    font-weight: 600;
}
.um-doc-source-link:hover {
    background: rgba(232, 160, 64, 0.22);
    color: #92600f;
}
/* S6 (#3): `.um-doc-close-btn` was here — the safety-net Close chip inside the
   doc-actions row. Its own JS comment recorded the root cause it defended against
   (float-controls with no backdrop gradient, so the scaffold close chip vanished
   into a light PDF poster) as already FIXED in mobile-sheet-3panel.css. A
   safety net kept after the hole is closed is just one more thing in the row. */

/* Placeholder icon for missing media */
.um-media-placeholder {
    font-size: calc(64px * var(--type-scale, 1));
    opacity: 0.4;
}

/* ── Right pane: info — light surface like face tagging ── */
.um-info-pane {
    width: 480px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    border-left: 2px solid #e0e0e0;
    background: #f5f5f5;
}
.um-mode-presentation .um-info-pane {
    width: 400px;
}

/* Header row: title + controls.
   S8 UMI layout standard (unifying-triptych-stagecraft W1, Joe walkthrough
   25:21–25:55): ALL controls at the TOP of the panel with the close X in the
   top-right corner — title left, control row floats top-right. Pre-S8 the
   controls rendered on a second line beneath the title. */
.um-header {
    padding: 16px 20px;
    border-bottom: 1px solid #ddd;
    background: #ececec;
    flex-shrink: 0;
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}
.um-title {
    font-size: calc(16px * var(--type-scale, 1));
    font-weight: 700;
    color: #1a1a2e;
    margin: 0;
    word-break: break-word;
    line-height: 1.3;
    flex: 1 1 auto;
    min-width: 0;
}
.um-controls {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-shrink: 0;
}
.um-ctrl-btn {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid #ccc;
    background: #e0e0e0;
    color: #444;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    padding: 0;
    transition: all 200ms;
}
.um-ctrl-btn:hover {
    background: #d0d0d0;
    border-color: #999;
    color: #111;
}
.um-ctrl-close {
    margin-left: auto;
}

/* ────────────────────────────────────────────────────────────────────────
   Affordance rail  (affording-umi-documents S2, 2026-07-17)
   Joe's "left hand side of the window": a slim glass pill of icon buttons
   (Open · Download · Play · Properties) floating over the left edge of the
   media pane. Consumes no layout column, never obscures the info pane.
   Desktop-only (mobile uses the scaffold + State-4 TabBar / MCP slots).
   ──────────────────────────────────────────────────────────────────────── */
.um-affordance-rail {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    z-index: 6;                 /* above media/doc content, below the info-pane close */
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px;
    border-radius: 999px;
    background: rgba(20, 24, 36, 0.62);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.12);
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
    opacity: 0;
    transition: opacity 260ms ease;
}
.um-overlay.visible .um-affordance-rail { opacity: 1; }
.um-rail-btn {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.06);
    color: #e8ecf4;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: background 160ms, transform 160ms, color 160ms;
}
.um-rail-btn:hover {
    background: rgba(155, 135, 245, 0.28);
    color: #fff;
    transform: translateY(-1px);
}
.um-rail-btn:active { transform: translateY(0); }
.um-rail-btn:disabled { opacity: 0.5; cursor: default; transform: none; }

/* Document-audio transport ("Play the document") — a native <audio controls>
   docked at the bottom-center of the media pane (standard play/pause/seek). */
.um-doc-transport {
    position: absolute;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
    width: min(72%, 460px);
    z-index: 6;
    filter: drop-shadow(0 3px 10px rgba(0, 0, 0, 0.4));
}

/* Document Properties panel — a discrete toggled metadata surface sliding in
   from the right edge of the modal. */
.um-properties-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(340px, 82%);
    z-index: 8;
    background: rgba(18, 22, 34, 0.97);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-left: 1px solid rgba(255, 255, 255, 0.1);
    box-shadow: -8px 0 24px rgba(0, 0, 0, 0.4);
    display: flex;
    flex-direction: column;
    animation: umPropSlideIn 220ms ease;
    color: #e8ecf4;
}
@keyframes umPropSlideIn {
    from { transform: translateX(100%); }
    to   { transform: translateX(0); }
}
.um-prop-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    flex-shrink: 0;
}
.um-prop-title { font-weight: 600; font-size: calc(15px * var(--type-scale, 1)); }
.um-prop-close {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.06);
    color: #cfd6e4;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.um-prop-close:hover { background: rgba(255, 255, 255, 0.14); color: #fff; }
.um-prop-body { padding: 8px 16px 20px; overflow-y: auto; }
.um-prop-row {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.um-prop-label {
    font-size: calc(11px * var(--type-scale, 1));
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #8b93a7;
}
.um-prop-value { font-size: calc(14px * var(--type-scale, 1)); color: #e8ecf4; word-break: break-word; }

/* finishing-umi-affordances S1 — mobile Properties panel. The mobile UMI has no
   `.um-modal`; the panel mounts on the scaffold overlay as a bottom sheet that
   rests ABOVE the State-4 TabBar (which owns z-index 11000 + the Details toggle),
   so the band stays tappable to toggle it back off. */
.um-properties-panel.um-properties-panel-mobile {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: var(--mobile-control-panel-height, calc(48px + env(safe-area-inset-bottom, 0px)));
    width: 100%;
    max-height: 60vh;
    z-index: 10990;
    border-left: none;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 28px rgba(0, 0, 0, 0.5);
    animation: umPropSlideUp 220ms ease;
}
@keyframes umPropSlideUp {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
}

/* Navigation bar */
.um-nav-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-bottom: 1px solid #ddd;
    background: #ececec;
    flex-shrink: 0;
}
.um-nav-btn {
    width: 28px;
    height: 28px;
    border-radius: 6px;
    border: 1px solid #ccc;
    background: #fff;
    color: #444;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: calc(14px * var(--type-scale, 1));
    transition: all 150ms;
}
.um-nav-btn:hover:not(:disabled) {
    background: #e8e8e8;
    border-color: #999;
}
.um-nav-btn:disabled {
    opacity: 0.3;
    cursor: default;
}
.um-nav-position {
    font-size: calc(12px * var(--type-scale, 1));
    color: #888;
    flex: 1;
    text-align: center;
}

/* ── Edge paging controls (certifying-desktop-frame S2 D7, issue #14) ────────
   Joe: "I want the forward and back controls in the UMI to page me through a
   media carousel" — "subtle" affordances on the left and right side of the
   modal chrome. Distinct from `.um-nav-bar` above, which lives in the info pane
   and carries the "3 of 49" position label; these are the paging gesture itself
   and appear on any surface that resolved a cohort, including the chapter
   carousels that previously had no traversal at all.

   Subtle by default and legible on approach: low opacity at rest, full on
   hover/focus. They sit OVER the media pane's left/right edges, vertically
   centred, and are the modal's own children so a media-pane re-render (which
   clears that pane's innerHTML on every navigation) cannot take them with it. */
.um-page-btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 6;
    width: 34px;
    height: 54px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 8px;
    background: rgba(18, 22, 33, 0.55);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    color: rgba(255, 255, 255, 0.9);
    font-size: calc(24px * var(--type-scale, 1));
    line-height: 1;
    cursor: pointer;
    opacity: 0.35;
    transition: opacity 160ms ease, background 160ms ease, border-color 160ms ease;
}
.um-modal:hover .um-page-btn { opacity: 0.7; }
.um-page-btn:hover:not(:disabled),
.um-page-btn:focus-visible {
    opacity: 1;
    background: rgba(18, 22, 33, 0.82);
    border-color: rgba(255, 255, 255, 0.42);
}
/* Never a mystery control: a spent direction is visibly spent, not merely
   inert. `pointer-events: none` so the disabled edge does not eat a click
   meant for the media beneath it. */
.um-page-btn:disabled {
    opacity: 0.12;
    cursor: default;
    pointer-events: none;
}
.um-page-prev { left: 10px; }
.um-page-next { right: 10px; }

/* A paging step that crosses into the next chapter's carousel is a bigger move
   than a step within one. The accent rim says so before the click; the button's
   aria-label says so for a screen reader (umUpdatePagingControls). */
.um-page-btn.um-page-crosses-chapter {
    border-color: color-mix(in srgb, var(--um-accent, #4338CA) 70%, white 30%);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--um-accent, #4338CA) 35%, transparent);
}

/* Mobile drives the UMI from the sheet scaffold and owns its own gestures —
   the edge controls would sit under the thumb on the very swipe paths that
   surface already uses. Desktop affordance only. */
body.um-mobile-open .um-page-btn { display: none; }

/* Scrollable body */
.um-body {
    flex: 1;
    overflow-y: auto;
    padding: 16px 20px;
    -webkit-overflow-scrolling: touch;
}

/* Sections */
.um-section {
    margin-bottom: 16px;
}
.um-section-label {
    display: block;
    font-size: calc(11px * var(--type-scale, 1));
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.8px;
    color: var(--um-accent);
    margin-bottom: 6px;
}
/* Attribution note inside a section label — "Narrative · from the recording"
   vs "· from the vault's curator" (directing-canvas-situations S2, Issue 9).
   The Narrative section now has TWO possible producers and the reader is
   entitled to know which one wrote what they are reading.

   Every one of these declarations cancels something the note would otherwise
   INHERIT from `.um-section-label`: the uppercase transform, the tracking, the
   bold weight, the full-size type. Colour is deliberately left to inherit, so
   the note follows the label through the Archive Dusk accent, the ffvc-framed
   bronze and the phone dress without three more rules; `opacity` is what makes
   it the quieter half of the pair in all three at once. Lives in the desktop
   sheet on purpose — a direct rule on the note beats the phone sheet's
   inherited label styling, so one rule dresses both. */
.um-section-note {
    margin-left: 8px;
    text-transform: none;
    letter-spacing: 0.01em;
    font-weight: 500;
    font-size: 0.92em;
    font-style: italic;
    opacity: 0.75;
}
.um-section-note::before {
    content: '· ';
    font-style: normal;
}

.um-section p {
    margin: 0;
    font-size: calc(13px * var(--type-scale, 1));
    line-height: 1.5;
    color: #333;
}

/* Meta row (type badge + date) */
.um-meta-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.um-type-badge {
    display: inline-block;
    padding: 3px 10px;
    background: var(--um-accent-wash);
    border-radius: 12px;
    font-size: calc(11px * var(--type-scale, 1));
    font-weight: 600;
    text-transform: uppercase;
    color: var(--um-accent);
}
.um-date {
    font-size: calc(13px * var(--type-scale, 1));
    color: #666;
}

/* AI Analysis */
.um-analysis {
    background: #ffffff;
    padding: 14px 16px;
    border-radius: 8px;
    border-left: 3px solid var(--um-accent);
    font-size: calc(13.5px * var(--type-scale, 1));
    line-height: 1.6;
    color: #333;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

/* Rendered family prose (coaching-enrichment-prose S3).
   `.um-prose` marks the two fields that render bold/italic/paragraphs/lists;
   every other artifact in this modal is still a plain-text slot. Paragraph
   spacing is the whole point of the upgrade — before S3 `.um-analysis` set no
   `white-space`, so a blank line collapsed to a single space and three
   paragraphs arrived as one wall of text. */
.um-prose > p {
    margin: 0 0 0.7em;
}
.um-prose > p:last-child {
    margin-bottom: 0;
}
.um-prose strong {
    font-weight: 650;
}
.um-prose em {
    font-style: italic;
}
.um-prose .ffa-prose-list {
    margin: 0 0 0.7em;
    padding-left: 1.35em;
}
.um-prose .ffa-prose-list:last-child {
    margin-bottom: 0;
}
.um-prose .ffa-prose-list li {
    margin: 0 0 0.25em;
}

/* People chips */
.um-people {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.um-person-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px;
    border-radius: 12px;
    font-size: calc(12px * var(--type-scale, 1));
    background: #e0f2fe;
    color: #1e40af;
    border: 1px solid #93c5fd;
}
.um-person-tappable {
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.um-person-tappable:hover {
    background: #bfdbfe;
    border-color: #60a5fa;
}

/* Details (dimensions, file size) */
.um-details {
    font-size: calc(12px * var(--type-scale, 1));
    color: #888;
}

/* Loading state */
.um-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 40px;
    color: #888;
}
.um-spinner {
    width: 24px;
    height: 24px;
    border: 2px solid #ddd;
    border-top-color: var(--um-accent);
    border-radius: 50%;
    animation: um-spin 0.7s linear infinite;
    margin-right: 10px;
}
@keyframes um-spin {
    to { transform: rotate(360deg); }
}

/* ── Action bar (bottom of info pane) ── */
.um-actions {
    padding: 10px 16px;
    border-top: 1px solid #ddd;
    background: #ececec;
    flex-shrink: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.um-action-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 12px;
    border-radius: 6px;
    border: 1px solid #ccc;
    background: #fff;
    color: #444;
    font-size: calc(12px * var(--type-scale, 1));
    cursor: pointer;
    transition: all 150ms;
    white-space: nowrap;
}
.um-action-btn:hover {
    background: #e8e8e8;
    border-color: #999;
}
.um-action-btn.active {
    background: var(--um-accent-wash);
    border-color: var(--um-accent);
    color: var(--um-accent);
}
.um-action-btn.um-action-delete {
    color: #dc2626;
    border-color: #fca5a5;
}
.um-action-btn.um-action-delete:hover {
    background: #fef2f2;
    border-color: #dc2626;
    color: #dc2626;
}

/* ── Document type badge ── */
.um-doc-type-badge {
    display: inline-block;
    padding: 3px 10px;
    background: #fef3c7;
    border-radius: 12px;
    font-size: calc(11px * var(--type-scale, 1));
    font-weight: 600;
    text-transform: uppercase;
    color: #b45309;
}
.um-doc-author {
    font-size: calc(12px * var(--type-scale, 1));
    color: #888;
    margin-top: 4px;
    font-style: italic;
}

/* ── Document subject summary ── */
.um-doc-summary {
    background: #fff;
    padding: 12px;
    border-radius: 8px;
    border-left: 3px solid #f59e0b;
    font-size: calc(13px * var(--type-scale, 1));
    line-height: 1.55;
    color: #333;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

/* ── Chip containers ── */
.um-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.um-concept-chip {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 12px;
    font-size: calc(11px * var(--type-scale, 1));
    background: #dcfce7;
    color: #166534;
    border: 1px solid #86efac;
}
.um-institution-chip {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 12px;
    font-size: calc(11px * var(--type-scale, 1));
    background: #fef3c7;
    color: #92400e;
    border: 1px solid #fcd34d;
}
.um-more-chip {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 12px;
    font-size: calc(11px * var(--type-scale, 1));
    background: #f0f0f0;
    color: #666;
    border: 1px solid #ddd;
    cursor: pointer;
    transition: all 150ms;
}
.um-more-chip:hover {
    background: #e0e0e0;
    color: #333;
}
.um-chip-role {
    font-size: calc(10px * var(--type-scale, 1));
    opacity: 0.6;
}
.um-hidden-chip {
    display: none;
}

/* ── Key quotes ── */
.um-quote {
    background: #fff;
    padding: 8px 12px;
    border-radius: 6px;
    border-left: 2px solid var(--um-accent);
    font-size: calc(12px * var(--type-scale, 1));
    line-height: 1.5;
    color: #555;
    font-style: italic;
    margin-bottom: 6px;
}

/* ── Collapsible sections ── */
.um-collapsible .um-collapsible-body {
    display: none;
}
.um-collapsible.open .um-collapsible-body {
    display: block;
}
.um-collapsible-toggle {
    cursor: pointer;
}
.um-toggle-arrow {
    display: inline-block;
    font-size: calc(8px * var(--type-scale, 1));
    transition: transform 200ms;
    margin-left: 4px;
}
.um-collapsible.open .um-toggle-arrow {
    transform: rotate(90deg);
}

/* ── Knowledge graph ── */
.um-kg-group {
    margin-bottom: 10px;
}
.um-kg-group-label {
    font-size: calc(11px * var(--type-scale, 1));
    font-weight: 600;
    color: #888;
    text-transform: capitalize;
    margin-bottom: 4px;
}
.um-kg-item {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    padding: 3px 0;
    font-size: calc(12px * var(--type-scale, 1));
    color: #444;
}
.um-kg-icon {
    flex-shrink: 0;
    font-size: calc(11px * var(--type-scale, 1));
}
.um-kg-label {
    flex: 1;
    min-width: 0;
}
.um-kg-claim {
    font-size: calc(10px * var(--type-scale, 1));
    color: #999;
    font-style: italic;
    display: block;
    margin-top: 1px;
}
.um-kg-overflow {
    color: #999;
    font-style: italic;
}

/* ── Extracted text preview ── */
.um-extracted-text {
    background: #fff;
    padding: 10px 12px;
    border-radius: 6px;
    font-size: calc(11px * var(--type-scale, 1));
    line-height: 1.5;
    color: #555;
    font-family: 'SF Mono', 'Monaco', 'Menlo', monospace;
    max-height: 200px;
    overflow-y: auto;
    white-space: pre-wrap;
    word-break: break-word;
    border: 1px solid #e0e0e0;
}
.um-expand-link {
    display: inline-block;
    margin-top: 6px;
    font-size: calc(12px * var(--type-scale, 1));
    color: var(--um-accent);
    text-decoration: none;
    cursor: pointer;
}
.um-expand-link:hover {
    color: var(--um-accent-deep);
    text-decoration: underline;
}

/* ── Commentary input ── */
.um-commentary-input {
    background: #fff;
    border: 1px solid var(--um-accent);
    border-radius: 8px;
    padding: 12px 16px;
    margin-bottom: 16px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.um-commentary-input textarea {
    width: 100%;
    background: #f9fafb;
    border: 1px solid #ddd;
    border-radius: 6px;
    color: #333;
    font-size: calc(13px * var(--type-scale, 1));
    line-height: 1.5;
    padding: 8px 10px;
    resize: vertical;
    font-family: inherit;
    margin-top: 6px;
    box-sizing: border-box;
}
.um-commentary-input textarea:focus {
    outline: none;
    border-color: var(--um-accent);
    box-shadow: 0 0 0 2px var(--um-accent-wash);
}
.um-commentary-input textarea::placeholder {
    color: #aaa;
}

/* quiet-pinning-keystone S2: wrapper for VoiceDictation mic button so it
   floats inside the textarea's visual frame. The textarea already has
   padding-right added below to reserve space for the button. */
.um-commentary-input-wrap {
    position: relative;
    margin-top: 6px;
}
.um-commentary-input-wrap textarea {
    margin-top: 0;
    padding-right: 44px;
}
.um-commentary-input-wrap .vd-mic-btn {
    position: absolute;
    right: 6px;
    top: 6px;
}

.um-commentary-actions {
    display: flex;
    gap: 6px;
    margin-top: 8px;
}
.um-commentary-send {
    background: var(--um-accent) !important;
    border-color: var(--um-accent) !important;
    color: #fff !important;
}
.um-commentary-send:hover {
    background: var(--um-accent-deep) !important;
}

/* ── Responsive: mobile stack ── */
@media (max-width: 768px) {
    .um-overlay {
        top: 0;
        left: 0;
    }
    .um-modal {
        flex-direction: column;
    }
    .um-media-pane {
        flex: none;
        height: 50%;
    }
    .um-info-pane,
    .um-mode-presentation .um-info-pane {
        width: 100%;
        border-left: none;
        border-top: 2px solid #e0e0e0;
    }
    .um-header {
        padding: 12px 16px;
    }
    .um-body {
        padding: 12px 16px;
    }
}

/* ── sweeping-unifying-canopy S3 D3 / Issue #11 — pointer ───────────────
   Mobile UMI vertical-fill rules live in mobile-sheet-3panel.css under
   .msp-root[data-msp-mode="umi"] — that file is the canonical home of
   the 3-panel scaffold sizing tokens (--msp-top-flex / --msp-middle-flex).
   This pointer rule preserves backwards-compat with the desktop UMI media
   pane (.um-media-pane object-fit: contain remains, no crop) while
   documenting the cross-file Iron-Law resolution. Grep marker for the
   deployment gate. */
.um-modal[data-train="sweeping-unifying-canopy-S3"] {
    /* Marker-only — no behavior change at desktop UMI layer. */
}

/* ══════════════════════════════════════════════════════════════════════════
   The Archivist's Light Table — UMI themed vessel (Issue 8)
   directing-desktop-scenes S6. Mounted-vessel pattern (R20): the .um-modal
   keeps its app-pane-filling geometry contract (window-manager citizenship,
   face-overlay math, FrameController all untouched); the chassis layer
   floats at positive inset inside it and the panes sit padded within the
   silhouette. Readability law (R21): the info pane becomes an ivory catalog
   card — the theme's dark glass is chrome, never under body text.
   EVERY rule here is scoped under .ffvc-framed, which only ever stamps on
   desktop (FFVChassis gates) — mobile + /about/ surfaces byte-identical.
   ════════════════════════════════════════════════════════════════════════ */

/* the room: a warm dark viewing room behind the mounted plate */
.um-overlay.ffv-theme-umi:has(> .um-modal.ffvc-framed) {
    background:
        radial-gradient(ellipse 85% 70% at 50% 22%,
            rgba(66, 44, 20, 0.32), rgba(12, 9, 14, 0.9) 80%),
        rgba(12, 9, 14, 0.62);
}

/* the plate: glass painted by the SVG chassis; panes inset within the wave
   zone of the silhouette (viewBox edge band ≈ 3% ⇒ ~40px at pane widths) */
.um-modal.ffvc-framed {
    background: transparent;
    padding: 42px 48px 44px;
    gap: 16px;
}
.um-modal.ffvc-framed > :not(.ffv-chassis-layer):not(.ffs-handle) {
    position: relative;
    z-index: 1;
}

/* the light-table window: media floats on deep warm glass */
.um-modal.ffvc-framed .um-media-pane {
    background: #17110c;
    border-radius: 8px 12px 9px 11px;
    border: 1px solid rgba(201, 123, 74, 0.22);
    box-shadow: inset 0 0 44px rgba(0, 0, 0, 0.42);
}

/* the catalog card: the penumbra on archival ivory */
.um-modal.ffvc-framed .um-info-pane {
    background: var(--ffv-card, #f4ecdb);
    border-left: none;
    border: 1px solid rgba(160, 106, 60, 0.35);
    border-radius: 9px 8px 12px 9px;
    overflow: hidden;
    box-shadow: 0 10px 34px rgba(10, 6, 4, 0.45);
}
.um-modal.ffvc-framed .um-header {
    background: var(--ffv-card-deep, #ece0c6);
    border-bottom-color: rgba(160, 106, 60, 0.28);
}
.um-modal.ffvc-framed .um-title {
    font-family: var(--ffv-display-font, 'Playfair Display', Georgia, serif);
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--ffv-card-ink, #33261a);
}
.um-modal.ffvc-framed .um-nav-bar {
    background: var(--ffv-card-deep, #ece0c6);
    border-bottom-color: rgba(160, 106, 60, 0.22);
}
.um-modal.ffvc-framed .um-actions {
    background: var(--ffv-card-deep, #ece0c6);
    border-top-color: rgba(160, 106, 60, 0.28);
}
.um-modal.ffvc-framed .um-section-label {
    color: var(--ffv-bronze, #8a5a2e);
}
.um-modal.ffvc-framed .um-ctrl-btn {
    background: #e6d8bd;
    border-color: #c9b490;
    color: #5a462e;
}
.um-modal.ffvc-framed .um-ctrl-btn:hover {
    background: #dbc9a6;
    border-color: #a98d5e;
    color: #33261a;
}

/* ══════════════════════════════════════════════════════════════════════════
   THE FAMILY PANEL — hardening-vault-faculties S6
   ──────────────────────────────────────────────────────────────────────────
   Joe, 2026-07-24: the supplementary information below the AI Analysis is for
   a family member, not a technical archivist. Six sections, in this order:

     In this photo → Where and when → Connected to → the collection sentence
     → See all connections → About this file

   `um-kg-group` / `um-kg-group-label` are retired from the render path (the
   rules survive below, unreferenced, until a follow-on sweeps the CSS — the
   conservative-deletion law applies to stylesheets too).
   ════════════════════════════════════════════════════════════════════════ */

/* Sentence-case headings. The uppercase-tracked label is archivist chrome;
   "In this photo" is a sentence, and a sentence set in caps reads as a filing
   category. Same weight and colour, different register. */
.um-section-label--family {
    text-transform: none;
    letter-spacing: 0.01em;
    font-size: calc(12px * var(--type-scale, 1));
}

/* A rendered date must never break across two lines — 320px is where that
   happens, and "February 18,⏎2013" is the shape it takes when it does. */
.um-nowrap {
    white-space: nowrap;
}

/* ── In this photo — avatar chips ── */
.um-avatar-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.um-avatar-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 12px 4px 4px;
    border-radius: 999px;
    background: var(--um-accent-wash);
    border: 1px solid transparent;
    font-size: calc(13px * var(--type-scale, 1));
    color: #333;
    min-height: 36px;
    box-sizing: border-box;
}
.um-avatar-chip.um-person-tappable {
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}
.um-avatar-chip.um-person-tappable:hover {
    border-color: var(--um-accent);
}
.um-avatar {
    position: relative;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border-radius: 50%;
    overflow: hidden;
    background: var(--um-accent);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.um-avatar-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.um-avatar-initials {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: calc(11px * var(--type-scale, 1));
    font-weight: 700;
    letter-spacing: 0.02em;
}
.um-avatar-name {
    white-space: nowrap;
}

/* ── Where and when — one line ── */
.um-where-when {
    margin: 0;
    font-size: calc(13px * var(--type-scale, 1));
    line-height: 1.5;
    color: #333;
}
.um-ww-sep {
    color: #999;
}

/* ── Part of — the situations this item belongs to ── */
.um-situation-line {
    margin: 0;
    font-size: calc(13px * var(--type-scale, 1));
    line-height: 1.5;
    color: #333;
}
.um-situation-name {
    font-weight: 600;
}

/* ── Connected to — a flat list of sentences ── */
.um-connections {
    display: flex;
    flex-direction: column;
}
.um-connection {
    display: flex;
    align-items: center;
    min-height: 32px;
    padding: 4px 0;
    font-size: calc(13px * var(--type-scale, 1));
    line-height: 1.45;
    color: #444;
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.um-connection:last-of-type {
    border-bottom: none;
}
.um-connection.um-person-tappable {
    cursor: pointer;
    color: var(--um-accent);
}
.um-connection-hidden {
    display: none;
}
.um-show-more {
    align-self: flex-start;
    margin-top: 8px;
    padding: 6px 12px;
    min-height: 32px;
    background: transparent;
    border: 1px dashed var(--um-accent);
    border-radius: 999px;
    color: var(--um-accent);
    font-size: calc(12px * var(--type-scale, 1));
    font-family: inherit;
    cursor: pointer;
}
.um-show-more:hover {
    background: var(--um-accent-wash);
}

/* ── The collection sentence — quiet, italic, no chips ── */
.um-collection-line {
    margin: 0;
    font-size: calc(12.5px * var(--type-scale, 1));
    line-height: 1.5;
    font-style: italic;
    color: #777;
}
.um-collection-name {
    cursor: pointer;
    color: var(--um-accent);
    font-style: italic;
    text-decoration-line: underline;
    text-decoration-style: dotted;
    text-underline-offset: 2px;
}

/* ── See all connections — the Constellation, in the panel ── */
.um-see-all-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    justify-content: center;
    min-height: 44px;
    padding: 10px 16px;
    border-radius: 8px;
    border: 1px solid var(--um-accent);
    background: var(--um-accent-wash);
    color: var(--um-accent);
    font-size: calc(13px * var(--type-scale, 1));
    font-family: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: background 150ms;
}
.um-see-all-btn:hover {
    background: color-mix(in srgb, var(--um-accent) 20%, transparent);
}
.um-see-all-icon {
    font-size: calc(15px * var(--type-scale, 1));
}

/* ── About this file — the quiet disclosure ── */
.um-about-file .um-collapsible-body {
    padding-top: 4px;
}
.um-file-row {
    display: flex;
    gap: 10px;
    padding: 5px 0;
    font-size: calc(12px * var(--type-scale, 1));
    line-height: 1.5;
    border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}
.um-file-row:last-child {
    border-bottom: none;
}
.um-file-key {
    flex: 0 0 88px;
    color: #999;
    font-weight: 600;
}
.um-file-val {
    flex: 1;
    min-width: 0;
    color: #555;
}
/* The sentence that keeps a scan date from reading as a photo date. */
.um-file-note {
    display: block;
    margin-top: 2px;
    font-size: calc(11px * var(--type-scale, 1));
    font-style: italic;
    color: #999;
    line-height: 1.45;
}

/* ── The Archivist's Light Table: the family panel on ivory ── */
.um-modal.ffvc-framed .um-avatar-chip {
    background: rgba(160, 106, 60, 0.10);
    color: var(--ffv-card-ink, #33261a);
}
.um-modal.ffvc-framed .um-avatar-chip.um-person-tappable:hover {
    border-color: var(--ffv-bronze, #8a5a2e);
}
.um-modal.ffvc-framed .um-avatar {
    background: var(--ffv-bronze, #8a5a2e);
}
.um-modal.ffvc-framed .um-where-when,
.um-modal.ffvc-framed .um-connection {
    color: var(--ffv-card-ink, #33261a);
}
.um-modal.ffvc-framed .um-connection {
    border-bottom-color: rgba(160, 106, 60, 0.14);
}
.um-modal.ffvc-framed .um-collection-line,
.um-modal.ffvc-framed .um-file-key,
.um-modal.ffvc-framed .um-file-val,
.um-modal.ffvc-framed .um-file-note {
    color: var(--ffv-card-soft, #6d5a3e);
}
.um-modal.ffvc-framed .um-connection.um-person-tappable,
.um-modal.ffvc-framed .um-collection-name,
.um-modal.ffvc-framed .um-show-more,
.um-modal.ffvc-framed .um-see-all-btn {
    color: var(--ffv-bronze, #8a5a2e);
    border-color: var(--ffv-bronze, #8a5a2e);
}
.um-modal.ffvc-framed .um-see-all-btn {
    background: rgba(160, 106, 60, 0.10);
}

/* ════════════════════════════════════════════════════════════════════════════
   enhancing-trio-biographies S3 (LS-009 · LS-011 · LS-012) — the redesigned
   information panel: a pinned TOOL ROW under the title (Say It, Tag Faces /
   Tag People, Fergi AI only where nothing else reaches it), the narration
   TRANSPORT beside the NARRATIVE heading, one See all connections, and no
   lower action cluster. Desktop pins the row; the phone keeps it at the top of
   the details (sticky), with Say It in its context bar.
   ════════════════════════════════════════════════════════════════════════════ */
.um-toolrow-wrap {
    flex-shrink: 0;
    padding: 10px 20px;
    border-bottom: 1px solid #ddd;
    background: #f0f0f0;
}
.um-toolrow {
    display: flex;
    flex-wrap: wrap;            /* actions wrap rather than squeeze the title */
    align-items: center;
    gap: 8px;
}
.um-toolrow .sayit-btn.um-sayit-btn {
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
}
/* Prominent without letting the artwork dominate the photo (POLICY, SRC-018). */
.um-toolrow .sayit-btn.um-sayit-btn .sayit-glyph {
    width: 38px;
    height: 38px;
}
.um-toolrow .sayit-btn.um-sayit-btn {
    background: rgba(94, 234, 212, 0.10);
    border: 1px solid rgba(15, 118, 110, 0.35);
}
.um-toolrow .um-tool-btn {
    min-height: 44px;
    padding: 6px 14px;
    font-size: calc(13px * var(--type-scale, 1));
}
.um-toolrow .um-fergi-btn img { display: block; }
.um-ambient-fergi-answer {
    margin: 8px 0 0;
    padding: 8px 10px;
    border-left: 2px solid rgba(240, 198, 106, 0.55);
    border-radius: 4px;
    background: rgba(240, 198, 106, 0.07);
    font-size: calc(13.5px * var(--type-scale, 1));
    line-height: 1.45;
    white-space: pre-wrap;
    color: inherit;
}
.um-modal.ffvc-framed .um-toolrow-wrap {
    background: var(--ffv-card-deep, #ece0c6);
    border-bottom-color: rgba(160, 106, 60, 0.22);
}

/* NARRATIVE + its transport: one heading group. On a narrow panel the group
   drops beneath the label while staying part of the heading. */
.um-narr-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 6px 10px;
    margin-bottom: 6px;
}
.um-narr-head .um-section-label { margin-bottom: 0; }
.um-narr-transport {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.um-narr-btn {
    min-width: 34px;
    height: 34px;
    padding: 0 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 17px;
    border: 1px solid var(--um-accent);
    background: var(--um-accent-wash);
    color: var(--um-accent);
    font: 600 calc(12px * var(--type-scale, 1)) / 1 inherit;
    font-family: inherit;
    cursor: pointer;
}
.um-narr-btn:disabled { opacity: 0.38; cursor: default; }
.um-narr-btn.um-narr-speed-boosted { background: var(--um-accent); color: #fff; }
.um-modal.ffvc-framed .um-narr-btn {
    color: var(--ffv-bronze, #8a5a2e);
    border-color: var(--ffv-bronze, #8a5a2e);
    background: rgba(160, 106, 60, 0.10);
}
.um-modal.ffvc-framed .um-narr-btn.um-narr-speed-boosted {
    background: var(--ffv-bronze, #8a5a2e);
    color: #fff;
}

.um-see-all-note {
    margin: 6px 2px 0;
    font-size: calc(12px * var(--type-scale, 1));
    opacity: 0.7;
}

/* Browse curation tools — at the END of the scrolling details, never pinned. */
.um-curation-tools {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 18px;
    padding-top: 12px;
    border-top: 1px solid rgba(0, 0, 0, 0.1);
}

/* Phone: the same row at the top of the details panel, sticky while the
   details scroll; touch-sized transport. */
.um-toolrow-wrap.um-toolrow-wrap-mobile {
    position: sticky;
    top: 0;
    z-index: 2;
    padding: 8px 0;
    margin-bottom: 8px;
    background: var(--msp-bg-mid, #15171f);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
/* The scroll container's own top padding would leave a strip of scrolled text
   visible ABOVE the stuck row (measured at 320 px); the row carries that
   padding instead, so it sticks flush to the panel's top edge. */
.msp-middle:has(> .um-toolrow-wrap-mobile) { padding-top: 0; }
.um-toolrow-wrap.um-toolrow-wrap-mobile { padding-top: 12px; }
.um-toolrow-wrap-mobile .um-action-btn {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.18);
    color: #e8eaf0;
}
.um-toolrow-wrap-mobile .um-toolrow:empty { display: none; }
.um-body.um-body-mobile .um-narr-btn {
    min-width: 44px;
    height: 44px;
    border-radius: 22px;
    /* The phone panel is dark: light ink on a lifted wash, never accent-on-dark. */
    color: #e6ecff;
    border-color: rgba(166, 186, 255, 0.55);
    background: rgba(110, 168, 255, 0.16);
}
.um-body.um-body-mobile .um-narr-btn.um-narr-speed-boosted {
    background: #6ea8ff;
    border-color: #6ea8ff;
    color: #0e1220;
}

/* Touch floors on a finger (Greg 2026-10-17, FergiPAD + FergiPhone probes): the media viewer is
   reached from every biography, story and Sources page, and its controls were drawn for a mouse —
   Close and Fullscreen 32 px, Previous/Next 28, the narration buttons 34, Select / Add to Profile /
   Delete 29 tall, the people chips 38, the side page arrow 34 wide. The desktop keeps its sizes. */
@media (pointer: coarse) {
    .um-ctrl-btn,
    .um-nav-btn { width: 44px; height: 44px; }
    .um-narr-btn { min-width: 44px; height: 44px; border-radius: 22px; }
    .um-action-btn,
    .um-avatar-chip.um-person-tappable { min-height: 44px; }
    .um-page-btn { width: 44px; }
}
