/* input(5404,5): run-time error CSS1019: Unexpected token, found '}'
input(6187,1): run-time error CSS1019: Unexpected token, found '}' */
/* ============================================================
   Reader Design System
   ============================================================ */

/* Reader tokens live in css/tokens.css (loaded first on both hosts). */

/* ============================================================
   Reader Shell
   ============================================================ */

.reader {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    overscroll-behavior-x: none;
    background: var(--surface-2);
    color: var(--text);
}

/* Keep .reader-content the only scroller: on iOS the URL-bar collapse makes
   100vh taller than the viewport, so the document rubber-bands as a second one. */
html:has(.reader),
body:has(.reader) {
    overflow: hidden;
    overflow-x: hidden;
    overscroll-behavior: none;
    height: 100dvh;
}

.reader:focus {
    outline: none;
}

/* ============================================================
   Header
   ============================================================ */

.reader-header {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0 0.875rem;
    background: var(--navy);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
    color: #ffffff;
    height: 62px;
}

/* Progress strip on the app bar's bottom edge; Blazor sets the fill width. */
.reader-header-progress {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    background: var(--navy-deep);
}

.reader-header-progress-fill {
    width: 0;
    height: 100%;
}

.reader-title {
    font-size: 0.9375rem;
    font-weight: 700;
    line-height: 1.3;
    color: #ffffff;
}

.reader-subtitle {
    font-size: 0.71875rem;
    font-weight: 400;
    color: var(--appbar-sub);
    line-height: 1.3;
}

/* ============================================================
   Icon Buttons
   ============================================================ */

.icon-btn {
    border: 1px solid transparent;
    background: transparent;
    color: var(--text);
    width: 38px;
    height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    transition: background 150ms ease, border-color 150ms ease;
}

.icon-btn:hover {
    background: var(--row-pressed);
}

.icon-btn.active {
    background: rgba(16, 42, 67, 0.06);
    border-color: var(--border);
}

.icon-btn:focus-visible {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
}

/* Navy command bar only; .reader-bottombar keeps the base .icon-btn rules. */
.reader-header .icon-btn {
    color: var(--appbar-icon-idle);
    width: 38px;
    height: 38px;
    border-radius: 10px;
}

.reader-header .icon-btn:hover {
    background: rgba(255, 255, 255, 0.1);
    color: #ffffff;
}

.reader-header .icon-btn:focus-visible {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
}

/* ============================================================
   Mobile Top Bar (MAUI host only)
   ============================================================ */

.reader-topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 22;
    display: flex;
    align-items: center;
    gap: 12px;
    /* 56px row + 10px pad = the Quiz header's 66px, so nothing jumps between tabs. */
    min-height: var(--reader-topbar-h);
    padding: 0 1rem 10px;
    /* Solid navy to match the panel headers and tab bar; no blur. */
    background: var(--navy);
    transform: translateY(0);
    transform-origin: center top;
    transition: transform var(--chrome-fold-anim) var(--chrome-ease), opacity 0.22s var(--chrome-ease);
}

/* The notch spacer is fixed-overlay here (host app.css), so it reserves no flow
   space: the top bar adds the safe-area inset itself. */
body.reader-safe-area-white .reader-topbar {
    padding-top: var(--safe-area-top);
    /* Border-box would let the padding eat min-height, so add the inset to it. */
    min-height: calc(var(--reader-topbar-h) + var(--safe-area-top));
}

/* Back circle shared by the top bar and the panel headers; the -2px optical
   offset applies on every tab so it doesn't shift between them. */
.reader-topbar-back,
.reader-panel-back {
    flex-shrink: 0;
    border: none;
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
    width: 40px;
    height: 40px;
    margin-left: -2px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    transition: background var(--duration-fast) ease, color var(--duration-fast) ease;
}

/* Reader-tab action chips (text options + search): squarer 38px tiles. */
.reader-topbar-action {
    flex-shrink: 0;
    border: none;
    background: rgba(255, 255, 255, 0.09);
    color: var(--appbar-icon-idle);
    width: 38px;
    height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 11px;
    font-size: 15px;
    font-weight: 700;
    transition: background var(--duration-fast) ease, color var(--duration-fast) ease;
}

.reader-topbar-back:hover,
.reader-topbar-back:active,
.reader-panel-back:hover,
.reader-panel-back:active,
.reader-topbar-action:hover,
.reader-topbar-action:active {
    background: rgba(255, 255, 255, 0.16); color: #fff;
}

.reader-topbar-back:focus-visible,
.reader-topbar-action:focus-visible,
.reader-panel-back:focus-visible {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
}

/* Back button leads the title row on the mobile panel headers; the title block
   truncates rather than pushing it off-screen. */
.reader-panel-titlerow {
    display: flex;
    align-items: center;
    gap: 12px;
}

.reader-panel-titleblock {
    flex: 1;
    min-width: 0;
}

/* Search + Display grouped at the right edge; active tints teal like the tab bar. */
.reader-topbar-actions {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

.reader-topbar-action.active {
    color: var(--accent-on-navy);
}

.reader-topbar-label {
    flex: 1;
    /* Lets the title truncate instead of shoving the buttons off screen.
       Bootstrap's min-w-0 isn't in this build, so it lives here. */
    min-width: 0;
}

.reader-topbar-title {
    font-size: 17px;
    font-weight: 800;
    letter-spacing: -0.2px;
    color: #fff;
    line-height: 1.15;
}

.reader-topbar-subtitle {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--appbar-sub);
    margin-top: 2px;
    line-height: 1.25;
}

/* Scroll-collapse, reading view only. Suppressed with a panel open or the find
   bar docked, which would otherwise be left floating mid-air. */
.reader-chrome-collapsed:not(.reader-panel-open):not(.reader-find-active) .reader-topbar {
    opacity: 0;
    transform: translateY(-100%);
    pointer-events: none;
    visibility: hidden;
    transition: transform var(--chrome-fold-anim) var(--chrome-ease), opacity 0.22s var(--chrome-ease), visibility 0s linear var(--chrome-fold-anim);
}


/* ============================================================
   Reader Body & Panels
   ============================================================ */

.reader-body {
    flex: 1;
    display: flex;
    min-height: 0;
    min-width: 0;
    overflow-x: hidden;
}

.reader-panel {
    background: var(--surface);
    border-right: 1px solid var(--border);
    box-shadow: var(--shadow);
    width: min(500px, 90vw);
    max-width: 90vw;
    display: flex;
    flex-direction: column;
    transform: translateX(-100%);
    transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1);
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    /* Only bites in the fractional 767.98-768px gap (zoom/DPI); 1000 there
       floated the panel above the tab bar and every chrome layer. */
    z-index: 24;
    padding-top: calc(3.4rem + var(--safe-area-top));
    pointer-events: none;
}

.reader-panel.open {
    transform: translateX(0);
    pointer-events: auto;
}

.reader-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border);
    background: var(--surface);
    gap: 0.5rem;
}

.reader-panel-heading {
    min-width: 0;
}

.reader-panel-title {
    font-weight: 600;
    font-size: 0.95rem;
}

.reader-close {
    border: 1px solid var(--hairline-2);
    background: var(--warm-input);
    color: var(--slate);
    font-size: 1.35rem;
    width: 40px;
    height: 40px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    padding: 0;
    flex-shrink: 0;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

.reader-close:hover,
.reader-close:focus-visible {
    background: var(--surface-2);
    border-color: var(--border);
}

.reader-panel-content {
    padding: 1rem;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* Navy scroll container so over-pulling reveals navy flush with the own-header,
   not the light panel surface; the inner wrappers still paint the body. */
.reader-panel-own-header .reader-panel-content,
.reader-web .reader-panel-own-header .reader-panel-content {
    background: var(--navy);
}

.reader-panel-placeholder {
    color: var(--muted);
    font-size: 0.9rem;
}

/* ---- Web sidebar chrome -------------------------------------------------
   The :has() guard keys off the shell title so own-header panels stay untouched. */
.reader-web .reader-panel-content {
    background: var(--panel-bg);
}

.reader-web .reader-panel-header:has(.reader-panel-title) {
    padding: 1.25rem 1.375rem 1rem;
    background: var(--paper);
    border-bottom: 1px solid var(--hairline);
}

.reader-web .reader-panel-title {
    font-size: 1.4375rem;
    font-weight: 800;
    letter-spacing: -0.4px;
    color: var(--ink);
}

.reader-web .reader-close {
    color: var(--slate);
}

.reader-web .reader-close:hover,
.reader-web .reader-close:focus-visible {
    background: var(--warm-input);
    border-color: transparent;
    color: var(--ink);
}

/* Shell bar goes navy over an own-header panel so the two read as one header. */
.reader-web .reader-panel-own-header .reader-panel-header {
    background: var(--navy);
    border-bottom: none;
}

.reader-web .reader-panel-own-header .reader-panel-content {
    padding-top: 0;
}

.reader-web .reader-panel-own-header .reader-toc-header,
.reader-web .reader-panel-own-header .reader-notebook-header,
.reader-web .reader-panel-own-header .reader-kc-header,
.reader-web .reader-panel-own-header .reader-downloads-header,
.reader-web .reader-panel-own-header .reader-search-header {
    margin-top: 0;
}

.reader-web .reader-panel-own-header .reader-close {
    border-color: rgba(255, 255, 255, 0.25);
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
}

.reader-web .reader-panel-own-header .reader-close:hover,
.reader-web .reader-panel-own-header .reader-close:focus-visible {
    background: rgba(255, 255, 255, 0.16);
    border-color: rgba(255, 255, 255, 0.4);
    color: #fff;
}

/* ============================================================
   Search
   ============================================================ */

.reader-search {
    display: flex;
    flex-direction: column;
    min-height: 100%;
    /* Type B (list) panel: flat rows on white, and white past the last result
       so a short result set has no gray tail. */
    background: var(--paper);
    box-sizing: border-box;
    margin: 0 -1rem -1rem;
    padding: 0 1rem 1rem;
    animation: reader-search-rise 280ms var(--ease-out);
}

/* Panels and the find card fade-and-rise on open. */
@keyframes reader-search-rise {
    from {
        opacity: 0;
        transform: translateY(8px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .reader-search,
    .reader-findbar,
    .reader-find-handoff {
        animation: none;
    }
}

/* Sticky navy app-bar header, same anatomy as Notebook. */
.reader-search .reader-search-header {
    position: sticky;
    top: 0;
    z-index: 2;
    margin: -1rem -1rem 0;
    padding: 0 1rem 12px;
    background: var(--navy);
}

.reader-search-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 2px;
}

.reader-search-pill {
    display: flex;
    align-items: center;
    gap: 9px;
    flex: 1;
    min-width: 0;
    padding: 11px 13px;
    background: var(--paper);
    border: 1px solid var(--card-border);
    border-radius: 12px;
    box-shadow: 0 1px 3px rgba(16, 42, 67, 0.05);
}

.reader-search-pill svg {
    flex-shrink: 0;
    color: var(--slate-2);
}

.reader-search-input {
    flex: 1;
    min-width: 0;
    border: none;
    background: transparent;
    padding: 0;
    font-family: var(--font-ui);
    /* 16px: also keeps iOS from zooming the page on focus. */
    font-size: 1rem;
    font-weight: 700;
    color: var(--ink);
    caret-color: var(--accent);
}

.reader-search-input:focus {
    outline: none;
}

.reader-search-input::placeholder {
    color: var(--muted);
    font-weight: 500;
}

/* Hide the UA's own clear affordance; the pill renders its own. */
.reader-search-input::-webkit-search-cancel-button,
.reader-search-input::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
}

.reader-search-clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    border: none;
    border-radius: 50%;
    background: var(--clear-circle);
    color: #fff;
    font-size: 10px;
    line-height: 1;
    cursor: pointer;
}

.reader-search-clear:hover,
.reader-search-clear:focus-visible {
    background: var(--muted);
}

.reader-search-cancel {
    flex-shrink: 0;
    border: none;
    background: transparent;
    padding: 0.25rem 0.125rem;
    font-family: var(--font-ui);
    font-size: 15px;
    font-weight: 700;
    color: #fff;
    cursor: pointer;
}

.reader-search-scope {
    display: flex;
    gap: 6px;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 11px;
    padding: 4px;
    margin-top: 10px;
}

.reader-search-scope-seg {
    flex: 1;
    border: none;
    background: transparent;
    height: 36px;
    padding: 0;
    border-radius: 8px;
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 700;
    color: var(--on-navy-seg);
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}

.reader-search-scope-seg:hover {
    color: #fff;
}

.reader-search-scope-seg.active {
    background: var(--surface);
    color: var(--navy);  /* theme-ok: active pill fill inverts to light in dark */
    font-weight: 700;
    box-shadow: 0 1px 3px rgba(8, 20, 35, 0.25);
}

/* Keeps its box while empty so results don't jump when the aria-live text lands. */
.reader-search-countline {
    min-height: 1.25rem;
    margin: 0 -1rem;
    padding: 11px 20px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.3px;
    text-transform: uppercase;
    color: var(--muted-2);
}

/* Bleeds past the panel's 1rem padding so bands and hairlines run edge to edge. */
.reader-search-list {
    flex: 1;
    min-height: 0;
    margin: 0 -1rem;
}

/* Prose states sit inside the bled list, so they take the row gutter back. */
.reader-search-status,
.reader-search-empty {
    padding: 0.75rem 20px;
    font-size: 0.85rem;
    color: var(--meta-quiet);
}

/* The 1px edges separate the band, not the fill. NOT sticky (unlike Downloads):
   the search header's height is variable, so there's no offset to pin against. */
.reader-search-group-head {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    border: none;
    border-top: 1px solid var(--divider-band);
    border-bottom: 1px solid var(--divider-band);
    background: var(--list-group-surface);
    padding: 8px 20px;
    cursor: pointer;
    text-align: left;
}

.reader-search-group-chevron {
    flex-shrink: 0;
    color: var(--slate);
    transition: transform var(--duration-fast) var(--ease-out);
}

.reader-search-group-chevron.collapsed {
    transform: rotate(-90deg);
}

.reader-search-group-title {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.3px;
    text-transform: uppercase;
    color: var(--slate);
}

.reader-search-group-badge {
    flex-shrink: 0;
    padding: 2px 8px;
    border-radius: 9px;
    background: var(--chip-neutral-bg);
    font-size: 11px;
    font-weight: 800;
    color: var(--slate);
}

/* The current page's badge reads accent; other sections stay neutral. */
.reader-search-group-badge.accent {
    background: var(--accent-soft);
    color: var(--on-accent-soft);
}

.reader-search-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    border: none;
    border-bottom: 1px solid var(--divider-row);
    background: transparent;
    padding: 13px 14px 13px 20px;
    cursor: pointer;
    text-align: left;
}

.reader-search-row:hover,
.reader-search-row:focus-visible {
    background: var(--row-pressed);
}

.reader-search-row[aria-current="true"] {
    background: var(--accent-wash);
}

.reader-search-row-snippet {
    flex: 1;
    min-width: 0;
    font-family: var(--font-reading);
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--reading-text);
    text-wrap: pretty;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.reader-search-row-chevron {
    flex-shrink: 0;
    color: var(--muted-2);
}

/* Teal, not yellow: a search hit must never read as a yellow-pen annotation. */
.reader-search-mark {
    background: var(--accent-soft);
    color: var(--accent-deep);
    border-radius: 3px;
    padding: 0 2px;
}

/* ============================================================
   Menu Items / TOC
   ============================================================ */

.reader-menu-item {
    border: 1px solid transparent;
    background: transparent;
    text-align: left;
    padding: 0.45rem 0.6rem;
    border-radius: 8px;
    color: var(--text);
    transition: background 150ms ease;
}

.reader-menu-item:hover,
.reader-menu-item:focus-visible {
    background: var(--surface-2);
}

.reader-menu-item.active {
    border-color: var(--border);
    background: var(--surface-2);
    font-weight: 500;
}

/* Type B (list) panel: white end to end, flat rows split by a hairline. On
   --page-surface the hairline would have nothing to divide. */
.reader-toc {
    display: flex;
    flex-direction: column;
    min-height: 100%;
    background: var(--paper);
    /* Bleed over the container padding on the sides and bottom so only the top
       overscroll strip reads navy, flush with the sticky header. */
    box-sizing: border-box;
    margin: 0 -1rem -1rem;
    padding: 0 1rem 1rem;
}

/* Sticky header bleeds past the .reader-panel-content 1rem padding.
   Grouped so the own-header panels cannot drift apart. */
.reader-toc-header,
.reader-notebook-header,
.reader-kc-header,
.reader-downloads-header,
.reader-search-header {
    position: sticky;
    top: 0;
    z-index: 2;
    margin: -1rem -1rem 0;
    padding: 0 1rem 10px;
    background: var(--navy);
}

/* Constant 56px row, matching the top bar, so nothing jumps between panels. */
.reader-panel-titlerow {
    min-height: var(--reader-titlerow-h);
}

.reader-toc-title,
.reader-notebook-title,
.reader-kc-title,
.reader-downloads-title,
.reader-search-title {
    margin: 0;
    font-size: 17px;
    font-weight: 800;
    color: #fff;
    letter-spacing: -0.2px;
    line-height: 1.15;
}

.reader-toc-subtitle,
.reader-notebook-subtitle,
.reader-kc-subtitle,
.reader-downloads-subtitle,
.reader-search-subtitle {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--on-navy-sub);
    margin-top: 2px;
    line-height: 1.25;
}

/* Contents second row: progress meter, tucked under the title row. */
.reader-toc-header {
    padding-bottom: 14px;
}

.reader-toc-progress {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 2px;
}

.reader-toc-progress-track {
    flex: 1;
    height: 6px;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.14);
    overflow: hidden;
}

.reader-toc-progress-fill {
    height: 100%;
    background: var(--accent-bright);
    border-radius: 4px;
}

.reader-toc-progress-label {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--on-navy-sub);
}

/* No padding here: the row wrapper's 10px plus the pill's 12px make a symmetric
   22px gutter on every row, selected or not. */
.reader-toc-body {
    margin: 0 -1rem;
    padding: 6px 0 10px;
}

.reader-toc-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Nesting is carried by the rail, not indentation: section and chapter titles
   share the same x. The 10px pill clearance is load-bearing: without it the
   current-section pill butts against the rail and reads as a rendering fault. */
.reader-toc-children {
    margin-left: 26px;
    padding-left: 10px;
    border-left: 2px solid var(--toc-guide);
}

/* Derived, not stored: the rail goes teal on the group holding the current
   section. */
.reader-toc-children:has(.reader-toc-row-current) {
    border-left-color: var(--toc-guide-active);
}

.reader-toc-item {
    position: relative;
}

/* Only chapters carry the wrapper inset; nested rows take their offset from
   the rail instead, so the inset never compounds with depth. */
.reader-toc-item-section {
    padding: 0 10px;
}

.reader-toc-item-section:not(:last-child)::after {
    content: "";
    position: absolute;
    left: 22px;
    right: 22px;
    bottom: 0;
    height: 1px;
    background: var(--divider-row);
}

/* No divider above or below the current row: a pill plus a hairline reads as a
   boxed-in row. The third selector covers a current row that ends an expanded
   group. */
.reader-toc-item-section:has(> .reader-toc-row-current)::after,
.reader-toc-item-section:has(+ .reader-toc-item-section > .reader-toc-row-current)::after,
.reader-toc-item-section:has(.reader-toc-list-nested > .reader-toc-item:last-child > .reader-toc-row-current)::after {
    content: none;
}

/* One grid for every row; only the control track width and padding vary.
   min-height (not height) lets a wrapped title grow the row while the expand
   box stays on the title's optical centre. Base is a leaf section: no track. */
.reader-toc-row {
    display: grid;
    grid-template-columns: 0 1fr;
    column-gap: 0;
    align-items: center;
    min-height: 38px;
    padding: 8px 12px 8px 16px;
    border-radius: 12px;
    transition: background var(--duration-fast) var(--ease-out);
}

/* 42px = the 28px box plus 14px of breathing room. */
.reader-toc-row-control {
    grid-template-columns: 42px 1fr;
    padding-left: 12px;
}

.reader-toc-item-section > .reader-toc-row {
    min-height: 54px;
    padding-top: 11px;
    padding-bottom: 11px;
}

.reader-toc-row:hover {
    background: var(--row-pressed);
}

.reader-toc-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
}

/* The cell stays in the DOM so the title keeps its grid track, but collapses
   with the control track it sits in rather than overflowing across the title. */
.reader-toc-row:not(.reader-toc-row-control) .reader-toc-cell {
    width: 0;
    overflow: hidden;
}

.reader-toc-toggle-icon {
    display: block;
}

/* Expanding fades the plus into a minus. Row insertion stays instant: a height
   animation on a long section list feels sluggish and fights the scroll. */
.reader-toc-toggle-stem {
    transition: opacity 150ms var(--ease-out);
}

