/* =============================================================================
   Fast Browse Interface — styles (Part 2A)
   Dark, refined, utilitarian. Mobile-first. Zero layout shift.
   ============================================================================= */

:root {
    /* LIVE-8 Item 3 (owner field walk): native controls were the last thing on
       these pages still rendering in the browser's default LIGHT scheme. A
       <select> inherited the shell's near-white text, and its OPTION LIST was
       painted by the UA on white — so the options were invisible except under
       the hover highlight. One declaration fixes every native control on the
       surface (option lists, scrollbars, form widgets, pickers) instead of
       chasing them one at a time; .fbrv-vid-speed's `option{background:#333}`
       is the per-control patch that was reached for last time, and it does not
       even work on every engine. This shell has no light variant, so it says
       `dark` rather than `light dark`. */
    color-scheme: dark;

    --fb-bg:          #14161a;
    --fb-bg-elevated: #1c1f26;
    --fb-bg-card:     #1a1d24;
    --fb-border:      #2a2e37;
    --fb-border-soft: #232730;
    --fb-text:        #e6e8ec;
    --fb-text-dim:    #9aa0ab;
    --fb-text-faint:  #6b7280;
    --fb-accent:      #5b9dff;
    --fb-accent-dim:  #3a6bc0;
    --fb-danger:      #ff6b6b;

    --fb-radius:      10px;
    --fb-radius-sm:   6px;
    --fb-gap:         12px;
    --fb-header-h:    56px;

    --fb-font: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    --fb-mono: "SF Mono", ui-monospace, "Cascadia Code", Menlo, monospace;

    /* ---- JOB 108e: the shared system, extended rather than forked ----------
       The Listen area was designed and mostly built before Fast Browse existed
       and carried a whole second palette of its own (a near-black ground, an
       amber accent, a serif for every word on the page). Unifying it needed
       seventeen things this block did not have — eleven with a value and six raw
       triples. Each one is ADDITIVE — no rule
       above or below changed value when they landed — and each is named for
       what it IS rather than for the surface that first wanted it, because a
       token called `--fb-listen-hover` would be the fork wearing a new coat.

       Anything a component measures about ITSELF (a player bar's height, a
       composer dock's depth) is deliberately NOT here: those stay local to the
       component, under its own prefix. This block is the design system. */

    /* The ground colours, again as raw triples, so a translucent chrome layer
       can be mixed from the SAME number the opaque one uses. .fb-header below
       used to spell rgba(20,22,26,0.85) by hand; Listen's header, player bar
       and composer dock each spelled a different literal. Now all four mix
       from these. */
    --fb-bg-rgb:          20, 22, 26;    /* == --fb-bg          #14161a */
    --fb-bg-card-rgb:     26, 29, 36;    /* == --fb-bg-card     #1a1d24 */
    --fb-bg-elevated-rgb: 28, 31, 38;    /* == --fb-bg-elevated #1c1f26 */

    /* A pressed/hover surface one step ABOVE elevated. Every surface in this
       shop reached for one and each invented its own: the grid used
       --fb-bg-card (which is BELOW elevated, so a hover on an elevated control
       went darker), Listen used #2a2a2a. */
    --fb-bg-hover:    #232833;

    /* The stronger of the two borders. --fb-border is what separates regions;
       this is what draws a control the user can type in or press, and without
       it every input on a unified Listen would have dissolved into its card. */
    --fb-border-strong: #363c48;

    /* Accent tints. A selected row, a focus ring and a soft-filled button all
       want the accent at low alpha, and rgba() cannot take a hex variable, so
       the triple is the only honest way to keep one source. --fb-accent-ink is
       the text colour that goes ON the accent, which is the one value a
       surface CANNOT derive for itself. */
    --fb-accent-rgb:     91, 157, 255;   /* == --fb-accent      #5b9dff */
    --fb-accent-dim-rgb: 58, 107, 192;   /* == --fb-accent-dim  #3a6bc0 */
    /* The two tints below MIX from the triple above rather than spelling the
       accent a third and fourth time (bench r2, grok). A custom property's own
       var() is substituted where the property is USED, so this resolves
       wherever --fb-accent-rgb is in scope — which is :root, everywhere. */
    --fb-accent-soft:  rgba(var(--fb-accent-rgb), 0.16);
    --fb-accent-faint: rgba(var(--fb-accent-rgb), 0.07);
    --fb-accent-ink:   #0b1220;
    /* The hover state of a FILLED accent control. It brightens rather than
       darkening, which is the opposite of what the amber it replaces did, and
       deliberately: --fb-accent-ink is a near-black, and darkening the fill
       under it walks the pair down towards each other. Brightening walks them
       apart. */
    --fb-accent-hi:    #77aeff;
    --fb-danger-rgb:   255, 107, 107;    /* == --fb-danger      #ff6b6b */
    --fb-danger-soft:  rgba(var(--fb-danger-rgb), 0.15);

    --fb-radius-pill: 999px;

    /* The shop's one transition curve and its one card shadow, so a surface
       does not have to guess at 0.18s and a cubic-bezier to feel like the rest
       of the product. */
    --fb-t:           0.18s cubic-bezier(0.4, 0, 0.2, 1);
    --fb-shadow-card: 0 2px 12px rgba(0, 0, 0, 0.4);

    /* THE READING FACE. This is the one thing Listen genuinely had that the
       shared system lacked: long-form body text a person reads for half an
       hour wants a serif, and --fb-font is a UI face. It is a token and not a
       Listen rule because Read wants the same thing for the same reason.
       Literata is a webfont; only a page that LOADS it gets it, and every
       other page falls through to a system serif, which is why the stack ends
       in generic families rather than in a second webfont. */
    --fb-font-read: "Literata", Georgia, "Iowan Old Style", "Times New Roman", serif;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--fb-bg);
    color: var(--fb-text);
    font-family: var(--fb-font);
    -webkit-font-smoothing: antialiased;
}

.fb-body {
    min-height: 100vh;
    min-height: 100dvh;
}

/* ---- Header ---------------------------------------------------------------- */
.fb-header {
    position: sticky;
    top: 0;
    z-index: 50;
    height: var(--fb-header-h);
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 14px;
    padding-top: env(safe-area-inset-top);
    /* JOB 108e: was the literal rgba(20,22,26,0.85), as were the four other
       translucent grounds in this file (the toolbar and three card buttons)
       and three more in Listen. Same computed colour everywhere, now mixed
       from --fb-bg-rgb, so a change to the ground moves the translucent chrome
       with it instead of leaving it a shade behind. */
    background: rgba(var(--fb-bg-rgb), 0.85);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--fb-border);
}

.fb-brand {
    font-weight: 650;
    font-size: 15px;
    letter-spacing: -0.01em;
    white-space: nowrap;
    color: var(--fb-text);
    flex-shrink: 0;
}

.fb-search-wrap {
    flex: 1;
    position: relative;
    min-width: 0;
}

.fb-search {
    width: 100%;
    height: 38px;
    padding: 0 14px 0 38px;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border);
    border-radius: 999px;
    color: var(--fb-text);
    font-size: 15px;
    font-family: inherit;
    outline: none;
    transition: border-color 0.15s, background 0.15s;
}
.fb-search:focus {
    border-color: var(--fb-accent-dim);
    background: var(--fb-bg-card);
}
.fb-search::placeholder { color: var(--fb-text-faint); }

/* Scope toggle ("search within current view") lives inside the search wrap,
   right side. Compact on mobile (icon only); shows a label on wider screens. */
.fb-search-wrap .fb-search { padding-right: 84px; }   /* room for the toggle */
/* People-mode header carries no scope toggle (no in-place view to scope to),
   so reclaim the space the toggle would have occupied. */
.fb-people-header .fb-search-wrap .fb-search { padding-right: 14px; }

.fb-scope-toggle {
    position: absolute;
    right: 5px;
    top: 50%;
    transform: translateY(-50%);
    height: 28px;
    padding: 0 10px;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    color: var(--fb-text-faint);
    font-size: 12.5px;
    font-family: inherit;
    cursor: pointer;
    transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.fb-scope-toggle svg {
    width: 15px;
    height: 15px;
    stroke: currentColor;
    flex-shrink: 0;
}
.fb-scope-toggle:hover { color: var(--fb-text); background: var(--fb-bg-card); }
.fb-scope-toggle.is-active {
    color: var(--fb-accent);
    border-color: var(--fb-accent-dim);
    background: rgba(91, 157, 255, 0.12);
}
.fb-scope-label { line-height: 1; }

/* When scope is ON, accent the whole search field so the user always sees it's
   active (and remembers to turn it off). The accent persists even after the
   placeholder is gone (i.e. once they've typed). */
.fb-search-wrap.fb-scoped .fb-search {
    border-color: var(--fb-accent);
    box-shadow: 0 0 0 1px var(--fb-accent-dim);
}

/* Tight phones: drop the label, keep the icon — zero horizontal cost. */
@media (max-width: 560px) {
    .fb-scope-label { display: none; }
    .fb-scope-toggle { padding: 0 8px; }
    .fb-search-wrap .fb-search { padding-right: 44px; }
}

.fb-search-icon {
    position: absolute;
    left: 13px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    stroke: var(--fb-text-faint);
    pointer-events: none;
}

.fb-header-btn {
    flex-shrink: 0;
    height: 38px;
    padding: 0 14px;
    background: transparent;
    border: 1px solid var(--fb-border);
    border-radius: 999px;
    color: var(--fb-text-dim);
    font-size: 13px;
    font-family: inherit;
    cursor: pointer;
    transition: all 0.15s;
    white-space: nowrap;
}
.fb-header-btn:hover {
    color: var(--fb-text);
    border-color: var(--fb-accent-dim);
}

/* Upload button — accent colored, icon + label */
.fb-upload-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--fb-accent-dim);
    border-color: var(--fb-accent);
    color: #fff;
    text-decoration: none;
}
.fb-upload-btn:hover {
    background: var(--fb-accent);
    color: #fff;
}
.fb-btn-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}
/* On narrow screens, collapse the upload button to icon-only */
@media (max-width: 600px) {
    .fb-upload-label { display: none; }
    .fb-upload-btn { padding: 0 11px; }
    /* Also shorten the Classic view button to save room */
    #fb-classic { padding: 0 10px; font-size: 12px; }
}

/* ---- Toolbar (sort / filter / count) -------------------------------------- */
.fb-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px 4px;
    flex-wrap: wrap;
    position: sticky;
    top: var(--fb-header-h);
    z-index: 45;
    background: rgba(var(--fb-bg-rgb), 0.85);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    transition: transform 0.22s ease;
}
/* Hide only the toolbar on scroll-down; the top header (navigation) stays put
   so navigation is always reachable. Toolbar restores on scroll-up. */
body.fb-chrome-hidden .fb-toolbar { transform: translateY(calc(-1 * (var(--fb-header-h) + 100%))); }
/* GRANTS Phase 4 landing hold: toolbar chrome is meaningless with no grid and
   every chrome-driven reload would 403 for a landing user. display:none (not
   bare [hidden] — author display rules beat it, the BIBLIO lesson) also drops
   it from the tab order. The search wrap is inert'd by JS; this is the
   visible-affordance half. */
body.fb-landing .fb-toolbar { display: none; }
/* ---- LIVE-COLLAB S1.8 ITEM 1 — THE STAGE TAKES THE DOCUMENT ---------------
   The owner's field walk: the LIVE stage mounted over the grid and inherited
   the LIBRARY GRID'S chrome — icon size, square/tall/wide, media type, sort
   order, and a count of 13,644 resources — none of which means anything over a
   presentation. Amendment G as corrected: the chrome belongs to the GRID; the
   bug is that the STAGE inherited it. Grid view keeps every one of these
   controls, because the event-gallery precedent keeps them and they are useful
   over a playlist.

   WHY A RULE HAD TO BE ADDED, rather than "adopt the RV's fbrv-open takeover".
   fbrv-open SUPPRESSES NOTHING. Its own rule is `overflow: hidden`
   (fb_resource.css:62); everything else it does with fbrv-inshell is three
   z-index LIFTS of .fb-header / .fb-sidebar / .fb-scrim — the opposite of
   suppression — and the toolbar merely ends up UNDERNEATH .fbrv-overlay, which
   is inset below the header. Covered is not hidden: it stays in the DOM, keeps
   a non-none computed display, stays focusable and stays in the accessibility
   tree. live_client.css:620-622 copied the same three lifts, so the LIVE stage
   inherited the same non-suppression. The S1.8 gate asserts COMPUTED STYLE, so
   nothing short of this rule answers it.

   KEYED ON fb-live-open, WHICH ALREADY MEANS "THE STAGE IS VISIBLE". It is
   added on open and resume and removed on mount failure, suspend and close
   (five sites in browse.js), and pages/live.php ships it on <body> — so the
   toolbar is suppressed ON FIRST PAINT, before any JavaScript runs, and comes
   back the moment the stage is suspended for the grid. A parallel class would
   have been a sixth site to keep in step, and the one that got missed would
   leave the toolbar hidden after the room was gone.

   The HEADER and the SEARCH BAR deliberately stay: Amendment F requires the
   search bar on this surface, and for a leader it IS the add-resources
   workflow. */
body.fb-live-open .fb-toolbar { display: none; }
body.fb-landing .fb-search-wrap { opacity: 0.4; pointer-events: none; }
/* Search stays denied-and-dimmed for resources-off users beyond the landing
   hold (build-r1 grok: search is resources-framed on every non-biblio view,
   so it would 403 even from an allowed events/albums grid). */
body.fb-search-denied .fb-search-wrap { opacity: 0.4; pointer-events: none; }

.fb-count {
    font-size: 13px;
    color: var(--fb-text-dim);
    font-variant-numeric: tabular-nums;
}

.fb-chip {
    height: 32px;
    padding: 0 12px;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border);
    border-radius: 999px;
    color: var(--fb-text-dim);
    font-size: 13px;
    font-family: inherit;
    cursor: pointer;
    transition: all 0.15s;
}
.fb-chip:hover { color: var(--fb-text); }
.fb-chip.is-active {
    background: var(--fb-accent-dim);
    border-color: var(--fb-accent);
    color: #fff;
}

.fb-toolbar-spacer { flex: 1; }

.fb-select {
    height: 32px;
    padding: 0 28px 0 12px;
    background: var(--fb-bg-elevated) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239aa0ab' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 10px center;
    border: 1px solid var(--fb-border);
    border-radius: 999px;
    color: var(--fb-text-dim);
    font-size: 13px;
    font-family: inherit;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
}

/* The shell's own selects need the same treatment as the LIVE panel's: an
   <option> inherits the select's `color` and `background`, so declaring
   color-scheme is necessary but not sufficient. This shell is unconditionally
   dark, so the option list says so outright. */
.fb-select option,
.fb-select optgroup {
    background: var(--fb-bg-elevated);
    color: var(--fb-text);
}

/* ---- Grid (uniform CSS Grid — stable order, no reshuffle) ----------------- */
.fb-grid {
    display: grid;
    gap: var(--fb-gap);
    padding: 10px 14px calc(40px + env(safe-area-inset-bottom));
    /* Column count derives from a min cell width set by the size slider, so
       resizing is pure CSS (no image reload). 'pre' (900px) is served, so cells
       always downscale and stay crisp across the whole slider range. */
    --fb-cell-min: 200px;
    grid-template-columns: repeat(auto-fill, minmax(min(var(--fb-cell-min), 100%), 1fr));
}

.fb-card {
    background: var(--fb-bg-card);
    border: 1px solid var(--fb-border-soft);
    border-radius: var(--fb-radius);
    overflow: hidden;
    cursor: pointer;
    transition: border-color 0.15s, transform 0.12s;
    position: relative;
    display: block;
    color: inherit;
    text-decoration: none;
    /* Stop iOS Safari from hijacking touch gestures (Save Image callout,
       text/image selection, native image drag) so our tap/drag-select works. */
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}
.fb-thumb { -webkit-user-drag: none; -webkit-touch-callout: none; }
.fb-card:hover {
    border-color: var(--fb-accent-dim);
    transform: translateY(-2px);
}
.fb-card:active { transform: translateY(0); }

/* The image well takes its shape from the grid's data-shape (uniform cells). */
.fb-thumb-well {
    width: 100%;
    background: var(--fb-bg-elevated);
    position: relative;
    overflow: hidden;
    aspect-ratio: 1 / 1;            /* default: square */
}
.fb-grid[data-shape="square"]    .fb-thumb-well { aspect-ratio: 1 / 1; }
.fb-grid[data-shape="portrait"]  .fb-thumb-well { aspect-ratio: 3 / 4; }
.fb-grid[data-shape="landscape"] .fb-thumb-well { aspect-ratio: 4 / 3; }

.fb-thumb {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0;
    transition: opacity 0.25s;
}
.fb-thumb.is-loaded { opacity: 1; }

/* Placeholder for non-image media (audio, docs without preview). Fills the
   uniform cell shape rather than forcing its own square. */
.fb-thumb-icon {
    width: 100%;
    height: 100%;
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #1f242c, #181b21);
}
.fb-thumb-icon svg {
    width: 36%;
    height: 36%;
    stroke: var(--fb-text-faint);
    fill: none;
    stroke-width: 1.5;
}

.fb-card-meta {
    padding: 8px 10px 10px;
}
.fb-card-title {
    font-size: 12.5px;
    line-height: 1.35;
    color: var(--fb-text);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
}
.fb-card-sub {
    margin-top: 3px;
    font-size: 11px;
    color: var(--fb-text-faint);
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Media type badge */
.fb-badge {
    position: absolute;
    top: 8px;
    right: 8px;
    height: 22px;
    width: 22px;
    border-radius: 6px;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
}
.fb-badge svg {
    width: 13px;
    height: 13px;
    stroke: #fff;
    fill: none;
    stroke-width: 2;
}
.fb-badge.is-image { display: none; } /* images don't need a badge */

/* S7C pkg B: promoted-document chip in the documents lens (curator payloads
   only carry browse_scope, so this can only ever render for curators). */
.fb-lib-chip {
    position: absolute;
    bottom: 8px;
    right: 8px;
    padding: 2px 8px;
    border-radius: 10px;
    background: rgba(46, 125, 50, 0.85);
    color: #fff;
    font-size: 0.68em;
    font-weight: 600;
    pointer-events: none;
}

/* ---- States --------------------------------------------------------------- */
.fb-sentinel {
    height: 1px;
    width: 100%;
}

.fb-loading, .fb-empty, .fb-error {
    text-align: center;
    padding: 48px 20px;
    color: var(--fb-text-dim);
    font-size: 14px;
}
.fb-error { color: var(--fb-danger); }

.fb-spinner {
    display: inline-block;
    width: 22px;
    height: 22px;
    border: 2px solid var(--fb-border);
    border-top-color: var(--fb-accent);
    border-radius: 50%;
    animation: fb-spin 0.7s linear infinite;
}
@keyframes fb-spin { to { transform: rotate(360deg); } }

.fb-footer-load {
    text-align: center;
    padding: 24px;
}

/* Skeleton shimmer for initial load */
.fb-skeleton {
    border-radius: var(--fb-radius);
    background: linear-gradient(100deg, #1a1d24 30%, #22262f 50%, #1a1d24 70%);
    background-size: 200% 100%;
    animation: fb-shimmer 1.3s ease-in-out infinite;
    aspect-ratio: 1 / 1;
}
.fb-grid[data-shape="portrait"]  .fb-skeleton { aspect-ratio: 3 / 4; }
.fb-grid[data-shape="landscape"] .fb-skeleton { aspect-ratio: 4 / 3; }
@keyframes fb-shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .fb-card, .fb-thumb, .fb-spinner, .fb-skeleton { transition: none; animation: none; }
}

/* =============================================================================
   Selection system (Part 2B)
   ============================================================================= */

/* Checkbox overlay on each card */
.fb-check {
    position: absolute;
    top: 8px;
    left: 8px;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: rgba(0,0,0,0.45);
    border: 2px solid rgba(255,255,255,0.85);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transform: scale(0.8);
    transition: opacity 0.12s, transform 0.12s, background 0.12s;
    z-index: 3;
    pointer-events: auto;
}
.fb-check svg { width: 15px; height: 15px; stroke: #fff; opacity: 0; transition: opacity 0.12s; }

/* Show checkbox on hover (desktop) or whenever in select mode */
.fb-card:hover .fb-check,
body.fb-selecting .fb-check { opacity: 1; transform: scale(1); }

/* Selected state */
.fb-card.is-selected { border-color: var(--fb-accent); }
.fb-card.is-selected .fb-check {
    opacity: 1;
    transform: scale(1);
    background: var(--fb-accent);
    border-color: var(--fb-accent);
}
.fb-card.is-selected .fb-check svg { opacity: 1; }
.fb-card.is-selected .fb-thumb-well::after {
    content: '';
    position: absolute; inset: 0;
    background: rgba(91,157,255,0.18);
    pointer-events: none;
    z-index: 2;
}

/* In select mode, dim the badge so the checkbox reads clearly */
body.fb-selecting .fb-badge { opacity: 0.35; }

/* Floating action bar */
.fb-actionbar {
    position: fixed;
    left: 50%;
    bottom: calc(18px + env(safe-area-inset-bottom));
    transform: translateX(-50%) translateY(140%);
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border);
    border-radius: 14px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.5);
    z-index: 100;
    max-width: calc(100vw - 24px);
    transition: transform 0.22s cubic-bezier(0.2,0.8,0.2,1);
}
.fb-actionbar.is-visible { transform: translateX(-50%) translateY(0); }

.fb-ab-close {
    width: 34px; height: 34px; flex-shrink: 0;
    border-radius: 9px; border: none; cursor: pointer;
    background: transparent; color: var(--fb-text-dim);
    display: flex; align-items: center; justify-content: center;
}
.fb-ab-close:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-ab-close svg { width: 18px; height: 18px; }

.fb-ab-count { font-size: 13px; font-weight: 600; color: var(--fb-text); white-space: nowrap; padding: 0 4px; }
.fb-ab-spacer { width: 4px; }

.fb-ab-btn {
    display: inline-flex; align-items: center; gap: 6px;
    height: 34px; padding: 0 12px;
    border-radius: 9px; border: 1px solid var(--fb-border);
    background: var(--fb-bg-card); color: var(--fb-text);
    font-size: 13px; font-family: inherit; cursor: pointer;
    white-space: nowrap; transition: background 0.12s, border-color 0.12s;
    -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
    touch-action: manipulation;
}
.fb-ab-btn:hover { border-color: var(--fb-accent-dim); }
/* TP-2 (2026-07-25): the JS hides per-view buttons via the HTML hidden
   attribute (e.g. the plain Delete in Trash views), but ANY author display
   rule — like the inline-flex above — overrides the UA's [hidden] styling.
   Field result: "Delete" sat visible next to "Delete forever" in the recycle
   bin and soft-RE-deleted binned items. Restore [hidden]'s meaning here. */
.fb-ab-btn[hidden] { display: none !important; }
.fb-ab-btn svg { width: 16px; height: 16px; flex-shrink: 0; }
.fb-ab-danger { color: var(--fb-danger); }
.fb-ab-danger:hover { background: rgba(255,107,107,0.12); border-color: var(--fb-danger); }

/* On narrow screens, hide button labels (icons only) */
@media (max-width: 640px) {
    .fb-ab-btn span { display: none; }
    .fb-ab-btn { padding: 0 10px; }
}

/* Collection picker modal */
.fb-modal-overlay {
    position: fixed; inset: 0; z-index: 200;
    background: rgba(0,0,0,0.6);
    display: flex; align-items: center; justify-content: center;
    padding: 20px;
    backdrop-filter: blur(2px);
}
.fb-modal {
    width: 100%; max-width: 420px; max-height: 70vh;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border);
    border-radius: 14px;
    display: flex; flex-direction: column;
    overflow: hidden;
}
.fb-modal-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 14px 16px; font-weight: 600; font-size: 15px;
    border-bottom: 1px solid var(--fb-border);
}
.fb-modal-x {
    width: 30px; height: 30px; border: none; background: transparent;
    color: var(--fb-text-dim); cursor: pointer; border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
}
.fb-modal-x:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-modal-x svg { width: 16px; height: 16px; }
.fb-coll-list { overflow-y: auto; padding: 8px; }
.fb-coll-row {
    display: flex; align-items: center; justify-content: space-between;
    width: 100%; text-align: left;
    padding: 11px 12px; margin-bottom: 4px;
    border: 1px solid transparent; border-radius: 9px;
    background: transparent; color: var(--fb-text);
    font-size: 14px; font-family: inherit; cursor: pointer;
}
.fb-coll-row:hover { background: var(--fb-bg-card); border-color: var(--fb-accent-dim); }
.fb-coll-count { font-size: 12px; color: var(--fb-text-faint); }

/* ---------------------------------------------------------------------------
   Sharing panel (job 115 — Owner Ruling 3)
   Built on .fb-modal-overlay / .fb-modal so it inherits the picker's shell and
   the keyboard reach CT-1 r5 put there. Only the inner layout is new. Tokens
   only — no literal colours, so light/dark and any brand follow the theme.
   --------------------------------------------------------------------------- */