.reader-toc-toggle[aria-expanded="true"] .reader-toc-toggle-stem {
    opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
    .reader-toc-toggle-stem {
        transition: none;
    }
}

.reader-toc-toggle {
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1.5px solid var(--control-border-idle);
    border-radius: 8px;
    background: var(--paper);
    color: var(--body-secondary);
    padding: 0;
    line-height: 1;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

.reader-toc-toggle:hover,
.reader-toc-toggle:focus-visible {
    border-color: var(--accent);
    color: var(--accent-text);
}

.reader-toc-link {
    margin: 0;
    min-width: 0;
    display: flex;
    align-items: center;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    text-align: left;
}

.reader-toc-link:hover,
.reader-toc-link:focus-visible {
    background: transparent;
}

.reader-toc-link.active {
    border: 0;
    background: transparent;
}

.reader-toc-link-label {
    flex: 1;
    min-width: 0;
    text-wrap: pretty;
}

.reader-toc-link-section .reader-toc-link-label {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--ink);
    line-height: 1.4;
}

/* Weight and size, plus the rail, carry the hierarchy that the indent used
   to. Titles start on the same x as a chapter's and keep the full column. */
.reader-toc-link-leaf .reader-toc-link-label {
    font-size: 13.5px;
    font-weight: 500;
    color: var(--slate);
    line-height: 1.4;
}

/* Current item: soft-teal pill. Padding and inset are the row's, not the
   state's, so selecting a row never shifts it. */
.reader-toc-row-current {
    background: var(--accent-soft);
}

.reader-toc-row-current:hover {
    background: var(--accent-soft-hover);
}

.reader-toc-row-current .reader-toc-link-label {
    font-weight: 700;
    color: var(--on-accent-soft);
}

.reader-toc-row-current .reader-toc-toggle {
    border-color: var(--accent-soft-border);
    color: var(--accent-text);
}

/* ============================================================
   Content Area
   ============================================================ */

.reader-content {
    flex: 1;
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
    overflow-anchor: none;
    overscroll-behavior: contain;
    touch-action: pan-y;
    position: relative;
    background: var(--surface-2);
    /* Set only while the web reconnect strip floats over the book, so focus
       never lands under it. */
    scroll-padding-top: var(--connection-strip-h, 0px);
}

/* The mobile top bar is a fixed glass overlay, so the scroll container reserves
   space for it via top padding (bottom space is handled by .reader-content-host).
   The scroll padding keeps scrolled-to items (the quiz score card) out from under it. */
.reader:not(.reader-web) .reader-content {
    --reader-topbar-clearance: calc(var(--reader-topbar-h) + var(--safe-area-top));
    padding-top: var(--reader-topbar-clearance);
    scroll-padding-top: var(--reader-topbar-clearance);
}

.reader-content-inner {
    max-width: 100%;
    min-width: 0;
    overflow-x: hidden;
    padding: 0;
}

.reader-web .reader-content-inner {
    width: 100%;
    padding: 0 1.25rem calc(4.5rem + env(safe-area-inset-bottom));
}

.reader-book-stage {
    position: relative;
    max-width: 100%;
    min-width: 0;
    overflow-x: hidden;
    touch-action: pan-y;
}

.reader-content-host {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-sizing: border-box;
    width: 100%;
    max-width: min(var(--reader-content-max-width), 100%);
    min-width: 0;
    margin: 0 auto;
    padding: 1.5rem;
    box-shadow: var(--shadow);
    overflow-x: hidden;
    touch-action: pan-y;
}

.reader-content-body {
    max-width: 100%;
    margin: 0 !important;
    /* Only a word too wide for its line breaks, at any letter. No hyphens: auto,
       which would also split heading words that fit (owner, 2026-09-25). */
    overflow-wrap: anywhere;
    transform-origin: top left;
}

/* Load failure inside the reading column (a refused book, a section that
   failed to render): flat and centered like the status pages, UI font. */
.reader-content-error {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
    max-width: 30rem;
    margin: 0 auto;
    padding: 3rem 1rem;
    font-family: var(--font-ui);
    text-align: center;
}

.reader-content-error-message {
    margin: 0;
    color: var(--reading-text);
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.5;
    text-wrap: pretty;
}

/* House primary button (.btn-primary carries the fill and its dark flip);
   this class only sizes it and seats the chevron. */
.reader-content-error-action {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    min-height: 48px;
    padding: 0.55rem 1.1rem 0.55rem 0.85rem;
    border: 0;
    font-size: 0.92rem;
    line-height: 1.2;
}

.reader-content-error-action:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Reading typography: inherited fallbacks only. Books ship their own CSS into
   .reader-content-body and must always win, so never use !important or
   descendant selectors here (drop cap and bullets use :where() for the same
   reason). */
.reader-content-host,
.reader-content-body {
    font-family: var(--font-reading);
    color: var(--reading-text);
    line-height: 1.72;
}

/* Drop cap on the first paragraph, ONLY for books that ship no CSS of their
   own (:not(:has(style))). A book with any embedded <style> is left alone, so
   the decoration is never forced onto styled content. */
:where(.reader-content-body:not(:has(style))) > p:first-of-type::first-letter {
    float: left;
    font-family: var(--font-reading);
    font-weight: 600;
    font-size: 3.4em;
    line-height: 0.82;
    color: var(--ink);
    padding: 0.06em 0.18em 0 0;
}

/* Teal-dot bullets, ONLY for books that ship no CSS of their own. */
:where(.reader-content-body:not(:has(style)) ul) {
    list-style: disc;
}

:where(.reader-content-body:not(:has(style)) ul) li::marker {
    color: var(--accent);
}

.reader-content-body body {
    margin: 0 !important;
}

.reader-content-body *,
.reader-content-body *::before,
.reader-content-body *::after {
    box-sizing: border-box;
    min-width: 0;
    max-width: 100%;
}

.reader-content-host img,
.reader-content-body img,
.reader-content-body svg,
.reader-content-body canvas,
.reader-content-body video {
    max-width: 100% !important;
    height: auto !important;
}

/* No height: auto here, embeds have no aspect ratio and shrank to the 150px
   default (SD-4440). renderSection gives pixel-sized ones their own ratio. */
.reader-content-body iframe,
.reader-content-body object {
    max-width: 100% !important;
}

.reader-content-body table {
    max-width: 100% !important;
    table-layout: auto;
}

/* Legacy web stretched book tables; legacy mobile sized them to their content. */
.reader-web .reader-content-body table {
    width: 100% !important;
}

/* Legacy never split a word in a table cell; the inherited anywhere lets auto
   layout squeeze columns letter by letter. */
.reader-content-body :is(td, th) {
    overflow-wrap: break-word;
}

/* So a table too wide for the column scrolls sideways, as in legacy, but in
   the book's box around it rather than the whole page. A scrolling box can't
   sit under a float (page markers), so it clears them to keep its width. */
:where(.reader-content-body div:not(#cssLockDown):has(> table)) {
    overflow-x: auto;
    clear: both;
}

/* reader.js makes an overflowing box a tab stop. The ring sits inside it,
   where the column's clipping can't cut it off. */
.reader-content-body .reader-table-scroll:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

/* Book templates class tables, rows and cells "table", which pulled in
   Bootstrap's .table: full-width cells and a boxed white fill on every word
   (SD-4433). Same specificity as Bootstrap's rules, so book CSS still wins. */
:where(.reader-content-body :is(table, tr, th, td)).table {
    width: auto;
}

/* Legacy mobile left cells at the browser default (middle); web keeps
   Bootstrap's top, like legacy web. */
:where(.reader:not(.reader-web) .reader-content-body) .table > :is(thead, tbody),
:where(.reader:not(.reader-web) .reader-content-body :is(tr, th, td)).table {
    vertical-align: revert;
}

:where(.reader-content-body :is(tr, th, td)).table > :not(caption) > * > * {
    padding: revert;
    color: revert;
    background-color: revert;
    border-bottom-width: 0;
    box-shadow: revert;
}

.reader-content-body pre {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.reader-content-body [style*="width"] {
    max-width: 100% !important;
}

/* Templates indent equation blocks by fixed ems (14em, 26em) for legacy's
   left-aligned math. MathJax centers display math, so drop the indent. */
.reader-content-body div[class^="equation"] {
    margin-inline: 0 !important;
}

/* Too-wide formulas scroll in their own box; faded edges hint at the hidden
   part, padding keeps the ends clear of them. Table cells grow to fit instead. */
.reader-content-body mjx-container[display="true"]:not(:is(td, th) *) {
    overflow-x: auto;
    overflow-y: hidden;
    padding-inline: 1.5em;
    mask-image: linear-gradient(to right, transparent, #000 1.5em, #000 calc(100% - 1.5em), transparent);
}

/* Natural width, or Firefox drops the end padding from the scroll range. */
.reader-content-body mjx-container[display="true"]:not(:is(td, th) *) > mjx-math {
    max-width: none;
}

@media (prefers-reduced-motion: no-preference) {
    .reader-content-body mjx-container[display="true"] {
        scroll-behavior: smooth;
    }
}

/* Holder and scroll buttons that book-package.js adds around those formulas. */
reader-formula-scroll {
    position: relative;
    display: block;
}

.reader-formula-scroll-btn {
    position: absolute;
    top: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--card-border);
    border-radius: 50%;
    background: var(--surface);
    color: var(--ink);
    box-shadow: var(--shadow-card);
    cursor: pointer;
    transform: translateY(-50%);
    user-select: none;
    transition: background var(--duration-fast) var(--ease-out);
}

/* A 48px hit area around the 32px circle; max-width undoes the book-content cap. */
.reader-formula-scroll-btn::before {
    content: "";
    position: absolute;
    inset: -8px;
    max-width: none;
}

.reader-formula-scroll-btn[data-direction="-1"] {
    left: 0;
}

.reader-formula-scroll-btn[data-direction="1"] {
    right: 0;
}

.reader-formula-scroll-btn:hover {
    background: var(--surface-hover);
}

.reader-formula-scroll-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.reader-formula-scroll-btn svg {
    width: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.25;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Card book-package.js puts in place of a library video in the apps. Book
   resets under #cssLockDown outrank classes, hence the !important. */
.reader-content-body .reader-library-video {
    max-width: 480px;
    margin: 0 auto !important;
    padding: 16px !important;
    border: 1px solid var(--card-border);
    border-radius: 10px;
    background: var(--surface);
    text-align: center !important;
}

.reader-content-body .reader-library-video-note {
    margin: 0 0 8px !important;
    font-family: var(--font-ui) !important;
    font-size: 15px !important;
    line-height: 1.45 !important;
    text-align: center !important;
    color: var(--body-secondary) !important;
}

.reader-content-body .reader-library-video-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 8px;
    border-radius: 4px;
    font-family: var(--font-ui);
    font-size: 16px;
    font-weight: 700;
    color: var(--accent-text) !important;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.reader-content-body .reader-library-video-link:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Older course templates shrink the chapter opener and its objectives box
   (nested or right after it) to centered 85-90% cards. Fill the text column
   instead, like the newer templates' opener does. */
.reader-content-body .chapter-opener,
.reader-content-body .chapter-opener :is(div.objectives, div.lo),
.reader-content-body .chapter-opener ~ :is(div.objectives, div.lo) {
    width: 100% !important;
    max-width: 100% !important;
    margin-inline: 0 !important;
}

/* ============================================================
   Section navigation (footer under the section)
   Layout lives in the mobile and wide blocks.
   ============================================================ */

.reader-section-nav {
    /* app.css paints every nav navy; this one sits on the reading sheet. */
    background: transparent;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    border-top: 1px solid var(--card-border);
}

.reader-section-nav-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    padding: 11px 16px;
    border-radius: 11px;
    font-size: 13.5px;
    font-weight: 700;
    cursor: pointer;
}

.reader-section-nav-prev {
    background: var(--paper);
    border: 1.5px solid var(--input-border);
    color: var(--ink);
}

/* Pushed right so it stays at the edge when there is no Previous button. */
.reader-section-nav-next {
    margin-left: auto;
    background: var(--btn-navy-bg);
    border: 0;
    color: #fff;
}

@media (hover: hover) {
    .reader-section-nav-prev:hover {
        background: var(--row-pressed);
    }

    .reader-section-nav-next:hover {
        background: var(--btn-navy-hover);
    }
}

.reader-section-nav-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* ============================================================
   Loading States
   ============================================================ */

.reader-loading {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 5;
    pointer-events: none;
}

.reader-loading .spinner-border {
    width: 2.25rem;
    height: 2.25rem;
}

.reader-loading-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    max-width: min(28rem, calc(100vw - 2rem));
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--border);
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.96);
    box-shadow: 0 18px 45px rgba(16, 42, 67, 0.14);
    color: var(--text);
}

.reader-loading-copy {
    display: grid;
    gap: 0.2rem;
    text-align: left;
}

.reader-loading-title {
    font-weight: 600;
    font-size: 0.98rem;
}

/* Download-progress variant (screen 16): full-area reading-canvas surface,
   teal arc spinner, navy title, teal bar + percent, helper text, cancel. */
.reader-loading-card.with-progress {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0;
    width: 100%;
    max-width: none;
    height: 100%;
    padding: 0 40px calc(env(safe-area-inset-bottom));
    border: none;
    border-radius: 0;
    background: var(--parchment);
    box-shadow: none;
    text-align: center;
}

.reader-loading-spinner {
    width: 46px;
    height: 46px;
    margin-bottom: 34px;
    animation: reader-download-spin 0.9s linear infinite;
}

@keyframes reader-download-spin {
    to { transform: rotate(360deg); }
}

.reader-loading-card.with-progress .reader-loading-title {
    margin: 0 0 30px;
    font-size: 30px;
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -0.4px;
    color: var(--ink);
}

.reader-loading-percent {
    margin-top: 18px;
    font-variant-numeric: tabular-nums;
    color: var(--accent-deep);
    font-weight: 700;
    font-size: 17px;
}

.reader-loading-message {
    margin: 14px 0 0;
    max-width: 280px;
    color: var(--muted);
    font-size: 15px;
    line-height: 1.55;
    overflow-wrap: anywhere;
}

.reader-loading-cancel {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 11px;
    margin-top: 54px;
}

.reader-loading-cancel-btn {
    width: 62px;
    height: 62px;
    padding: 0;
    border-radius: 50%;
    border: 2px solid var(--danger-hover);
    background: var(--danger-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.reader-loading-cancel-btn:hover {
    background: var(--danger-hover);
    border-color: var(--danger);
}

.reader-loading-cancel-btn svg {
    width: 24px;
    height: 24px;
}

.reader-loading-cancel-label {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.4px;
    color: var(--muted-2);
}

.reader-loading-progress-bar {
    position: relative;
    width: 100%;
    max-width: 300px;
    height: 8px;
    background: var(--progress-track);
    border-radius: 4px;
    overflow: hidden;
}

.reader-loading-progress-fill {
    height: 100%;
    width: 0;
    background: var(--accent);
    border-radius: inherit;
    transition: width 220ms ease-out;
}

.reader-loading-progress-bar.indeterminate .reader-loading-progress-fill {
    width: 35%;
    animation: reader-loading-indeterminate 1.4s ease-in-out infinite;
}

@keyframes reader-loading-indeterminate {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(285%); }
}

@media (prefers-reduced-motion: reduce) {
    .reader-loading-progress-fill { transition: none; }
    .reader-loading-progress-bar.indeterminate .reader-loading-progress-fill {
        animation: none;
    }
}

.reader-loading-viewport {
    position: fixed;
    inset: 0;
    z-index: 1200;
    background: rgba(246, 247, 249, 0.72);
    pointer-events: auto;
    backdrop-filter: blur(2px);
}

.reader-loading-section {
    position: sticky;
    inset: 0 0 auto 0;
    height: 100vh;
    height: 100dvh;
    margin-bottom: -100vh;
    margin-bottom: -100dvh;
    z-index: 5;
    pointer-events: auto;
    background: rgba(255, 255, 255, 0.72); /* reading-canvas (white) veil */
}

/* ============================================================
   Bottom Bar (Mobile)
   ============================================================ */

.reader-bottombar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: space-around;
    gap: 0.5rem;
    padding: 0.4rem 0.75rem calc(0.4rem + env(safe-area-inset-bottom));
    background: var(--surface);
    border-top: 1px solid var(--border);
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.04);
    z-index: 25;
}

/* MAUI mobile only: the bottom tab bar floats as a navy-glass pill. The web
   reader keeps its flat white bar even at narrow widths. Inherits z-index 25,
   above full-screen panels. */
.reader:not(.reader-web) .reader-bottombar {
    /* Full-width opaque navy bar anchored to the bottom edge (design Navy tone).
       Overrides the floating-pill base; web-narrow keeps its parchment fallback. */
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    max-width: none;
    align-items: stretch;
    gap: 0;
    padding: 0.5rem 0.375rem calc(0.375rem + env(safe-area-inset-bottom));
    background: var(--navy);
    border: none;
    border-top: 1px solid var(--glass-border);
    border-radius: 0;
    box-shadow: 0 -12px 30px rgba(0, 0, 0, 0.24);
    transform: translateY(0);
    transform-origin: center bottom;
    transition: transform var(--chrome-fold-anim) var(--chrome-ease), opacity 0.22s var(--chrome-ease);
}

/* On-navy tab colors: idle muted, active bright tint (override mobile-media). */
.reader:not(.reader-web) .reader-bottombar .reader-tab {
    position: relative;
    color: var(--nav-idle);
    gap: 4px;
    padding: 6px 0 0;
}

.reader:not(.reader-web) .reader-bottombar .reader-tab.active {
    color: var(--accent-on-navy);
}

.reader:not(.reader-web) .reader-bottombar .reader-tab.active .reader-tab-label {
    font-weight: 700;
}

/* 26x3 rounded indicator pinned to the top edge of the active tab. */
.reader:not(.reader-web) .reader-bottombar .reader-tab.active::before {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 26px;
    height: 3px;
    border-radius: 2px;
    background: var(--accent-on-navy);
}

/* Collapsed bottom state: the full bar slides down and a single circular FAB
   appears bottom-right (design), wearing the Reader glyph. Opaque navy. */
.reader-bottombar-peek {
    position: fixed;
    right: var(--chrome-edge-gap);
    bottom: calc(var(--chrome-edge-gap) + env(safe-area-inset-bottom));
    z-index: 31;
    box-sizing: border-box;
    width: 52px;
    height: 52px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--glass-border);
    border-radius: 50%;
    background: var(--navy);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.32);
    color: var(--accent-on-navy);
    opacity: 0;
    transform: scale(0.55);
    pointer-events: none;
    visibility: hidden;
    transition: transform var(--chrome-fold-anim) var(--chrome-ease), opacity 0.22s var(--chrome-ease), visibility 0s linear var(--chrome-fold-anim);
}

.reader-bottombar-peek:focus-visible {
    outline: 2px solid var(--accent-on-navy);
    outline-offset: 2px;
}

/* Collapsed (reading view, scrolled down): the full bar slides down + fades,
   the FAB pops in. */
.reader:not(.reader-web).reader-chrome-collapsed:not(.reader-panel-open):not(.reader-find-active) .reader-bottombar {
    opacity: 0;
    transform: translateY(130%);
    pointer-events: none;
    visibility: hidden;
    transition: transform var(--chrome-fold-anim) var(--chrome-ease), opacity 0.22s var(--chrome-ease), visibility 0s linear var(--chrome-fold-anim);
}

.reader-chrome-collapsed:not(.reader-panel-open):not(.reader-find-active) .reader-bottombar-peek {
    opacity: 1;
    transform: scale(1);
    pointer-events: auto;
    visibility: visible;
    transition: transform var(--chrome-fold-anim) var(--chrome-ease), opacity 0.22s var(--chrome-ease);
}

/* Honor reduced-motion: snap the chrome instead of sliding/scaling it.
   !important so it beats the higher-specificity collapsed/open state transitions. */
@media (prefers-reduced-motion: reduce) {
    .reader-topbar,
    .reader:not(.reader-web) .reader-bottombar,
    .reader-bottombar-peek {
        transition-duration: 1ms !important;
    }
}

/* ============================================================
   Overlay / Scrim
   ============================================================ */

.reader-scrim {
    position: fixed;
    inset: 0;
    background: rgba(14, 20, 32, 0.22);
    z-index: 20;
}

/* ============================================================
   Annotations
   ============================================================ */

.reader-annotation-error {
    color: var(--danger);
    font-size: 0.85rem;
}

/* Non-blocking error banner: sits above the notebook list so a failed
   save/delete is surfaced without hiding annotations that are still loaded. */
.reader-annotation-error-banner {
    margin: 0 0 0.75rem;
    padding: 0.6rem 0.8rem;
    border-radius: var(--radius);
    background: var(--danger-soft);
    border: 1px solid var(--danger-hover);
    color: var(--danger);
    font-size: 0.85rem;
}

/* ============================================================
   Notebook Panel
   ============================================================ */

.reader-notebook {
    display: flex;
    flex-direction: column;
    min-height: 100%;
    background: var(--panel-bg);
    /* See .reader-toc: bleed over the container padding so only the top
       overscroll strip reads navy, flush with the sticky header. */
    box-sizing: border-box;
    margin: 0 -1rem -1rem;
    padding: 0 1rem 1rem;
}

/* Navy app-bar header: bleeds past the panel padding to span full width and sit
   flush while scrolling. Title rules are shared with the TOC header; Notebook
   adds only the count badge and filter row. */
.reader-notebook-header {
    padding-bottom: 12px;
}

.reader-notebook-title-wrap {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.reader-notebook-count {
    background: var(--accent-soft);
    color: var(--accent-text);
    font-size: 11px;
    font-weight: 800;
    padding: 2px 9px;
    border-radius: 20px;
    line-height: 1.4;
}

/* Segmented filter on a translucent track: active = white pill, inactive =
   muted on-navy labels. */
.reader-notebook-filters {
    display: flex;
    gap: 4px;
    margin-top: 2px;
    padding: 4px;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 13px;
}

.reader-notebook-filter {
    flex: 1;
    background: transparent;
    border: 0;
    color: var(--on-navy-seg);
    font-size: 13px;
    font-weight: 700;
    height: 36px;
    padding: 0;
    border-radius: 10px;
    cursor: pointer;
    transition: background 150ms ease, color 150ms ease;
}

.reader-notebook-filter:hover {
    color: #fff;
}

.reader-notebook-filter.active {
    background: var(--surface);
    color: var(--navy);  /* theme-ok: navy label on the ACTIVE segmented pill, whose fill is inverted to light in dark */
    box-shadow: 0 1px 3px rgba(8, 20, 35, 0.25);
}

.reader-notebook-body {
    display: grid;
    gap: 1.25rem;
    padding-top: 1.1rem;
}

.reader-notebook-section {
    display: grid;
    gap: 0.65rem;
}

.reader-notebook-heading {
    margin: 0;
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--eyebrow);
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

.reader-notebook-list {
    display: grid;
    gap: 0.85rem;
}

.reader-notebook-item {
    border: 1px solid var(--hairline);
    border-radius: var(--radius-card);
    background: var(--paper);
    padding: 1rem;
    display: grid;
    gap: 0.5rem;
    box-shadow: var(--shadow-card);
}

.reader-notebook-item-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.reader-notebook-item-meta {
    font-size: 0.75rem;
    color: var(--meta-quiet);
}

.reader-annotation-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.25rem 0.6rem;
    border-radius: var(--radius-chip);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.reader-annotation-chip-note {
    background: var(--accent-soft);
    color: var(--accent-deep);
}

.reader-annotation-chip-glyph {
    display: block;
}

.reader-annotation-chip-highlight {
    background: var(--warm-input);
    color: var(--slate-2);
}

.reader-annotation-chip-swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    flex-shrink: 0;
}

.reader-notebook-note-text {
    margin: 0;
    color: var(--ink);
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
    font-size: 0.95rem;
    font-weight: 600;
}

.reader-notebook-quote {
    margin: 0;
    font-family: var(--font-reading);
    font-size: 0.98rem;
    line-height: 1.55;
    color: var(--reading-text);
    word-break: break-word;
    padding-left: 0.7rem;
    border-left: 3px solid var(--accent);
    border-radius: 3px;
}

.reader-notebook-item-footer {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.reader-notebook-item-colors {
    display: flex;
    gap: 0.4rem;
    /* Pin the colour selector to the right edge of the footer row, level with
       the Go to action, instead of stacking above it. */
    margin-left: auto;
    flex-shrink: 0;
}

/* Page meta + overflow (...) grouped on the right of the card's top row. */
.reader-notebook-item-actions {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.reader-notebook-overflow {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    /* 40px hit area pulled tight with negative margins so it doesn't bloat the row. */
    margin: -0.5rem -0.6rem -0.5rem 0;
    border: 0;
    border-radius: 11px;
    background: transparent;
    color: var(--meta-quiet);
    cursor: pointer;
    transition: background 150ms ease;
}

.reader-notebook-overflow:hover,
.reader-notebook-overflow:focus-visible {
    background: var(--warm-input-2);
    outline: none;
}

/* Primary "Go to passage" / "Go to" action: teal text + arrow, 44px tap target. */
.reader-notebook-goto {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 44px;
    /* Offset the padding so the label sits flush with the card content. */
    margin-left: -0.5rem;
    padding: 0.5rem;
    border: 0;
    border-radius: 11px;
    background: transparent;
    font-family: var(--font-ui);
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--accent-text);
    cursor: pointer;
    transition: background 150ms ease;
}

.reader-notebook-goto:hover,
.reader-notebook-goto:focus-visible {
    background: var(--accent-soft-2);
    outline: none;
}

/* ============================================================
   Knowledge Check Panel
   ============================================================ */

.reader-kc {
    display: flex;
    flex-direction: column;
    min-height: 100%;
    background: var(--panel-bg);
    box-sizing: border-box;
    /* Bleed over the scroll-container padding (sides + bottom) so the panel
       surface reads edge to edge under the navy app-bar header. */
    margin: 0 -1rem -1rem;
    padding: 0 1rem 1rem;
}

/* Header/title/subtitle rules are shared with the TOC header (grouped there). */

/* Top padding only: the panel's own bottom padding already spaces the list,
   and a bottom pad here would let the report's sticky footer scroll off the
   panel surface. */
.reader-kc-body {
    padding-top: 18px;
}

.reader-kc-live {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.reader-kc-intro {
    margin: 0 4px 18px;
    color: var(--muted);
    font-size: 0.85rem;
    line-height: 1.45;
}

.reader-kc-error {
    color: var(--danger);
    background: var(--danger-soft);
    border: 1px solid var(--danger-hover);
}

/* Type A (card) panel: a quiz attempt is an object you act on in more than one
   way, so it is a card on the page surface. Cards carry the separation, so
   there are no dividers anywhere in here. */
.reader-kc-chapter {
    margin-bottom: 22px;
}

.reader-kc-chapter:last-child {
    margin-bottom: 0;
}

/* Active chapter: the chip carries the state in words, so no container is
   needed around the cards. aria-current carries it programmatically. */
.reader-kc-chapter-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 4px 10px;
}

.reader-kc-chapter-title {
    flex: 1;
    min-width: 0;
    margin: 0;
    font-size: 11px;
    font-weight: 800;
    color: var(--slate);
    text-transform: uppercase;
    letter-spacing: 1.2px;
    line-height: 1.45;
    text-wrap: pretty;
}

/* Always present, so the title wraps to the same width with or without it. */
.reader-kc-chapter-flag {
    flex-shrink: 0;
}

.reader-kc-chapter-chip {
    display: inline-block;
    padding: 3px 8px;
    border-radius: var(--radius-chip);
    background: var(--accent-soft);
    color: var(--on-accent-soft);
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.8px;
    text-transform: uppercase;
}

.reader-kc-tests {
    display: grid;
    gap: 12px;
}

.reader-kc-test {
    position: relative;
    padding: 14px;
    background: var(--paper);
    border: 1px solid var(--hairline);
    border-radius: 14px;
    box-shadow: var(--shadow-card);
    transition: box-shadow 150ms ease, border-color 150ms ease;
}

.reader-kc-test:hover {
    box-shadow: var(--shadow-md);
}

/* Active test. The teal border is the WCAG 1.4.11 state indicator, doubled by an
   inset shadow to avoid the layout shift a thicker border would cause. No teal
   wash: it would match the high-score pill's fill and swallow it. */
.reader-kc-test--current {
    border-color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent), var(--shadow-card);
}

.reader-kc-test-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
}

/* Type chip. Neutral for both pre and post: the word says which one it is,
   and colour is reserved for the score band on the other side of the row. */
.reader-kc-eyebrow {
    display: inline-block;
    font-size: 10.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.9px;
    color: var(--slate);
    background: var(--chip-neutral-bg);
    padding: 4px 9px;
    border-radius: var(--radius-chip);
}

.reader-kc-score {
    display: inline-flex;
    align-items: center;
    padding: 4px 11px;
    border-radius: 9px;
    font-size: 13px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    border: 1px solid transparent;
}

.reader-kc-score--none {
    color: var(--muted);
    background: var(--row-pressed);
    border-color: var(--hairline);
}

.reader-kc-score--high {
    color: var(--score-high-text);
    background: var(--score-high-bg);
}

.reader-kc-score--mid {
    color: var(--score-mid-text);
    background: var(--score-mid-bg);
}

.reader-kc-score--low {
    color: var(--score-low-text);
    background: var(--score-low-bg);
}

.reader-kc-status {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 12px 0 0;
    color: var(--ink);
    font-size: 13.5px;
    font-weight: 600;
}

.reader-kc-status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* The dot follows the score band: a low score beside a green dot was the
   clearest contradiction in the old panel. */
.reader-kc-status-dot--high {
    background: var(--score-high-dot);
}

.reader-kc-status-dot--mid {
    background: var(--score-mid-dot);
}

.reader-kc-status-dot--low {
    background: var(--score-low-dot);
}

.reader-kc-status-dot--none,
.reader-kc-status-dot--todo {
    background: var(--hairline);
    border: 1px solid var(--muted-2);
}

.reader-kc-status-text {
    flex: 1 1 auto;
    min-width: 0;
}

/* Aligned under the date, past the dot. */
.reader-kc-detail {
    margin: 4px 0 0 16px;
    font-size: 12.5px;
    color: var(--muted-2);
}

.reader-kc-actions {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0 10px;
    margin-top: 13px;
}

.reader-kc-actions--split {
    grid-template-columns: 1fr 1fr;
}

.reader-kc-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 11px 0;
    border-radius: 11px;
    font-size: 13.5px;
    font-weight: 700;
    border: 1px solid transparent;
    cursor: pointer;
    line-height: 1.2;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
}

.reader-kc-btn--primary {
    background: var(--btn-navy-bg);
    color: #fff;
    border-color: var(--btn-navy-bg);
}

.reader-kc-btn--primary:hover,
.reader-kc-btn--primary:focus-visible {
    background: var(--btn-navy-hover);
    border-color: var(--btn-navy-hover);
}

.reader-kc-btn--secondary {
    background: var(--paper);
    color: var(--ink);
    border: 1.5px solid var(--input-border);
}

.reader-kc-btn--secondary:hover,
.reader-kc-btn--secondary:focus-visible {
    background: var(--row-pressed);
}

.reader-kc-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .reader-kc-test,
    .reader-kc-btn {
        transition: none;
    }
}

/* Per-chapter "View Progress Report" action under the test cards. A
   chapter-level action, so it reads as a link rather than carrying the same
   weight as the per-quiz buttons. */
.reader-kc-report-link {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-height: 44px;
    margin: 10px 0 0;
    padding: 2px 4px;
    border: 0;
    background: transparent;
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 700;
    color: var(--accent-text);
    cursor: pointer;
}

.reader-kc-report-link:hover,
.reader-kc-report-link:focus-visible {
    text-decoration: underline;
}

/* ── Knowledge Check progress report (drill-in) ─────────────── */

/* Progress report: comparison card with delta chip, outcome-grouped objectives
   with question pips, review sections ordered by missed count, sticky footer. */

.reader-kcr {
    display: grid;
    gap: 1.15rem;
}

/* ── Score comparison card ── */

.reader-kcr-hero {
    padding: 1rem 1rem 0.875rem;
    background: var(--paper);
    border: 1px solid var(--card-border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
}

.reader-kcr-scores {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.reader-kcr-cell {
    flex: 1;
    min-width: 0;
    display: grid;
    align-content: start;
    justify-items: start;
}

.reader-kcr-cell--post {
    text-align: right;
    justify-items: end;
}

.reader-kcr-cell-kicker {
    font-size: 0.594rem;
    font-weight: 800;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--muted);
}

.reader-kcr-cell--post .reader-kcr-cell-kicker {
    color: var(--accent-text);
}

.reader-kcr-cell-value {
    margin-top: 5px;
    display: inline-flex;
    align-items: baseline;
    gap: 2px;
    font-size: 1.875rem;
    font-weight: 800;
    letter-spacing: -0.033em;
    line-height: 1;
    color: var(--muted-2);
    font-variant-numeric: tabular-nums;
}

.reader-kcr-cell--post .reader-kcr-cell-value {
    color: var(--ink);
}

.reader-kcr-cell-unit {
    font-size: 0.875rem;
    font-weight: 800;
    letter-spacing: normal;
}

.reader-kcr-cell--post .reader-kcr-cell-unit {
    color: var(--accent);
}

.reader-kcr-cell-detail {
    margin-top: 5px;
    font-size: 0.719rem;
    font-weight: 600;
    color: var(--muted);
}

.reader-kcr-cell--post .reader-kcr-cell-detail {
    color: var(--body-secondary);
}

.reader-kcr-cell-date {
    margin-top: 1px;
    font-size: 0.6875rem;
    font-weight: 500;
    color: var(--meta-tertiary);
}

.reader-kcr-cell-none {
    margin-top: 6px;
    font-size: 0.85rem;
    color: var(--muted);
}

/* Delta chip: the words carry the meaning; the tint only reinforces it. */
.reader-kcr-delta-col {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding-top: 14px;
}

.reader-kcr-delta {
    display: inline-flex;
    align-items: center;
    padding: 4px 9px;
    border-radius: var(--radius-full);
    font-size: 0.6875rem;
    font-weight: 800;
    color: var(--slate-2);
    background: var(--seg-track);
}

.reader-kcr-delta--improved {
    background: var(--success-tint);
    color: var(--success-text);
}

.reader-kcr-delta--regressed {
    background: var(--danger-tint);
    color: var(--danger-text);
}

.reader-kcr-delta-arrow {
    display: inline-flex;
    color: var(--slate-2);
}

/* Overall pre/post mini bars under the divider. */
.reader-kcr-minibars {
    display: grid;
    gap: 6px;
    margin-top: 14px;
    padding-top: 13px;
    border-top: 1px solid var(--row-divider);
}

.reader-kcr-bar-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.reader-kcr-bar-label {
    width: 30px;
    flex-shrink: 0;
    font-size: 0.5625rem;
    font-weight: 800;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--muted-2);
}

.reader-kcr-bar-label--post {
    color: var(--accent-text);
}

.reader-kcr-bar-track {
    flex: 1;
    height: 7px;
    border-radius: 4px;
    background: var(--progress-track);
    overflow: hidden;
}

.reader-kcr-bar-fill {
    height: 100%;
    border-radius: inherit;
    animation: reader-kcr-grow 400ms ease-out;
}

/* Pre = slate, Post = teal: both ≥3:1 against the track (§9.2), and every
   bar carries a Pre/Post text label plus the score, so hue never carries
   the meaning alone (§9.3). */
.reader-kcr-bar-fill--pre {
    background: var(--slate-2);
}

.reader-kcr-bar-fill--post {
    background: var(--accent);
}

@keyframes reader-kcr-grow {
    from { width: 0; }
}

/* ── Section heads (objectives / review) ── */

.reader-kcr-sechead {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 2px 4px;
}

.reader-kcr-heading {
    margin: 0;
    font-size: 0.625rem;
    font-weight: 800;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--accent);
}

.reader-kcr-sechead-rule {
    flex: 1;
    height: 1px;
    align-self: center;
    background: var(--card-border);
}

.reader-kcr-sechead-count {
    font-size: 0.656rem;
    font-weight: 700;
    color: var(--muted-2);
}

.reader-kcr-helper {
    margin: 0 2px 12px;
    font-size: 0.719rem;
    font-weight: 500;
    line-height: 1.45;
    color: var(--muted-2);
}

/* ── Objective groups ── */

.reader-kcr-group {
    margin-bottom: 16px;
}

.reader-kcr-group:last-child {
    margin-bottom: 0;
}

.reader-kcr-group-head {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 2px 8px;
}

.reader-kcr-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.reader-kcr-dot--needs {
    background: var(--danger);
}

.reader-kcr-dot--progressing {
    background: var(--accent);
}

.reader-kcr-dot--mastered {
    background: var(--success);
}

.reader-kcr-group-label {
    margin: 0;
    font-size: 0.75rem;
    font-weight: 800;
    letter-spacing: -0.008em;
    color: var(--slate);
}

.reader-kcr-group-count {
    font-size: 0.6875rem;
    font-weight: 700;
    color: var(--muted-2);
}

.reader-kcr-objs {
    display: grid;
    gap: 8px;
}

/* Detailed objective card: status-colored left edge + PRE/POST pip rows. */
.reader-kcr-obj {
    background: var(--paper);
    border: 1px solid var(--card-border);
    border-left-width: 3px;
    border-radius: var(--radius-card);
    padding: 12px 13px 11px;
    box-shadow: var(--shadow-xs);
}

.reader-kcr-obj--needs {
    border-left-color: var(--danger);
}

.reader-kcr-obj--progressing {
    border-left-color: var(--accent);
}

.reader-kcr-obj--mastered {
    border-left-color: var(--success);
}

.reader-kcr-obj-kicker {
    margin: 0 0 5px;
    font-size: 0.5625rem;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted-2);
}

.reader-kcr-obj-title {
    margin: 0;
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.58;
    color: var(--reading-text);
    text-wrap: pretty;
}

.reader-kcr-obj-rows {
    display: grid;
    gap: 5px;
    margin-top: 10px;
}

.reader-kcr-piprow {
    display: flex;
    align-items: center;
    gap: 8px;
}

.reader-kcr-pip-label {
    width: 30px;
    flex-shrink: 0;
    font-size: 0.5625rem;
    font-weight: 800;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--muted-2);
}

.reader-kcr-pip-label--post {
    color: var(--accent-text);
}

/* One pip per question: ✓/✗ glyph shape + the fraction text carry the
   result, never the tint alone (§9.3). */
.reader-kcr-pips {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    flex: 1;
    min-width: 0;
}