.fb-share-modal { max-width: 520px; }
.fb-share-scope {
    padding: 12px 16px; border-bottom: 1px solid var(--fb-border);
    display: flex; flex-direction: column; gap: 8px; font-size: 13px;
}
.fb-share-scope-opt { display: flex; align-items: flex-start; gap: 8px; cursor: pointer; }
.fb-share-scope-off { color: var(--fb-text-faint); cursor: default; }
.fb-share-scope-off input { cursor: default; }
.fb-share-note {
    display: block; width: 100%; font-size: 12px; color: var(--fb-text-faint); margin-top: 2px;
}
.fb-share-list { overflow-y: auto; padding: 8px 16px; min-height: 60px; font-size: 14px; }
.fb-share-row {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 9px 0; border-bottom: 1px solid var(--fb-border);
}
.fb-share-row:last-child { border-bottom: none; }
.fb-share-who { flex: 1 1 40%; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fb-share-fixed { font-size: 12px; color: var(--fb-text-faint); }
/* The level control is THE control this panel exists for, and it is driven by
   finger on the Ruling 65 surfaces, so it carries the same 44px minimum as the
   buttons beside it. The first cut wrote the rule and then applied it to
   everything except this (diff bench r1, grok). */
.fb-share-level {
    flex: 1 1 auto; min-width: 0; max-width: 100%; min-height: 44px;
    background: var(--fb-bg-card); color: var(--fb-text);
    border: 1px solid var(--fb-border); border-radius: 8px;
    padding: 10px 12px; font-size: 14px; font-family: inherit;
}
/* 44px minimum touch target — the Ruling 65 surfaces are driven by finger. */
.fb-share-remove, .fb-share-cand {
    min-height: 44px; padding: 8px 12px;
    background: transparent; color: var(--fb-text);
    border: 1px solid var(--fb-border); border-radius: 8px;
    font-size: 13px; font-family: inherit; cursor: pointer;
}
.fb-share-remove:hover, .fb-share-cand:hover { background: var(--fb-bg-card); }
.fb-share-add { padding: 12px 16px; border-top: 1px solid var(--fb-border); }
.fb-share-add-label { display: block; font-size: 12px; color: var(--fb-text-dim); margin-bottom: 6px; }
.fb-share-q {
    width: 100%; box-sizing: border-box; min-height: 44px;
    background: var(--fb-bg-card); color: var(--fb-text);
    border: 1px solid var(--fb-border); border-radius: 9px;
    padding: 10px 12px; font-size: 14px; font-family: inherit;
}
.fb-share-results { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; max-height: 180px; overflow-y: auto; }
.fb-share-cand { text-align: left; }
.fb-share-err { color: var(--fb-danger); font-size: 13px; padding: 6px 0; }

/* Toast */
.fb-toast {
    position: fixed; left: 50%; bottom: 84px;
    transform: translateX(-50%) translateY(20px);
    background: var(--fb-bg-card); color: var(--fb-text);
    border: 1px solid var(--fb-border); border-radius: 10px;
    padding: 11px 18px; font-size: 13px;
    box-shadow: 0 8px 30px rgba(0,0,0,0.5);
    opacity: 0; pointer-events: none; z-index: 300;
    transition: opacity 0.2s, transform 0.2s;
    max-width: calc(100vw - 32px);
}
.fb-toast.is-visible { opacity: 1; transform: translateX(-50%) translateY(0); }
.fb-toast.is-error { border-color: var(--fb-danger); color: var(--fb-danger); }

/* =============================================================================
   ZIP-2a — split Download control, options menu, progress chip
   ============================================================================= */

/* Split button: one-click zip + a caret for the other routes. The caret is the
   ONLY route to originals on touch (Shift is desktop-only). */
.fb-ab-split { position: relative; display: inline-flex; }
/* Same trap as .fb-ab-btn[hidden] above: the author inline-flex beats the UA
   [hidden] rule, so per-view hiding (Edit in Trash) needs this restored. */
.fb-ab-split[hidden] { display: none !important; }
.fb-ab-split-main {
    border-top-right-radius: 0; border-bottom-right-radius: 0;
    border-right-color: transparent;
}
.fb-ab-split-caret {
    border-top-left-radius: 0; border-bottom-left-radius: 0;
    padding: 0 7px; margin-left: -1px;
}
.fb-ab-split-caret svg { width: 14px; height: 14px; }
.fb-ab-split-caret[aria-expanded="true"] { border-color: var(--fb-accent-dim); background: var(--fb-bg-elevated); }

.fb-zipmenu {
    position: absolute; bottom: calc(100% + 8px); right: 0; z-index: 320;
    min-width: 232px; padding: 6px;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border); border-radius: 12px;
    box-shadow: 0 10px 34px rgba(0,0,0,0.55);
}
.fb-zipmenu-item {
    display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
    width: 100%; text-align: left;
    padding: 9px 11px; border: 1px solid transparent; border-radius: 9px;
    background: transparent; color: var(--fb-text);
    font-family: inherit; cursor: pointer;
}
.fb-zipmenu-item:hover { background: var(--fb-bg-card); border-color: var(--fb-accent-dim); }
.fb-zipmenu-label { font-size: 13px; font-weight: 600; }
.fb-zipmenu-hint  { font-size: 11px; color: var(--fb-text-faint); }

/* Progress chip: outlives a toast, because a zip build does. Sits above the
   action bar and carries the job from dispatch to outcome. */
.fb-zipchip {
    position: fixed; left: 50%; bottom: 84px;
    transform: translateX(-50%) translateY(20px);
    display: flex; align-items: center; gap: 9px;
    background: var(--fb-bg-card); color: var(--fb-text);
    border: 1px solid var(--fb-border); border-radius: 10px;
    padding: 10px 10px 10px 14px; font-size: 13px;
    box-shadow: 0 8px 30px rgba(0,0,0,0.5);
    opacity: 0; pointer-events: none; z-index: 310;
    transition: opacity 0.2s, transform 0.2s;
    max-width: calc(100vw - 32px);
}
.fb-zipchip.is-visible { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; }
.fb-zipchip svg { width: 16px; height: 16px; flex-shrink: 0; }
.fb-zipchip-msg { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fb-zipchip-x {
    width: 24px; height: 24px; flex-shrink: 0; margin-left: 2px;
    border: none; background: transparent; color: var(--fb-text-faint);
    border-radius: 7px; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
}
.fb-zipchip-x:hover { background: var(--fb-bg-elevated); color: var(--fb-text); }
.fb-zipchip-x svg { width: 13px; height: 13px; }
.fb-zipchip.is-building { border-color: var(--fb-accent-dim); }
.fb-zipchip.is-building .fb-zipchip-msg { color: var(--fb-text-dim); }
.fb-zipchip.is-ready { border-color: var(--fb-accent); }
.fb-zipchip.is-ready > svg { color: var(--fb-accent); }
.fb-zipchip.is-error { border-color: var(--fb-danger); }
.fb-zipchip.is-error { flex-wrap: wrap; }
.fb-zipchip.is-error .fb-zipchip-msg { white-space: normal; overflow-wrap: anywhere; flex: 1; min-width: 120px; }
.fb-zipchip-action {
    border: 1px solid var(--fb-border); border-radius: 7px;
    background: var(--fb-bg-elevated); color: var(--fb-text);
    padding: 7px 10px; font: inherit; cursor: pointer;
}
.fb-zipchip-action:disabled { opacity: 0.5; cursor: default; }
.fb-zipchip.is-error > svg, .fb-zipchip.is-error .fb-zipchip-msg { color: var(--fb-danger); }

.fb-spin { animation: fb-spin 0.9s linear infinite; transform-origin: 50% 50%; }
@keyframes fb-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .fb-spin { animation: none; } }

/* =============================================================================
   Collection picker groups + create + delete-guardrail dialog (Round A)
   ============================================================================= */

/* Group headers in the picker */
.fb-coll-group {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--fb-text-faint);
    padding: 12px 12px 4px;
}
.fb-coll-group:first-child { padding-top: 4px; }

.fb-coll-row { gap: 10px; }
.fb-coll-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Create-new collection area */
.fb-coll-create {
    padding: 8px 12px;
    border-bottom: 1px solid var(--fb-border);
}
.fb-coll-new {
    display: inline-flex; align-items: center; gap: 7px;
    width: 100%;
    padding: 9px 10px;
    border: 1px dashed var(--fb-border);
    border-radius: 9px;
    background: transparent; color: var(--fb-accent);
    font-size: 13px; font-family: inherit; cursor: pointer;
}
.fb-coll-new:hover { border-color: var(--fb-accent); background: rgba(91,157,255,0.08); }
.fb-coll-new svg { width: 16px; height: 16px; }

.fb-coll-new-form { display: flex; gap: 8px; }
.fb-coll-new-input {
    flex: 1; min-width: 0;
    padding: 9px 11px;
    border: 1px solid var(--fb-border); border-radius: 9px;
    background: var(--fb-bg-card); color: var(--fb-text);
    font-size: 14px; font-family: inherit;
}
.fb-coll-new-input:focus { outline: none; border-color: var(--fb-accent); }
.fb-coll-new-save {
    padding: 0 14px;
    border: none; border-radius: 9px;
    background: var(--fb-accent); color: #fff;
    font-size: 13px; font-family: inherit; cursor: pointer; white-space: nowrap;
}
.fb-coll-new-save:hover { filter: brightness(1.08); }

/* Delete-guardrail (blocked) dialog */
.fb-blocked-body { padding: 14px 16px; overflow-y: auto; }
.fb-blocked-ok { color: var(--fb-text); font-size: 14px; margin: 0 0 8px; }
.fb-blocked-intro { color: var(--fb-text-dim); font-size: 13px; margin: 0 0 12px; }
.fb-blocked-list { display: flex; flex-direction: column; gap: 6px; }
.fb-blocked-row {
    display: flex; align-items: center; justify-content: space-between;
    padding: 9px 11px;
    background: var(--fb-bg-card);
    border: 1px solid var(--fb-border);
    border-left: 3px solid var(--fb-danger);
    border-radius: 8px;
}
.fb-blocked-ref { font-weight: 600; color: var(--fb-text); font-size: 13px; }
.fb-blocked-why { font-size: 12px; color: var(--fb-danger); }

.fb-modal-foot {
    padding: 12px 16px;
    border-top: 1px solid var(--fb-border);
    display: flex; justify-content: flex-end;
}
.fb-modal-ok {
    padding: 8px 18px;
    border: none; border-radius: 9px;
    background: var(--fb-accent); color: #fff;
    font-size: 13px; font-family: inherit; cursor: pointer;
}
.fb-modal-ok:hover { filter: brightness(1.08); }

/* =============================================================================
   Share-status icons + resource # on cards
   ============================================================================= */
.fb-share-link {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    gap: 4px;
    z-index: 4;
    cursor: pointer;
}
.fb-share-ic {
    width: 22px; height: 22px;
    border-radius: 6px;
    display: flex; align-items: center; justify-content: center;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(2px);
    transition: color 0.12s, background 0.12s, opacity 0.12s;
}
.fb-share-ic svg { width: 13px; height: 13px; }

/* Shared = green and clearly "on" */
.fb-share-ic.is-on { color: #34d399; }
.fb-share-link:hover .fb-share-ic.is-on { background: rgba(52,211,153,0.18); }

/* Not shared = dim, reveals on hover so it's discoverable but unobtrusive */
.fb-share-ic.is-off { color: rgba(255,255,255,0.55); opacity: 0; }
.fb-card:hover .fb-share-ic.is-off { opacity: 1; }
.fb-share-link:hover .fb-share-ic.is-off { color: #fff; background: rgba(0,0,0,0.7); }

/* Hide share icons while in select mode so the checkbox reads clearly */
body.fb-selecting .fb-share-link { opacity: 0.2; pointer-events: none; }

/* Media-type badge to bottom-right so it doesn't collide with share icons */
.fb-badge {
    top: auto !important;
    bottom: 8px;
    right: 8px;
}

.fb-card-ref {
    font-variant-numeric: tabular-nums;
    color: var(--fb-text-faint);
    font-weight: 600;
}

/* =============================================================================
   Sidebar (Claude-style slide-in collections navigation)
   ============================================================================= */
.fb-menu-btn {
    flex-shrink: 0;
    width: 38px; height: 38px;
    border: none; background: transparent;
    color: var(--fb-text); cursor: pointer;
    border-radius: 9px;
    display: flex; align-items: center; justify-content: center;
    margin-right: 4px;
}
.fb-menu-btn:hover { background: var(--fb-bg-card); }
.fb-menu-btn svg { width: 20px; height: 20px; }

.fb-scrim {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.5);
    opacity: 0; pointer-events: none;
    transition: opacity 0.22s;
    z-index: 150;
}
.fb-scrim.is-open { opacity: 1; pointer-events: auto; }

.fb-sidebar {
    position: fixed;
    top: 0; left: 0; bottom: 0;
    width: 300px; max-width: 84vw;
    background: var(--fb-bg-elevated);
    border-right: 1px solid var(--fb-border);
    transform: translateX(-102%);
    transition: transform 0.24s cubic-bezier(0.2,0.8,0.2,1);
    z-index: 160;
    display: flex; flex-direction: column;
    box-shadow: 4px 0 30px rgba(0,0,0,0.4);
}
.fb-sidebar.is-open { transform: translateX(0); }

.fb-sb-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px;
    border-bottom: 1px solid var(--fb-border);
}
.fb-sb-title { font-weight: 700; font-size: 15px; color: var(--fb-text); }
.fb-sb-close {
    width: 32px; height: 32px; border: none; background: transparent;
    color: var(--fb-text-dim); cursor: pointer; border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
}
.fb-sb-close:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-sb-close svg { width: 16px; height: 16px; }

/* P-M0 r3: the sidebar "Library" label is the admin triple-tap reveal target.
   Kill the long-press callout / text selection so rapid taps count cleanly; a
   gold underline (quarantine gold #f5c850) marks LATCHED reveal mode so a
   toggled state is never invisible (any pointer - desktop can latch too). */
.fb-sb-title {
    touch-action: manipulation;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    cursor: pointer;   /* iOS: interactive-signal for tap handling */
}
body.fb-ctrlshift .fb-sb-title { box-shadow: 0 2px 0 0 #f5c850; }

.fb-sb-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 8px; }

/* Account menu pinned to the bottom of the sidebar (Claude-style). The body
   above is flex:1 + scroll, so this footer always sits at the bottom edge. */
.fb-sb-foot {
    flex-shrink: 0;
    padding: 8px;
    border-top: 1px solid var(--fb-border);
}
.fb-sb-acct {
    /* Override the top-bar pill look: full-width row inside the sidebar. */
    width: 100%;
    height: auto;
    min-height: 52px;   /* comfortable for the 38px initials circle */
    padding: 6px 10px;
    display: flex;
    align-items: center;
    gap: 10px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 10px;
    color: var(--fb-text);
    cursor: pointer;
    text-align: left;
}
.fb-sb-acct:hover { background: var(--fb-bg-card); }
.fb-sb-acct[aria-expanded="true"] { background: var(--fb-bg-card); }
/* The foot button carries BOTH .fb-acct-btn (a 38px circle w/ 1px border) and
   .fb-sb-acct (full-width row). Kill the inherited circular border/sizing so no
   stray 1px ring shows around the avatar — the foot is a row, not a pill. */
.fb-sb-acct.fb-acct-btn {
    width: 100%;
    height: auto;
    border: none;
    border-radius: 10px;
}
/* Account foot identity: vertical stack (name on top, usergroup below) that
   takes the remaining row width. Claude-style. */
.fb-sb-acct-meta {
    flex: 1; min-width: 0;
    display: flex; flex-direction: column;
    gap: 1px;
    overflow: hidden;
}
.fb-sb-acct-name {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 14px; font-weight: 600; line-height: 1.25;
}
.fb-sb-acct-sub {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 12px; font-weight: 400; line-height: 1.2;
    color: var(--fb-text-dim);
}

.fb-sb-home,
.fb-sb-section {
    display: flex; align-items: center; gap: 9px;
    width: 100%;
    padding: 11px 12px;
    border: none; background: transparent;
    color: var(--fb-text); font-size: 14px; font-family: inherit;
    cursor: pointer; border-radius: 9px; text-align: left;
}
.fb-sb-home:hover,
.fb-sb-section:hover { background: var(--fb-bg-card); }
.fb-sb-home svg,
.fb-sb-section svg { width: 17px; height: 17px; flex-shrink: 0; }
.fb-sb-home span,
.fb-sb-section span:not(.fb-sb-chev) { flex: 1; }

.fb-sb-section { font-weight: 600; }
.fb-sb-chev {
    display: inline-flex; width: 16px; height: 16px;
    transition: transform 0.18s; flex-shrink: 0;
}
.fb-sb-chev svg { width: 16px; height: 16px; }
.fb-sb-section.is-open .fb-sb-chev { transform: rotate(90deg); }

.fb-sb-list {
    display: none;
    margin: 2px 0 6px;
}
.fb-sb-list.is-open { display: block; }

.fb-sb-coll {
    display: flex; align-items: center; gap: 5px;
    width: 100%; min-width: 0;
    padding: 9px 10px;
    border: none; background: transparent;
    color: var(--fb-text-dim); font-size: 13px; font-family: inherit;
    cursor: pointer; border-radius: 8px; text-align: left;
}
.fb-sb-coll:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-sb-coll-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-sb-coll-count { font-size: 11px; color: var(--fb-text-faint); font-variant-numeric: tabular-nums; flex-shrink: 0; }

/* Clusters drawer item: Shift-revealed "re-run clustering" control (admin only).
   Hidden until Shift is held (body.fb-shift-active), the row is hovered, or the
   triple-tap reveal latch (body.fb-ctrlshift) is on - the latch is the mobile
   path, where Shift and hover do not exist. Spins via the shared fb-spin
   keyframe while a run is in flight. */
.fb-sb-cluster-run {
    flex-shrink: 0;
    display: none;
    align-items: center; justify-content: center;
    width: 22px; height: 22px;
    border-radius: 6px;
    color: var(--fb-text-faint);
    cursor: pointer;
    transition: color 0.12s, background 0.12s;
}
body.fb-shift-active .fb-sb-cluster-run,
body.fb-ctrlshift .fb-sb-cluster-run,
.fb-sb-coll--cluster:hover .fb-sb-cluster-run { display: inline-flex; }
.fb-sb-cluster-run:hover { color: var(--fb-accent); background: var(--fb-bg-card); }
.fb-sb-cluster-run svg { width: 14px; height: 14px; }
.fb-sb-cluster-run.is-running { display: inline-flex; color: var(--fb-accent); animation: fb-spin 0.9s linear infinite; transform-origin: 50% 50%; }
/* Row-level "in flight" tell: the label itself says Clustering… and pulses. */
.fb-sb-coll--cluster.is-clustering .fb-sb-coll-name { color: var(--fb-accent); animation: fb-clustering-pulse 1.6s ease-in-out infinite; }
@keyframes fb-clustering-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) {
    .fb-sb-cluster-run.is-running { animation: none; }
    .fb-sb-coll--cluster.is-clustering .fb-sb-coll-name { animation: none; }
}
.fb-sb-folder { display: inline-flex; width: 15px; height: 15px; flex-shrink: 0; color: var(--fb-accent-dim); }
.fb-sb-folder svg { width: 15px; height: 15px; }
.fb-sb-dot {
    display: inline-flex; width: 14px; height: 14px; flex-shrink: 0;
    margin-right: 2px;
    align-items: center; justify-content: center;
}
.fb-sb-dot::before { content: '\2022'; color: var(--fb-text-faint); font-size: 11px; line-height: 1; }

/* Childless folders: blank spacer the exact size of the chevron toggle, so the
   folder name aligns with chevron-bearing siblings while leaving the chevron as
   the sole visual cue for "has subfolders". */
.fb-sb-nochild {
    display: inline-flex; width: 14px; height: 14px; flex-shrink: 0;
    margin-right: 2px;
}

/* Chevron indicating a featured node has sub-collections (uniform look) */
.fb-sb-haschild {
    display: inline-flex; width: 13px; height: 13px; flex-shrink: 0;
    color: var(--fb-text-dim); margin-right: 2px;
    align-items: center; justify-content: center;
}
.fb-sb-haschild svg { width: 13px; height: 13px; }

/* Featured folders are collapsible (treated as real folders). The toggle is the
   chevron marker; clicking it expands/collapses without navigating. It rotates
   90deg when open. The children container is hidden until the parent is open. */
.fb-sb-folder-toggle {
    /* Keep the icon's content box when touch padding enlarges its target. */
    box-sizing: content-box;
    display: inline-flex; width: 14px; height: 14px; flex-shrink: 0;
    color: var(--fb-text-dim); margin-right: 2px; border-radius: 4px;
    align-items: center; justify-content: center;
    cursor: pointer; transition: transform 0.16s, color 0.12s, background 0.12s;
}
.fb-sb-folder-toggle:hover { color: var(--fb-text); background: var(--fb-bg-card); }
.fb-sb-folder-toggle svg { width: 13px; height: 13px; }
.fb-sb-folder-toggle.is-open { transform: rotate(90deg); }

/* THE CHEVRON IS A TOUCH TARGET, and 14x14 is not one (build bench r2, grok
   SHOULD FIX 3). A near-miss on this control is not a no-op: the tap falls
   through to the row, and 280ms later the collection opens and the sidebar
   closes — so the cost of missing is being taken somewhere you did not ask to
   go. Ruling 60 lists expand/collapse as one of the interactions; it has to be
   hittable with a finger.

   The HIT AREA grows, the PAINTED ICON does not: padding plus an equal negative
   margin, so the row's layout is untouched and only the target changes. Applied
   on coarse pointers only, where it is needed and where nothing hovers.
   `transform` is left alone — it carries the open/closed rotation. */
@media (hover: none), (pointer: coarse) {
    .fb-sb-folder-toggle {
        /* Asymmetric on purpose. The row is about 31px tall, so 15px of
           VERTICAL padding would make the target overlap the row above and
           below — and a stray hit on a neighbour's chevron is its own small
           wrongness (build bench r3, grok OBSERVATION 10). Horizontal room is
           free, vertical room is not: 12px each way takes the target from
           14x14 to roughly 44x38, which clears the miss that used to fall
           through to the row and navigate, without reaching into the
           neighbouring rows. */
        padding: 12px 15px;
        margin: -12px 2px -12px -15px;
        border-radius: 8px;
    }
}

.fb-sb-children { display: none; }
.fb-sb-children.is-open { display: block; }

/* Section header + right-aligned add button */
.fb-sb-section-wrap {
    display: flex; align-items: center;
}
.fb-sb-section-wrap .fb-sb-section { flex: 1; }
.fb-sb-add {
    flex-shrink: 0;
    width: 30px; height: 30px;
    border: none; background: transparent;
    color: var(--fb-text-dim); cursor: pointer; border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    margin-right: 4px;
}
.fb-sb-add:hover { background: var(--fb-bg-card); color: var(--fb-accent); }
.fb-sb-add svg { width: 16px; height: 16px; }

/* Collection actions share the same menu as right-click and double-tap. */
.fb-sb-row { display: flex; align-items: center; }
.fb-sb-row .fb-sb-coll { flex: 1; min-width: 0; }
.fb-tree-menu { flex: 0 0 32px; min-height: 32px; border: 0; border-radius: 5px; background: transparent; color: var(--fb-text-faint); font-size: 21px; cursor: pointer; touch-action: manipulation; }
.fb-tree-menu:hover, .fb-tree-menu:focus-visible { color: var(--fb-text); background: var(--fb-hover, rgba(127,127,127,.15)); }
@media (pointer: coarse) { .fb-tree-menu { flex-basis: 44px; min-height: 44px; } }

/* THE ROW IS A DOUBLE-TAP TARGET NOW, so it needs what every other double-tap
   target in this sidebar already has (compare the Library title above).
   Ruling 65 chose double-tap BECAUSE press-and-hold is problematic on iOS;
   leaving the iOS long-press callout and double-tap-to-zoom live on the very
   control the ruling built would hand the problem straight back.
     touch-action: manipulation   — no double-tap zoom on this element
     -webkit-touch-callout: none  — no long-press callout menu
     -webkit-user-select: none    — no long-press text selection
   (build bench, grok SHOULD FIX 6) */
.fb-sb-coll {
    touch-action: manipulation;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}

.fb-sb-loading,
.fb-sb-empty { padding: 10px 12px; font-size: 12px; color: var(--fb-text-faint); }

/* "Viewing: <collection>" indicator in the toolbar */
.fb-viewing {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 13px; color: var(--fb-text); font-weight: 600;
}
.fb-viewing-sep { color: var(--fb-text-faint); }
.fb-viewing-clear {
    width: 20px; height: 20px; border: none; background: transparent;
    color: var(--fb-text-dim); cursor: pointer; border-radius: 5px;
    display: inline-flex; align-items: center; justify-content: center;
}
.fb-viewing-clear:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-viewing-clear svg { width: 13px; height: 13px; }

/* "All resources" / "My resources" — top-level nav items share .fb-sb-item
   styling with the section headers (same hit-area, icon size, hover). */
.fb-sb-item {
    display: flex; align-items: center; gap: 9px;
    width: 100%;
    padding: 11px 12px;
    border: none; background: transparent;
    color: var(--fb-text); font-size: 14px; font-family: inherit;
    cursor: pointer; border-radius: 9px; text-align: left;
}
.fb-sb-item:hover { background: var(--fb-bg-card); }
/* Same trap as .fb-ab-btn[hidden]: the flex rule above beats the UA [hidden]
   rule, so a scope row the shell starts hidden (the leader-only Live "Add
   resources", fb_shell.js scopeNavHtml) was shown to every viewer (job 402). */