.reader-kcr-pip {
    width: 15px;
    height: 15px;
    border-radius: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.reader-kcr-pip--ok {
    background: var(--success-tint);
    color: var(--success-text);
}

.reader-kcr-pip--miss {
    background: var(--danger-tint);
    color: var(--danger);
}

.reader-kcr-frac {
    flex-shrink: 0;
    font-size: 0.656rem;
    font-weight: 700;
    color: var(--muted-2);
    font-variant-numeric: tabular-nums;
}

.reader-kcr-frac--post {
    color: var(--body-secondary);
}

.reader-kcr-pips-none {
    flex: 1;
    font-size: 0.6875rem;
    color: var(--muted);
}

/* Mastered objectives collapse into one compact checked list. */
.reader-kcr-mastered {
    list-style: none;
    margin: 0;
    padding: 0;
    background: var(--paper);
    border: 1px solid var(--card-border);
    border-radius: var(--radius-card);
    overflow: hidden;
}

.reader-kcr-mastered-row {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 11px 13px;
    border-bottom: 1px solid var(--row-divider);
}

.reader-kcr-mastered-row:last-child {
    border-bottom: 0;
}

.reader-kcr-mcheck {
    width: 14px;
    height: 14px;
    margin-top: 2px;
    border-radius: 50%;
    background: var(--success-tint);
    color: var(--success-text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.reader-kcr-mastered-title {
    flex: 1;
    min-width: 0;
    font-size: 0.781rem;
    font-weight: 500;
    line-height: 1.55;
    color: var(--muted-2);
    text-wrap: pretty;
}

.reader-kcr-mastered-score {
    flex-shrink: 0;
    margin-top: 2px;
    font-size: 0.656rem;
    font-weight: 700;
    color: var(--success-text);
    font-variant-numeric: tabular-nums;
}

.reader-kcr-note {
    margin: 0;
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--muted);
}

/* ── Review sections ── */

.reader-kcr-review-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 8px;
}

.reader-kcr-sec {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    padding: 11px 12px;
    background: var(--paper);
    border: 1px solid var(--card-border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-xs);
    text-align: left;
    cursor: pointer;
    transition: background 150ms ease, border-color 150ms ease;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
}

.reader-kcr-sec:hover {
    border-color: var(--accent);
    background: var(--row-pressed);
}

.reader-kcr-sec:focus-visible {
    /* --accent, not --accent-bright: the bright teal measures ~2.8:1 on the
       light paper surface (it's tuned for navy chrome); --accent holds ≥3:1
       against paper in both themes (§5.2/§9.2). */
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.reader-kcr-sec--current {
    border-color: var(--accent-soft);
}

/* Missed-count badge, tinted by severity (≥3 / 2 / 1). */
.reader-kcr-sec-badge {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: var(--radius-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.719rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

.reader-kcr-sec-badge--high {
    background: var(--danger-tint);
    color: var(--danger-text);
}

.reader-kcr-sec-badge--mid {
    background: var(--warn-tint);
    color: var(--warn-text);
}

.reader-kcr-sec-badge--low {
    background: var(--seg-track);
    color: var(--body-secondary);
}

.reader-kcr-sec-main {
    flex: 1;
    min-width: 0;
}

.reader-kcr-sec-title {
    display: block;
    font-family: var(--font-reading);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--ink);
    text-wrap: pretty;
}

.reader-kcr-sec-meta {
    display: block;
    margin-top: 3px;
    font-size: 0.656rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--muted-2);
}

.reader-kcr-sec-meta--current {
    color: var(--accent);
}

.reader-kcr-sec-arrow {
    flex-shrink: 0;
    display: inline-flex;
    color: var(--muted-2);
}

/* ── Sticky action footer ── */
/* Bleeds over .reader-kc padding and sticks to the scrollport bottom. The border
   carries the separation; an upward navy-alpha shadow would vanish in dark. */
.reader-kcr-footer {
    position: sticky;
    bottom: 0;
    z-index: 2;
    display: flex;
    gap: 10px;
    margin: 0 -1rem -1rem;
    padding: 16px 1rem 18px;
    background: var(--panel-bg);
    border-top: 1px solid var(--card-border);
}

.reader-kcr-footer .reader-kc-btn {
    min-height: 52px;
    font-size: 0.9375rem;
}

.reader-kcr-footer .reader-kc-btn--primary {
    flex: 1.25 1 0;
}

.reader-kcr-footer .reader-kc-btn--secondary {
    flex: 1 1 0;
    background: var(--paper);
    border-color: var(--input-border);
}

.reader-kcr-footer .reader-kc-btn--secondary:hover,
.reader-kcr-footer .reader-kc-btn--secondary:focus-visible {
    background: var(--row-pressed);
}

/* With a footer present, drop the scroll container's bottom padding (and the
   panel's compensating bleed margin) so bottom: 0 means the true bottom. The
   mobile tab-bar layout overrides this again below. */
.reader-panel-content:has(.reader-kcr-footer) {
    padding-bottom: 0;
}

.reader-panel-content:has(.reader-kcr-footer) .reader-kc {
    margin-bottom: 0;
}

@media (prefers-reduced-motion: reduce) {
    .reader-kcr-bar-fill {
        animation: none;
    }

    .reader-kcr-sec {
        transition: none;
    }
}

/* ============================================================
   Highlight / Note Colors
   ============================================================ */

.reader-annotation-highlight {
    border-radius: 0.2rem;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
}

/* Inline note indicator: a 22px teal speech-bubble circle trailing the noted
   phrase (replaces the old gray "N" badge). The ::before overlay expands the
   effective touch target to ≥44px without adding visual bulk. */
.reader-note-anchor {
    position: relative;
    z-index: 2;
    width: 22px;
    min-width: 22px;
    height: 22px;
    border: none;
    border-radius: 999px;
    padding: 0;
    margin-left: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: 2px;
    background: var(--accent-soft);
    color: var(--accent-text);
    line-height: 1;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
}

.reader-note-anchor::before {
    content: "";
    position: absolute;
    inset: -11px;
    max-width: none;
    border-radius: 999px;
}

/* The badge wears the note's pen color: tint background (matching the wash on
   the phrase) with the pen's chip-text tone for the bubble icon. Teal base
   above stays as the fallback for legacy pen colors. */
.reader-note-anchor.markup_bg_1 { background: var(--pen-yellow-tint); color: var(--pen-yellow-chip-text); }
.reader-note-anchor.markup_bg_2 { background: var(--pen-pink-tint); color: var(--pen-pink-chip-text); }
.reader-note-anchor.markup_bg_3 { background: var(--pen-green-tint); color: var(--pen-green-chip-text); }
.reader-note-anchor.markup_bg_5 { background: var(--pen-blue-tint); color: var(--pen-blue-chip-text); }

/* ============================================================
   View-annotation bottom sheet (AnnotationViewSheet)
   Same card family as the selection popup, plus a scrim: modal
   sheets dim the page, the transient selection toolbar does not.
   ============================================================ */

/* Scrim for the modal sheets. Class-toggled opacity by default so a permanently
   mounted scrim never replays its animation; -enter adds a mount fade for the
   scrims that render conditionally. */
.annotation-sheet-scrim {
    position: fixed;
    inset: 0;
    /* Under the sheet wraps (1260) and over the reader chrome/find bar. */
    z-index: 1255;
    background: var(--scrim);
    opacity: 0;
    pointer-events: none;
    transition: opacity .2s ease;
}

.annotation-sheet-scrim.visible {
    opacity: 1;
    pointer-events: auto;
}

.annotation-sheet-scrim-enter {
    animation: annotation-scrim-fade .2s ease;
}

.annotation-view-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

/* Kind chip: HIGHLIGHT wears the pen's chip pair (bg/text of the same hue,
   see tokens.css); NOTE wears the teal pair. */
.annotation-view-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    padding: 5px 11px;
    border-radius: 9px;
}

.annotation-view-chip-note {
    background: var(--accent-soft);
    color: var(--accent-text);
}

.annotation-view-chip.markup_bg_1 { background: var(--pen-yellow-chip-bg); color: var(--pen-yellow-chip-text); }
.annotation-view-chip.markup_bg_2 { background: var(--pen-pink-chip-bg); color: var(--pen-pink-chip-text); }
.annotation-view-chip.markup_bg_3 { background: var(--pen-green-chip-bg); color: var(--pen-green-chip-text); }
.annotation-view-chip.markup_bg_5 { background: var(--pen-blue-chip-bg); color: var(--pen-blue-chip-text); }

.annotation-view-chip-swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    flex-shrink: 0;
}

.annotation-view-chip-swatch.markup_bg_1 { background: var(--pen-yellow-swatch); }
.annotation-view-chip-swatch.markup_bg_2 { background: var(--pen-pink-swatch); }
.annotation-view-chip-swatch.markup_bg_3 { background: var(--pen-green-swatch); }
.annotation-view-chip-swatch.markup_bg_5 { background: var(--pen-blue-swatch); }

.annotation-view-note-text {
    margin: 0;
    font-size: 15.5px;
    font-weight: 600;
    color: var(--reading-text);
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
}

.annotation-view-actions {
    display: flex;
    align-items: stretch;
    gap: 10px;
}

.annotation-view-actions .annotation-btn-lead {
    flex: 1.4;
}

.annotation-btn-destructive {
    flex: 1;
    background: var(--paper);
    border: 1.5px solid var(--danger-border);
    color: var(--danger);
}

.annotation-btn-destructive:hover,
.annotation-btn-destructive:active {
    background: var(--danger-active);
}

@keyframes annotation-scrim-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* Desktop/web: the sheet family docks bottom-center at a card width instead
   of spanning the whole viewport. */
@media (min-width: 768px) {
    .annotation-popup-wrap {
        left: 0;
        right: 0;
        margin: 0 auto;
        width: min(440px, calc(100vw - 24px));
    }
}

.reader-annotation-highlight[data-annotation-id] {
    cursor: pointer;
}

.reader-note-anchor[data-annotation-id] {
    cursor: pointer;
}

.markup_bg_4 {
    background: var(--pen-orange);
}

.markup_bg_6 {
    background: var(--pen-green-2);
}

/* ============================================================
   Annotation sheet family: shared card/swatch/button styles
   One container for every annotation and reading-settings surface:
   selection popup, view sheet, text-size sheet, Notebook picker.
   ============================================================ */

.annotation-card {
    background: var(--paper);
    border: 1px solid var(--card-border);
    border-radius: 26px;
    box-shadow: 0 -2px 10px rgba(16, 42, 67, .05), 0 18px 50px rgba(16, 42, 67, .22);
}

.annotation-swatch-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 0 2px;
}

.annotation-swatch {
    width: 46px;
    height: 46px;
    border-radius: 50%;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    background: var(--paper);
    border: 2.5px solid var(--card-border);
    box-shadow: none;
    transition: border-color 150ms ease, box-shadow 150ms ease;
}

.annotation-swatch.active {
    border-color: var(--navy);
    box-shadow: 0 0 0 4px rgba(16, 42, 67, .07);
}

/* Notebook-card variant: as close to the sheet's 46px swatch as the card
   footer affords. 38px is the ceiling that keeps a note card's footer
   ("Go to passage" + 4 swatches) on one line on 360px-wide phones. */
.annotation-swatch-sm {
    width: 38px;
    height: 38px;
    border-width: 2px;
}

.annotation-swatch-dot {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: inset 0 0 0 1px rgba(16, 42, 67, .10);
    color: var(--navy);  /* theme-ok: check on the vivid light swatch; the dark block overrides dot fill to the tint and this check to --ink */
}

.annotation-swatch-sm .annotation-swatch-dot {
    width: 25px;
    height: 25px;
}

.annotation-swatch-check {
    stroke-width: 3;
}

.annotation-popup-color-label {
    font-size: 13px;
    font-weight: 700;
    color: var(--ink);
    margin-left: auto;
}

.annotation-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    min-height: 50px;
    border-radius: 15px;
    border: none;
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: 15px;
    font-weight: 700;
    transition: background 150ms ease, border-color 150ms ease, transform 100ms ease;
}

.annotation-btn:active {
    transform: scale(0.97);
}

.annotation-btn-primary {
    flex: 1.5;
    background: var(--btn-navy-bg);
    color: #fff;
    font-size: 15.5px;
}

.annotation-btn-primary:hover {
    background: var(--btn-navy-hover);
}

.annotation-btn-secondary {
    flex: 1;
    background: var(--paper);
    border: 1.5px solid var(--input-border);
    color: var(--ink);
}

.annotation-btn-secondary:hover {
    background: var(--row-pressed);
    border-color: var(--btn-navy-bg);
}

.annotation-btn-icon {
    flex: none;
    width: 50px;
    background: var(--row-pressed);
    color: var(--slate-2);
}

.annotation-btn-icon:hover {
    background: var(--card-border);
}

.annotation-btn-icon-sm {
    width: 34px;
    height: 34px;
    min-height: 34px;
    border-radius: 10px;
}

.annotation-btn-save {
    flex: 1.4;
    background: var(--accent-fill);
    color: #fff;
}

.annotation-btn-save:hover {
    background: var(--btn-fill-hover);
}

.annotation-btn-save:disabled {
    opacity: .55;
    cursor: not-allowed;
}

.annotation-btn-dot {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .45);
    display: inline-block;
}

/* ============================================================
   Annotation selection popup (AnnotationSelectionPopup)
   ============================================================ */

.annotation-popup-wrap {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: calc(26px + env(safe-area-inset-bottom));
    /* Above the reader overlay family (inline-popup ~1250) but below
       action-sheet/note-editor (1300) so a sheet can still layer on top. */
    z-index: 1260;
    transform: translateY(115%);
    opacity: 0;
    pointer-events: none;
    transition: transform .32s cubic-bezier(.2, .85, .2, 1), opacity .24s;
}

.annotation-popup-wrap.visible {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
}

.annotation-popup {
    padding: 18px 18px 16px;
    display: grid;
    gap: 16px;
}

.annotation-popup-selected {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 0 2px;
    /* Grid item that can shrink below its content so the quote inside truncates
       instead of forcing the fixed-width card wider. */
    min-width: 0;
}

.annotation-popup-kicker {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 1.3px;
    color: var(--accent);
    text-transform: uppercase;
    flex-shrink: 0;
}

/* Quoted book text, reusing the app-wide quoted-passage size/color (see
   .reader-notebook-quote) rather than a bespoke px value. */
.annotation-popup-quote {
    flex: 1;
    min-width: 0;
    font-family: var(--font-reading);
    font-style: italic;
    font-size: 0.98rem;
    line-height: 1.55;
    color: var(--slate);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border-left: 2px solid var(--accent);
    padding-left: 10px;
}

/* Note-compose variant: wrap the quoted source (clamped) so long selections
   never overflow the card horizontally. */
.annotation-popup-quote-block {
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    text-overflow: initial;
}

.annotation-popup-actions {
    display: flex;
    align-items: stretch;
    gap: 10px;
}

/* Web's Copy link makes four buttons, which overrun a 360px-wide card at 50px
   each; 44px still meets the minimum touch target. */
@media (max-width: 379.98px) {
    .annotation-popup-actions:has(> :nth-child(4)) > .annotation-btn-icon {
        width: 44px;
    }
}

.annotation-note-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.annotation-note-header-label {
    display: flex;
    align-items: center;
    gap: 9px;
}

.annotation-note-title {
    font-size: 15.5px;
    font-weight: 800;
    color: var(--ink);
}

.annotation-note-textarea {
    width: 100%;
    height: 84px;
    resize: none;
    border: 1.5px solid var(--input-border);
    border-radius: 14px;
    padding: 12px 14px;
    font-family: inherit;
    font-size: 16px;
    line-height: 1.5;
    color: var(--reading-text);
    background: var(--input-bg);
    outline: none;
}

.annotation-note-textarea:focus {
    border-color: var(--accent);
}

.annotation-note-actions {
    display: flex;
    gap: 10px;
}

@media (prefers-reduced-motion: reduce) {
    .annotation-popup-wrap {
        transition: opacity .15s linear;
    }
}

/* ============================================================
   Annotation save-confirmation toast (AnnotationToast)
   ============================================================ */

.annotation-toast-wrap {
    max-width: calc(100vw - 24px);
    width: max-content;
    position: fixed;
    left: 50%;
    bottom: calc(34px + env(safe-area-inset-bottom));
    /* Above the selection popup (1260) so a toast is never hidden behind it. */
    z-index: 1270;
    transform: translate(-50%, 140%);
    opacity: 0;
    pointer-events: none;
    transition: transform .3s cubic-bezier(.2, .8, .2, 1), opacity .24s;
}

/* On the mobile host the toast rises above the bottom tab bar (the body class
   is set only while the MAUI reader is mounted; the toast portals to the
   layout root, outside .reader, so it can't scope off the shell). */
body.reader-safe-area-white .annotation-toast-wrap {
    bottom: calc(76px + env(safe-area-inset-bottom));
}

.annotation-toast-wrap.visible {
    transform: translate(-50%, 0);
    opacity: 1;
    pointer-events: auto;
}

.annotation-toast {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--snackbar);
    color: #E7EEF5;
    font-size: 13.5px;
    font-weight: 600;
    padding: 11px 18px;
    border-radius: 30px;
    box-shadow: 0 12px 30px rgba(8, 20, 35, .4);
    white-space: normal;
}

.annotation-toast-undoable {
    padding-right: 12px;
}

.annotation-toast-undo {
    background: none;
    border: none;
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: 13.5px;
    font-weight: 800;
    color: var(--accent-on-navy);
    padding: 6px 8px;
    margin: -6px 0;
}

.annotation-toast-dot {
    width: 13px;
    height: 13px;
    border-radius: 50%;
    flex-shrink: 0;
    display: inline-block;
}

@media (prefers-reduced-motion: reduce) {
    .annotation-toast-wrap {
        transition: opacity .15s linear;
    }
}

/* ============================================================
   First-open reader tour (ReaderTour)
   reader.js writes the --reader-tour-* geometry on the root element.
   ============================================================ */

/* Blocker and scrim sit under the selection popup (1260), which step 3
   shows undimmed; the card sits above it. */
.reader-tour-blocker {
    position: fixed;
    inset: 0;
    z-index: 1255;
}

.reader-tour-spot {
    position: fixed;
    z-index: 1255;
    left: var(--reader-tour-spot-x, 50%);
    top: var(--reader-tour-spot-y, 50%);
    width: var(--reader-tour-spot-w, 0px);
    height: var(--reader-tour-spot-h, 0px);
    border-radius: var(--radius-xl);
    /* Ring first, so the scrim's spread never dims it. */
    box-shadow: 0 0 0 2px var(--accent-on-navy), 0 0 0 200vmax var(--scrim);
    opacity: 0;
    pointer-events: none;
    transition: left .4s var(--chrome-ease), top .4s var(--chrome-ease),
                width .4s var(--chrome-ease), height .4s var(--chrome-ease),
                border-radius .4s var(--chrome-ease), opacity .2s ease-out;
}

.reader-tour-spot[data-target="sentence"] {
    border-radius: var(--radius-md);
}

.reader-tour-spot[data-target="reader-button"] {
    border-radius: var(--radius-full);
}

:root.reader-tour-no-spot .reader-tour-spot {
    box-shadow: 0 0 0 200vmax var(--scrim);
}

/* Starts at the bottom edge, so it still shows (unlit) if reader.js never places it. */
.reader-tour-card {
    position: fixed;
    z-index: 1265;
    left: 16px;
    right: 16px;
    top: var(--reader-tour-card-top, auto);
    bottom: var(--reader-tour-card-bottom, 16px);
    padding: 16px 18px;
    border-radius: var(--radius-xl);
    background: var(--paper);
    box-shadow: var(--shadow-modal);
    font-family: var(--font-ui);
    animation: reader-tour-card-in .2s ease-out;
    transition: top .4s var(--chrome-ease), bottom .4s var(--chrome-ease);
}

@keyframes reader-tour-card-in {
    from { opacity: 0; }
}

/* The scrim waits for reader.js to measure the first target. */
:root.reader-tour-placed .reader-tour-spot {
    opacity: 1;
}

.reader-tour-card:focus,
.reader-tour-title:focus {
    outline: none;
}

.reader-tour-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}

.reader-tour-count {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--eyebrow);
}

.reader-tour-skip,
.reader-tour-back {
    border: 0;
    background: none;
    color: var(--slate-2);
    font: inherit;
    font-weight: 700;
    cursor: pointer;
}

/* 44px to tap, without pushing the header row taller. */
.reader-tour-skip {
    min-height: 44px;
    margin: -12px -8px;
    padding: 0 8px;
    border-radius: var(--radius-sm);
    font-size: 0.8125rem;
}

.reader-tour-title {
    margin: 0 0 6px;
    font-size: 1.125rem;
    font-weight: 800;
    line-height: 1.25;
    color: var(--ink);
}

.reader-tour-body {
    margin: 0;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--body-secondary);
    text-wrap: pretty;
}

.reader-tour-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 16px;
}

.reader-tour-dots {
    display: flex;
    gap: 6px;
}

.reader-tour-dot {
    width: 7px;
    height: 7px;
    border-radius: 4px;
    background: var(--control-border-idle);
    transition: width .25s, background-color .25s;
}

.reader-tour-dot.active {
    width: 18px;
    background: var(--accent);
}

.reader-tour-actions {
    display: flex;
    align-items: center;
    gap: 6px;
}

.reader-tour-back {
    min-height: 44px;
    padding: 0 12px;
    border-radius: var(--radius-md);
    font-size: 0.875rem;
}

.reader-tour-next {
    min-height: 44px;
    padding: 0 20px;
    border: 0;
    border-radius: var(--radius-md);
    background: var(--btn-navy-bg);
    color: #fff;
    font: inherit;
    font-size: 0.875rem;
    font-weight: 800;
    cursor: pointer;
}

@media (hover: hover) {
    .reader-tour-skip:hover,
    .reader-tour-back:hover {
        background: var(--row-pressed);
    }

    .reader-tour-next:hover {
        background: var(--btn-navy-hover);
    }
}

.reader-tour-skip:focus-visible,
.reader-tour-back:focus-visible,
.reader-tour-next:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .reader-tour-spot,
    .reader-tour-card,
    .reader-tour-dot {
        transition: none;
    }

    .reader-tour-card {
        animation: none;
    }
}

/* ============================================================
   Unified pen palette: context-scoped color rules
   Two classes beat the flat .markup_bg_N rules above, so these win
   without removing them. Retired markup_bg_4/6 still resolve through
   the flat rules so already-saved annotations keep their look.
   ============================================================ */

.reader-annotation-highlight.markup_bg_1 { background: var(--pen-yellow-tint); }
.reader-annotation-highlight.markup_bg_2 { background: var(--pen-pink-tint); }
.reader-annotation-highlight.markup_bg_3 { background: var(--pen-green-tint); }
.reader-annotation-highlight.markup_bg_5 { background: var(--pen-blue-tint); }

.reader-annotation-highlight.reader-note-tint.markup_bg_1 { background: var(--pen-yellow-note-tint); }
.reader-annotation-highlight.reader-note-tint.markup_bg_2 { background: var(--pen-pink-note-tint); }
.reader-annotation-highlight.reader-note-tint.markup_bg_3 { background: var(--pen-green-note-tint); }
.reader-annotation-highlight.reader-note-tint.markup_bg_5 { background: var(--pen-blue-note-tint); }

.annotation-swatch-dot.markup_bg_1 { background: var(--pen-yellow-swatch); }
.annotation-swatch-dot.markup_bg_2 { background: var(--pen-pink-swatch); }
.annotation-swatch-dot.markup_bg_3 { background: var(--pen-green-swatch); }
.annotation-swatch-dot.markup_bg_5 { background: var(--pen-blue-swatch); }

.annotation-btn-dot.markup_bg_1 { background: var(--pen-yellow-swatch); }
.annotation-btn-dot.markup_bg_2 { background: var(--pen-pink-swatch); }
.annotation-btn-dot.markup_bg_3 { background: var(--pen-green-swatch); }
.annotation-btn-dot.markup_bg_5 { background: var(--pen-blue-swatch); }