.fb-sb-item[hidden] { display: none !important; }
.fb-sb-item svg { width: 17px; height: 17px; flex-shrink: 0; }
.fb-sb-item span { flex: 1; }

/* Pin button in the sidebar head (between title and close). Active = pinned. */
.fb-sb-pin {
    width: 32px; height: 32px; border: none; background: transparent;
    color: var(--fb-text-dim); cursor: pointer; border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    margin-left: auto; margin-right: 2px;
}
.fb-sb-pin:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-sb-pin.is-active { color: var(--fb-accent); }
.fb-sb-pin svg { width: 16px; height: 16px; }
/* Pin only makes sense on desktop (where the column can dock). Hide < 1100px. */
@media (max-width: 1099px) { .fb-sb-pin { display: none; } }

/* On wider screens, push content instead of overlay (optional Claude-style) */
@media (min-width: 1100px) {
    .fb-sidebar { box-shadow: none; }

    /* PINNED: the sidebar becomes a docked left column and the page content
       (header, toolbar, grid, sentinel, footer, actionbar) shifts right by the
       sidebar width. Works for the grid (#fb-app children) and any FB page that
       sets body.fb-sb-pinned. The scrim is suppressed while docked. */
    body.fb-sb-pinned .fb-sidebar {
        transform: translateX(0);
        box-shadow: none;
    }
    body.fb-sb-pinned .fb-scrim { display: none; }

    /* Grid page: its chrome is fixed/sticky and full-width, so pad the left. */
    body.fb-sb-pinned .fb-header,
    body.fb-sb-pinned .fb-toolbar,
    body.fb-sb-pinned .fbtok-chips { padding-left: 316px; }
    body.fb-sb-pinned .fb-grid,
    body.fb-sb-pinned .fb-sentinel,
    body.fb-sb-pinned .fb-footer-load,
    body.fb-sb-pinned .fb-actionbar { margin-left: 300px; }
    /* Job 397 (owner 2026-10-08, item 7): the sentinel is width:100% for the
       observer, and 100% PLUS the 300px docked margin made the document 300px
       wider than the viewport on every pinned page — blank space to the right
       that a horizontal scroll (keys, trackpad, a programmatic scrollTo) could
       reach, under the Resource View included. The containing width is
       corrected here; nothing swallows keys or clips content. */
    body.fb-sb-pinned .fb-sentinel { width: auto; }

    /* Generic content pages (uploader etc.) opt in by shifting their own
       content wrapper. They add .fb-pin-shift to the element that should move. */
    body.fb-sb-pinned .fb-pin-shift { margin-left: 300px; }

    /* The pinned column hides its own close button (you unpin to dismiss). */
    body.fb-sb-pinned .fb-sb-close { display: none; }

    /* Pinned = the sidebar is a docked column, so the hamburger no longer acts
       as a menu toggle (it's redundant). Hide it on every FB page — grid,
       People view, uploader. Unpinning restores it (this rule is pinned-only).
       The header keeps its 316px left padding, so the logo sits in the gutter
       just past the docked column. */
    body.fb-sb-pinned .fb-menu-btn { display: none; }
}

/* Chevron in the add-to-collection picker (featured node with children) */
.fb-coll-chev {
    display: inline-flex; width: 13px; height: 13px; flex-shrink: 0;
    color: var(--fb-text-dim); margin-right: 4px;
    align-items: center; justify-content: center;
}
.fb-coll-chev svg { width: 13px; height: 13px; }
.fb-coll-chev-empty { /* reserves the slot so same-depth items align */ }

/* Names truncate; counts stay pinned right — layout holds at any depth/length */
.fb-coll-row { min-width: 0; }
.fb-coll-name {
    flex: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fb-coll-count { flex-shrink: 0; }

/* =============================================================================
   Grid shape toggle (square / portrait / landscape)
   ============================================================================= */
.fb-shape-toggle {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    background: var(--fb-bg-card);
    border: 1px solid var(--fb-border);
    border-radius: 9px;
}
.fb-shape-btn {
    width: 30px; height: 28px;
    border: none; background: transparent;
    color: var(--fb-text-dim); cursor: pointer; border-radius: 7px;
    display: flex; align-items: center; justify-content: center;
    transition: background 0.12s, color 0.12s;
}
.fb-shape-btn:hover { color: var(--fb-text); }
.fb-shape-btn.is-active { background: var(--fb-accent); color: #fff; }
.fb-shape-btn svg { width: 16px; height: 16px; }

/* On very narrow screens, keep the toggle but let the selects wrap below */
@media (max-width: 520px) {
    .fb-shape-btn { width: 26px; height: 26px; }
    .fb-shape-btn svg { width: 14px; height: 14px; }
}

/* =============================================================================
   Size slider (controls grid cell width; images always served at 'pre')
   ============================================================================= */
.fb-size-control {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    color: var(--fb-text-faint);
}
.fb-size-ico { width: 15px; height: 15px; flex-shrink: 0; }
.fb-size-slider {
    -webkit-appearance: none;
    appearance: none;
    width: 100px;
    height: 6px;
    border-radius: 3px;
    background: var(--fb-text-faint);
    outline: none;
    cursor: pointer;
    /* Touches on the slider are for the slider only — never pan/scroll the
       page. This makes the thumb grab instantly on a fast touch instead of the
       browser guessing "scroll" and moving the whole screen. */
    touch-action: none;
}
.fb-size-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 18px; height: 18px;
    border-radius: 50%;
    background: var(--fb-accent);
    cursor: pointer;
    border: 2px solid var(--fb-bg-card);
    box-shadow: 0 0 0 1px var(--fb-accent);
}
.fb-size-slider::-moz-range-thumb {
    width: 18px; height: 18px;
    border-radius: 50%;
    background: var(--fb-accent);
    cursor: pointer;
    border: 2px solid var(--fb-bg-card);
}
@media (max-width: 520px) {
    .fb-size-slider { width: 64px; }
    .fb-size-ico { width: 13px; height: 13px; }
}

/* =============================================================================
   Sidebar Actions section (Export CSV / Classic view / future advanced actions)
   ============================================================================= */
.fb-sb-actions-wrap { margin-top: 6px; border-top: 1px solid var(--fb-border-soft); padding-top: 6px; }
.fb-sb-action {
    display: flex; align-items: center; gap: 9px;
    width: 100%;
    padding: 10px 12px 10px 16px;
    border: none; background: transparent;
    color: var(--fb-text-dim); font-size: 13px; font-family: inherit;
    cursor: pointer; border-radius: 8px; text-align: left;
}
.fb-sb-action:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-sb-action svg { width: 16px; height: 16px; flex-shrink: 0; }
.fb-sb-action span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* =============================================================================
   Events section (sidebar)
   ============================================================================= */
.fb-sb-group {
    padding: 8px 12px 4px;
    font-size: 11px; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.06em; color: var(--fb-text-faint);
}
.fb-ev { margin: 1px 0; }
.fb-ev-head {
    display: flex; align-items: center; gap: 6px;
    width: 100%; min-width: 0;
    padding: 9px 12px;
    border: none; background: transparent;
    color: var(--fb-text-dim); font-size: 13px; font-family: inherit;
    cursor: pointer; border-radius: 8px; text-align: left;
}
.fb-ev-head:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-ev-head .fb-sb-chev { transition: transform 0.15s; flex-shrink: 0; }
.fb-ev-head.is-open .fb-sb-chev { transform: rotate(90deg); }
.fb-ev-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-ev-badge {
    flex-shrink: 0; min-width: 18px; height: 18px; padding: 0 5px;
    border-radius: 9px; background: var(--fb-accent); color: #fff;
    font-size: 11px; font-weight: 600; display: flex; align-items: center; justify-content: center;
}
.fb-ev-states { display: none; }
.fb-ev.is-open .fb-ev-states { display: block; }
.fb-ev-state {
    display: flex; align-items: center; gap: 7px;
    width: 100%; min-width: 0;
    padding: 7px 12px 7px 30px;
    border: none; background: transparent;
    color: var(--fb-text-dim); font-size: 12px; font-family: inherit;
    cursor: pointer; border-radius: 8px; text-align: left;
}
.fb-ev-state:hover { background: var(--fb-bg-card); color: var(--fb-text); }
/* PAREA S8e — the private-area block (All items / Collections / Trash / Activity /
   Back to Main) puts its icon DIRECTLY inside the row, while album and collection
   rows wrap theirs in .fb-alb-ico. Every ICONS.* glyph carries only a viewBox and
   no width/height, and NOTHING sized a bare svg here — so inside this flex row
   they stretched to the full sidebar width. Reported by the owner on the field
   walk: "the icons to create collections Home Trash are huge filling the full
   width of the sidebar".
   The direct-child selector covers the BARE svgs. The claim that "wrapped icons
   keep the rules they already have" was FALSE and the build bench said so
   (grok S4): the only .fb-alb-ico sizing is scoped to .fb-alb-row, so the area
   PICKER rows (fb_shell.js:408) and the in-area COLLECTION list (fb_shell.js:789)
   wrap their glyph in .fb-alb-ico and are sized by nothing at all — the same
   mechanism, one wrapper tag away. The base rule below sizes any .fb-alb-ico svg
   that no more specific rule reaches; .fb-alb-row's own rule (0,2,1) still wins
   where it applies, so nothing that renders correctly today changes. */
.fb-ev-state > svg { width: 14px; height: 14px; flex: 0 0 14px; }
.fb-alb-ico svg { width: 14px; height: 14px; }
.fb-ev-state-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-ev-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; background: var(--fb-text-faint); }
.fb-ev-approved .fb-ev-dot { background: #3fb950; }
.fb-ev-pending  .fb-ev-dot { background: #d29922; }
.fb-ev-rejected .fb-ev-dot { background: #f85149; }

/* =============================================================================
   Event moderation — action-bar buttons + per-card quick buttons
   ============================================================================= */
.fb-ab-mod { display: inline-flex; gap: 6px; }
.fb-ab-ok { color: #3fb950; }
.fb-ab-ok:hover { background: rgba(63,185,80,0.14); border-color: #3fb950; }

/* Per-card quick moderation buttons (bottom-left of the thumbnail well) */
.fb-card-mod {
    position: absolute;
    left: 6px; bottom: 6px;
    display: flex; gap: 5px;
    z-index: 3;
}
.fb-card-mod-btn {
    width: 30px; height: 30px;
    border: none; border-radius: 8px;
    background: rgba(var(--fb-bg-rgb), 0.78);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    color: #fff; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
    touch-action: manipulation;
    box-shadow: 0 1px 4px rgba(0,0,0,0.4);
    transition: background 0.12s, transform 0.1s;
}
.fb-card-mod-btn:hover { transform: scale(1.08); }
.fb-card-mod-btn svg { width: 16px; height: 16px; }
.fb-card-mod-btn.is-ok:hover     { background: #3fb950; }
.fb-card-mod-btn.is-danger:hover { background: #f85149; }

/* =============================================================================
   Event state switcher (toolbar) — quick Approved/Pending/Rejected
   ============================================================================= */
.fb-state-switch { display: none; }
.fb-state-switch.is-on {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    background: var(--fb-bg-card);
    border: 1px solid var(--fb-border);
    border-radius: 9px;
}
.fb-state-btn {
    height: 28px; padding: 0 12px;
    border: none; background: transparent;
    color: var(--fb-text-dim); font-size: 12px; font-family: inherit;
    cursor: pointer; border-radius: 7px;
    display: inline-flex; align-items: center; gap: 5px;
    transition: background 0.12s, color 0.12s;
}
.fb-state-btn:hover { color: var(--fb-text); }
.fb-state-btn.is-active.fb-state-approved { background: #2ea04326; color: #3fb950; }
.fb-state-btn.is-active.fb-state-pending  { background: #d2992226; color: #d29922; }
.fb-state-btn.is-active.fb-state-rejected { background: #f8514926; color: #f85149; }
@media (max-width: 600px) {
    .fb-state-btn { padding: 0 9px; font-size: 11px; }
}

/* ---- Cached target archive button (ZIP-2b) --------------------------------
   States render from the DB on every view load: none/stale neutral, building
   amber (pulses), ready green. Hidden entirely when no target applies or the
   archive toggle is off for a non-manager. */
.fb-archive { display: none; position: relative; }
.fb-archive.is-on { display: inline-flex; align-items: center; gap: 2px; }
.fb-archive-btn, .fb-archive-gear {
    height: 32px; width: 32px;
    border: 1px solid var(--fb-border); background: var(--fb-bg-card);
    color: var(--fb-text-dim);
    cursor: pointer; border-radius: 9px;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.fb-archive-btn svg, .fb-archive-gear svg { width: 16px; height: 16px; }
.fb-archive-btn:hover, .fb-archive-gear:hover { color: var(--fb-text); }
.fb-archive-btn.is-stale { color: var(--fb-text); }
.fb-archive-btn.is-building {
    color: #d29922; border-color: #d2992255; background: #d2992212;
    animation: fb-archive-pulse 2s ease-in-out infinite;
}
.fb-archive-btn.is-ready {
    color: #3fb950; border-color: #2ea04355; background: #2ea04312;
}
@keyframes fb-archive-pulse {
    0%, 100% { box-shadow: 0 0 0 0 #d2992200; }
    50%      { box-shadow: 0 0 0 4px #d2992222; }
}
.fb-archive-gear { width: 26px; }
.fb-archive-gear svg { width: 13px; height: 13px; }
.fb-archive-pop {
    position: absolute; top: 38px; right: 0; z-index: 60;
    min-width: 240px; padding: 10px 12px;
    background: var(--fb-bg-card); border: 1px solid var(--fb-border);
    border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.35);
    font-size: 12px; color: var(--fb-text);
}
.fb-archive-pop-title { font-weight: 600; margin-bottom: 8px; }
.fb-archive-pop-row {
    display: flex; align-items: center; gap: 7px;
    padding: 4px 0; cursor: pointer; color: var(--fb-text);
}
.fb-archive-pop-hint { margin-top: 7px; color: var(--fb-text-dim); font-size: 11px; line-height: 1.4; }

/* ---- Branding logo (in the 56px header) ----------------------------------- */
a.fb-brand {
    display: flex;
    align-items: center;
    text-decoration: none;
    flex-shrink: 0;
}
.fb-brand-logo {
    height: 32px;        /* header is 56px; matches weight of 38px controls */
    width: auto;
    max-width: 200px;
    display: block;
    object-fit: contain;
}

/* ---- Account button (avatar) + dropdown menu ------------------------------ */
.fb-acct-btn {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--fb-border);
    border-radius: 999px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: border-color 0.15s, background 0.15s;
}
.fb-acct-btn:hover { border-color: var(--fb-accent-dim); }
.fb-acct-btn[aria-expanded="true"] { border-color: var(--fb-accent); }

.fb-acct-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 999px;
    background: var(--fb-accent-dim);
    color: #fff;
    font-size: 13px;
    font-weight: 650;
    line-height: 1;
    user-select: none;
    overflow: hidden; /* clip the face <img> to the circle */
}
.fb-acct-avatar-lg { width: 34px; height: 34px; font-size: 15px; }

/* Sidebar (bottom) account button: a clean Claude/OS-style circle with the
   user's INITIALS (the face avatar lives at the top of the popover, not here).
   ~38px feels right next to the username row. */
.fb-sb-acct .fb-acct-avatar {
    width: 38px;
    height: 38px;
    font-size: 16px;
    flex-shrink: 0;
    /* A shade lighter than --fb-accent-dim for the initials fill (cleaner on the
       dark sidebar). Only the initials state uses this; .has-face goes clear. */
    background: #4f7fd0;
}

/* When the avatar holds a real face, drop the blue (--fb-accent-dim) backing so
   it can't peek unevenly around the image (that was the "lopsided blue circle"):
   the face image IS the circle. The initial-only state keeps the blue fill.
   The .has-face modifier is added by acctAvatarHtml() when it emits an <img>. */
.fb-acct-avatar.has-face {
    background: transparent;
}

/* Linked-face avatar: fill the circle, crop to cover. Falls back to the text
   initial (img onerror replaces itself) when no/!stale face. */
.fb-acct-face {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    border-radius: inherit;
}

.fb-acct-menu {
    position: fixed;
    z-index: 200;   /* above the sidebar (160); trigger now lives in sidebar foot */
    min-width: 240px;
    max-width: calc(100vw - 16px);
    padding: 6px;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border);
    border-radius: var(--fb-radius);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.16s ease, transform 0.16s ease;
    pointer-events: none;
}
.fb-acct-menu.is-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.fb-acct-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px 10px;
}
.fb-acct-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--fb-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Menu-header identity stack: name on top, usergroup/role below (muted). */
.fb-acct-meta {
    min-width: 0;
    display: flex; flex-direction: column;
    gap: 1px;
    overflow: hidden;
}
.fb-acct-sub {
    font-size: 12px;
    font-weight: 400;
    color: var(--fb-text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.2;
}

.fb-acct-sep {
    height: 1px;
    margin: 4px 0;
    background: var(--fb-border-soft);
}

.fb-acct-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    gap: 10px;
    padding: 10px 10px;
    background: transparent;
    border: none;
    border-radius: var(--fb-radius-sm);
    color: var(--fb-text);
    font-size: 14px;
    font-family: inherit;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
}
.fb-acct-row:hover { background: var(--fb-bg-card); }
.fb-acct-row svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    color: var(--fb-text-faint);
}
.fb-acct-logout { color: var(--fb-danger); }
.fb-acct-logout:hover { background: rgba(255, 107, 107, 0.10); }

/* ============================================================================
   Search token UI (@person dropdown + chips) — pages/fb_tokens.js
   ============================================================================ */

/* Dropdown anchored under the search wrap. */
.fbtok-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    max-height: 360px;
    overflow-y: auto;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border);
    border-radius: var(--fb-radius);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    z-index: 1200;
    display: none;
    padding: 4px;
}
.fbtok-dropdown.is-open { display: block; }

.fbtok-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 8px;
    border-radius: var(--fb-radius-sm);
    cursor: pointer;
}
.fbtok-row.is-active { background: rgba(91, 157, 255, 0.16); }

.fbtok-av {
    width: 32px; height: 32px;
    flex-shrink: 0;
    border-radius: 50%;
    background-color: var(--fb-bg-card);
    background-repeat: no-repeat;
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 600;
    color: var(--fb-text-dim);
    border: 1px solid var(--fb-border-soft);
}
.fbtok-av-initial { background-image: none !important; }
.fbtok-av-img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}

.fbtok-text { min-width: 0; flex: 1; }
.fbtok-name {
    font-size: 14px; color: var(--fb-text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fbtok-org {
    font-size: 12px; color: var(--fb-text-faint);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fbtok-empty {
    padding: 14px 10px; text-align: center;
    color: var(--fb-text-faint); font-size: 13px;
}

/* Selected-people row below the search bar: compact avatar-only circles to save
   horizontal space on mobile. Each shows an "x" on hover/tap; a Clear removes all. */
.fbtok-chips {
    display: none;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 8px 16px 6px;
    border-bottom: 1px solid var(--fb-border-soft);
}
.fbtok-chips.has-chips { display: flex; }

.fbtok-chip {
    position: relative;
    width: 30px; height: 30px;
    flex-shrink: 0;
    border-radius: 50%;
    cursor: default;
}
.fbtok-chip-av {
    width: 100%; height: 100%;
    border-radius: 50%;
    overflow: hidden;
    background: var(--fb-bg-card);
    border: 1.5px solid var(--fb-accent-dim);
    display: flex; align-items: center; justify-content: center;
    font-size: 11px; font-weight: 600; color: var(--fb-text-dim);
}
.fbtok-chip-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fbtok-chip-av-initial { background: var(--fb-bg-card); }

/* Remove "x": small badge top-right, revealed on hover (desktop) / always on
   touch (no hover) so it's tappable. */
.fbtok-chip-x {
    position: absolute;
    top: -5px; right: -5px;
    width: 17px; height: 17px;
    border-radius: 50%;
    border: none;
    background: var(--fb-danger);
    color: #fff;
    font-size: 13px; line-height: 1;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s;
    padding: 0;
}
.fbtok-chip:hover .fbtok-chip-x { opacity: 1; }
@media (hover: none) {
    .fbtok-chip-x { opacity: 1; }   /* touch devices: always visible */
}

.fbtok-chip-clear {
    height: 26px;
    padding: 0 12px;
    border: 1px solid var(--fb-border);
    background: transparent;
    color: var(--fb-text-dim);
    border-radius: 999px;
    font-size: 12.5px; font-family: inherit;
    cursor: pointer;
    flex-shrink: 0;
}
.fbtok-chip-clear:hover { color: var(--fb-text); background: var(--fb-bg-card); }

/* Facet chips ("facet: value") are pill-shaped with text, not avatar-only
   circles like person chips. Contributor facet chips also carry a small avatar. */
.fbtok-chip-facet {
    width: auto; height: 26px;
    border-radius: 999px;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 0 8px 0 10px;
    background: rgba(91, 157, 255, 0.12);
    border: 1px solid var(--fb-accent-dim);
}
.fbtok-chip-facet .fbtok-chip-av {
    width: 20px; height: 20px; border-width: 1px;
}
.fbtok-chip-facet-label {
    font-size: 12.5px; color: var(--fb-text);
    white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis;
}
.fbtok-chip-facet .fbtok-chip-x {
    position: static;          /* inline, not the corner-overlay used on circles */
    opacity: 1;
    width: 16px; height: 16px;
    background: transparent; color: var(--fb-text-dim);
    font-size: 15px;
}
.fbtok-chip-facet .fbtok-chip-x:hover { color: var(--fb-danger); }

/* The "#" affordance on level-1 facet rows. */
.fbtok-facet-tag {
    width: 24px; height: 24px; flex-shrink: 0;
    border-radius: 6px;
    background: var(--fb-bg-card);
    color: var(--fb-text-dim);
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 14px;
}

/* ---- #date calendar picker (full-screen overlay) ---- */
.fbtok-date-ov {
    position: fixed; inset: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 3000;
    display: flex; align-items: center; justify-content: center;
    padding: 16px;
}
.fbtok-date-panel {
    width: 100%; max-width: 360px;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border);
    border-radius: var(--fb-radius);
    box-shadow: 0 20px 50px rgba(0,0,0,0.5);
    padding: 16px;
    color: var(--fb-text);
}
.fbtok-date-head {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 12px;
}
.fbtok-date-title { font-size: 16px; font-weight: 600; }
.fbtok-date-close {
    border: none; background: transparent; color: var(--fb-text-dim);
    font-size: 22px; line-height: 1; cursor: pointer;
}
.fbtok-date-basis {
    display: flex; gap: 6px; margin-bottom: 12px;
}
.fbtok-date-basis-btn {
    flex: 1; height: 32px; border-radius: var(--fb-radius-sm);
    border: 1px solid var(--fb-border);
    background: transparent; color: var(--fb-text-dim);
    font-size: 13px; font-family: inherit; cursor: pointer;
}
.fbtok-date-basis-btn.is-on {
    background: rgba(91,157,255,0.16);
    border-color: var(--fb-accent-dim);
    color: var(--fb-accent);
}
.fbtok-date-navrow { margin: 8px 0; }
.fbtok-date-month, .fbtok-date-year {
    width: 100%; height: 36px;
    background: var(--fb-bg-card); color: var(--fb-text);
    border: 1px solid var(--fb-border); border-radius: var(--fb-radius-sm);
    font-size: 14px; font-family: inherit; padding: 0 8px;
}
.fbtok-date-dows {
    display: grid; grid-template-columns: repeat(7, 1fr);
    margin-bottom: 4px;
}
.fbtok-date-dows span {
    text-align: center; font-size: 11px; color: var(--fb-text-faint);
    padding: 4px 0;
}
.fbtok-date-days {
    display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px;
}
.fbtok-date-day {
    aspect-ratio: 1 / 1;
    display: flex; align-items: center; justify-content: center;
    font-size: 14px; border-radius: 50%;
    cursor: pointer; color: var(--fb-text);
}
.fbtok-date-day:not(.fbtok-date-empty):hover { background: var(--fb-bg-card); }
.fbtok-date-day.is-sel { background: var(--fb-accent); color: #fff; font-weight: 600; }
.fbtok-date-empty { cursor: default; }
.fbtok-date-sel {
    text-align: center; font-size: 14px; color: var(--fb-text-dim);
    margin: 12px 0;
}
.fbtok-date-actions {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.fbtok-date-back {
    height: 38px; padding: 0 16px;
    border: 1px solid var(--fb-border); background: transparent;
    color: var(--fb-text-dim); border-radius: var(--fb-radius-sm);
    font-size: 14px; font-family: inherit; cursor: pointer;
}
.fbtok-date-next {
    height: 38px; padding: 0 24px; margin-left: auto;
    border: none; background: var(--fb-accent); color: #fff;
    border-radius: var(--fb-radius-sm);
    font-size: 14px; font-weight: 600; font-family: inherit; cursor: pointer;
}

@media (max-width: 560px) {
    .fbtok-dropdown { max-height: 300px; }
}

/* =============================================================================
   High-res grid toggle (HD/UHD) — only shown at the largest (1-column) size.
   Ported on top of the MAPS browse.css (source of truth for search/scope/chips).
   ============================================================================= */
.fb-hires-btn {
    height: 32px;
    min-width: 32px;
    padding: 0 9px;
    gap: 5px;
    background: var(--fb-bg-card);
    border: 1px solid var(--fb-border);
    border-radius: 9px;
    color: var(--fb-text-dim);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.fb-hires-btn[hidden] { display: none; }
.fb-hires-btn:hover { color: var(--fb-text); border-color: var(--fb-accent-dim); }
.fb-hires-btn svg { width: 18px; height: 18px; flex-shrink: 0; }
.fb-hires-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    line-height: 1;
}
/* On: accent fill. Max (UHD/hpr): brighter fill + ring. */
.fb-hires-btn.is-on {
    background: var(--fb-accent-dim);
    border-color: var(--fb-accent);
    color: #fff;
}
.fb-hires-btn.is-on.is-max {
    background: var(--fb-accent);
    box-shadow: 0 0 0 2px var(--fb-accent-dim);
}
@media (max-width: 520px) {
    .fb-hires-btn { height: 28px; min-width: 28px; padding: 0 7px; }
    .fb-hires-btn svg { width: 15px; height: 15px; }
    .fb-hires-label { font-size: 10px; }
}

/* ---- Public gallery drawer (mountPublicDrawer in browse.js) -------------- */
/* Reuses .fb-sidebar / .fb-scrim / .fb-sb-item; these add only the public-only
   bits: current-item highlight, section divider/label, and a footer pinned to
   the bottom for the sign-in link. */
.fb-sidebar-public { display: flex; flex-direction: column; }
.fb-sidebar-public .fb-sb-body { flex: 1 1 auto; overflow-y: auto; }
.fb-sidebar-public .fb-sb-foot {
    margin-top: auto;
    border-top: 1px solid var(--fb-border, rgba(255,255,255,.08));
    padding-top: 6px;
}
.fb-sb-item.is-current {
    background: var(--fb-bg-card, rgba(255,255,255,.06));
    font-weight: 600;
}
.fb-sb-divider {
    height: 1px;
    margin: 8px 12px;
    background: var(--fb-border, rgba(255,255,255,.08));
}
.fb-sb-grouplabel {
    padding: 4px 16px;
    font-size: .72em;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--fb-text-dim, #8a8a90);
}

/* =============================================================================
   Management sheet bottom bar (#fbms-bar)
   Styles live HERE (always-loaded browse.css) so the bar is styled on first
   paint. Scroll-fade is tied to body.fb-chrome-hidden — the SAME class the
   toolbar uses (toggled by the scroll handler in browse.js) — so the pill fades
   out in lock-step with the toolbar sliding away, and fades back on scroll-up.
   ============================================================================= */
#fbms-bar {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
    z-index: 60;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 18px;
    /* Background is 80% opaque (a touch translucent for polish); the gear + label
       sit at full strength on top because the element-level opacity is 1. */
    background: rgba(28, 31, 38, 0.80);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 1px solid var(--fb-border, #2a2e37);
    border-radius: 999px;
    color: var(--fb-text, #e6e8ec);
    font: 600 13px/1 var(--fb-font, -apple-system, system-ui, sans-serif);
    letter-spacing: .2px;
    cursor: pointer;
    opacity: 1;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
    transition: opacity 0.22s ease, transform 0.22s ease, visibility 0.22s ease, background .15s ease;
}
#fbms-bar:hover { background: rgba(34, 38, 46, 0.86); }
#fbms-bar:active { transform: translateX(-50%) scale(0.97); }
#fbms-bar .fbms-bar-ico { width: 17px; height: 17px; display: inline-flex; color: var(--fb-accent, #5b9dff); }
#fbms-bar .fbms-bar-ico svg { width: 100%; height: 100%; }
#fbms-bar .fbms-bar-label { white-space: nowrap; }

/* Scroll-fade: when the chrome hides (scroll-down) the pill disappears COMPLETELY
   — opacity 0 + visibility hidden so there's no faint ghost over the photos — and
   stops taking taps. On scroll-up the class is removed and it fades back to its
   resting 0.9. Matched to the toolbar's 0.22s ease so they move together. */
body.fb-chrome-hidden #fbms-bar {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateX(-50%) translateY(6px);
}

/* When the resource overlay is open, the bar is hidden outright (JS toggles
   this class) so it never floats over a full-screen resource view. */
#fbms-bar.fbms-bar-hidden {
    opacity: 0 !important;
    pointer-events: none !important;
    transform: translateX(-50%) translateY(8px) !important;
}

/* ---- MOD-1 quarantine (per-event 4th moderation state) ----------------------
   No bespoke surface: the quarantine album renders through the SAME grid as the
   other three states. This block only styles the ADMIN reveal that rides on
   body.fb-ctrlshift (held Ctrl+Shift; a triple-tap on the sidebar Library
   label latches the same class - P-M0 r3).
   Gold accent (#f5c850) is the shared moderation-surface colour, matching the
   Resource View 'pending' pill. (It formerly matched .fb-mod-chip, the MOD-1
   review chip, retired 2026-07-27 — the event's Pending state row already tells
   a moderator what is waiting.) */

/* Sidebar: the event's Rejected row relabels to "Quarantine" and swaps in the
   quarantine count while Ctrl+Shift is held. Each label/count carries two spans and
   we toggle which shows. Default (no key): show -normal, hide -q. */
.fb-ev-quar { display: none; }
body.fb-ctrlshift .fb-ev-quar { display: flex; color: #f5c850; }
body.fb-ctrlshift .fb-ev-quar .fb-ev-dot { background: #f5c850; }

/* Dedicated Quarantine button (bulk + per-card): admin-only, hidden until Ctrl+Shift
   is held. Distinct from Reject, so it works from EVERY normal state view - including
   the Rejected view, which has no Reject button. The client only renders .fb-q-send for
   admins outside the album. Gold to match the shared moderation accent. */
.fb-ab-btn.fb-q-send,
.fb-card-mod-btn.fb-q-send { display: none; }
body.fb-ctrlshift .fb-ab-btn.fb-q-send {
    display: inline-flex;
    color: #f5c850;
    border-color: rgba(245, 200, 80, 0.55);
}
body.fb-ctrlshift .fb-ab-btn.fb-q-send svg { stroke: #f5c850; }
body.fb-ctrlshift .fb-card-mod-btn.fb-q-send {
    display: flex;
    color: #f5c850;
    border-color: rgba(245, 200, 80, 0.6);
    box-shadow: 0 0 0 1px rgba(245, 200, 80, 0.35);
}
body.fb-ctrlshift .fb-card-mod-btn.fb-q-send svg { stroke: #f5c850; }
/* =============================================================================
   Recycle bin (soft delete) — admin-only Trash row + per-card hold / actions.
   The Trash row stays hidden until Ctrl+Shift is held (body.fb-ctrlshift), the
   same admin reveal as the Quarantine relabel above.
   ============================================================================= */
.fb-ev-trash { display: none; }
body.fb-ctrlshift .fb-ev-trash { display: flex; color: #b9c2cc; }
.fb-ev-trash .fb-ev-dot { background: #8b949e; }
/* Part B: the MASTER recycle-bin row (top of the sidebar) rides the same
   reveal latch as the per-event rows; markup exists only for admins. */
.fb-sb-trash-all { display: none; }
body.fb-ctrlshift .fb-sb-trash-all { display: flex; color: #b9c2cc; }
.fb-sb-trash-all .fb-sb-coll-count { margin-left: auto; }
/* Part B: master-lens card meta — derived event name(s) / "No event" + date. */
.fb-card-trashmeta {
    font-size: 11px; color: var(--fb-text-dim, #8b949e);
    margin-top: 2px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Legal-hold chip on a trashed card (top-left, above the quick buttons). */
.fb-card-hold {
    position: absolute;
    left: 6px; top: 6px;
    width: 26px; height: 26px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 7px;
    background: rgba(var(--fb-bg-rgb), 0.82);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    color: #f5c850;
    box-shadow: 0 1px 4px rgba(0,0,0,0.4);
    z-index: 4;
    pointer-events: none;
}
.fb-card-hold svg { width: 15px; height: 15px; }

/* Per-card Restore reuses .is-ok (green hover). The on-hold toggle reads amber;
   Delete-forever is disabled (dimmed, no hover) while an item is on legal hold. */
.fb-card-mod-btn.fb-hold-on { color: #f5c850; }
.fb-card-mod-btn.fb-hold-on:hover { background: rgba(245,200,80,0.22); }
.fb-card-mod-btn[disabled] { opacity: 0.4; cursor: default; }
.fb-card-mod-btn[disabled]:hover { transform: none; background: rgba(var(--fb-bg-rgb), 0.78); }

/* ===== FA-2: Albums (sidebar section + per-event album group) ============= */
/* The per-event group label — a quiet divider between state rows and albums. */
.fb-ev-albgroup {
    padding: 6px 12px 2px 34px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--fb-text-dim, #8a94a6);
}
/* Album rows reuse .fb-ev-state button chrome; swap the dot for an icon. */
.fb-alb-row .fb-alb-ico {
    width: 14px; height: 14px; flex: 0 0 14px;
    display: inline-flex; align-items: center;
    color: var(--fb-text-dim, #8a94a6);
}
.fb-alb-row .fb-alb-ico svg { width: 14px; height: 14px; }
.fb-alb-row .fb-alb-lock { font-size: 10px; }
/* Independent albums live directly in a .fb-sb-list (no .fb-ev-states parent),
   so give the rows the same inset the event rows inherit. */
#fb-sb-albums .fb-ev-state { padding-left: 24px; }

/* FA-2 r2 (Mike): RESTRICTED albums ride the SAME admin reveal latch as
   Quarantine/Trash — invisible in everyday chrome, revealed by the triple-tap
   Library latch (body.fb-ctrlshift). The server still gates access
   (admin-only in browse + manage); this is CONCEALMENT, not authorization.
   Gold accent matches the rest of the latched moderation surface. */
.fb-alb-row--r { display: none; }
body.fb-ctrlshift .fb-alb-row--r { display: flex; }
body.fb-ctrlshift .fb-ev-albgroup.fb-alb-row--r { display: block; }
body.fb-ctrlshift .fb-alb-row--r .fb-ev-state-label { color: #f5c850; }
body.fb-ctrlshift .fb-alb-row--r .fb-alb-ico { color: #f5c850; }

/* ===== FA-4 r2: PUBLIC drawer polish ====================================== */
.fb-public .fb-sidebar .fb-ev-state { padding: 10px 16px; font-size: 14px; }
.fb-public #fb-sb-albums .fb-ev-state { padding-left: 16px; }
.fb-public .fb-alb-row .fb-alb-ico { width: 16px; height: 16px; flex: 0 0 16px; }
.fb-public .fb-alb-row .fb-alb-ico svg { width: 16px; height: 16px; }
.fb-public .fb-alb-row--current { background: rgba(59, 130, 246, .16); }
.fb-public .fb-alb-row--current .fb-ev-state-label { color: #93c5fd; font-weight: 600; }
.fb-public .fb-sb-section { pointer-events: none; }   /* single section: a heading, not a toggle */
.fb-public .fb-sb-section .fb-sb-chev { display: none; }

/* ===== FA-4 r3: event branding (only when set; stock look otherwise) ====== */
.fb-sb-logo { width: 22px; height: 22px; border-radius: 5px; object-fit: cover; margin-right: 8px; flex: 0 0 22px; }
.fb-public .fb-sb-item.is-current { color: var(--fb-pub-accent, #93c5fd); }
.fb-public .fb-sb-item.is-current svg { color: var(--fb-pub-accent, #93c5fd); }
/* U1 r2: border AND hover follow the event accent too — the background-only
   override left a stock-blue ring around an accent-tinted button. */
.fb-public .fb-upload-btn {
    background: var(--fb-pub-accent, #3b82f6);
    border-color: var(--fb-pub-accent, #3b82f6);
}
.fb-public .fb-upload-btn:hover {
    background: var(--fb-pub-accent, var(--fb-accent));
    border-color: var(--fb-pub-accent, var(--fb-accent));
    filter: brightness(1.12);
}

/* ============================================================================
   BIB-S5 — bibliography lens (freeze S2 amendment: positive-polarity reading
   cards inside the dark FB chrome, via the scoped --biblio-* token set so a
   dark reading preference can be added later without restructuring views).
   Tokens also scope to the citation overlay opened from the Documents grid.
   ============================================================================ */
body.fb-biblio, .fbrv-biblio {
    --biblio-card-bg: #ffffff;
    --biblio-title:   #b45416;
    --biblio-text:    #333333;
    --biblio-dim:     #55534e;
    --biblio-hair:    #ececec;
    --biblio-chip-bg: #1d3050;
    --biblio-chip-fg: #dbe6f5;
    --biblio-accent:  #b45416;
}
body.fb-biblio .fb-grid {
    --fb-cell-min: 340px;      /* citation cards read best 1-3 across */
    align-items: start;        /* cards keep natural height, not row-stretched */
}
.fbb-card {
    background: var(--biblio-card-bg);
    border-radius: 10px;
    padding: 14px 16px;
    color: var(--biblio-text);
    font-size: 13px;
    line-height: 1.45;
    /* C20 wrapping moved OFF the card onto the content-text elements below —
       card-wide overflow-wrap:anywhere also shattered BUTTON text at the
       smallest slider stop ('Abstract' -> 'Abst/ract', '+2 more' stacking
       one character per line; Mike field report 2026-07-17). */
}
.fbb-title {
    color: var(--biblio-title);
    font-size: 15px;
    font-weight: 600;
    line-height: 1.35;
    margin-bottom: 4px;
}
/* C20: unicode / absurd-length titles (and long tags/abstracts) wrap, never
   overflow — content text only, never controls. */
.fbb-title, .fbb-authors, .fbb-journal, .fbb-abstract, .fbb-chip { overflow-wrap: anywhere; }
.fbb-authors { font-style: italic; color: var(--biblio-dim); margin-bottom: 2px; }
.fbb-journal { margin-bottom: 8px; }
.fbb-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 10px; }
.fbb-chip {
    background: var(--biblio-chip-bg);
    color: var(--biblio-chip-fg);
    border: 1px solid transparent;
    font: inherit;
    font-size: 11px;
    padding: 3px 9px;
    border-radius: 4px;
    cursor: pointer;
}
.fbb-chip:hover { filter: brightness(1.25); }
.fbb-chip.is-active {
    background: var(--biblio-accent);
    color: #fff;
}
.fbb-chip-more, .fbb-more-docs {
    color: var(--biblio-dim);
    font-size: 11px;
    align-self: center;
    white-space: nowrap;       /* '+2 more' is a unit — wraps whole, never per-char */
}
.fbb-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; row-gap: 6px; }
.fbb-btn {
    display: inline-block;
    border: 1px solid var(--biblio-accent);
    color: var(--biblio-accent);
    background: transparent;
    font: inherit;
    font-size: 12px;
    padding: 5px 12px;
    border-radius: 6px;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;       /* button labels never break mid-word */
}
.fbb-btn:hover { background: rgba(180, 84, 22, 0.08); }
.fbb-btn-primary { background: var(--biblio-accent); color: #fff; }
.fbb-btn-primary:hover { background: #9d4712; }
.fbb-abstract {
    border-top: 1px solid var(--biblio-hair);
    margin-top: 10px;
    padding-top: 8px;
    font-size: 12px;
    line-height: 1.55;
    color: var(--biblio-text);
    white-space: pre-line;
}
/* Skeletons on the biblio grid: card-shaped, not photo-square. */
body.fb-biblio .fb-skeleton { aspect-ratio: auto; height: 150px; border-radius: 10px; }

/* BIB-S5: collapsible Bibliographies sidebar group. */
.fbb-sb-group {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    background: transparent;
    border: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    text-align: left;
}
.fbb-sb-chev {
    display: inline-block;
    transition: transform .15s ease;
    font-size: 14px;
    opacity: .7;
}
.fbb-sb-group.is-open .fbb-sb-chev { transform: rotate(90deg); }

/* BIB-S5 (Mike, 2026-07-17): compact citation cards — applied by applySize
   when the computed cell width runs narrow (the mobile 2-up stop). Tighter
   padding + smaller type so a 165px cell reads cleanly. */
.fb-grid.fbb-compact .fbb-card { padding: 9px 10px; font-size: 12px; }
.fb-grid.fbb-compact .fbb-title { font-size: 13px; }
.fb-grid.fbb-compact .fbb-chip { font-size: 10px; padding: 2px 6px; }
.fb-grid.fbb-compact .fbb-btn { font-size: 11px; padding: 4px 9px; }
.fb-grid.fbb-compact .fbb-actions { gap: 6px; }

/* BIB-S7: staff status badges on citation cards (R1 — status said out loud).
   Also reused inside the manage sheet's edit header (same page, same sheet).
   Color tokens only — no tenant strings, no hardcoded brand hues. */
.fbb-badges { display: flex; flex-wrap: wrap; gap: 5px; margin: 6px 0 2px; }
.fbb-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .3px;
    text-transform: uppercase;
    border: 1px solid transparent;
}
.fbb-badge-ok   { background: #e8f6ee; color: #1a7f4b; border-color: #bfe6d0; }
.fbb-badge-warn { background: #fdf3e2; color: #9a6414; border-color: #f0ddb6; }
.fbb-badge-bad  { background: #fdeaea; color: #b42318; border-color: #f3c6c2; }
.fbb-badge-dim  { background: #eef0f3; color: #5b6572; border-color: #dde1e6; }
.fbb-edit-btn { margin-left: auto; }
.fbrv-bib-edit { align-self: flex-start; }

/* BIB-S7: two-level Bibliography nav (All references / Documents parents
   with indented drill-down children; chevron toggles the sub-list). */
.fb-bibnav-head { display: flex; align-items: center; }
.fb-bibnav-head .fb-sb-coll { flex: 1 1 auto; min-width: 0; }
.fb-bibnav-chev {
    flex: 0 0 auto; width: 26px; height: 26px; margin-right: 6px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; border: 0; color: inherit; opacity: .6;
    cursor: pointer; transition: transform .15s ease;
}
.fb-bibnav-chev svg { width: 14px; height: 14px; }
.fb-bibnav-chev.is-open { transform: rotate(90deg); }
.fb-bibnav-chev:hover { opacity: 1; }
.fb-bibnav-subrow { padding-left: 34px !important; font-size: 12.5px; }

/* ---- BIB-DS2: documents lens card extras -------------------------------
   The citation-context line (plan §3.3) and the content snippet (§2.5).
   Both sit under the card's existing sub-line and inherit its muted
   treatment: the TITLE is still the card's subject, and neither of these
   may compete with it. The snippet is clamped to two lines because a
   300-character window is a taste of the match, not the match itself —
   the document view is where the text is read. */
.fb-card-citation {
    margin-top: 3px;
    font-size: 11px;
    color: var(--fb-text-faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fb-card-snippet {
    margin-top: 4px;
    font-size: 11px;
    line-height: 1.35;
    color: var(--fb-text-dim, var(--fb-text-faint));
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.fb-card-citation-link {
    color: inherit;
    text-decoration: none;
}
.fb-card-citation-link:hover,
.fb-card-citation-link:focus-visible {
    text-decoration: underline;
}

/* ---- PAREA S6: Private areas — sidebar section + in-lens block --------------- */
.fb-area-row { text-decoration: none; }
.fb-area-row.is-active { color: var(--fb-accent); }
.fb-area-row.is-active .fb-alb-ico { color: var(--fb-accent); }
.fb-area-block { padding: 2px 0 6px 10px; border-left: 2px solid var(--fb-accent-dim); margin: 2px 0 4px 18px; }
.fb-area-block .fb-ev-state { padding-left: 12px; text-decoration: none; }
.fb-area-block .fb-area-sub { cursor: default; justify-content: flex-start; }
.fb-area-block .fb-area-sub .fb-sb-add { margin-left: auto; }
.fb-area-colls .fb-coll-row { padding-left: 24px; font-size: 12px; text-decoration: none; }
.fb-area-colls .fb-sb-empty, .fb-area-colls .fb-sb-loading { padding-left: 24px; font-size: 11px; }
/* the lens's in-area "Add to" menu: an inline create row (name + button) */
.fb-areaadd-new { display: flex; gap: 6px; align-items: center; cursor: default; }
.fb-areaadd-name { flex: 1 1 auto; min-width: 0; padding: 5px 8px; border-radius: 6px; border: 1px solid var(--fb-accent-dim); background: var(--fb-bg-card); color: var(--fb-text); font: inherit; font-size: 12px; }
.fb-areaadd-create { flex: 0 0 auto; }


/* ==========================================================================
   THE OBJECT CONTEXT MENU (CT-1, Owner Ruling 65)
   Right-click on desktop opens .fb-ctx at the pointer; double-tap on touch
   opens the SAME MENU as .fb-ctx-sheet, docked to the bottom edge with rows
   sized for a thumb. One item list, two presentations - built once in
   pages/fb_tree.js. There is no press-and-hold anywhere, by ruling.
   ========================================================================== */
.fb-ctx-overlay {
    position: fixed; inset: 0; z-index: 260;
    background: transparent;
}
.fb-ctx-overlay.is-sheet {
    background: rgba(0,0,0,0.5);
    backdrop-filter: blur(2px);
    display: flex; align-items: flex-end;
}
.fb-ctx {
    position: absolute;
    min-width: 208px;
    padding: 6px;
    background: var(--fb-bg-elevated);
    border: 1px solid var(--fb-border);
    border-radius: var(--fb-radius);
    box-shadow: 0 12px 32px rgba(0,0,0,0.45);
    display: flex; flex-direction: column;
}
.fb-ctx-sheet {
    position: static;
    width: 100%;
    padding: 6px 8px calc(8px + env(safe-area-inset-bottom, 0px));
    border-radius: 16px 16px 0 0;
    border-bottom: none;
    max-height: 70vh; overflow-y: auto;
}
.fb-ctx-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 8px;
    padding: 10px 10px 8px;
    border-bottom: 1px solid var(--fb-border-soft);
    margin-bottom: 4px;
}
.fb-ctx-title {
    font-size: 14px; font-weight: 600; color: var(--fb-text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fb-ctx-x {
    flex-shrink: 0;
    width: 30px; height: 30px; border: none; background: transparent;
    color: var(--fb-text-dim); cursor: pointer; border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
}
.fb-ctx-x:hover { background: var(--fb-bg-card); color: var(--fb-text); }
.fb-ctx-x svg { width: 16px; height: 16px; }
.fb-ctx-item {
    width: 100%; text-align: left;
    padding: 9px 12px;
    border: none; border-radius: var(--fb-radius-sm);
    background: transparent; color: var(--fb-text);
    font-size: 14px; font-family: inherit; cursor: pointer;
}
.fb-ctx-item:hover,
.fb-ctx-item:focus-visible { background: var(--fb-bg-card); color: var(--fb-accent); outline: none; }
.fb-ctx-item.is-danger { color: var(--fb-danger); }
.fb-ctx-item.is-danger:hover { background: rgba(255,107,107,0.12); }
/* Touch rows are taller: the sheet exists because a finger is the pointer. */
.fb-ctx-sheet .fb-ctx-item { padding: 14px 12px; font-size: 15px; }
#fb-sb-shop-floor[hidden] { display: none !important; }

/* Shop is a normal sidebar row, with the same label treatment as buttons. */
#fb-sb-shop-floor { text-decoration: none; }

/* Selected-area Sharing is a Browse lens, including on a cold load. */
.fb-card-share-summary { font-size:12px; line-height:1.45; color:var(--fb-text-dim); white-space:normal; overflow-wrap:anywhere; margin:6px 0; }
.fb-sharing-entries, .fb-sharing-revoke { font:inherit; font-size:12px; border:1px solid var(--fb-border); border-radius:6px; padding:6px 9px; background:var(--fb-bg-elevated); color:var(--fb-text); cursor:pointer; }
.fb-sharing-entries:focus-visible, .fb-sharing-revoke:focus-visible { outline:2px solid var(--fb-text-dim); outline-offset:2px; }
.fb-sharing-panel { border-top:1px solid var(--fb-border); margin-top:8px; font-size:12px; white-space:normal; }
.fb-sharing-line { display:flex; gap:8px; align-items:center; padding:8px 0; overflow-wrap:anywhere; }
.fb-sharing-line .grow { flex:1; min-width:0; }
.fb-sharing-revoke { color:#e47474; flex-shrink:0; }
.fb-sharing-empty { padding:8px 0; color:var(--fb-text-dim); }
/* Real-home/association fact, refreshed after Browse placement. */
.fb-placement-badge { position:absolute; left:6px; bottom:6px; max-width:calc(100% - 12px);
    padding:3px 6px; border-radius:4px; background:rgba(0,0,0,.78); color:#fff;
    font-size:11px; line-height:1.3; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* A long worksheet previews its opening rows at the card width. */
.fb-card-workbook .fb-thumb{height:auto;min-height:0;object-fit:contain;object-position:top left}

.fb-biblio-lenses { display:flex; gap:16px; padding:8px 16px; }
.fb-biblio-lenses a { color:inherit; }