.annotation-toast-dot.markup_bg_1 { background: var(--pen-yellow-swatch); }
.annotation-toast-dot.markup_bg_2 { background: var(--pen-pink-swatch); }
.annotation-toast-dot.markup_bg_3 { background: var(--pen-green-swatch); }
.annotation-toast-dot.markup_bg_5 { background: var(--pen-blue-swatch); }

.reader-notebook-quote.markup_bg_1,
.reader-annotation-chip.markup_bg_1,
.reader-annotation-chip-swatch.markup_bg_1 { background: var(--pen-yellow-tint); }
.reader-notebook-quote.markup_bg_2,
.reader-annotation-chip.markup_bg_2,
.reader-annotation-chip-swatch.markup_bg_2 { background: var(--pen-pink-tint); }
.reader-notebook-quote.markup_bg_3,
.reader-annotation-chip.markup_bg_3,
.reader-annotation-chip-swatch.markup_bg_3 { background: var(--pen-green-tint); }
.reader-notebook-quote.markup_bg_5,
.reader-annotation-chip.markup_bg_5,
.reader-annotation-chip-swatch.markup_bg_5 { background: var(--pen-blue-tint); }

/* Note chips wear their pen's chip pair (parity with highlight chips and the
   view sheet's NOTE chip); the teal -note pair is only the no-color fallback.
   Three classes so these out-specify the raw-tint rules above. */
.reader-annotation-chip.reader-annotation-chip-note.markup_bg_1 { background: var(--pen-yellow-chip-bg); color: var(--pen-yellow-chip-text); }
.reader-annotation-chip.reader-annotation-chip-note.markup_bg_2 { background: var(--pen-pink-chip-bg); color: var(--pen-pink-chip-text); }
.reader-annotation-chip.reader-annotation-chip-note.markup_bg_3 { background: var(--pen-green-chip-bg); color: var(--pen-green-chip-text); }
.reader-annotation-chip.reader-annotation-chip-note.markup_bg_5 { background: var(--pen-blue-chip-bg); color: var(--pen-blue-chip-text); }

/* Live preview on the uncommitted selection: Blazor sets
   --selection-preview-color inline on .reader-content and this ::selection rule
   picks it up, so the browser's native selection range is never touched. */
.reader-content ::selection {
    background: var(--selection-preview-color, revert);
}

/* Declared AFTER the annotation colors so an active search wins at equal
   specificity on a span that also carries an annotation; the annotation color
   returns when the highlight clears. Teal so it never reads as a pen color.
   The span qualifier ties Bootstrap's .table cell rule, so hits inside book
   tables still show (SD-4433); pen colors still outrank it. */
span.reader-search-hit {
    background: var(--accent-soft);
    color: var(--accent-deep);
    border-radius: 0.2rem;
    padding: 0 0.12em;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
}

span.reader-search-hit-active {
    background: var(--accent-soft);
    color: var(--accent-text);
    font-weight: 600;
    border-radius: 4px;
    padding: 1px 4px;
    box-shadow: 0 0 0 2px var(--accent);
    outline: none;
}

/* ============================================================
   In-reader find bar: term + counter + stepper, then scope links
   ============================================================ */

.reader-findbar {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(1rem + env(safe-area-inset-bottom));
    z-index: 30; /* above the bottombar (25) and scrim (20) */
    width: calc(100% - 2rem);
    max-width: 400px;
    background: var(--paper);
    /* One step darker than --card-border, plus the heavier find-bar shadow:
       the white card floats over the pure-white reading canvas and washed out
       with the handoff's lighter card shadow. */
    border: 1px solid var(--hairline-2);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-findbar);
    overflow: hidden;
    font-family: var(--font-ui);
    color: var(--ink);
    animation: reader-search-rise 280ms var(--ease-out);
}

.reader-findbar-main {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 8px 9px 14px;
}

.reader-findbar-term {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    min-width: 0;
    padding: 6px 8px;
    margin-left: -8px;
    border: none;
    border-radius: 10px;
    background: transparent;
    color: var(--ink);
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out);
}

.reader-findbar-term svg {
    flex-shrink: 0;
    color: var(--slate-2);
}

.reader-findbar-term:hover {
    background: var(--row-pressed);
}

.reader-findbar-term-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 15px;
    font-weight: 700;
}

.reader-findbar-count {
    flex: 0 0 auto;
    color: var(--match-counter);
    font-size: 13px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.reader-findbar-nohit {
    color: var(--match-counter);
}

.reader-findbar-btn,
.reader-findbar-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    padding: 0;
    border: none;
    border-radius: 11px;
    background: var(--row-pressed);
    color: var(--slate);
    line-height: 1;
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out);
}

.reader-findbar-btn:hover:not(:disabled) {
    background: var(--card-border);
}

/* Next is the primary step: navy, like the design's forward affordance. */
.reader-findbar-btn-next {
    background: var(--btn-navy-bg);
    color: #fff;
}

.reader-findbar-btn-next:hover:not(:disabled) {
    background: var(--btn-navy-hover);
}

.reader-findbar-btn:disabled {
    opacity: 0.35;
    cursor: default;
}

.reader-findbar-close {
    background: transparent;
    color: var(--muted);
}

.reader-findbar-close:hover {
    background: var(--row-pressed);
}

.reader-findbar-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    border-top: 1px solid var(--row-divider);
    padding: 9px 14px;
}

.reader-findbar-scopelabel {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--meta-quiet);
}

.reader-findbar-viewall {
    border: none;
    background: transparent;
    padding: 0;
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 700;
    color: var(--accent);
    cursor: pointer;
}

/* Boundary hand-off pill (mobile): floats above the tab bar once the user
   sits on the last in-page match; the explicit path into the next section. */
.reader-find-handoff {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(6rem + env(safe-area-inset-bottom));
    z-index: 30;
    display: inline-flex;
    align-items: center;
    gap: 11px;
    max-width: calc(100% - 2rem);
    border: none;
    border-radius: 14px;
    background: var(--btn-navy-bg);
    color: #fff;
    padding: 11px 16px;
    box-shadow: 0 12px 30px rgba(16, 42, 67, 0.3);
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

.reader-find-handoff-label {
    flex-shrink: 0;
}

.reader-find-handoff-divider {
    flex-shrink: 0;
    width: 1px;
    height: 16px;
    background: rgba(255, 255, 255, 0.25);
}

.reader-find-handoff-next {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    color: var(--accent-on-navy);
    font-weight: 700;
}

.reader-find-handoff-next svg {
    flex-shrink: 0;
}

.reader-find-handoff-next-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Touch with the native top bar: dock under it instead. The keyboard is down in
   this state and the matched text must stay visible below the card. Narrow web
   windows keep the bottom dock. */
@media (max-width: 767.98px) {
    .reader:not(.reader-web) .reader-findbar {
        top: calc(var(--reader-topbar-h) + var(--safe-area-top) + 12px);
        bottom: auto;
        left: 16px;
        right: 16px;
        transform: none;
        width: auto;
        max-width: none;
    }
}

/* On the web host the reading area has no bottom toolbar, so the card docks
   bottom-center of the reading area (matching the web handoff find-bar spec)
   with a slightly wider max-width. */
.reader-web .reader-findbar {
    /* Keep the home-indicator clearance every other bottom overlay carries, so the
       bar doesn't sit in the gesture zone in landscape / on future devices. */
    bottom: calc(34px + env(safe-area-inset-bottom));
    max-width: 440px;
}

/* ============================================================
   Font Size Dialog
   ============================================================ */

.reader-fontsize-overlay {
    position: fixed;
    inset: 0;
    z-index: 1250;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    background: var(--scrim);
    animation: reader-fontsize-fade var(--duration-fast) var(--ease-out);
}

/* Slim inset scrollbar for the dense list surfaces (print section tree,
   downloads list). WebKit-only by nature; Firefox falls back to the
   `scrollbar-*` pair, everything else keeps the platform scrollbar. */
.reader-thin-scroll {
    scrollbar-width: thin;
    scrollbar-color: var(--control-border-idle) transparent;
}

.reader-thin-scroll::-webkit-scrollbar {
    width: 9px;
}

.reader-thin-scroll::-webkit-scrollbar-thumb {
    background: var(--control-border-idle);
    border-radius: 8px;
    border: 3px solid transparent;
    background-clip: content-box;
}

.reader-thin-scroll::-webkit-scrollbar-track {
    background: transparent;
}

/* ── Print dialog (web only) ───────────────────────────────────
   Same overlay family as the font-size sheet, but centered: the section
   tree needs vertical room, and print is a desktop-first surface. */

/* Width alone lets landscape phones and tablets through, so touch screens never
   get a Print entry. !important to beat Bootstrap's d-md-flex. */
@media (hover: none) {
    .reader-print-entry {
        display: none !important;
    }
}

.reader-print-overlay {
    position: fixed;
    inset: 0;
    z-index: 1250;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--scrim);
    animation: reader-fontsize-fade var(--duration-fast) var(--ease-out);
}

/* Padding lives on the individual blocks, not the dialog: the section tree
   is the only scrolling region, and it has to reach the dialog's own edges
   for its border and custom scrollbar to sit right. */
.reader-print-dialog {
    display: flex;
    flex-direction: column;
    width: calc(100% - 24px);
    max-width: 560px;
    max-height: min(88vh, 760px);
    margin: 12px;
    border-radius: var(--radius-modal);
    animation: reader-fontsize-rise var(--duration-normal) var(--ease-out);
}

.reader-print-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 20px 24px 16px;
}

.reader-print-title {
    font-size: 21px;
    font-weight: 800;
    color: var(--ink);
    letter-spacing: -0.4px;
    line-height: 1.15;
}

.reader-print-subtitle {
    font-size: 13px;
    color: var(--muted-2);
    margin-top: 3px;
}

.reader-print-close {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    border-radius: 9px;
    background: var(--row-pressed);
    color: var(--muted-2);
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out);
}

.reader-print-close:hover,
.reader-print-close:focus-visible {
    background: var(--card-border);
}

.reader-print-unavailable {
    margin: 0;
    padding: 0 24px 20px;
    color: var(--muted);
    font-size: 0.9rem;
}

/* Instruction band, restored from the legacy dialog. */
.reader-print-hint {
    display: flex;
    gap: 10px;
    margin: 0 24px 18px;
    padding: 12px 14px;
    border: 1px solid var(--accent-soft);
    border-radius: 12px;
    background: var(--accent-soft-2);
}

.reader-print-hint-icon {
    flex-shrink: 0;
    margin-top: 1px;
    color: var(--accent-deep);
}

.reader-print-hint-copy {
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--accent-text);
}

.reader-print-hint-meta {
    color: var(--muted-2);
}

.reader-print-hint-meta a {
    color: var(--accent-deep);
    font-weight: 700;
    text-decoration: underline;
}

.reader-print-modes {
    border: 0;
    margin: 0;
    padding: 0 24px 16px;
}

.reader-print-legend {
    display: block;
    font-size: 10.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 1.3px;
    color: var(--eyebrow);
    padding: 0;
    margin-bottom: 9px;
}

.reader-print-modelist {
    display: flex;
    gap: 8px;
}

/* Three equal-width option cards; the native radio stays in the markup
   (visually hidden) so keyboard and screen-reader behavior is unchanged. */
.reader-print-mode {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 5px;
    padding: 11px 12px;
    border: 1.5px solid var(--hairline);
    border-radius: 12px;
    background: var(--paper);
    color: var(--control-border-idle);
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
}

.reader-print-mode--on {
    border-color: var(--accent-fill);
    background: var(--accent-soft-2);
    color: var(--accent-fill);
}

.reader-print-mode:has(input:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.reader-print-radio {
    flex: none;
}

.reader-print-mode-label {
    font-size: 12.5px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--slate);
}

.reader-print-mode--on .reader-print-mode-label {
    color: var(--accent-text);
}

.reader-print-treehead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px;
    margin-bottom: 8px;
}

.reader-print-treehead .reader-print-legend {
    margin-bottom: 0;
}

.reader-print-treeactions {
    display: flex;
    gap: 14px;
}

.reader-print-textaction {
    padding: 0;
    border: none;
    background: none;
    font-family: var(--font-ui);
    font-size: 12px;
    font-weight: 700;
    color: var(--accent-deep);
    cursor: pointer;
}

.reader-print-textaction--quiet {
    color: var(--muted-2);
}

.reader-print-textaction:hover,
.reader-print-textaction:focus-visible {
    text-decoration: underline;
}

.reader-print-treewrap {
    flex: 1 1 auto;
    min-height: 0;
    max-height: 460px;
    overflow-y: auto;
    margin: 0 24px;
    border: 1px solid var(--hairline);
    border-radius: 13px;
    background: var(--page-surface);
}

/* Fixed-height rows: the flat row list means depth changes the left inset,
   never the row height, so the tree stays on a single rhythm. */
.reader-print-row {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding-right: 12px;
    border-bottom: 1px solid var(--row-divider);
}

.reader-print-row:last-child {
    border-bottom: none;
}

.reader-print-row:hover {
    background: var(--row-pressed);
}

.reader-print-row--on,
.reader-print-row--on:hover {
    background: var(--accent-soft-2);
}

.reader-print-caret,
.reader-print-caret-spacer {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
}

.reader-print-caret {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    background: none;
    color: var(--slate);
    cursor: pointer;
}

.reader-print-check {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 17px;
    height: 17px;
    padding: 0;
    border: 1.5px solid var(--control-border-idle);
    border-radius: 5px;
    background: var(--paper);
    color: var(--paper);   /* theme-ok: tick/dash sit on the filled --accent-fill swatch, which is a light-on-dark fill in BOTH themes */
    cursor: pointer;
}

.reader-print-check--on,
.reader-print-check--partial {
    border-color: var(--accent-fill);
    background: var(--accent-fill);
}

.reader-print-rowlabel {
    min-width: 0;
    flex: 1;
    font-size: 13px;
    font-weight: 500;
    color: var(--ink);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.reader-print-rowlabel--parent {
    font-weight: 700;
}

.reader-print-row--current .reader-print-rowlabel {
    color: var(--accent-text);
}

.reader-print-count {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem 0.8rem;
    padding: 14px 24px 0;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--muted-2);
    font-variant-numeric: tabular-nums;
}

.reader-print-limit-warning {
    color: var(--danger);
    font-weight: 600;
}

.reader-print-error {
    margin: 8px 0 0;
    padding: 0 24px;
    font-size: 0.82rem;
    color: var(--danger);
}

.reader-print-actions {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    padding: 10px 24px 20px;
}

/* The footer buttons are compact next to the 50px annotation-sheet default. */
.reader-print-btn {
    flex: none;
    min-height: 42px;
    padding: 11px 20px;
    border-radius: 11px;
    font-size: 13.5px;
}

.reader-print-actions .annotation-btn-primary {
    padding: 11px 26px;
    font-size: 13.5px;
}

.reader-print-actions .annotation-btn-primary:disabled {
    background: var(--control-border-idle);
    cursor: not-allowed;
}

/* Below the modal breakpoint the dialog goes full-screen and the footer
   pins to the bottom safe area. */
@media (max-width: 620px) {
    .reader-print-dialog {
        width: 100%;
        max-width: none;
        max-height: none;
        height: 100%;
        margin: 0;
        border: none;
        border-radius: 0;
    }

    .reader-print-treewrap {
        max-height: none;
    }

    .reader-print-actions {
        padding-bottom: calc(20px + env(safe-area-inset-bottom));
    }
}

@media (prefers-reduced-motion: reduce) {
    .reader-print-overlay,
    .reader-print-dialog {
        animation: none;
    }
}

/* Floating card from the annotation-sheet family (.annotation-card supplies the
   surface). Caps at the family's 440px width on wide viewports, still
   bottom-docked like every other sheet. */
.reader-fontsize-dialog {
    width: calc(100% - 24px);
    max-width: 440px;
    margin: 0 12px calc(26px + env(safe-area-inset-bottom));
    padding: 18px 18px 16px;
    animation: reader-fontsize-rise var(--duration-normal) var(--ease-out);
}

/* Web presents the text-size sheet as a centred modal, matching the print dialog
   it shares a toolbar with. Bottom-docking is a touch idiom that strands the
   control far from its button on desktop. Mobile keeps the sheet. */
.reader-web .reader-fontsize-overlay {
    align-items: center;
}

.reader-web .reader-fontsize-dialog {
    margin: 12px;
    border-radius: var(--radius-modal);
}

.reader-fontsize-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 4px;
}

.reader-fontsize-title {
    font-size: 15.5px;
    font-weight: 800;
    color: var(--ink);
}

.reader-fontsize-subtitle {
    margin-top: 2px;
    color: var(--meta-tertiary);
    font-size: 12.5px;
    font-weight: 600;
}

.reader-fontsize-presets {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 8px;
    margin: 14px 0 18px;
}

.reader-fontsize-preset {
    min-height: 54px;
    border: 2px solid transparent;
    background: var(--sheet-surface);
    color: var(--slate);
    border-radius: 13px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.reader-fontsize-preset:hover,
.reader-fontsize-preset:focus-visible {
    /* One visible step darker than the resting --sheet-surface fill. */
    background: var(--card-border);
}

.reader-fontsize-preset.active {
    background: var(--accent-wash);
    border-color: var(--navy);
    color: var(--navy);  /* theme-ok: overridden for dark below (.reader-fontsize-preset.active gets a light glyph) */
}

.reader-fontsize-slider {
    width: 100%;
    margin: 0;
    accent-color: var(--accent);
    /* Comfortable drag target: the input box (not the visual track) is what
       captures touches, so give it a >=44px band. */
    height: 44px;
    cursor: pointer;
}

.reader-fontsize-scale {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 0.5rem;
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 600;
}

.reader-fontsize-actions {
    display: flex;
    align-items: stretch;
    gap: 10px;
    margin-top: 18px;
}

/* Done, the sheet family's closing primary action: navy in light, teal on
   dark (the navy→teal primary-button rule). */
.annotation-btn-done {
    flex: 1.4;
    min-height: 48px;
    border-radius: 14px;
    background: var(--btn-navy-bg);
    color: #fff;
}

.annotation-btn-done:hover,
.annotation-btn-done:active {
    background: var(--btn-navy-hover);
}

@keyframes reader-fontsize-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes reader-fontsize-rise {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
}

/* ============================================================
   Responsive: mobile (< 768px)
   ============================================================ */

@media (max-width: 767.98px) {
    /* White reading canvas: the content host sits directly on it, with no card
       border or shadow on mobile. */
    .reader,
    .reader-body,
    .reader-content {
        background: var(--parchment);
    }

    /* Panel headers absorb the notch inset so the safe-area strip reads white and
       flush with the header, instead of the panel surface showing above it.
       Shell header here (Search/Quiz/Downloads); own-header panels below. */
    .reader-panel-header {
        align-items: flex-start;
        padding-top: calc(0.75rem + var(--safe-area-top));
    }

    /* Tab pages, not side panels: a full page above the bottom tab bar. z-index
       sits above the top bar (replacing it) but below the tab bar. Switching is
       done via the tabs, so no slide and no scrim. */
    .reader-panel {
        position: fixed;
        inset: 0;
        width: auto;
        max-width: none;
        transform: none;
        transition: none;
        z-index: 24;
        /* Override the base panel's calc(3.4rem + inset) top padding to 0: the
           (white) panel headers absorb the notch inset themselves, so the strip
           reads white and flush rather than the panel surface bleeding in. */
        padding-top: 0;
        border-right: none;
        box-shadow: none;
        background: var(--panel-bg);
        display: none;
    }

    .reader-panel.open {
        display: flex;
        transform: none;
    }

    .reader-panel-content {
        flex: 1;
        min-height: 0;
        /* Clear the fixed bottom tab bar, which paints over the page. */
        padding-bottom: calc(4rem + env(safe-area-inset-bottom));
    }

    /* Progress-report footer: the fixed tab bar owns the bottom edge here,
       so keep the tab-bar clearance and let the footer end the flow instead
       of sticking (overrides the base :has() rules above). */
    .reader-panel-content:has(.reader-kcr-footer) {
        padding-bottom: calc(4rem + env(safe-area-inset-bottom));
    }

    .reader-kcr-footer {
        position: static;
    }

    /* Tab model has no close button. Own-header panels (TOC/Notebook) drop the
       shell header entirely (they render their own); other panels (Search) keep
       their title header but lose the X. */
    .reader-panel-own-header .reader-panel-header {
        display: none;
    }

    .reader-close {
        display: none;
    }

    /* Search is launched from the top bar, not the bottom tab bar; its own
       header's Cancel button is the way back to the reader (the shell close
       button stays hidden like every own-header panel). */

    /* Own-header panels: drop the content's top padding and the header's top
       bleed so the header sits flush (the negative margin doesn't cancel the
       padding once stuck). Right padding keeps text clear of the close button. */
    .reader-panel-own-header .reader-panel-content {
        padding-top: 0;
    }

    .reader-panel-own-header .reader-toc-header,
    .reader-panel-own-header .reader-notebook-header,
    .reader-panel-own-header .reader-kc-header,
    .reader-panel-own-header .reader-search-header {
        margin-top: 0;
        /* Navy header fills the notch; the 56px title row starts right below
           the status bar, matching the reader top bar. */
        padding-top: var(--safe-area-top);
    }

    .reader-panel-search .reader-search-header .reader-panel-titlerow {
        display: none;
    }

    .reader-panel-own-header.reader-panel-search .reader-search-header {
        padding-top: calc(var(--safe-area-top) + 12px);
    }

    .reader-content-inner {
        min-height: 100%;
        display: flex;
        flex-direction: column;
        padding-bottom: 0;
    }

    .reader-book-stage {
        min-height: 100%;
        flex: 1;
        display: flex;
        flex-direction: column;
        /* Bottom padding of whatever ends the sheet; clears the tab bar. */
        --reader-sheet-end: calc(1.875rem + 5rem + env(safe-area-inset-bottom));
    }

    .reader-content-host {
        min-height: 100%;
        flex: 1;
        background: var(--parchment);
        border: none;
        border-radius: 0;
        box-shadow: none;
        /* Side padding matches the bookshelf gutter (--page-inset) to maximize
           the reading width; top stays 1.875rem, bottom clears the tab bar. */
        padding: 1.875rem var(--page-inset);
        padding-bottom: var(--reader-sheet-end);
    }

    /* The section footer takes over the tab bar clearance when it follows. */
    .reader-content-host:has(+ .reader-section-nav) {
        padding-bottom: 1.875rem;
    }

    /* Two equal halves; a lone button keeps half width at its own edge. */
    .reader-section-nav {
        align-items: stretch;
        gap: 12px;
        margin: 0 var(--page-inset);
        padding: 20px 0 var(--reader-sheet-end);
    }

    .reader-section-nav-btn {
        flex: 0 0 calc(50% - 6px);
        gap: 6px;
        padding: 10px 12px;
    }

    .reader-section-nav-label {
        flex: 1;
        min-width: 0;
        text-align: left;
    }

    .reader-section-nav-next .reader-section-nav-label {
        text-align: right;
    }

    .reader-section-nav-kicker {
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 11px;
        font-weight: 800;
        letter-spacing: 0.8px;
        text-transform: uppercase;
    }

    .reader-section-nav-colon {
        display: none;
    }

    /* Two lines at most; very long words break instead of overflowing. */
    .reader-section-nav-title {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        overflow-wrap: anywhere;
        line-height: 1.3;
    }

    /* Newer templates cut their opener padding to 1em on small screens; match. */
    .reader-content-body .chapter-opener,
    .reader-content-body .chapter-opener :is(div.objectives, div.lo),
    .reader-content-body .chapter-opener ~ :is(div.objectives, div.lo) {
        padding-inline: 1em !important;
    }

    /* Flat full-width tab bar on the same reading surface (per the design):
       icon + label per tab, teal active, navy-slate idle. */
    .reader-bottombar {
        gap: 0.25rem;
        padding: 0.375rem 0.5rem calc(0.375rem + env(safe-area-inset-bottom));
        background: var(--parchment);
        border-top: 1px solid var(--hairline);
        box-shadow: none;
    }

    .reader-bottombar .reader-tab {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 3px;
        padding: 0.25rem 0;
        border: none;
        background: transparent;
        color: var(--slate);
        font-family: var(--font-ui);
        transition: color var(--duration-fast) ease;
    }

    .reader-bottombar .reader-tab-label {
        font-size: 0.6875rem;
        font-weight: 600;
        line-height: 1;
    }

    .reader-bottombar .reader-tab.active {
        color: var(--accent);
    }

    .reader-scrim {
        background: rgba(0, 0, 0, 0.3);  /* theme-ok: reader scrim, a black veil is correct over both themes */
        z-index: 20;
    }
}

/* ============================================================
   Responsive: desktop (>= 768px)
   ============================================================ */

@media (min-width: 768px) {
    .reader-body {
        position: relative;
    }

    /* One centered column: the reading page, then the section footer. */
    .reader-web .reader-book-stage {
        display: flex;
        flex-direction: column;
        align-items: center;
        flex: 1;
        min-height: 0;
    }

    /* The reading column sits flush on the white page: no card border or
       shadow on web, matching mobile. Column padding 46/40/120. */
    .reader-web .reader-content-host {
        width: 100%;
        max-width: var(--reader-column-width);
        background: transparent;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        padding: 46px 40px 120px;
    }

    /* With a footer below, it carries the 120px instead; without one (single
       section, TOC not loaded) the column keeps it. */
    .reader-web .reader-content-host:has(+ .reader-section-nav) {
        padding-bottom: 24px;
    }

    .reader-bottombar {
        display: none;
    }
}

/* ============================================================
   Wide layouts (>= 768px): top bar, tool rail, content toolbar
   ============================================================ */

/* On-surface teal, not the button fill: the strip sits on the navy bar. */
.reader-header-progress-fill {
    background: var(--accent-bright);
}

@media (min-width: 768px) {
    .reader-header {
        height: 60px;
        padding: 0 24px 0 16px;
        gap: 14px;
    }

    /* The MAUI host has no fixed top bar at this width, so the header carries
       the notch inset itself and the scroller reserves no space for one. */
    .reader:not(.reader-web) .reader-header {
        padding-top: var(--safe-area-top);
        height: calc(60px + var(--safe-area-top));
    }

    .reader:not(.reader-web) .reader-content {
        --reader-topbar-clearance: 0px;
    }

    /* Two classes to out-specify the .reader-header .icon-btn chrome above. */
    .reader-header .reader-header-back {
        width: 38px;
        height: 38px;
        border-radius: 999px;
        background: rgba(255, 255, 255, 0.08);
        color: #fff;
    }

    @media (hover: hover) {
        .reader-header .reader-header-back:hover {
            background: rgba(255, 255, 255, 0.16);
            color: #fff;
        }
    }

    .reader-header-titles {
        display: flex;
        align-items: center;
        gap: 14px;
        min-width: 0;
        flex: 1 1 auto;
    }

    .reader-header-book {
        font-size: 15px;
        font-weight: 500;
        color: var(--appbar-icon-idle);
        flex: 0 1 auto;
        max-width: 34%;
        min-width: 0;
    }

    .reader-header-divider {
        width: 1px;
        height: 20px;
        background: rgba(255, 255, 255, 0.18);
        flex-shrink: 0;
    }

    .reader-header-section {
        font-size: 16px;
        font-weight: 800;
        color: #fff;
        letter-spacing: -0.2px;
        flex: 1 1 auto;
        min-width: 0;
    }

    .reader-header-account {
        margin-left: auto;
    }

    /* ---- Tool rail ---------------------------------------------------- */

    .reader-rail {
        width: 94px;
        flex-shrink: 0;
        background: var(--paper);
        border-right: 1px solid var(--card-border);
        display: flex;
        flex-direction: column;
        gap: 4px;
        padding: 10px 7px;
        /* Above the sliding panel (8) so it really does come out from behind
           the rail; the content toolbar (6) stays under both. */
        z-index: 9;
    }

    .reader-rail-item {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 6px;
        padding: 13px 4px 11px;
        border: 0;
        border-radius: 12px;
        background: transparent;
        color: var(--body-secondary);
        font-family: var(--font-ui);
        cursor: pointer;
        transition: background var(--duration-fast) ease, color var(--duration-fast) ease;
    }

    .reader-rail-label {
        font-size: 11px;
        font-weight: 700;
        line-height: 1.2;
        text-align: center;
    }

    .reader-rail-item.active {
        background: var(--accent-soft);
        color: var(--on-accent-soft);
    }

    @media (hover: hover) {
        .reader-rail-item:hover {
            background: var(--row-pressed);
        }

        .reader-rail-item.active:hover {
            background: var(--accent-soft-hover);
        }
    }

    .reader-rail-item:focus-visible {
        /* --accent, not --accent-bright: bright teal is 2.8:1 on paper in light (A11Y-059). */
        outline: 2px solid var(--accent);
        outline-offset: 2px;
    }

    /* ---- Floating controls -------------------------------------------- */

    /* The base overflow-x: hidden computes overflow-y to auto, which would
       park the sticky wrapper in a box that never scrolls. The reading
       column and .reader-content still clip wide content. */
    .reader-content-inner {
        overflow: visible;
    }

    /* Zero-height sticky wrapper: its children pin to the top of the reading
       area while the page scrolls without taking a band of their own. Sits
       under the overlay panel (z 8) and every dialog. */
    .reader-float {
        position: sticky;
        top: 0;
        height: 0;
        z-index: 6;
    }

    .reader-float-controls {
        position: absolute;
        top: 14px;
        right: 20px;
        display: flex;
        align-items: center;
        gap: 2px;
        padding: 3px;
        background: var(--paper-glass);
        border: 1px solid var(--card-border);
        border-radius: var(--radius-md);
    }

    @supports (backdrop-filter: blur(8px)) or (-webkit-backdrop-filter: blur(8px)) {
        .reader-float-controls {
            backdrop-filter: blur(8px);
            -webkit-backdrop-filter: blur(8px);
        }
    }

    .reader-float-btn {
        width: 40px;
        height: 36px;
        border: 0;
        border-radius: 9px;
        background: transparent;
        color: var(--ink);
        display: inline-flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
    }

    @media (hover: hover) {
        .reader-float-btn:hover {
            background: var(--row-pressed);
        }
    }

    /* After the hover rule: an open dialog keeps its teal while hovered. */
    .reader-float-btn.active {
        background: var(--accent-soft);
        color: var(--on-accent-soft);
    }

    .reader-float-btn:focus-visible {
        /* --accent, not --accent-bright: bright teal is 2.8:1 on the paper-glass pill in light (A11Y-059). */
        outline: 2px solid var(--accent);
        outline-offset: 2px;
    }

    /* A11Y-060: MAUI-only 44pt hit box; the painted pill keeps its size. Only
       the outer edges grow sideways, so neighboring buttons never overlap. */
    .reader:not(.reader-web) .reader-float-btn {
        position: relative;
    }

    .reader:not(.reader-web) .reader-float-btn::before {
        content: "";
        position: absolute;
        top: -4px;
        bottom: -4px;
        left: 0;
        right: 0;
    }

    .reader:not(.reader-web) .reader-float-btn:first-child::before {
        left: -4px;
    }

    .reader:not(.reader-web) .reader-float-btn:last-child::before {
        right: -4px;
    }

    .reader-float-aa {
        font-family: var(--font-reading);
        font-weight: 600;
        line-height: 1;
        display: inline-flex;
        align-items: baseline;
    }

    .reader-float-aa span:first-child {
        font-size: 13px;
    }

    .reader-float-aa span:last-child {
        font-size: 20px;
    }

    @media (prefers-reduced-motion: reduce) {
        .reader-rail-item {
            transition: none;
        }
    }

    /* ---- Search navigator ---------------------------------------------- */

    /* Centred by a transform, so the shared rise keyframes (which set
       transform) would drop the centring mid-animation. */
    @keyframes reader-navigator-rise {
        from {
            opacity: 0;
            transform: translate(-50%, 8px);
        }

        to {
            opacity: 1;
            transform: translateX(-50%);
        }
    }

    /* The find card floated top-center of the reading area (handoff v3). Two
       classes so the .reader-web bottom-dock rule cannot out-specify the reset. */
    .reader-findbar.reader-findbar--navigator {
        position: absolute;
        top: 14px;
        left: 50%;
        right: auto;
        bottom: auto;
        transform: translateX(-50%);
        z-index: auto;
        width: auto;
        max-width: calc(100% - 32px);
        margin: 0;
        padding: 5px 6px 5px 14px;
        display: flex;
        align-items: center;
        gap: 8px;
        white-space: nowrap;
        background: var(--paper);
        border: 1px solid var(--card-border);
        border-radius: 14px;
        box-shadow: var(--shadow-cover);
        /* The card clipped its own corners; floated it would clip focus rings. */
        overflow: visible;
        animation: reader-navigator-rise 160ms var(--ease-out);
    }

    .reader-findbar--navigator .reader-findbar-term {
        flex: 0 1 auto;
        padding: 4px 6px;
        margin-left: -6px;
    }

    .reader-findbar--navigator .reader-findbar-term svg {
        color: var(--muted-2);
    }

    .reader-findbar--navigator .reader-findbar-term-text {
        max-width: 180px;
        font-size: 14px;
    }

    .reader-findbar--navigator .reader-findbar-count {
        font-size: 12.5px;
    }

    .reader-findbar-divider {
        width: 1px;
        height: 18px;
        margin: 0 2px;
        flex-shrink: 0;
        background: var(--card-border);
    }

    .reader-findbar--navigator .reader-findbar-btn,
    .reader-findbar--navigator .reader-findbar-close {
        width: 34px;
        height: 34px;
        border-radius: 10px;
    }

    /* A11Y-060: MAUI-only 44pt hit boxes; the painted pill keeps its size. Next
       takes the whole gap on both sides, so Prev and Close only grow outward. */
    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-term,
    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-btn,
    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-close {
        position: relative;
    }

    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-term::before {
        content: "";
        position: absolute;
        top: -10px;
        bottom: -10px;
        left: -10px;
        right: -10px;
    }

    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-btn::before,
    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-close::before {
        content: "";
        position: absolute;
        top: -5px;
        bottom: -5px;
        left: 0;
        right: 0;
    }

    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-btn:not(.reader-findbar-btn-next)::before {
        left: -10px;
    }

    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-close::before {
        right: -10px;
    }

    .reader:not(.reader-web) .reader-findbar--navigator .reader-findbar-btn-next::before {
        left: -8px;
        right: -8px;
    }

    @media (prefers-reduced-motion: reduce) {
        .reader-findbar.reader-findbar--navigator {
            animation: none;
        }
    }

    /* ---- Panel modes --------------------------------------------------- */

    /* Overlay, the default at this width: the panel slides out from behind the
       rail over the page. A tap on the page dismisses it (reader.js), so no
       scrim. */
    .reader-panel {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 94px;
        width: 380px;
        max-width: calc(100vw - 94px);
        height: auto;
        padding-top: 0;
        background: var(--paper);
        border: 0;
        border-right: 1px solid var(--card-border);
        border-radius: 0;
        box-shadow: var(--shadow-hero);
        transform: translateX(calc(-100% - 94px));
        visibility: hidden;
        pointer-events: none;
        transition: transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1), visibility 0s linear 240ms;
        z-index: 8;
    }

    .reader-panel.open {
        transform: none;
        visibility: visible;
        pointer-events: auto;
        transition: transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
    }

    /* Overlay: the open panel covers inert content, so this becomes a
       transparent click-catcher: tap-to-dismiss keeps working (inert content
       takes no clicks) with no visual veil. Under the panel (8) and the rail
       (9), over the content column and its floating controls (6). */
    .reader-scrim {
        background: transparent;
        z-index: 7;
    }

    /* Desktop: the panel is a column of the page and the reading area makes
       room for it, so there is nothing to slide over and nothing to dismiss. */
    @media (min-width: 1280px) {
        .reader-web .reader-panel {
            position: relative;
            top: auto;
            bottom: auto;
            left: auto;
            flex: 0 0 380px;
            width: 380px;
            max-width: none;
            box-shadow: none;
            transform: none;
            visibility: visible;
            transition: none;
        }

        .reader-web .reader-panel:not(.open) {
            display: none;
        }

        .reader-web .reader-panel.open {
            animation: reader-panel-slide-in 180ms ease;
        }

        @keyframes reader-panel-slide-in {
            from { opacity: 0; transform: translateX(-10px); }
            to { opacity: 1; transform: none; }
        }
    }

    @media (prefers-reduced-motion: reduce) {
        .reader-panel,
        .reader-panel.open {
            transition: none;
        }

        .reader-web .reader-panel.open {
            animation: none;
        }
    }

    /* ---- Wide panel header --------------------------------------------- */

    /* The panel is a light surface here, so the navy app-bar headers the panels
       render become plain titles on paper. */
    .reader-toc-header,
    .reader-notebook-header,
    .reader-kc-header,
    .reader-downloads-header,
    .reader-search-header,
    .reader-search .reader-search-header {
        background: var(--paper);
        border-bottom: 1px solid var(--card-border);
        padding: 18px 20px 14px;
        margin: 0;
    }

    /* Only the title row clears the floating close button (14px inset + 32px
       button); the rows under it span the header. Content height, not 56px. */
    .reader-panel-own-header .reader-panel-titlerow {
        min-height: 0;
        padding-right: 40px;
    }

    /* The navy chevron treatment would be invisible on these paper headers. */
    .reader-panel-own-header .reader-panel-back {
        background: var(--row-pressed);
        color: var(--body-secondary);
    }

    /* The shared bright ring is for navy bars; on paper it needs --accent. */
    .reader-panel-own-header .reader-panel-back:focus-visible {
        outline-color: var(--accent);
    }

    @media (hover: hover) {
        .reader-panel-own-header .reader-panel-back:hover {
            background: var(--card-border);
            color: var(--ink);
        }
    }

    .reader-toc-title,
    .reader-notebook-title,
    .reader-kc-title,
    .reader-downloads-title,
    .reader-search-title {
        color: var(--ink);
        font-size: 17px;
        font-weight: 800;
        letter-spacing: -0.2px;
    }

    .reader-toc-subtitle,
    .reader-notebook-subtitle,
    .reader-kc-subtitle,
    .reader-downloads-subtitle,
    .reader-search-subtitle {
        color: var(--muted-2);
    }

    /* Nothing but the close control is left in the shell header; it floats over
       the panel's own title row. The web selectors match the navy rules above. */
    .reader-panel-header,
    .reader-web .reader-panel-own-header .reader-panel-header {
        position: absolute;
        top: 14px;
        right: 14px;
        z-index: 3;
        padding: 0;
        background: transparent;
        border: 0;
    }

    .reader-close,
    .reader-web .reader-close,
    .reader-web .reader-panel-own-header .reader-close {
        width: 32px;
        height: 32px;
        border: 0;
        background: var(--row-pressed);
        color: var(--body-secondary);
        font-size: 15px;
    }

    @media (hover: hover) {
        .reader-close:hover,
        .reader-web .reader-close:hover,
        .reader-web .reader-panel-own-header .reader-close:hover {
            background: var(--card-border);
            color: var(--ink);
        }
    }

    .reader-close:focus-visible,
    .reader-web .reader-close:focus-visible,
    .reader-web .reader-panel-own-header .reader-close:focus-visible {
        background: var(--card-border);
        color: var(--ink);
    }

    /* ---- Panel scroll structure ---------------------------------------- */

    /* The panel body scrolls here, not the shell content box, so the own header
       stays put and a sticky group band pins to the top of the list. The navy
       over-scroll surface goes with the navy headers.
       The .reader-panel-own-header prefix is load-bearing on top of that: the
       Downloads block sits further down the file and wins on source order. */
    .reader-panel-own-header .reader-panel-content,
    .reader-web .reader-panel-own-header .reader-panel-content {
        flex: 1;
        min-height: 0;
        display: flex;
        flex-direction: column;
        background: var(--paper);
        padding: 0;
        overflow: hidden;
    }

    .reader-panel-own-header .reader-toc,
    .reader-panel-own-header .reader-notebook,
    .reader-panel-own-header .reader-kc,
    .reader-panel-own-header .reader-downloads,
    .reader-panel-own-header .reader-search {
        flex: 1;
        min-height: 0;
        display: flex;
        flex-direction: column;
        /* The bleed margins pay for the scroll container's 1rem padding, which
           is gone at this width. */
        margin: 0;
        padding: 0;
    }

    .reader-panel-own-header .reader-toc-header,
    .reader-panel-own-header .reader-notebook-header,
    .reader-panel-own-header .reader-kc-header,
    .reader-panel-own-header .reader-downloads-header,
    .reader-panel-own-header .reader-search-header {
        position: static;
        flex-shrink: 0;
    }

    .reader-panel-own-header .reader-toc-body,
    .reader-panel-own-header .reader-search-list,
    .reader-panel-own-header .reader-notebook-body,
    .reader-panel-own-header .reader-kc-body,
    .reader-panel-own-header .reader-downloads-body {
        flex: 1;
        min-height: 0;
        margin: 0;
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    /* Count line sits between the header and the list, and scrolls with
       neither. */
    .reader-panel-own-header .reader-search-countline {
        flex-shrink: 0;
        margin: 0;
    }

    /* Its bleed paid for the same 1rem padding; the footer keeps its own. */
    .reader-panel-own-header .reader-kcr-footer {
        margin: 0;
    }

    /* ---- Contents ------------------------------------------------------- */

    .reader-toc-progress {
        margin-top: 14px;
    }

    .reader-toc-progress-track {
        height: 7px;
        background: var(--progress-track);
    }

    .reader-toc-progress-fill {
        background: var(--accent);
    }

    .reader-toc-progress-label {
        color: var(--muted-2);
    }

    /* Size and color carry the hierarchy at this width, not weight. */
    .reader-toc-link-section .reader-toc-link-label {
        font-weight: 500;
    }

    .reader-toc-link-leaf .reader-toc-link-label {
        color: var(--body-secondary);
    }

    /* Restated after the idle rules above, which are equally specific and would
       otherwise win on source order. */
    .reader-toc-row-current .reader-toc-link-label {
        font-weight: 700;
        color: var(--on-accent-soft);
    }

    /* ---- Search --------------------------------------------------------- */

    .reader-search-pill {
        border: 1.5px solid var(--input-border);
        padding: 0 13px;
    }

    .reader-search-pill svg {
        color: var(--muted-2);
    }

    .reader-search-input {
        font-size: 14.5px;
        padding: 10px 0;
    }

    .reader-search-scope {
        gap: 4px;
        background: var(--seg-track);
    }

    .reader-search-scope-seg {
        padding: 8px 0;
        color: var(--body-secondary);
    }

    @media (hover: hover) {
        /* The track is light here, so the navy-bar hover (white) would erase
           the label. */
        .reader-search-scope-seg:hover {
            color: var(--ink);
        }
    }

    .reader-search-scope-seg.active {
        background: var(--paper);
        color: var(--ink);
        box-shadow: var(--shadow-card);
    }

    .reader-search-empty {
        padding: 48px 28px;
        text-align: center;
        font-size: 13.5px;
        font-weight: 500;
        line-height: 1.55;
        color: var(--muted-2);
    }

    /* Panel text, not book text: the snippet takes the UI ink. */
    .reader-search-row-snippet {
        color: var(--ink);
    }

    /* ---- Downloads ------------------------------------------------------ */

    /* The body is the scroller now, so the band pins to its top edge instead of
       clearing a panel header that no longer scrolls with it. */
    .reader-panel-own-header .reader-downloads-grouphead {
        top: 0;
    }

    /* ---- Notebook -------------------------------------------------------- */

    /* The body is the scroller here, so it carries the inset the scroll
       container used to supply; without it the list runs to the panel edges.
       gap: 0 here and on the section and list below: spacing at this width is
       the margins alone, which the mobile grid gaps would otherwise add to. */
    .reader-notebook-body {
        background: var(--page-surface);
        padding: 16px 14px 20px;
        gap: 0;
    }

    /* Wide-only chapter band over each run of sections. The base display comes
       from d-none / d-md-block on the heading itself. */
    .reader-notebook-chapter {
        font-size: 14px;
        font-weight: 800;
        color: var(--ink);
        line-height: 1.35;
        margin: 0 4px 12px;
    }

    /* A new run opens 22px below the previous section, 4px more than the 18px
       between sections of one chapter. The first heading keeps its 0 top. */
    .reader-notebook-section + .reader-notebook-chapter {
        margin-top: 4px;
    }

    .reader-notebook-heading {
        font-size: 11px;
        font-weight: 800;
        letter-spacing: 1.3px;
        text-transform: uppercase;
        color: var(--muted-2);
        margin: 0 0 10px 4px;
    }

    .reader-notebook-section {
        margin-bottom: 18px;
        gap: 0;
    }

    .reader-notebook-list {
        gap: 0;
    }

    .reader-notebook-count {
        font-size: 11.5px;
        padding: 3px 9px;
        border-radius: 10px;
        background: var(--accent-soft);
        color: var(--on-accent-soft);
    }

    .reader-notebook-filters {
        background: var(--seg-track);
        border-radius: 11px;
        padding: 4px;
    }

    .reader-notebook-filter {
        color: var(--body-secondary);
        height: auto;
        padding: 8px 0;
        border-radius: 8px;
    }

    @media (hover: hover) {
        /* The track is light here, so the navy-bar hover (white) would erase
           the label. */
        .reader-notebook-filter:hover {
            color: var(--ink);
        }
    }

    .reader-notebook-filter.active {
        background: var(--paper);
        color: var(--ink);
        box-shadow: var(--shadow-card);
    }

    .reader-notebook-tools {
        align-items: center;
        margin-top: 12px;
        justify-content: flex-end;
    }

    .reader-notebook-print {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        padding: 6px 8px;
        border: 0;
        border-radius: 8px;
        background: transparent;
        font-size: 12.5px;
        font-weight: 700;
        color: var(--accent-text);
    }

    @media (hover: hover) {
        .reader-notebook-print:hover {
            background: var(--accent-wash);
        }
    }

    .reader-notebook-item {
        padding: 14px;
        margin-bottom: 12px;
        border-radius: 14px;
    }

    /* Otherwise the trailing card margin would add to the section's own 18px. */
    .reader-notebook-item:last-child {
        margin-bottom: 0;
    }

    /* The rail takes the pen's swatch and the fill its tint, so a quote reads
       as the same pen as the highlight it came from. */
    .reader-notebook-quote {
        border-left-width: 4px;
        border-left-style: solid;
        border-radius: 0 6px 6px 0;
        padding: 9px 12px;
        font-family: var(--font-reading);
        font-size: 14.5px;
        line-height: 1.5;
        color: var(--ink);
    }

    .reader-notebook-quote.markup_bg_1 {
        border-left-color: var(--pen-yellow-swatch);
        background: var(--pen-yellow-tint);
    }

    .reader-notebook-quote.markup_bg_2 {
        border-left-color: var(--pen-pink-swatch);
        background: var(--pen-pink-tint);
    }

    .reader-notebook-quote.markup_bg_3 {
        border-left-color: var(--pen-green-swatch);
        background: var(--pen-green-tint);
    }

    .reader-notebook-quote.markup_bg_5 {
        border-left-color: var(--pen-blue-swatch);
        background: var(--pen-blue-tint);
    }

    .reader-notebook-goto {
        font-size: 13px;
        font-weight: 700;
        color: var(--accent-text);
    }

    /* 30px hit area around the 20px glyph: pull only the 5px of slack on the
       right, so the icon sits on the card's 14px padding edge. */
    .reader-notebook-overflow {
        width: 30px;
        height: 30px;
        border-radius: 8px;
        margin: 0 -5px 0 0;
    }

    @media (hover: hover) {
        .reader-notebook-overflow:hover {
            background: var(--row-pressed);
        }
    }

    /* ---- Notebook inline undo -------------------------------------------- */

    /* Takes the deleted card's slot in the list: a dashed well, so the row
       reads as a gap that can be filled back in rather than a card. */
    .reader-notebook-deleted {
        display: flex;
        align-items: center;
        justify-content: space-between;
        background: var(--row-pressed);
        border: 1px dashed var(--input-border);
        border-radius: 14px;
        padding: 12px 16px;
        margin-bottom: 12px;
    }

    .reader-notebook-deleted-label {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        font-size: 13px;
        font-weight: 600;
        color: var(--muted-2);
    }

    .reader-notebook-undo {
        border: 0;
        background: transparent;
        padding: 6px 10px;
        border-radius: 8px;
        font-size: 13px;
        font-weight: 800;
        color: var(--accent-text);
    }

    @media (hover: hover) {
        .reader-notebook-undo:hover {
            background: var(--accent-wash);
        }
    }

    /* ---- Knowledge Check ------------------------------------------------ */

    /* The body is the scroller here too; without its own surface and padding
       the list runs to the panel edges, same as Notebook. */
    .reader-kc-body {
        background: var(--page-surface);
        padding: 18px 14px 20px;
    }

    /* ---- Reading canvas and sheet -------------------------------------- */

    .reader-content {
        background: var(--page-surface);
    }

    /* The reading sheet floating on the canvas. --parchment (not --paper) is
       deliberate: it is the tuned reading canvas color in dark mode. */
    .reader-content-inner {
        max-width: 1080px;
        margin: 0 auto;
        min-height: 100%;
        background: var(--parchment);
        padding: 0;
        display: flex;
        flex-direction: column;
    }

    /* The base web rule out-specifies the sheet above; its side inset and find
       bar clearance are mobile-only, so the sheet keeps its own edges here. */
    .reader-web .reader-content-inner {
        padding: 0;
    }

    .reader-book-stage {
        flex: 1;
    }

    /* The content host carries the column width itself, matching the web
       reading column at this width. */
    .reader:not(.reader-web) .reader-content-host {
        background: transparent;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        max-width: var(--reader-column-width);
        margin: 0 auto;
        padding: 46px 40px 120px;
    }

    /* With a footer below, it carries the 120px instead; without one (single
       section, TOC not loaded) the column keeps it. */
    .reader:not(.reader-web) .reader-content-host:has(+ .reader-section-nav) {
        padding-bottom: 24px;
    }

    /* ---- Section navigation ---------------------------------------------- */

    .reader-section-nav {
        width: 100%;
        max-width: var(--reader-column-width);
        margin: 64px auto 120px;
        padding: 24px 40px 0;
    }

    .reader-section-nav-btn {
        max-width: 45%;
    }

    /* Long section titles shrink to one ellipsised line, never a second row. */
    .reader-section-nav-label {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* ---- Text size popover ---------------------------------------------- */

    /* reader.positionPopover pins the dialog under the floating pill's text-size
       button and tags it. The overlay then keeps only its outside-click job:
       no scrim, no centring. */
    .reader-fontsize-overlay:has(.reader-popover--anchored) {
        background: transparent;
        align-items: flex-start;
        justify-content: flex-start;
        animation: none;
    }

    .reader-fontsize-dialog.reader-popover--anchored {
        width: 312px;
        max-width: calc(100vw - 16px);
        background: var(--paper);
        border: 1px solid var(--card-border);
        border-radius: 14px;
        box-shadow: var(--shadow-hero);
        padding: 16px;
        animation: reader-fontsize-rise 160ms var(--ease-out);
    }

    .reader-popover--anchored .reader-fontsize-title {
        font-size: 14.5px;
        font-weight: 800;
        color: var(--ink);
    }

    .reader-popover--anchored .reader-fontsize-subtitle {
        font-size: 12.5px;
        font-weight: 600;
        color: var(--muted-2);
    }

    .reader-popover--anchored .reader-fontsize-presets {
        gap: 8px;
    }

    .reader-popover--anchored .reader-fontsize-preset {
        min-height: 52px;
        border-radius: 11px;
        background: var(--row-pressed);
        border: 2px solid var(--card-border);
        color: var(--ink);
    }

    .reader-popover--anchored .reader-fontsize-preset.active {
        background: var(--accent-wash);
        border-color: var(--ink);
    }

    /* The resting fill above outranks the sheet's hover/focus tint, so restate
       it one step darker. */
    .reader-popover--anchored .reader-fontsize-preset:focus-visible {
        background: var(--card-border);
    }

    @media (hover: hover) {
        .reader-popover--anchored .reader-fontsize-preset:hover {
            background: var(--card-border);
        }
    }

    /* Fixed specimen sizes, in the reading face: at this width the tiles read as
       a type scale rather than the sheet's rem ramp. */
    .reader-popover--anchored .reader-fontsize-preset-sample {
        font-family: var(--font-reading);
        font-weight: 600;
    }

    .reader-popover--anchored .reader-fontsize-preset:nth-child(1) .reader-fontsize-preset-sample {
        font-size: 13px;
    }

    .reader-popover--anchored .reader-fontsize-preset:nth-child(2) .reader-fontsize-preset-sample {
        font-size: 15.5px;
    }

    .reader-popover--anchored .reader-fontsize-preset:nth-child(3) .reader-fontsize-preset-sample {
        font-size: 18px;
    }

    .reader-popover--anchored .reader-fontsize-preset:nth-child(4) .reader-fontsize-preset-sample {
        font-size: 20.5px;
    }

    .reader-popover--anchored .reader-fontsize-preset:nth-child(5) .reader-fontsize-preset-sample {
        font-size: 23px;
    }

    .reader-popover--anchored .reader-fontsize-actions {
        justify-content: space-between;
    }

    /* Reset reads as a link at this size, Done as a compact button; neither
       stretches across the footer. */
    .reader-popover--anchored .reader-fontsize-actions .annotation-btn-secondary {
        flex: none;
        min-height: 0;
        padding: 0;
        border: 0;
        background: transparent;
        color: var(--accent-text);
        font-size: 13px;
        font-weight: 700;
    }

    .reader-popover--anchored .reader-fontsize-actions .annotation-btn-done {
        flex: none;
        min-height: 0;
        padding: 9px 16px;
        border-radius: 10px;
        background: var(--btn-navy-bg);
        color: #fff;
        font-size: 13px;
        font-weight: 700;
    }

    @media (hover: hover) {
        .reader-popover--anchored .reader-fontsize-actions .annotation-btn-secondary:hover {
            text-decoration: underline;
        }

        .reader-popover--anchored .reader-fontsize-actions .annotation-btn-done:hover {
            background: var(--btn-navy-hover);
        }
    }

    @media (prefers-reduced-motion: reduce) {
        .reader-fontsize-dialog.reader-popover--anchored {
            animation: none;
        }
    }

    /* ---- View sheet ------------------------------------------------------ */

    /* The card takes the pen's rail, same grammar as a notebook quote. */
    .annotation-popup.markup_bg_1 { border-left: 4px solid var(--pen-yellow-swatch); }
    .annotation-popup.markup_bg_2 { border-left: 4px solid var(--pen-pink-swatch); }
    .annotation-popup.markup_bg_3 { border-left: 4px solid var(--pen-green-swatch); }
    .annotation-popup.markup_bg_5 { border-left: 4px solid var(--pen-blue-swatch); }

    /* Margins net out the card's 16px grid gap: 12px above the eyebrow, 5px
       between it and the note it labels. */
    .annotation-view-eyebrow {
        font-size: 11px;
        font-weight: 800;
        letter-spacing: 1.2px;
        text-transform: uppercase;
        color: var(--muted-2);
        margin: -4px 0 -11px;
    }

    /* ---- Scrollbars ---------------------------------------------------- */

    /* Desktop web: thin inset scrollbar, matching the print tree's
       .reader-thin-scroll (WebKit pseudo-elements; Firefox via scrollbar-*).
       The panel scroller is the body at these widths (see Panel scroll
       structure), so each list names the bodies next to the content box. */
    @media (min-width: 1280px) {
        .reader-web .reader-content,
        .reader-web .reader-panel-content,
        .reader-web :is(.reader-toc-body, .reader-search-list, .reader-notebook-body, .reader-kc-body, .reader-downloads-body) {
            scrollbar-width: thin;
            scrollbar-color: var(--control-border-idle) transparent;
        }

        .reader-web .reader-content::-webkit-scrollbar,
        .reader-web .reader-panel-content::-webkit-scrollbar,
        .reader-web :is(.reader-toc-body, .reader-search-list, .reader-notebook-body, .reader-kc-body, .reader-downloads-body)::-webkit-scrollbar {
            width: 9px;
        }

        .reader-web .reader-content::-webkit-scrollbar-thumb,
        .reader-web .reader-panel-content::-webkit-scrollbar-thumb,
        .reader-web :is(.reader-toc-body, .reader-search-list, .reader-notebook-body, .reader-kc-body, .reader-downloads-body)::-webkit-scrollbar-thumb {
            background: var(--control-border-idle);
            border-radius: 8px;
            border: 3px solid transparent;
            background-clip: content-box;
        }

        .reader-web .reader-content::-webkit-scrollbar-track,
        .reader-web .reader-panel-content::-webkit-scrollbar-track,
        .reader-web :is(.reader-toc-body, .reader-search-list, .reader-notebook-body, .reader-kc-body, .reader-downloads-body)::-webkit-scrollbar-track {
            background: transparent;
        }
    }

    /* Overlay-width web (rail eats the room a scrollbar needs) and every
       MAUI width: hide the scrollbar, the platform overlay still scrolls. */
    @media (min-width: 768px) and (max-width: 1279.98px) {
        .reader-web .reader-content,
        .reader-web .reader-panel-content,
        .reader-web :is(.reader-toc-body, .reader-search-list, .reader-notebook-body, .reader-kc-body, .reader-downloads-body) {
            scrollbar-width: none;
        }

        .reader-web .reader-content::-webkit-scrollbar,
        .reader-web .reader-panel-content::-webkit-scrollbar,
        .reader-web :is(.reader-toc-body, .reader-search-list, .reader-notebook-body, .reader-kc-body, .reader-downloads-body)::-webkit-scrollbar {
            width: 0;
            height: 0;
        }
    }

    @media (min-width: 768px) {
        .reader:not(.reader-web) .reader-content,
        .reader:not(.reader-web) .reader-panel-content,
        .reader:not(.reader-web) :is(.reader-toc-body, .reader-search-list, .reader-notebook-body, .reader-kc-body, .reader-downloads-body) {
            scrollbar-width: none;
        }

        .reader:not(.reader-web) .reader-content::-webkit-scrollbar,
        .reader:not(.reader-web) .reader-panel-content::-webkit-scrollbar,
        .reader:not(.reader-web) :is(.reader-toc-body, .reader-search-list, .reader-notebook-body, .reader-kc-body, .reader-downloads-body)::-webkit-scrollbar {
            width: 0;
            height: 0;
        }
    }
}

/* ============================================================
   Diagnostic Quiz
   ============================================================ */

.diag-quiz {
    padding: 1.25rem 0 2rem;
    color: var(--text);
    font-size: 1rem;
}

/* ── Header ───────────────────────────────────────────── */

.diag-header {
    margin-bottom: 1.25rem;
}

.diag-eyebrow {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent-deep);
    background: var(--accent-soft-2);
    padding: 0.25rem 0.7rem;
    border-radius: var(--radius-chip);
    margin-bottom: 0.5rem;
}

.diag-title {
    font-size: 1.25rem;
    font-weight: 700;
    margin: 0 0 0.35rem;
    color: var(--ink);
    line-height: 1.3;
}

.diag-intro {
    color: var(--muted);
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.5;
}

.diag-disclaimer {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0.75rem 0 0;
    padding: 0.55rem 0.8rem;
    background: var(--accent-soft-2);
    border: 1px solid var(--accent-soft);
    border-radius: var(--radius-chip);
    font-size: 0.82rem;
    color: var(--accent-deep);
    line-height: 1.45;
}

.diag-disclaimer::before {
    content: "ⓘ";
    font-size: 0.95rem;
    line-height: 1.2;
    color: var(--accent);
    flex-shrink: 0;
}

/* ── Question list ────────────────────────────────────── */

.diag-questions {
    list-style: none;
    padding: 0;
    margin: 0 0 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}

.diag-question {
    background: var(--paper);
    border: 1px solid var(--hairline);
    border-radius: 18px;
    padding: 1.15rem;
    box-shadow: var(--shadow-card);
}

/* Subtle alternating tint keeps a perceivable rhythm across many questions
   while staying on the cool surface palette (the card border stays visible). */
.diag-question:nth-child(even) {
    background: var(--panel-bg);
    border-color: var(--hairline-2);
}

.diag-question-num {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--eyebrow);
    margin-bottom: 0.5rem;
}

.diag-question-text {
    display: block;
    font-size: 1.03rem;
    font-weight: 600;
    line-height: 1.4;
    margin: 0 0 1rem;
    color: var(--ink);
}

/* ── Answers ──────────────────────────────────────────── */

.diag-answers {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.diag-answer {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
}

.diag-answer-row {
    position: relative;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
    padding: 0.875rem;
    border: 1.5px solid var(--hairline);
    border-radius: 13px;
    background: var(--paper);
    transition: border-color 120ms ease, background 120ms ease, box-shadow 120ms ease;
}

/* Hover only when the row is still interactive. */
.diag-answer-row:not(:has(input:disabled)):hover {
    border-color: var(--hairline-2);
    background: var(--warm-input);
}

/* Selected state (pre-grading): light teal tint + emphasized accent border. */
.diag-answer-row:has(input:checked:not(:disabled)) {
    border-color: var(--accent);
    background: var(--accent-soft-2);
    box-shadow: inset 0 0 0 1px var(--accent);
}

.diag-answer-label {
    flex: 1;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    cursor: pointer;
    font-size: 0.97rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--ink);
    margin: 0;
}

/* Extend the label's click target to cover the entire visible row,
   so clicks anywhere in the row's padding/gap area still toggle the
   associated input (matches the area that gets the :hover effect). */
.diag-answer-label::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    cursor: inherit;
}

.diag-answer-row:has(input:disabled) .diag-answer-label,
.diag-answer-row:has(input:disabled) .diag-answer-label::before {
    cursor: default;
}

.diag-answer-text {
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
    position: relative;
}

/* Keep actual interactive/visual children above the overlay so they
   remain focusable, hoverable and aren't visually obscured. */
.diag-answer-input,
.diag-answer-status {
    position: relative;
}

/* Custom-styled radio (donut) and checkbox (filled square) */
.diag-answer-input {
    appearance: none;
    -webkit-appearance: none;
    width: 20px;
    height: 20px;
    border: 2px solid var(--muted-2);
    background: var(--paper);
    flex-shrink: 0;
    margin: 0;
    cursor: pointer;
    transition: border-color 120ms ease, background 120ms ease, border-width 120ms ease;
}

.diag-answer-input[type="radio"] {
    border-radius: 999px;
}

.diag-answer-input[type="checkbox"] {
    border-radius: 5px;
}

.diag-answer-input[type="radio"]:checked {
    border-width: 6px;
    border-color: var(--accent);
}

.diag-answer-input[type="checkbox"]:checked {
    border-color: var(--accent);
    background-color: var(--accent-fill);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M2 6.2l2.4 2.4L10 3.2' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 75% 75%;
}

.diag-answer-input:disabled {
    cursor: default;
}

.diag-answer-input:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Graded answer rows: both the correct answer and the user's wrong pick get a
   colored border + soft fill, reinforced by the radio donut (green for correct,
   filled red for the wrong pick). */
.diag-answer-correct .diag-answer-row,
.diag-answer-missed .diag-answer-row {
    border-color: var(--success);
    background: var(--success-soft);
}

/* Correct answer the user actually selected → filled green donut. */
.diag-answer-correct .diag-answer-input[type="radio"]:checked {
    border-color: var(--success);
}

.diag-answer-correct .diag-answer-input[type="checkbox"]:checked {
    border-color: var(--success);
    background-color: var(--success);
}

/* Correct answer the user missed → empty green-ring donut (not selected). */
.diag-answer-missed .diag-answer-input {
    border-color: var(--success);
    border-width: 2px;
    background: var(--paper);
}

.diag-answer-wrong .diag-answer-row {
    border-color: var(--danger);
    background: var(--danger-soft);
}

.diag-answer-wrong .diag-answer-input[type="radio"]:checked {
    border-color: var(--danger);
}

.diag-answer-wrong .diag-answer-input[type="checkbox"]:checked {
    border-color: var(--danger);
    background-color: var(--danger-solid);
}

/* Status tag */
.diag-answer-status {
    margin-left: auto;
    font-size: 0.66rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.25rem 0.55rem;
    border-radius: 7px;
    flex-shrink: 0;
    line-height: 1.4;
}

/* "Correct" / "Correct answer" → green; "Your answer" → red. Text tone, not
   --success: the fill tone is 3.49:1 as 0.66rem text on the soft tint. */
.diag-answer-status--ok,
.diag-answer-status--miss {
    background: var(--success-soft);
    color: var(--success-text);
}

.diag-answer-status--bad {
    background: var(--danger-soft);
    color: var(--danger);
}

/* Explanation callout: soft-green box, green left rule, reading serif. */
.diag-explanation {
    margin: 0;
    padding: 0.85rem 0.95rem;
    background: var(--success-soft);
    border-left: 3px solid var(--success);
    border-radius: 0 10px 10px 0;
    font-family: var(--font-reading);
    font-size: 0.9rem;
    color: var(--reading-text);
    line-height: 1.55;
}

.diag-review-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    margin-top: 0.35rem;
    padding: 0 0.15rem;
    border: 0;
    background: none;
    color: var(--accent-text);
    font: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.18em;
    cursor: pointer;
}

.diag-review-link:hover {
    text-decoration-thickness: 2px;
}

/* ── Submit / actions (pre-grading) ───────────────────── */

.diag-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 1rem;
}

.diag-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    padding: 0.6rem 1.1rem;
    border-radius: 999px;
    font-size: 0.9rem;
    font-weight: 600;
    border: 1px solid transparent;
    cursor: pointer;
    line-height: 1;
    transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
}

.diag-btn-primary {
    background: var(--btn-navy-bg);
    color: #fff;
    border-color: var(--btn-navy-bg);
}

.diag-btn-primary:hover,
.diag-btn-primary:focus-visible {
    background: var(--btn-navy-hover);
    border-color: var(--btn-navy-hover);
}

.diag-btn-primary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* ── Score summary (navy hero) ────────────────────────── */

.diag-actions.diag-actions-graded {
    display: block;
    margin-top: 1.5rem;
}

.diag-score-summary {
    display: flex;
    align-items: center;
    gap: 1.15rem;
    padding: 1.25rem;
    background: linear-gradient(135deg, var(--navy-mid) 0%, var(--navy) 100%);
    border-radius: var(--radius-lg);
    color: #ffffff;
    box-shadow: var(--shadow-hero);
    flex-wrap: wrap;
}

/* Graded layout: the score card leads the page (inserted right after the
   Pre/Post-Test header), so it needs the gap the actions row used to carry. */
.diag-header + .diag-score-summary {
    margin-bottom: 1.5rem;
}

.diag-score-ring {
    --p: 0;
    position: relative;
    width: 72px;
    height: 72px;
    border-radius: 999px;
    background: conic-gradient(var(--accent-bright) calc(var(--p) * 1%), rgba(255, 255, 255, 0.18) 0);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.diag-score-ring::after {
    content: "";
    position: absolute;
    inset: 7px;
    background: var(--navy);
    border-radius: 999px;
}

.diag-score-ring span {
    position: relative;
    font-size: 1.05rem;
    font-weight: 800;
    color: #ffffff;
    z-index: 1;
    font-variant-numeric: tabular-nums;
}

.diag-score-text {
    display: grid;
    gap: 0.15rem;
    min-width: 0;
}

.diag-score-headline {
    margin: 0;
    font-size: 1.12rem;
    font-weight: 800;
    line-height: 1.3;
}

.diag-score-detail {
    font-size: 0.82rem;
    color: rgba(255, 255, 255, 0.78);
}

.diag-score-actions {
    margin-left: auto;
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* Persistence-failure notice inside the graded score hero (dark navy bg): the
   result couldn't be saved, so we say so and offer a retry rather than losing
   the attempt silently. Light literals match the hero's own white-on-navy set. */
.diag-save-error {
    flex-basis: 100%;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-top: 0.25rem;
    padding-top: 0.75rem;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
}

.diag-save-error-text {
    font-size: 0.82rem;
    font-weight: 600;
    color: #ffd9d2;
}

.diag-save-retry {
    padding: 0.3rem 0.75rem;
    font-size: 0.8rem;
}

.diag-btn-continue {
    background: #ffffff;  /* theme-ok: white button on the NAVY score panel, which stays navy in both themes */
    color: var(--navy);  /* theme-ok: navy label on the white Continue button, which sits on the always-navy score panel */
    border-color: #ffffff;
}

.diag-btn-continue:hover,
.diag-btn-continue:focus-visible {
    background: rgba(255, 255, 255, 0.88);
    border-color: rgba(255, 255, 255, 0.88);
}

.diag-btn-retake,
.diag-btn-report {
    background: transparent;
    color: #ffffff;
    border-color: rgba(255, 255, 255, 0.45);
}

.diag-btn-retake:hover,
.diag-btn-retake:focus-visible,
.diag-btn-report:hover,
.diag-btn-report:focus-visible {
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.7);
}

.diag-btn-continue:focus-visible,
.diag-btn-retake:focus-visible,
.diag-btn-report:focus-visible {
    outline: 2px solid var(--accent-bright);
    outline-offset: 2px;
}

/* ── Pre-Test required gate ───────────────────────────── */

.diag-gate {
    padding: 2rem 0;
}

.diag-gate-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
    padding: 1.75rem 1.5rem;
    text-align: center;
    max-width: 32rem;
    margin: 0 auto;
}

.diag-gate-card .diag-title {
    margin-bottom: 0.5rem;
}

.diag-gate-card .diag-intro {
    line-height: 1.6;
}

.diag-gate-card .diag-actions {
    justify-content: center;
}

/* ── Responsive: mobile (< 640px) ─────────────────────── */

@media (max-width: 639.98px) {
    .diag-score-summary {
        gap: 0.85rem;
    }

    .diag-score-actions {
        margin-left: 0;
        width: 100%;
    }

    /* Primary-first stack: Continue reading owns the first row, the other
       two split the next. Labels never wrap. */
    .diag-score-actions .diag-btn {
        white-space: nowrap;
    }

    .diag-score-actions .diag-btn-continue {
        flex-basis: 100%;
        order: -1;
    }

    .diag-score-actions .diag-btn-retake,
    .diag-score-actions .diag-btn-report {
        flex: 1 1 0;
    }
}

@media (max-width: 379.98px) {
    /* Too narrow for the Retake / View Progress Report pair: stack them too. */
    .diag-score-actions .diag-btn-retake,
    .diag-score-actions .diag-btn-report {
        flex-basis: 100%;
    }
}

/* ============================================================
   Downloads Panel
   ============================================================ */

/* Type B (list) panel: white body, flat rows, hairline separation. */
.reader-downloads {
    display: flex;
    flex-direction: column;
    min-height: 100%;
    background: var(--paper);
    box-sizing: border-box;
    margin: 0 -1rem -1rem;
    padding: 0 1rem 1rem;
}

/* Bleeds past the panel's 1rem side padding so the group headers and row
   hairlines run edge to edge, the way a dense list should. */
.reader-downloads-body {
    margin: 0 -1rem;
}

/* The body bleeds to the panel edges for the list; the loading / error /
   empty states are prose and need the gutter back. */
.reader-downloads-body > .reader-panel-placeholder {
    padding: 1.1rem 1rem 0;
}

/* Sticky group header. The scroller here is .reader-panel-content, not this
   body, so `top` must clear the navy panel header stuck at 0 or the group name
   pins behind it. --reader-topbar-h is that header's height. (Wide layouts hand
   the scrolling to the body and reset `top`.) */
.reader-downloads-grouphead {
    position: sticky;
    top: var(--reader-topbar-h);
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 8px 20px;
    background: var(--list-group-surface);
    /* The 1px EDGE, not the fill change, is what separates a sticky band from
       the row beneath it: a fill change alone disappears the moment the band
       scrolls over a hovered row. */
    border-top: 1px solid var(--divider-band);
    border-bottom: 1px solid var(--divider-band);
}

/* --slate, not the usual --eyebrow: the eyebrow tone lands at 4.32:1 on the
   group band, just under the 4.5:1 this 10.5px label needs. */
.reader-downloads-heading {
    margin: 0;
    font-size: 11px;
    font-weight: 800;
    color: var(--slate);
    text-transform: uppercase;
    letter-spacing: 1.3px;
}

.reader-downloads-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Flat rows on a white panel: the 1px hairline is the only separation, inset to
   the text column and dropped on a group's last row where the next band's edge
   already does that job. */
.reader-downloads-item {
    position: relative;
}

/* Pseudo-element, not a border: the row stays full-bleed so its hover fill
   reaches both edges while the hairline starts at the text column. */
.reader-downloads-item:not(:last-child)::after {
    content: "";
    position: absolute;
    left: 20px;
    right: 0;
    bottom: 0;
    height: 1px;
    background: var(--divider-row);
}

.reader-downloads-link {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 8px 14px 8px 20px;
    text-decoration: none;
    transition: background var(--duration-fast) var(--ease-out);
}

.reader-downloads-link:hover,
.reader-downloads-link:focus-visible {
    background: var(--row-pressed);
}

.reader-downloads-item-display {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 13.5px;
    font-weight: 500;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.reader-downloads-action {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 8px;
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--accent-text);
    transition: background var(--duration-fast) var(--ease-out);
}

.reader-downloads-link:hover .reader-downloads-action,
.reader-downloads-link:focus-visible .reader-downloads-action {
    background: var(--accent-soft-2);
}

/* ============================================================
   Dark theme surface fixes
   For hardcoded colors that can't be repointed to a token without
   changing light mode. Light mode is untouched.
   ============================================================ */

/* Translucent-white loading veils read as light scrims over the dark
   reading canvas; swap to a dark scrim at the same alpha. */
:root[data-theme="dark"] .reader-loading-card {
    background: rgba(20, 38, 57, 0.96);   /* card #142639 at the light veil's alpha */
}

:root[data-theme="dark"] .reader-loading-section {
    background: rgba(17, 26, 36, 0.72);   /* reading canvas #111A24 at the light veil's alpha */
}

/* Active controls on the navy chrome use a light fill + navy text. --surface is
   a dark card in dark mode, which would go navy-on-navy, so invert the fill to
   the light text tone (13.3:1 with the navy label). */
:root[data-theme="dark"] .reader-notebook-filter.active,
:root[data-theme="dark"] .reader-search-scope-seg.active {
    background: var(--ink);
    color: var(--navy);  /* theme-ok: navy label on the dark-mode INVERTED pill (fill is var(--ink) directly above) */
}

/* Selected text-size preset: its --navy border + glyph vanish on the dark
   #163F4A fill; swap to the teal border + light glyph the handoff specifies. */
:root[data-theme="dark"] .reader-fontsize-preset.active {
    border-color: var(--accent-deep);
    color: var(--ink);
}

/* Selected pen swatch: the navy ring + navy-tinted glow disappear against the
   dark sheet; the handoff calls for a teal ring around the selected swatch. */
:root[data-theme="dark"] .annotation-swatch.active {
    border-color: var(--accent);
    box-shadow: 0 0 0 4px rgba(100, 183, 203, .16);
}

/* The full-screen loading veil is a light page-tint wash: over the dark UI it
   reads as a white-out flash. Re-tint to the dark page at the same alpha. */
:root[data-theme="dark"] .reader-loading-viewport {
    background: rgba(11, 24, 38, 0.72);
}

:root[data-theme="dark"] .reader-search-input::placeholder {
    color: var(--faint); /* the handoff's dark placeholder tone */
}

/* Search matches sit on the soft-teal fill; the on-surface teal reads 5.0:1
   there in dark, the fill's own ink token reads 6.9:1. */
:root[data-theme="dark"] .reader-search-hit,
:root[data-theme="dark"] .reader-search-hit-active {
    color: var(--on-accent-soft);
}

/* Aa presets: light marks the unselected tiles with fill alone (transparent
   border); in dark the handoff gives them the inactive-control border so the
   tiles read against the sheet. The .active rule above still wins with teal. */
:root[data-theme="dark"] .reader-fontsize-preset {
    border-color: var(--control-border-idle);
}

/* --danger-hover/--danger-border sit at ~1.3-1.5:1 against the dark card, so the
   outlines vanish and fail WCAG 1.4.11. Outline with the destructive text tone
   instead (5.2:1). */
:root[data-theme="dark"] .reader-loading-cancel-btn,
:root[data-theme="dark"] .annotation-btn-destructive {
    border-color: var(--danger);
}

/* ---- Book content, dark ----
   Books bake light-mode text colors into their own CSS, so force the reading
   palette with !important or the book sheet wins. Annotation spans are
   deliberately excluded: a direct rule beats an inherited value, so note anchors
   keep their pen colors and highlighted text gets its own rule below. */
:root[data-theme="dark"] .reader-content-body :is(p, div, li, dt, dd, blockquote, figcaption, caption, td, th) {
    color: var(--reading-text) !important;
}

:root[data-theme="dark"] .reader-content-body :is(h1, h2, h3, h4, h5, h6) {
    color: var(--ink) !important;
}

:root[data-theme="dark"] .reader-content-body a {
    color: var(--accent) !important;
}

/* Text on a solid highlight brightens to --ink: the dark fills are tuned to
   >=3:1 against the canvas, which leaves the body tone short of AA on them
   (~3.6:1) while ink reads 4.6-4.9:1. Translucent note washes keep the body
   tone, so a note still reads lighter than a highlight. */
:root[data-theme="dark"] .reader-annotation-highlight:is(.markup_bg_1, .markup_bg_2, .markup_bg_3, .markup_bg_5):not(.reader-note-tint),
:root[data-theme="dark"] .reader-notebook-quote:is(.markup_bg_1, .markup_bg_2, .markup_bg_3, .markup_bg_5) {
    color: var(--ink);
}

/* ---- Publisher-styled boxes and inline colors, dark ----
   The rules above only force foreground, and only on block elements, so a
   book's own pale box fills survive into dark mode and its inline colors
   (glossary terms, learning objectives) keep beating the inherited reading
   tone. book-package.js tags both at render time by rendered luminance, since
   the class names are publisher-authored and differ per title. Dark-only by
   selector: light mode and the print document never match. */
:root[data-theme="dark"] .reader-content-body .book-retint-surface {
    background-color: var(--paper) !important;
}

/* One tier down, so a book that layered a darker box on a paler one keeps the
   distinction instead of flattening to a single fill. */
:root[data-theme="dark"] .reader-content-body .book-retint-surface-raised {
    background-color: var(--row-pressed) !important;
}

/* A retinted box that drew no border of its own dissolves into the canvas. An
   inset ring draws the edge without the layout shift a real border would add. */
:root[data-theme="dark"] .reader-content-body .book-retint-edge {
    box-shadow: inset 0 0 0 1px var(--card-border);
}

:root[data-theme="dark"] .reader-content-body .book-retint-border {
    border-color: var(--card-border) !important;
}

/* Annotation spans are excluded so pen colors and the highlight ink tone above
   still win on text the reader has marked up. */
:root[data-theme="dark"] .reader-content-body .book-retint-text:not(.reader-annotation-highlight):not(.reader-note-anchor) {
    color: var(--reading-text) !important;
}

:root[data-theme="dark"] .reader-content-body .book-retint-text-strong:not(.reader-annotation-highlight):not(.reader-note-anchor) {
    color: var(--ink) !important;
}

/* ---- Pen picker dots, dark ----
   The fill shows the real rendered tint while a ring keeps the pen's identity
   color: raw tints alone sit under 3:1 against the sheet and blur together.
   Tiny indicator dots keep the identity swatch, since a tint-fill plus ring is
   unreadable at that size. */
:root[data-theme="dark"] .annotation-swatch-dot {
    color: var(--ink);
}

:root[data-theme="dark"] .annotation-swatch-dot.markup_bg_1 {
    background: var(--pen-yellow-tint);
    box-shadow: inset 0 0 0 2px var(--pen-yellow-swatch);
}

:root[data-theme="dark"] .annotation-swatch-dot.markup_bg_2 {
    background: var(--pen-pink-tint);
    box-shadow: inset 0 0 0 2px var(--pen-pink-swatch);
}

:root[data-theme="dark"] .annotation-swatch-dot.markup_bg_3 {
    background: var(--pen-green-tint);
    box-shadow: inset 0 0 0 2px var(--pen-green-swatch);
}

:root[data-theme="dark"] .annotation-swatch-dot.markup_bg_5 {
    background: var(--pen-blue-tint);
    box-shadow: inset 0 0 0 2px var(--pen-blue-swatch);
}

/* Accessible result lists preserve the existing flat row layout. */
.reader-search-results {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Identify unselected pens on light surfaces as well as selected ones. */
.annotation-swatch-dot.markup_bg_1 { box-shadow: inset 0 0 0 2px var(--pen-yellow-chip-text); }
.annotation-swatch-dot.markup_bg_2 { box-shadow: inset 0 0 0 2px var(--pen-pink-chip-text); }
.annotation-swatch-dot.markup_bg_3 { box-shadow: inset 0 0 0 2px var(--pen-green-chip-text); }
.annotation-swatch-dot.markup_bg_5 { box-shadow: inset 0 0 0 2px var(--pen-blue-chip-text); }

.reader-note-anchor:focus-visible,
.annotation-swatch:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

/* On the navy snackbar the on-surface accent is only 2.52:1; the on-navy tone
   (also the Undo label color) is 6.43:1 light / 6.40:1 dark. */
.annotation-toast button:focus-visible {
    outline: 3px solid var(--accent-on-navy);
    outline-offset: 2px;
}

.annotation-toast-dismiss {
    border: 0;
    background: transparent;
    color: inherit;
    min-width: 44px;
    min-height: 44px;
    padding: 6px;
}

@media (prefers-reduced-motion: reduce) {
    .reader-loading-spinner,
    .reader-fontsize-dialog,
    .annotation-sheet-scrim-enter {
        animation: none !important;
    }

    /* The mobile slide-over: the desktop block's transition:none only covers
       >=768px, so phones animated the 200ms slide under reduce. */
    .reader-panel {
        transition: none !important;
    }
}

.annotation-toast-undo,
.annotation-toast-dismiss {
    flex-shrink: 0;
}

/* Keep native question grouping within the existing quiz-card layout. */
.diag-question-group {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.diag-question-group > legend {
    float: none;
    width: 100%;
    padding: 0;
    margin: 0;
    font: inherit;
}

.diag-title:focus {
    outline: 3px solid var(--accent);
    outline-offset: 3px;
}

.diag-score-headline:focus {
    outline: 3px solid var(--accent-on-navy);
    outline-offset: 3px;
}

/* Web: ReconnectModal.razor.js marks Blazor-bound reader controls while the
   circuit is down. Taps still land, so its guard can refuse them out loud. */
[data-reconnect-disabled] {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Undimmed while focused, so the ring keeps its 3:1. */
[data-reconnect-disabled]:focus-visible {
    opacity: 1;
}

/* A drag would move the thumb but never resize the text. */
input[type="range"][data-reconnect-disabled] {
    pointer-events: none;
}
