/* =========================================================
   bookSHelf theme — kami print-grade tokens with Wedgwood blue accent
   Scope: pipeline-wide default stylesheet for all published chapter pages
   (templates/themes/bookshelf/skeleton.html). The sole layout theme;
   alternates (canvas-lms / clean-textbook / dark-canvas) were deprecated.
   Source: scripts/workflows/templates/attribution_template.html
   - Warm parchment canvas, single chromatic accent (Wedgwood),
     serif at one weight (500), no italic, warm grays only.
   - Depth via 1px rings + whisper shadows; no hard drops.
   - Tag fills are solid hex (pre-blended over parchment) so
     print renderers don't double-paint alpha.
   - Body line-height 1.55 (kami's editorial reading rhythm).
   - Wedgwood (#4e6e8e) substitutes for kami's ink-blue (#1B365D):
     the heritage cream-and-blue pottery counterpart to terracotta.
     Single accent, <= 5% of any visible surface.
   ========================================================= */
:root {
    /* Brand */
    --wedgwood: #4e6e8e;
    --wedgwood-light: #7a9bbf;
    --wedgwood-deep: #3d5a80;
    --focus-blue: #3898ec;

    /* Surfaces */
    --parchment: #f5f4ed;
    --ivory: #faf9f5;
    --pure-white: #ffffff;
    --warm-sand: #e8e6dc;
    --dark-surface: #30302e;
    --deep-dark: #141413;

    /* Ink (warm ramp) */
    --ink-near-black: #141413;
    --ink-charcoal: #3d3d3a;
    --ink-olive: #504e49;
    --ink-stone: #6b6a64;
    --ink-warm-silver: #b0aea5;
    --ink-on-dark: #faf9f5;
    --ink-on-accent: #faf9f5;
    --link-on-dark: var(--wedgwood-light);

    /* Borders & rings */
    --border-cream: #f0eee6;
    --border-warm: #e8e6dc;
    --border-soft: #e5e3d8;
    --border-dark: #30302e;
    --ring-warm: #d1cfc5;
    --ring-deep: #c2c0b6;

    /* Tag tints — pre-blended Wedgwood over parchment */
    --tag-bg: #dde5ed;
    --tag-bg-strong: #c3ccd1;

    /* Shadows */
    --whisper-shadow: 0 4px 24px rgba(0, 0, 0, 0.05);

    /* Spacing scale */
    --xxs: 4px;
    --xs: 8px;
    --sm: 12px;
    --md: 16px;
    --lg: 24px;
    --xl: 32px;
    --xxl: 48px;
    --section: 72px;

    /* Radius scale */
    --radius-tag: 2px;
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-xl: 16px;
    --radius-pill: 9999px;

    /* Type stacks */
    --font-serif: "Charter", "Anthropic Serif", Georgia, "Times New Roman", serif;
    --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

    /* Legacy aliases for site-shared classes */
    --primary-color: var(--ink-near-black);
    --secondary-color: var(--wedgwood);
    --accent-color: var(--wedgwood);
    --bg-light: var(--parchment);
    --bg-highlight: var(--warm-sand);
    --bg-insight: var(--ivory);
    --border-color: var(--border-cream);
}

* { box-sizing: border-box; }
/* `overflow-x: clip` suppresses the ~15px horizontal rocking caused by
 * `.figure-row { width: 100vw }` (full-bleed multi-figure rows) when a
 * vertical scrollbar is present: 100vw includes the scrollbar gutter,
 * so a 100vw element overshoots the content area by the scrollbar
 * width. `clip` (not `hidden`) is required so it doesn't create a new
 * scroll container — `position: sticky` on the navbar would break
 * under `hidden`. Chrome 90+/Firefox 81+/Safari 16+. */
html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overflow-x: clip; }

body {
    font-family: var(--font-serif);
    font-size: 16px;
    font-weight: 400;
    line-height: 1.55;
    margin: 0;
    padding: 0;
    color: var(--ink-near-black);
    background-color: var(--parchment);
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

:focus { outline: none; }
:focus-visible {
    outline: 2px solid var(--focus-blue);
    outline-offset: 2px;
    border-radius: var(--radius-md);
}

.container {
    flex: 1;
    width: 100%;
    max-width: 1120px;
    margin: 0 auto;
    /* Minimum side padding so content never kisses the viewport edges
     * on a window narrower than max-width. Padding is inside the
     * max-width thanks to global box-sizing: border-box. */
    padding: 0 30px;
}
.main-content { width: 100%; }

/* =========================================================
   Global nav — warm parchment, sticky, hairline border
   ========================================================= */
.navbar {
    background-color: rgba(245, 244, 237, 0.85);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    color: var(--ink-near-black);
    padding: 0 var(--lg);
    height: 56px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: sticky;
    top: 0;
    z-index: 1000;
    border-bottom: 1px solid var(--border-cream);
    /* Bookshelf navbar uses the same serif as headings + brand so dropdown
     * buttons (Sections / Examples / Problems / Videos / Theme) and the
     * settings cog labels read consistently with the rest of the theme. */
    font-family: var(--font-serif);
}
.navbar-brand {
    font-family: var(--font-serif);
    font-size: 17px;
    font-weight: 500;
    letter-spacing: 0;
}
.navbar-brand a {
    color: var(--ink-near-black);
    text-decoration: none;
    transition: color 0.2s ease;
}
.navbar-brand a:hover { color: var(--wedgwood); }
.navbar-toggle {
    display: none;
    background: none;
    border: none;
    cursor: pointer;
    padding: var(--xs);
    flex-direction: column;
    gap: 4px;
}
.navbar-toggle .hamburger-bar {
    display: block;
    width: 22px;
    height: 2px;
    background: var(--ink-near-black);
    border-radius: 1px;
}
.navbar-nav {
    display: flex;
    gap: var(--md);
    align-items: center;
    flex-wrap: wrap;
}
.nav-dropdown { position: relative; }
.nav-dropdown-btn {
    color: var(--ink-near-black);
    background: none;
    border: none;
    padding: var(--xs) 0;
    /* Bookshelf navbar uses the same serif (Charter) as headings and
     * the brand. The uppercase + letterspaced Bootstrap-ish form
     * (13px / sans / 0.4px / UPPERCASE) was retired 2026-05-15 — it
     * clashed with the print-grade kami aesthetic. */
    font-family: var(--font-serif);
    font-size: 15px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: color 0.2s ease;
    white-space: nowrap;
}
.nav-dropdown-btn:hover { color: var(--wedgwood); }
.nav-dropdown-btn::after {
    content: '\25BC';
    font-size: 9px;
    opacity: 0.5;
    transform: translateY(1px);
}
.nav-dropdown-btn.video-btn { color: var(--ink-near-black); }
.nav-dropdown-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: var(--xs);
    background: var(--ivory);
    border: 1px solid var(--border-cream);
    border-radius: var(--radius-md);
    box-shadow: var(--whisper-shadow);
    min-width: 280px;
    max-height: 400px;
    overflow-y: auto;
    display: none;
    z-index: 1001;
    padding: var(--xs) 0;
}
.nav-dropdown-menu.show { display: block; }
.nav-dropdown-menu .nav-list { list-style: none; padding: 0; margin: 0; }
.nav-dropdown-menu .nav-item { margin: 0; }
.nav-dropdown-menu .nav-link {
    display: block;
    padding: 10px var(--md);
    color: var(--ink-near-black);
    text-decoration: none;
    font-family: var(--font-serif);
    font-size: 15px;
    font-weight: 400;
    line-height: 1.55;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.nav-dropdown-menu .nav-link:hover,
.nav-dropdown-menu .nav-link.active {
    background-color: var(--warm-sand);
    color: var(--wedgwood);
}
.nav-dropdown-menu .nav-link.external::after {
    content: ' \2197';
    font-size: 12px;
    opacity: 0.5;
}
.nav-translate-widget { display: inline-flex; align-items: center; }

.theme-toggle {
    color: var(--ink-charcoal);
    background: var(--warm-sand);
    border: none;
    padding: 6px 12px;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    font-family: var(--font-sans);
    box-shadow: 0 0 0 1px var(--ring-warm);
    transition: box-shadow 0.2s ease, transform 0.1s ease;
}
.theme-toggle:hover { box-shadow: 0 0 0 1px var(--ring-deep); }
.theme-toggle:active { transform: translateY(1px); }

/* =========================================================
   Floating nav — Wedgwood CTAs with ring shadow
   ========================================================= */
.float-nav {
    position: fixed;
    right: var(--xl);
    bottom: var(--xl);
    display: flex;
    flex-direction: column;
    gap: var(--sm);
    z-index: 999;
    opacity: 0;
    transition: opacity 0.35s ease;
    pointer-events: auto;
}
.float-nav:hover, .float-nav:focus-within { opacity: 1; }
.float-nav-btn {
    background-color: var(--wedgwood);
    color: var(--ink-on-accent);
    border: none;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    box-shadow: 0 0 0 1px var(--wedgwood);
    transition: background-color 0.2s ease, transform 0.1s ease;
}
.float-nav-btn:hover { background-color: var(--wedgwood-deep); }
.float-nav-btn:active { transform: translateY(1px); }
.float-nav-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.float-nav-btn:disabled:hover { background-color: var(--wedgwood); }
.float-nav-btn:disabled:active { transform: none; }

/* =========================================================
   Generic content blocks shared with chapter pages
   ========================================================= */
a {
    color: var(--wedgwood);
    text-decoration: underline;
    text-decoration-color: rgba(78, 110, 142, 0.35);
    text-underline-offset: 3px;
}
a:hover { text-decoration-color: var(--wedgwood); }
code {
    font-family: var(--font-mono);
    font-size: 0.94em;
    background: var(--ivory);
    border: 1px solid var(--border-soft);
    padding: 2px 6px;
    border-radius: var(--radius-sm);
}
strong { font-weight: 500; }

h1, h2, h3, h4 {
    font-family: var(--font-serif);
    color: var(--ink-near-black);
    font-weight: 500;
    margin: 0;
}
/* Each section heading needs breathing room below it so the body text
 * doesn't bump up against the heading baseline. Tuned to roughly 0.6×
 * the heading's font-size — enough air to read as a deliberate gap,
 * not so much that the heading floats away from its section. */
h1 { font-size: calc(40px * var(--reader-font-scale, 1)); line-height: 1.10; letter-spacing: -0.5px; margin-top: var(--xxl); margin-bottom: var(--xl); }
h2 { font-size: calc(28px * var(--reader-font-scale, 1)); line-height: 1.20; letter-spacing: 0.4px; margin-bottom: var(--xl); }
h3 { font-size: calc(21px * var(--reader-font-scale, 1)); line-height: 1.20; margin-bottom: var(--md); }
h4 { font-size: calc(18px * var(--reader-font-scale, 1)); line-height: 1.30; margin-bottom: var(--md); }

p { margin: 0 0 16px; }
img { max-width: 100%; height: auto; }
figure { margin: var(--lg) 0; }
figure em { color: var(--ink-stone); font-style: normal; font-size: calc(14px * var(--reader-font-scale, 1)); }

.learning-objectives,
.context-pause,
.insight-note,
.definition,
.theorem,
.key-terminology,
.important-rule,
.problem-set {
    background-color: var(--ivory);
    padding: var(--lg) var(--xl);
    margin: var(--xl) 0;
    /* Shared left-accent treatment for all callouts — no full ring/border.
     * Per-callout overrides below set the strip colour AND a matching
     * tinted background (strip and bg in the same hue family) so the
     * block reads as a colour family rather than an accent on a neutral
     * card. */
    border-left: 6px solid var(--wedgwood);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    font-size: calc(16px * var(--reader-font-scale, 1));
    line-height: 1.55;
}

/* Per-callout colour pairs — strip + 50% transparent background tinted
 * from the same hue family. The 50% alpha lets the parchment page show
 * through so each callout reads as a tinted region rather than a
 * hard-edged card. Print-grade muted tones — not Bootstrap brights. */
.learning-objectives {
    /* Whisper-soft warm cream — base #f5e4d0 (mostly neutral with a
     * hint of warmth) at 30% alpha so the orange tint barely peeks
     * through the parchment. Two reductions from the original
     * #e8a35a / 50% pair: dropped saturation AND alpha, per user
     * feedback that the orange was too prominent vs the other three
     * 50% tints. The strip stays burnt orange so the colour-family
     * signal still reads. */
    background-color: rgba(245, 228, 208, 0.3);
    border-left-color: #c97a2c;
}
.context-pause {
    background-color: rgba(244, 233, 209, 0.3);  /* 30% pale honey — matches learning-objectives whisper */
    border-left-color: #b8842c;                  /* warm amber */
}
.insight-note {
    background-color: rgba(220, 234, 233, 0.3);  /* 30% pale sage — matches learning-objectives whisper */
    border-left-color: #4d7e7c;                  /* muted teal */
}

/* Sidebar layout — context-pause and insight-note pull to the right
 * third of the content column and let surrounding body text wrap around
 * them. Only THESE two callout types float; definitions, learning
 * objectives, key terminology, problem sets stay full-width because
 * they're structurally load-bearing (you have to read them in order).
 * The 33% width keeps body text on the left wide enough to remain
 * comfortable at a 1080px content max. `clear: right` makes two
 * consecutive callouts stack vertically rather than collide. */
.context-pause,
.insight-note {
    float: right;
    clear: right;
    width: 33%;
    margin: 0 0 var(--md, 0.75rem) var(--lg, 1.5rem);
}
/* `.callout-inline` opt-out: when a callout is too long for the narrow
 * 33% sidebar (would overhang into the next figure / TIN / Example),
 * the pipeline tags it `callout-inline` so it renders as a full-width
 * block in normal flow instead. Pairs with the pair-grid skip in
 * fixup_phase_a.pair_callout_with_definition. */
.context-pause.callout-inline,
.insight-note.callout-inline {
    float: none;
    clear: both;
    width: auto;
    margin: var(--xl, 2rem) 0;
}
/* Section boundaries clear the float so a callout never bleeds into
 * the next h2/h3 region. */
h2, h3 {
    clear: right;
}
/* BFC for full-width block callouts. Without this, a `.definition`
 * (or sibling block-styled container) placed adjacent to a floated
 * sidebar lets its background and border extend UNDER the float —
 * the box doesn't visually account for the float at all and the two
 * regions overlap. `display: flow-root` establishes a fresh block
 * formatting context, which shrinks the block to sit cleanly beside
 * the float. Applies to every full-width content block that has a
 * background, border, or padding the float would visibly overlap. */
.definition,
.theorem,
.example,
.problem,
.try-it-now,
.learning-objectives,
.key-terminology,
.problem-set,
.important-rule {
    display: flow-root;
}

/* Callout + definition pairing. Phase A wraps a (callout + paragraph
 * + definition) trio in `.callout-def-pair` so the two cells share a
 * grid row and the callout's bottom aligns with the definition's
 * bottom. Without this wrapper, a float-only callout that's shorter
 * than its adjacent definition would leave whitespace below itself.
 * Inside the pair, the global float treatment is overridden — the
 * callout fills its grid cell. */
.callout-def-pair {
    display: grid;
    grid-template-columns: 1fr 33%;
    gap: var(--lg, 1.5rem);
    align-items: stretch;
    margin: var(--xl, 2rem) 0;
}
.callout-def-pair-main {
    display: flow-root;
}
.callout-def-pair-aside {
    display: flex;
    flex-direction: column;
}
.callout-def-pair-aside > .context-pause,
.callout-def-pair-aside > .insight-note {
    float: none;
    clear: none;
    width: auto;
    margin: 0;
    flex: 1;            /* fill the grid cell vertically */
}
/* The grid stretches both cells to the same height (align-items: stretch),
 * but the def's visual box only fills its content height by default —
 * leaving its bg/border short of the cell bottom while the callout's box
 * fills its cell. Mirror the def to its cell height AND zero its outer
 * margin (the base .definition has 32px top/bottom margin that shoves
 * the box down inside the grid cell, breaking top-edge alignment with
 * the paired callout). The grid `gap` already handles separation from
 * surrounding content. */
.callout-def-pair-main > .definition {
    height: 100%;
    margin: 0;
    box-sizing: border-box;
}
@media (max-width: 768px) {
    /* Mobile / tablet: collapse the pair to a single column, callout
     * stacks above the definition. */
    .callout-def-pair {
        grid-template-columns: 1fr;
    }
    .callout-def-pair-aside {
        order: -1;       /* callout first when stacked */
    }
}
@media (max-width: 768px) {
    /* Mobile / tablet: revert to full-width stacking — too narrow to
     * float a sidebar. */
    .context-pause,
    .insight-note {
        float: none;
        clear: none;
        width: auto;
        margin: var(--xl) 0;
    }
}
.definition {
    background-color: rgba(225, 232, 240, 0.3);  /* 30% pale wedgwood — matches learning-objectives whisper */
    border-left-color: var(--wedgwood);
}
.theorem {
    /* Theorems get a muted purple tint so they read as "named result"
     * (distinct from .definition's wedgwood "named idea"). Same callout
     * chrome family as the other tinted whispers — print-grade muted
     * purple, not Bootstrap brights. */
    background-color: rgba(228, 220, 240, 0.35);  /* pale lavender whisper */
    border-left-color: #6b5b95;                   /* deep muted purple accent */
}
.key-terminology {
    background-color: rgba(220, 235, 220, 0.3);  /* 30% pale sage — matches whisper family */
    border-left-color: #3e6b40;
}
.context-pause::before {
    content: "Context pause";
    font-family: var(--font-sans);
    font-weight: 500;
    display: block;
    margin-bottom: var(--xs);
    color: var(--ink-stone);
    font-size: calc(12px * var(--reader-font-scale, 1));
    letter-spacing: 0.4px;
    text-transform: uppercase;
}
.insight-note::before {
    content: "Insight";
    font-family: var(--font-sans);
    font-weight: 500;
    display: block;
    margin-bottom: var(--xs);
    color: var(--ink-stone);
    font-size: calc(12px * var(--reader-font-scale, 1));
    letter-spacing: 0.4px;
    text-transform: uppercase;
}
.definition-title,
.theorem-title {
    font-family: var(--font-serif);
    font-weight: 500;
    color: var(--ink-near-black);
    margin-bottom: var(--xs);
    font-size: calc(18px * var(--reader-font-scale, 1));
}

/* Key Terms list — hanging-indent glossary layout. Each term prints
 * on its own line in Wedgwood small-caps sans, with the definition
 * indented underneath. Targets both rendered patterns: the older
 * `.definition` wrapper (Ch 1) and the `.key-terminology` wrapper
 * (Ch 3+). The inner repeat of "Key Terms" / "Key Terminology" is
 * redundant with the h2 above and is hidden. A small DOM pass in
 * script.js strips the leading ": " (Ch 1) or "— " (Ch 3) separator
 * from the body text node so the indented line reads clean. */
h2#key-terms + .definition,
h2#key-terms + .key-terminology {
    padding-top: var(--md);
    padding-bottom: var(--md);
}
h2#key-terms + .definition {
    background-color: rgba(221, 229, 221, 0.3);  /* desaturated sage — softer than .key-terminology */
    border-left-color: #7a9a78;                  /* muted gray-green */
}
[data-theme="dark"] h2#key-terms + .definition {
    background: rgba(30, 37, 30, 0.3);           /* near-neutral dark green */
    border-left-color: #8a9e88;                  /* muted light sage */
}
h2#key-terms + .definition > .definition-title,
h2#key-terms + .key-terminology > strong:first-child {
    display: none;
}
h2#key-terms + .definition > p,
h2#key-terms + .key-terminology > p {
    margin: 0 0 var(--md) 0;
    padding: 0 0 0 var(--xl);
}
h2#key-terms + .definition > p:last-child,
h2#key-terms + .key-terminology > p:last-child {
    margin-bottom: 0;
}
h2#key-terms + .definition > p > strong:first-child,
h2#key-terms + .key-terminology > p > strong:first-child {
    display: block;
    margin-left: calc(-1 * var(--xl));
    margin-bottom: var(--xs);
    color: inherit;
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: calc(12px * var(--reader-font-scale, 1));
    letter-spacing: 0.6px;
    text-transform: uppercase;
}

.important-rule {
    background-color: var(--deep-dark);
    color: var(--ink-warm-silver);
    box-shadow: 0 0 0 1px var(--dark-surface);
}
.important-rule a { color: var(--link-on-dark); text-decoration-color: rgba(122, 155, 191, 0.45); }

.example,
.problem {
    background-color: var(--ivory);
    box-shadow: 0 0 0 1px var(--border-cream);
    padding: var(--xl);
    margin: var(--xl) 0;
    border-radius: var(--radius-md);
    scroll-margin-top: 80px;
}
.example-title {
    font-family: var(--font-sans);
    font-weight: 500;
    color: var(--ink-stone);
    font-size: calc(12px * var(--reader-font-scale, 1));
    letter-spacing: 0.4px;
    text-transform: uppercase;
    margin-bottom: var(--md);
}
.problem-set {
    border-left: none;
    border-radius: var(--radius-md);
}
.problem-set .problem {
    background-color: transparent;
    box-shadow: none;
    padding: var(--md) 0;
    margin: 0;
    border-bottom: 1px solid var(--border-cream);
}
.problem-set .problem:last-child { border-bottom: none; }

details.solution {
    background-color: var(--warm-sand);
    border-radius: var(--radius-md);
    margin-top: var(--md);
    overflow: hidden;
}
details.solution summary {
    background-color: var(--warm-sand);
    color: var(--ink-charcoal);
    padding: var(--sm) var(--md);
    cursor: pointer;
    font-weight: 500;
    font-size: calc(14px * var(--reader-font-scale, 1));
    list-style: none;
    display: flex;
    align-items: center;
    transition: filter 0.2s ease;
}
details.solution summary:hover { filter: brightness(0.97); }
details.solution summary::-webkit-details-marker { display: none; }
details.solution summary::before {
    content: "\25B6";
    margin-right: var(--xs);
    font-size: calc(9px * var(--reader-font-scale, 1));
    transition: transform 0.2s ease;
}
details.solution[open] summary::before { transform: rotate(90deg); }
.solution-content { padding: var(--md) var(--lg); background: var(--ivory); }

/* Cluster-end solution accordion — inherits the .solution look but
 * sits as a sibling AFTER the last problem of a shared-direction
 * cluster (problems 1-6, 7-13, …). Each individual solution inside is
 * preceded by an <h4 class="cluster-solution-heading"> sub-heading.  */
details.cluster-solution {
    background-color: var(--warm-sand);
    border-radius: var(--radius-md);
    margin: var(--lg) 0;
    overflow: hidden;
}
details.cluster-solution summary {
    background-color: var(--warm-sand);
    color: var(--ink-charcoal);
    font-family: var(--font-serif);
    font-weight: 600;
    padding: var(--sm) var(--md);
    cursor: pointer;
    list-style: none;
    user-select: none;
    transition: filter 0.2s ease;
}
details.cluster-solution summary:hover { filter: brightness(0.97); }
details.cluster-solution summary::-webkit-details-marker { display: none; }
details.cluster-solution summary::before {
    content: "\25B6";
    margin-right: var(--xs);
    display: inline-block;
    transition: transform 0.2s ease;
}
details.cluster-solution[open] summary::before { transform: rotate(90deg); }
details.cluster-solution .solution-content {
    padding: var(--md) var(--lg);
    background: var(--ivory);
}
h4.cluster-solution-heading {
    font-family: var(--font-serif);
    font-weight: 700;
    font-size: calc(16.8px * var(--reader-font-scale, 1));
    margin: var(--lg) 0 var(--xs);
    color: var(--ink-charcoal);
    border-bottom: 1px solid var(--border-warm);
    padding-bottom: var(--xs);
}
h4.cluster-solution-heading:first-child { margin-top: 0; }

/* ── Tables — OpenStax-derived minimal aesthetic ─────────────────────
 * Modeled on the OpenStax Calculus Vol 1 §1.1 table styling
 * (inspected via Playwright 2026-05-16): light gray cell borders,
 * bold non-uppercase headers, no background fills, no outer border,
 * no shadow. Captions sit BELOW the table with the bold "Table X.Y"
 * label flush left. Cell padding 8px×16px, body-size font. The result
 * reads as a clean reference object that quietly belongs to the
 * surrounding prose, instead of asserting itself with chrome. */
table {
    border-collapse: collapse;
    width: auto;
    max-width: 100%;
    margin: var(--lg) auto;
    font-size: calc(15px * var(--reader-font-scale, 1));
    background: transparent;
}
th, td {
    border: 1px solid var(--border-warm);
    padding: var(--xs) var(--md);
    text-align: left;
    font-family: inherit;
    color: var(--ink-near-black);
}
th {
    text-align: center;
    font-weight: 700;
    font-size: inherit;
    background: transparent;
    text-transform: none;
    letter-spacing: 0;
    /* Slightly thicker bottom border so the header row reads as a
     * separator from the data rows (matches OpenStax's 2px header
     * border vs 0.8px cell borders). */
    border-bottom: 2px solid var(--border-warm);
}
caption {
    caption-side: bottom;
    text-align: left;
    margin-top: var(--xs);
    font-style: normal;
    font-size: calc(14px * var(--reader-font-scale, 1));
    color: var(--ink-near-black);
}
hr { border: none; border-top: 1px solid var(--border-warm); margin: var(--xl) 0; }

/* Compact data tables — for short reference lists like Table 1.1
 * (24 rows). Cell text is centered with tabular-nums; the legacy
 * max-width:480px cap was retired 2026-05-16 along with the
 * heavier visual treatment, so .data-table now just controls cell
 * alignment and inherits the base minimal table chrome. */
.data-table td {
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.data-table th {
    text-align: center;
}

/* ── Desktop transpose for tall 2-col tables ─────────────────────────
 * 2-col × many-row tables (e.g. Problem Set "Relation given by the
 * table" inputs/outputs) read fine on mobile (natural tall layout
 * already fits the narrow viewport), but waste a lot of vertical
 * real estate on desktop. The transpose flips them visually using
 * display:flex + display:contents — no markup changes, no JS, and
 * mobile renders the original tall layout because the rules sit
 * inside a min-width media query.
 *
 * Phase-A fixup `mark_tables_for_transpose` adds the class to any
 * 2-col table with 6-12 rows (skips `.data-table`, which has its
 * own compact layout and is often much longer). The threshold
 * keeps very long tables (e.g. the 25-row temperature data table)
 * from transposing into something far too wide.
 *
 * How the flex transpose works:
 *   <table> becomes a horizontal flex row.
 *   <thead> and <tbody> use display:contents so their <tr>
 *     children become direct flex items of the table.
 *   Each <tr> becomes a vertical flex column.
 *   Cells inside a row stack vertically, columns sit side by side.
 *
 * The thead's row becomes the LEFTMOST column (label column);
 * each tbody row becomes a numbered column to its right. */
/* Plain (un-classed) tables inside problem-set cards are almost always
 * the same x|y "Relation given by the table" shape, regardless of row
 * count — they should always transpose on desktop without waiting for
 * the row-threshold fixup. `.data-table` is excluded because it carries
 * its own compact layout. */
@media (min-width: 768px) {
    table.transpose-on-desktop,
    .problem-set .problem table:not(.data-table) {
        display: flex;
        flex-direction: row;
        align-items: stretch;
        flex-wrap: wrap;
        overflow-x: auto;
        width: auto;
        max-width: 100%;
        margin: var(--lg) auto;
    }
    table.transpose-on-desktop thead,
    table.transpose-on-desktop tbody,
    .problem-set .problem table:not(.data-table) thead,
    .problem-set .problem table:not(.data-table) tbody {
        display: contents;
    }
    table.transpose-on-desktop tr,
    .problem-set .problem table:not(.data-table) tr {
        display: flex;
        flex-direction: column;
        flex: 0 0 auto;
    }
    table.transpose-on-desktop th,
    table.transpose-on-desktop td,
    .problem-set .problem table:not(.data-table) th,
    .problem-set .problem table:not(.data-table) td {
        min-width: 56px;
        text-align: center;
        font-variant-numeric: tabular-nums;
        border: 1px solid var(--border-warm);
        padding: var(--xs) var(--md);
    }
    /* In the transposed layout, the original thead row becomes the
     * LEFTMOST column. Mark it as the label column with bold weight
     * and a thicker right border (matching OpenStax's 2px header
     * separator pattern, just rotated 90°). */
    table.transpose-on-desktop tr:first-child th,
    table.transpose-on-desktop tr:first-child td,
    .problem-set .problem table:not(.data-table) tr:first-child th,
    .problem-set .problem table:not(.data-table) tr:first-child td {
        font-weight: 700;
        background: transparent;
        text-transform: none;
        letter-spacing: 0;
        border-right: 2px solid var(--border-warm);
    }
    /* Caption sits at the END of the flex row (i.e. below the
     * transposed grid) matching OpenStax's caption-side: bottom.
     * `order: 99` pushes it past every <tr> regardless of count;
     * `flex-basis: 100%` lets it take a full row of its own. */
    table.transpose-on-desktop > caption,
    .problem-set .problem table:not(.data-table) > caption {
        flex-basis: 100%;
        order: 99;
        text-align: left;
        margin-top: var(--xs);
    }
}

.title-home-link {
    color: var(--ink-near-black);
    text-decoration: none;
}
.title-home-link:hover { color: var(--wedgwood); }

.manim-figure { margin: var(--xl) 0; }
.manim-figure video { display: block; width: 100%; height: auto; border-radius: var(--radius-md); box-shadow: 0 0 0 1px var(--border-cream); }

/* =========================================================
   kami page chrome — eyebrow / hero / opener video /
   manifesto / metrics / chapters / footer
   ========================================================= */
.kami-page {
    margin: 0 calc(50% - 50vw);
    padding: 0;
    font-family: var(--font-serif);
    color: var(--ink-near-black);
    background: var(--parchment);
}

.kami-eyebrow {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 12px;
    padding: 24px 24px 20px;
    font-family: var(--font-sans);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--ink-stone);
    border-bottom: 1px solid var(--border-cream);
    flex-wrap: wrap;
}
.kami-eyebrow-sep { color: var(--ink-stone); opacity: 0.5; }

.kami-hero {
    text-align: center;
    padding: 96px 24px 64px;
    max-width: 1080px;
    margin: 0 auto;
}
.kami-hero-headline {
    font-family: var(--font-serif);
    font-size: 84px;
    font-weight: 500;
    line-height: 1.05;
    letter-spacing: -1.2px;
    color: var(--ink-near-black);
    margin: 0 0 24px;
}
.kami-hero-tagline {
    font-family: var(--font-serif);
    font-size: 21px;
    font-weight: 500;
    line-height: 1.30;
    color: var(--ink-olive);
    margin: 0 auto 28px;
    max-width: 720px;
}
.kami-hero-tokens {
    display: flex;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 24px;
}
.kami-hero-token {
    display: inline-block;
    background: var(--tag-bg);
    color: var(--wedgwood);
    font-family: var(--font-sans);
    font-size: 12px;
    font-weight: 500;
    padding: 4px 10px;
    border-radius: var(--radius-sm);
    letter-spacing: 0.4px;
}
.kami-hero-byline {
    font-family: var(--font-serif);
    font-size: 14px;
    font-weight: 400;
    color: var(--ink-stone);
    margin: 0;
    font-variant-numeric: tabular-nums;
}

.kami-opener-video {
    max-width: 960px;
    margin: 0 auto 64px;
    padding: 0 24px;
}
.kami-opener-video video {
    width: 100%;
    height: auto;
    display: block;
    border-radius: var(--radius-md);
    box-shadow: 0 0 0 1px var(--border-cream), var(--whisper-shadow);
}

.kami-manifesto {
    max-width: 720px;
    margin: 0 auto;
    padding: 32px 0;
    border-left: 2px solid var(--wedgwood);
    padding-left: 24px;
}
.kami-manifesto-body {
    font-family: var(--font-serif);
    font-size: 20px;
    font-weight: 400;
    line-height: 1.55;
    letter-spacing: 0.05em;
    color: var(--ink-near-black);
    margin: 0 0 16px;
}
.kami-manifesto-signature {
    font-family: var(--font-serif);
    font-size: 14px;
    font-weight: 500;
    color: var(--ink-stone);
    letter-spacing: 0.4px;
    margin: 0;
}

.kami-metrics {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--xl);
    max-width: 960px;
    margin: 56px auto 80px;
    padding: 32px 24px;
    border-top: 1px solid var(--border-cream);
    border-bottom: 1px solid var(--border-cream);
}
.kami-metric { text-align: center; }
.kami-metric-value {
    font-family: var(--font-serif);
    font-size: 32px;
    font-weight: 500;
    color: var(--wedgwood);
    font-variant-numeric: tabular-nums;
    margin-bottom: var(--xxs);
    line-height: 1.10;
}
.kami-metric-label {
    font-family: var(--font-sans);
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-stone);
    letter-spacing: 0.4px;
    text-transform: uppercase;
}

/* Chapters — relax width vs the attribution spec (720px)
   to a comfortable measure for math display equations. */
.kami-chapters {
    max-width: 960px;
    margin: 0 auto;
    padding: 0 24px 96px;
}
.kami-chapter {
    padding: 56px 0;
    border-top: 1px solid var(--border-cream);
}
.kami-chapter:first-child { border-top: none; padding-top: 24px; }
.kami-chapter-head { margin-bottom: 28px; }
.kami-chapter-num {
    display: block;
    font-family: var(--font-serif);
    font-size: 14px;
    font-weight: 500;
    color: var(--wedgwood);
    letter-spacing: 0.4px;
    font-variant-numeric: tabular-nums;
    margin-bottom: 8px;
}
.kami-chapter-title {
    font-family: var(--font-serif);
    font-size: 36px;
    font-weight: 500;
    line-height: 1.20;
    letter-spacing: 0.4px;
    color: var(--ink-near-black);
    margin: 0;
}
.kami-chapter-body {
    font-family: var(--font-serif);
    font-size: 16px;
    font-weight: 400;
    line-height: 1.55;
    color: var(--ink-near-black);
}
.kami-chapter-body p { margin: 0 0 16px; }
.kami-chapter-body p:last-child { margin-bottom: 0; }
.kami-chapter-body strong { font-weight: 500; color: var(--ink-near-black); }
.kami-chapter-body h3 {
    font-size: 22px;
    margin-top: var(--xl);
    margin-bottom: var(--sm);
    color: var(--wedgwood);
}
.kami-chapter-body ul,
.kami-chapter-body ol { padding-left: var(--lg); margin: 0 0 16px; }
.kami-chapter-body ul li,
.kami-chapter-body ol li { margin-bottom: 6px; }

.kami-footer {
    background: var(--ivory);
    padding: 80px 24px 56px;
    border-top: 1px solid var(--border-cream);
}
.kami-footer-kicker {
    font-family: var(--font-serif);
    font-size: 72px;
    font-weight: 500;
    line-height: 1.05;
    letter-spacing: -1px;
    color: var(--ink-near-black);
    text-align: center;
    margin: 0 auto 56px;
    max-width: 1080px;
}
.kami-footer-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--xl);
    max-width: 1080px;
    margin: 0 auto;
}
.kami-footer-label {
    font-family: var(--font-sans);
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-stone);
    letter-spacing: 0.4px;
    text-transform: uppercase;
    margin: 0 0 12px;
}
.kami-footer-line {
    font-family: var(--font-serif);
    font-size: 14px;
    font-weight: 400;
    color: var(--ink-olive);
    margin: 0 0 6px;
    line-height: 1.55;
}
.kami-footer-line a {
    color: var(--wedgwood);
    text-decoration-color: rgba(78, 110, 142, 0.35);
}

/* =========================================================
   Dark mode — kami's near-black surface palette
   ========================================================= */
[data-theme="dark"] {
    --parchment: #141413;
    --ivory: #1a1a18;
    --pure-white: #1f1f1d;
    --warm-sand: #30302e;
    --dark-surface: #30302e;
    --deep-dark: #1a1a1a;
    --ink-near-black: #e8e2d2;
    --ink-charcoal: #c4c1b6;
    --ink-olive: #b0aea5;
    --ink-stone: #87867f;
    --border-cream: rgba(255, 255, 255, 0.06);
    --border-warm: rgba(255, 255, 255, 0.10);
    --border-soft: rgba(255, 255, 255, 0.06);
    --ring-warm: rgba(255, 255, 255, 0.12);
    --ring-deep: rgba(255, 255, 255, 0.20);
    --tag-bg: #2a3340;
}
[data-theme="dark"] body { background-color: var(--deep-dark); }
[data-theme="dark"] a { color: var(--wedgwood-light); text-decoration-color: rgba(122, 155, 191, 0.45); }
[data-theme="dark"] a:hover { text-decoration-color: var(--wedgwood-light); }
[data-theme="dark"] code { background: var(--dark-surface); border-color: var(--border-warm); color: var(--ink-near-black); }
[data-theme="dark"] .navbar { background-color: rgba(20, 20, 19, 0.85); border-bottom-color: var(--border-warm); }
[data-theme="dark"] .nav-dropdown-menu { background: #1f1f1d; }
[data-theme="dark"] .theme-toggle { background: var(--dark-surface); color: var(--ink-near-black); box-shadow: 0 0 0 1px var(--ring-warm); }
/* Dark-mode shared callout — examples, problems, key terminology,
 * problem set sit on the dark surface with the lighter wedgwood accent.
 * Coloured callouts (Learning Objectives / Context Pause / Insight
 * Note / Definition) override below with their own 50% transparent
 * tinted dark backgrounds so each block stays a colour family in dark
 * mode too. */
[data-theme="dark"] .example,
[data-theme="dark"] .problem,
[data-theme="dark"] .key-terminology,
[data-theme="dark"] .problem-set {
    background: var(--dark-surface);
    border-left-color: var(--wedgwood-light);
}
[data-theme="dark"] .problem-set { border-left: none; }
/* Dark-mode callout colour pairs — 50% transparent bg in same hue
 * family as the light-mode pair. Lighter strips for visibility against
 * the dark page; transparent bg lets the page's dark canvas show
 * through so the block reads as a tinted region. */
[data-theme="dark"] .learning-objectives {
    background: rgba(40, 33, 27, 0.3);    /* warm tobacco — ultra-whisper, ~4ch off bg */
    border-left-color: #e09a55;           /* lighter burnt orange */
}
[data-theme="dark"] .context-pause {
    background: rgba(40, 36, 28, 0.3);    /* muted ochre — ultra-whisper, ~4ch off bg */
    border-left-color: #d4a35a;           /* lighter amber */
}
[data-theme="dark"] .insight-note {
    background: rgba(27, 38, 37, 0.3);    /* dusty teal — ultra-whisper, ~4ch off bg */
    border-left-color: #7aabaa;           /* lighter teal */
}
[data-theme="dark"] .definition {
    background: rgba(29, 35, 44, 0.3);    /* dusty denim — ultra-whisper, ~5ch off bg */
    border-left-color: var(--wedgwood-light);
}
[data-theme="dark"] .theorem {
    background: rgba(38, 32, 50, 0.40);   /* dusty plum — ultra-whisper, same family as light lavender */
    border-left-color: #9b87c2;           /* lighter muted purple for dark mode */
}
[data-theme="dark"] .key-terminology {
    background: rgba(30, 42, 30, 0.3);    /* dusty sage — ultra-whisper, mirrors definition pair */
    border-left-color: #8fb88f;
}
[data-theme="dark"] .important-rule { background-color: var(--deep-dark); color: var(--ink-near-black); }
[data-theme="dark"] th { background-color: var(--dark-surface); color: var(--ink-near-black); }
[data-theme="dark"] details.solution { background-color: var(--dark-surface); color: var(--ivory); }
[data-theme="dark"] details.solution summary { background-color: #4d4d4a; color: var(--ink-on-dark); }
[data-theme="dark"] .solution-content { background: #1a1a18; color: var(--ink-on-dark); }
[data-theme="dark"] details.cluster-solution { background-color: var(--dark-surface); color: var(--ivory); }
[data-theme="dark"] details.cluster-solution summary { background-color: #4d4d4a; color: var(--ink-on-dark); }
[data-theme="dark"] details.cluster-solution .solution-content { background: #1a1a18; color: var(--ink-on-dark); }
[data-theme="dark"] h4.cluster-solution-heading { color: var(--ink-on-dark); border-bottom-color: #4d4d4a; }
[data-theme="dark"] .kami-page { background: var(--deep-dark); }
[data-theme="dark"] .kami-eyebrow { border-bottom-color: var(--border-warm); }
[data-theme="dark"] .kami-metrics { border-color: var(--border-warm); }
[data-theme="dark"] .kami-chapter { border-top-color: var(--border-warm); }
[data-theme="dark"] .kami-footer { background: var(--ivory); border-top-color: var(--border-warm); }
[data-theme="dark"] .kami-hero-token { background: var(--tag-bg); color: var(--wedgwood-light); }
[data-theme="dark"] .kami-metric-value,
[data-theme="dark"] .kami-chapter-num { color: var(--wedgwood-light); }
[data-theme="dark"] .kami-manifesto { border-left-color: var(--wedgwood-light); }
[data-theme="dark"] .kami-chapter-body h3 { color: var(--wedgwood-light); }

/* =========================================================
   Responsive
   ========================================================= */
@media (max-width: 991px) {
    .navbar { flex-direction: column; gap: var(--xs); padding: var(--sm) var(--md); height: auto; }
    .navbar-nav { gap: var(--md); }
    .container { padding: 0; }
    .kami-hero { padding: 56px 24px 40px; }
    .kami-hero-headline { font-size: 52px; letter-spacing: -0.5px; }
    .kami-hero-tagline { font-size: 18px; }
    .kami-hero-tokens { display: none; }
    .kami-opener-video { margin-bottom: 40px; padding: 0 20px; }
    .kami-manifesto { padding: 32px 0 32px 20px; }
    .kami-manifesto-body { font-size: 17px; }
    .kami-metrics { margin: 40px auto 48px; padding: 24px 20px; }
    .kami-chapter { padding: 40px 0; }
    .kami-chapter-title { font-size: 26px; }
    .kami-chapters { padding: 0 20px 64px; }
    .kami-footer { padding: 56px 20px 40px; }
    .kami-footer-kicker { font-size: 48px; letter-spacing: -0.5px; margin-bottom: 40px; }
    .kami-footer-grid { grid-template-columns: 1fr; gap: 20px; }
    .float-nav { right: var(--md); bottom: var(--md); }
}
@media (max-width: 479px) {
    .kami-hero-headline { font-size: 38px; letter-spacing: -0.3px; }
    .kami-footer-kicker { font-size: 36px; letter-spacing: -0.3px; }
    .example, .problem, .learning-objectives, .context-pause,
    .insight-note, .definition, .key-terminology, .problem-set {
        padding: var(--md) var(--lg);
    }
}

/* =========================================================
   Animated figures — dual-theme swap
   .figure-anim is a <video> tag (paired light/dark). The dark
   variant only shows when [data-theme="dark"] is set on <html>.
   ========================================================= */
.figure-anim-wrap { margin: 1.5rem auto; max-width: 100%; }
/* Same viewport-height cap as .figure-static — solo animations scale
 * down preserving aspect ratio when 80vh is the binding constraint. */
.figure-anim { display: block; max-width: 100%; max-height: 80vh; height: auto; width: auto; margin: 0 auto; }
.figure-anim.figure-dark { display: none; }
[data-theme="dark"] .figure-anim.figure-light { display: none; }
[data-theme="dark"] .figure-anim.figure-dark { display: block; }

.figure-anim-controls {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 0.5rem auto 0;
    padding: 0 0.25rem;
    font-size: 0.9rem;
    color: var(--ink-charcoal);
}
.figure-anim-play {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    border: 1px solid var(--ink-stone);
    background: transparent;
    color: var(--ink-near-black);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.85rem;
    line-height: 1;
    padding: 0;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}
.figure-anim-play:hover { background: var(--warm-sand); border-color: var(--wedgwood); }
.figure-anim-scrubber {
    flex: 1 1 auto;
    accent-color: var(--wedgwood);
    cursor: pointer;
    height: 0.4rem;
}
.figure-anim-readout {
    flex: 0 0 auto;
    min-width: 5.5rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--ink-olive);
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
[data-theme="dark"] .figure-anim-play { color: var(--ivory); border-color: var(--ink-warm-silver); }
[data-theme="dark"] .figure-anim-play:hover { background: var(--dark-surface); border-color: var(--wedgwood-light); }

/* ── Reading-font picker (parity with style.css) ─────────────────────── */
/* The .font-pick navbar links + script.js JS add a font-<name> body class.
 * style-bookshelf.css needs the matching @font-face + body.font-* rules
 * so bookshelf-themed pages honour the picker the same way as the
 * default theme. */

@font-face {
    font-family: 'OpenDyslexic';
    src: url('https://cdn.jsdelivr.net/npm/open-dyslexic@1.0.3/woff/OpenDyslexic-Regular.woff') format('woff');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'OpenDyslexic';
    src: url('https://cdn.jsdelivr.net/npm/open-dyslexic@1.0.3/woff/OpenDyslexic-Bold.woff') format('woff');
    font-weight: bold;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'OpenDyslexic';
    src: url('https://cdn.jsdelivr.net/npm/open-dyslexic@1.0.3/woff/OpenDyslexic-Italic.woff') format('woff');
    font-weight: normal;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: 'OpenDyslexic';
    src: url('https://cdn.jsdelivr.net/npm/open-dyslexic@1.0.3/woff/OpenDyslexic-BoldItalic.woff') format('woff');
    font-weight: bold;
    font-style: italic;
    font-display: swap;
}

body.font-opendyslexic {
    font-family: 'OpenDyslexic', 'Comic Sans MS', cursive;
    --font-body: 'OpenDyslexic', 'Comic Sans MS', cursive;
    letter-spacing: 0.05em;
    word-spacing: 0.12em;
    line-height: 1.8;
}
body.font-lexend {
    font-family: 'Lexend', sans-serif;
    --font-body: 'Lexend', sans-serif;
    letter-spacing: 0.02em;
    line-height: 1.75;
}
body.font-atkinson {
    font-family: 'Atkinson Hyperlegible', sans-serif;
    --font-body: 'Atkinson Hyperlegible', sans-serif;
    line-height: 1.7;
}
body.font-comic {
    font-family: 'Comic Sans MS', 'Comic Sans', cursive;
    --font-body: 'Comic Sans MS', 'Comic Sans', cursive;
    letter-spacing: 0.02em;
    line-height: 1.7;
}

/* Keep navbar / code / math in their original fonts regardless of pick. */
body.font-opendyslexic .navbar,
body.font-opendyslexic .nav-dropdown-btn,
body.font-opendyslexic .theme-toggle,
body.font-opendyslexic code,
body.font-opendyslexic pre,
body.font-opendyslexic kbd,
body.font-opendyslexic .mjx-container,
body.font-lexend .navbar,
body.font-lexend .nav-dropdown-btn,
body.font-lexend .theme-toggle,
body.font-lexend code,
body.font-lexend pre,
body.font-lexend kbd,
body.font-lexend .mjx-container,
body.font-atkinson .navbar,
body.font-atkinson .nav-dropdown-btn,
body.font-atkinson .theme-toggle,
body.font-atkinson code,
body.font-atkinson pre,
body.font-atkinson kbd,
body.font-atkinson .mjx-container,
body.font-comic .navbar,
body.font-comic .nav-dropdown-btn,
body.font-comic .theme-toggle,
body.font-comic code,
body.font-comic pre,
body.font-comic kbd,
body.font-comic .mjx-container {
    /* Keep navbar/code/math in the bookshelf theme font when the dyslexic
     * switch is on. --font-heading is the clean-textbook-style variable;
     * bookshelf defines --font-serif (Charter) instead. Use the chain so
     * the navbar stays in its native theme font under every active theme,
     * not the browser-default serif that bare `var(--font-heading)`
     * resolves to in bookshelf. */
    font-family: var(--font-heading, var(--font-serif, sans-serif));
    letter-spacing: normal;
    word-spacing: normal;
}

/* ── Settings cog + squircle controls ────────────────────────────────── */
/* Used by the consolidated settings dropdown in the navbar partial.
 * Same block lives in both style.css and style-bookshelf.css so all
 * theme variants render the cog identically.
 */

.nav-settings {
    position: relative;
    display: inline-flex;
    align-items: center;
    margin-left: 0.25rem;
}
.nav-settings-btn {
    background: transparent;
    border: 1px solid transparent;
    color: inherit;
    padding: 0.3rem;
    border-radius: 8px;
    cursor: pointer;
    line-height: 0;
    transition: background 0.15s, border-color 0.15s, transform 0.2s;
}
.nav-settings-btn:hover,
.nav-settings-btn[aria-expanded="true"] {
    background: rgba(120, 120, 140, 0.12);
    border-color: rgba(120, 120, 140, 0.25);
}
.nav-settings-btn .settings-cog {
    display: block;
    transition: transform 0.4s ease;
}
.nav-settings-btn[aria-expanded="true"] .settings-cog {
    transform: rotate(60deg);
}

.nav-settings-menu {
    display: none;
    position: absolute;
    right: 0;
    top: calc(100% + 0.4rem);
    min-width: 320px;
    max-width: 92vw;
    z-index: 110;
    background: var(--card-bg, #fff);
    color: var(--ink, #1c1c1e);
    border: 1px solid var(--card-border, rgba(60, 60, 67, 0.18));
    border-radius: 14px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16);
    padding: 0.85rem 1rem 1rem;
}
.nav-settings-menu.open {
    display: block;
}

.settings-heading {
    margin: 0 0 0.6rem;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted, #6b6b73);
}

.settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.85rem;
    padding: 0.55rem 0;
    border-top: 1px solid var(--divider, rgba(60, 60, 67, 0.12));
}
.settings-row:first-of-type {
    border-top: none;
}
.settings-label {
    flex: 1 1 auto;
    font-size: 0.95rem;
    color: var(--ink, #1c1c1e);
}

/* Squircle switch — used for binary toggles (Dark Mode, Dyslexic Font) */
.squircle-switch {
    position: relative;
    display: inline-block;
    width: 46px;
    height: 26px;
    flex: 0 0 auto;
    cursor: pointer;
}
.squircle-switch input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}
.squircle-slider {
    position: absolute;
    inset: 0;
    background: var(--switch-off, #cbd5e0);
    /* Squircle = pill outline + slightly-rounded inner knob */
    border-radius: 6px;
    transition: background 0.18s;
}
.squircle-slider::before {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 20px;
    height: 20px;
    /* Squircle knob — not a full circle, not a square; ~40% radius */
    border-radius: 4px;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
    transition: transform 0.18s, border-radius 0.18s;
}
.squircle-switch input:checked + .squircle-slider {
    background: var(--wedgwood, #4a7ba6);
}
.squircle-switch input:checked + .squircle-slider::before {
    transform: translateX(20px);
}
.squircle-switch input:focus-visible + .squircle-slider {
    outline: 2px solid var(--wedgwood-light, #6a96bf);
    outline-offset: 2px;
}

/* Squircle action button — used for Save Offline. Squircle silhouette,
 * single-press action (not stateful). */
.squircle-action {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.8rem;
    background: var(--wedgwood, #4a7ba6);
    color: #fff;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: 600;
    line-height: 1;
    transition: transform 0.12s, box-shadow 0.12s, background 0.15s;
    flex: 0 0 auto;
}
.squircle-action:hover {
    background: var(--wedgwood-dark, #3a6892);
    transform: translateY(-1px);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
}
.squircle-action:active {
    transform: translateY(0);
}
.squircle-action svg {
    display: block;
}
.squircle-action-label {
    display: inline-block;
}

/* Slides "Present" link, injected by publish.py survival guard before
 * the saveOfflineBtn. Render as a squircle-action so it visually
 * matches the rest of the dropdown. publish.py emits the link with
 * classes `theme-toggle slides-link`; the settings-row scope keeps
 * old un-themed instances looking sane. */
.nav-settings-menu .slides-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.8rem;
    background: var(--wedgwood, #4a7ba6);
    color: #fff;
    border-radius: 6px;
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 600;
    line-height: 1;
    transition: background 0.15s, transform 0.12s;
}
.nav-settings-menu .slides-link:hover {
    background: var(--wedgwood-dark, #3a6892);
    transform: translateY(-1px);
}

/* Dark-theme variant — recolor switch off-state + cog hover */
[data-theme="dark"] .squircle-slider {
    background: #4a4a52;
}
[data-theme="dark"] .nav-settings-menu {
    background: var(--dark-surface, #2a2a30);
    color: var(--ink-near-black);
    border-color: rgba(255, 255, 255, 0.08);
}
[data-theme="dark"] .settings-label {
    color: var(--ink-near-black);
}
[data-theme="dark"] .nav-settings-btn:hover,
[data-theme="dark"] .nav-settings-btn[aria-expanded="true"] {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.18);
}

/* Hide the old Light/Dark text button if the new checkbox swap is in
 * place but a stale page snapshot still has both. Defensive only. */
button.theme-toggle#themeToggle { display: none; }

/* Heading font swap when dyslexic font is on. The default theme styles
 * H1-H4 via var(--font-serif) which overrides the body font, so toggling
 * font-opendyslexic on the body alone leaves headings in their serif. */
body.font-opendyslexic h1,
body.font-opendyslexic h2,
body.font-opendyslexic h3,
body.font-opendyslexic h4,
body.font-opendyslexic .definition-title,
body.font-opendyslexic .example-title,
body.font-opendyslexic .navbar-brand,
body.font-opendyslexic summary {
    font-family: 'OpenDyslexic', 'Comic Sans MS', cursive !important;
    letter-spacing: 0.03em;
}
body.font-lexend h1,
body.font-lexend h2,
body.font-lexend h3,
body.font-lexend h4,
body.font-lexend .definition-title,
body.font-lexend .example-title,
body.font-lexend .navbar-brand,
body.font-lexend summary {
    font-family: 'Lexend', sans-serif !important;
}
body.font-atkinson h1,
body.font-atkinson h2,
body.font-atkinson h3,
body.font-atkinson h4,
body.font-atkinson .definition-title,
body.font-atkinson .example-title,
body.font-atkinson .navbar-brand,
body.font-atkinson summary {
    font-family: 'Atkinson Hyperlegible', sans-serif !important;
}
body.font-comic h1,
body.font-comic h2,
body.font-comic h3,
body.font-comic h4,
body.font-comic .definition-title,
body.font-comic .example-title,
body.font-comic .navbar-brand,
body.font-comic summary {
    font-family: 'Comic Sans MS', 'Comic Sans', cursive !important;
}

/* ── Static manim figures (theme-aware light/dark PNG pair) ─────────── */
/* Used by figure_animate when mode: static. Two `<img>` tags inside
 * a single wrapper; CSS shows the light variant by default and swaps
 * to dark on `[data-theme="dark"]`. The dark img carries
 * aria-hidden="true" so screen readers only see the light variant's
 * alt text. */
.figure-static-wrap {
    display: block;
    margin: var(--xl, 2rem) 0;
    text-align: center;
}
.figure-static-wrap .figure-static {
    max-width: 100%;
    /* Cap solo figures at the available viewport height — a 1280×720 manim
     * still on a tall column otherwise dominates the viewport. 80vh leaves
     * ~20% for navbar + breathing room. The browser scales down preserving
     * aspect ratio to honor BOTH max-width: 100% AND max-height: 80vh.
     * In-row figures override this to `max-height: none` because the grid
     * cell already constrains them. */
    max-height: 80vh;
    height: auto;
    width: auto;
    display: inline-block;
}
.figure-static-wrap .figure-dark {
    display: none;
}
[data-theme="dark"] .figure-static-wrap .figure-light {
    display: none;
}
[data-theme="dark"] .figure-static-wrap .figure-dark {
    display: inline-block;
}

/* Multi-figure row grouping (mirrors default theme rules).
 *
 * FULL-BLEED: rows break out of the .container max-width and span the
 * viewport width, so multi-figure layouts (especially 2-col + 3-col)
 * read at comfortable size on wide screens. The negative-margin trick:
 * 50% is half the row's content width (= half the container content
 * area); 50vw is half the viewport. The difference pulls the row
 * leftward by the gap between container edge and viewport edge, then
 * 100vw width spans the viewport. */
.figure-row {
    display: grid;
    gap: 1.25rem;
    margin: var(--xl, 2rem) calc(50% - 50vw);
    width: 100vw;
    max-width: 100vw;
    align-items: start;
    /* Restore the page's 30px side gutter inside the full-bleed row so
     * the figures don't kiss the viewport edges. */
    padding: 0 30px;
    box-sizing: border-box;
}
.figure-row-2col { grid-template-columns: 1fr 1fr; }
.figure-row-3col { grid-template-columns: 1fr 1fr 1fr; }
.figure-row .figure-row-cell {
    display: flex;
    flex-direction: column;
    align-items: stretch;     /* fill cell width — was `center` which left
                                  * whitespace gutters around inline-block imgs */
}
.figure-row .figure-row-cell .figure-static-wrap,
.figure-row .figure-row-cell .figure-anim-wrap {
    margin: 0 0 0.4rem 0;
    width: 100%;
}
/* Inside a row cell, force the figure media to fill the cell width
 * instead of capping at its natural pixel size. Default `.figure-static`
 * uses `display: inline-block` + `max-width: 100%` so a 1280×720 manim
 * PNG centres in any cell wider than 1280px. Inside a row we always
 * want the image to span the cell. Also unset the solo `max-height: 80vh`
 * cap — the grid cell already constrains the figure; viewport height
 * shouldn't shrink a row cell. */
.figure-row .figure-row-cell .figure-static,
.figure-row .figure-row-cell .figure-anim {
    display: block;
    width: 100%;
    height: auto;
    max-height: none;
}
/* Theme toggle override at the in-row scope. The rules above set
 * `display: block` on every `.figure-static` / `.figure-anim` inside a
 * row cell, which is more specific than the default
 * `.figure-static-wrap .figure-dark { display: none }` toggle and
 * therefore shows BOTH light + dark variants simultaneously. These
 * rules re-establish the theme toggle at matching specificity so only
 * one variant renders at a time. */
.figure-row .figure-row-cell .figure-static.figure-dark,
.figure-row .figure-row-cell .figure-anim.figure-dark {
    display: none;
}
[data-theme="dark"] .figure-row .figure-row-cell .figure-static.figure-light,
[data-theme="dark"] .figure-row .figure-row-cell .figure-anim.figure-light {
    display: none;
}
[data-theme="dark"] .figure-row .figure-row-cell .figure-static.figure-dark,
[data-theme="dark"] .figure-row .figure-row-cell .figure-anim.figure-dark {
    display: block;
}
.figure-row .figure-row-cell p {
    margin: 0;
    text-align: center;
    font-size: 0.9em;
}
@media (max-width: 1399px) {
    /* Laptop / small-desktop (≤ 1399px catches 1280, 1366 laptop widths;
     * 1440+ widescreen monitors keep 3-col): 3-col rows reflow to 2-col
     * so cells stay readable. The grid auto-flow handles odd counts —
     * a 3rd figure in a 2-col grid simply lands in the left column of
     * row 2, leaving the right cell empty. Same behavior for any group:
     * cells fall into 2 or 3 cols and overflow rows naturally. */
    .figure-row-3col { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 768px) {
    /* Mobile / tablet: every row collapses to single-column stacking. */
    .figure-row-2col,
    .figure-row-3col { grid-template-columns: 1fr; }
}

/* Drawing Canvas */
.draw-canvas {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    z-index: 998;
    pointer-events: none;
    cursor: crosshair;
}
.draw-canvas.active { pointer-events: auto; }

.draw-toolbar {
    position: fixed;
    right: calc(2rem + 50px + 0.75rem);
    bottom: 2rem;
    display: flex;
    gap: 0.5rem;
    align-items: center;
    background: white;
    padding: 0.5rem 0.75rem;
    border-radius: 25px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.2);
    z-index: 999;
    opacity: 0;
    visibility: hidden;
    transform: translateX(10px);
    transition: opacity 0.2s, visibility 0.2s, transform 0.2s;
}
.draw-toolbar.show { opacity: 1; visibility: visible; transform: translateX(0); }

.draw-toolbar .draw-mode-btn {
    background: none;
    border: 1px solid var(--border-color);
    padding: 0.3rem 0.5rem;
    border-radius: 4px;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    min-width: 32px;
    text-align: center;
}
.draw-toolbar .draw-mode-btn:hover { background-color: var(--bg-light); }
.draw-toolbar .draw-mode-btn.active { background-color: var(--secondary-color); color: white; border-color: var(--secondary-color); }

.draw-toolbar .draw-sep {
    width: 1px;
    height: 24px;
    background: var(--border-color);
    margin: 0 0.25rem;
}

.draw-toolbar button {
    background: none;
    border: 1px solid var(--border-color);
    padding: 0.3rem 0.6rem;
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.85rem;
}
.draw-toolbar button:hover { background-color: var(--bg-light); }
.draw-toolbar button.active { background-color: var(--secondary-color); color: white; border-color: var(--secondary-color); }
.draw-toolbar input[type="color"] { width: 28px; height: 28px; border: none; border-radius: 50%; cursor: pointer; padding: 0; }
.draw-toolbar input[type="range"] { width: 80px; cursor: pointer; }
.draw-toolbar .size-preview { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; }
.draw-toolbar .size-dot { background-color: #333; border-radius: 50%; }

/* Laser Pointer */
.laser-dot {
    position: fixed;
    width: 12px;
    height: 12px;
    background: #ff0000;
    border-radius: 50%;
    pointer-events: none;
    z-index: 1002;
    display: none;
    box-shadow: 0 0 10px 5px rgba(255, 0, 0, 0.5), 0 0 20px 10px rgba(255, 0, 0, 0.2);
    transform: translate(-50%, -50%);
}
.laser-dot.show { display: block; }
.laser-trail {
    position: fixed;
    width: 8px;
    height: 8px;
    background: #ff0000;
    border-radius: 50%;
    pointer-events: none;
    z-index: 997;
    opacity: 0.5;
    animation: laser-fade 0.4s ease-out forwards;
    transform: translate(-50%, -50%);
}
@keyframes laser-fade {
    to { opacity: 0; transform: translate(-50%, -50%) scale(0.3); }
}

/* Dark Mode — neutral gray palette */
[data-theme="dark"] .float-nav-btn { background-color: #333; }
[data-theme="dark"] .float-nav-btn:hover { background-color: var(--secondary-color); }
[data-theme="dark"] .float-nav-btn:disabled:hover { background-color: #333; }
[data-theme="dark"] .draw-toolbar { background: #2a2a2a; }
[data-theme="dark"] .draw-toolbar button { border-color: #484848; color: #d4d4d4; }
[data-theme="dark"] .draw-toolbar button:hover { background-color: #333; }
[data-theme="dark"] .draw-toolbar .size-dot { background-color: #d4d4d4; }

@media (max-width: 768px) {
    .draw-toolbar { right: calc(1rem + 45px + 0.75rem); }
}

/* ---------------------------------------------------------------------
 * In-navbar search box + reader font-size A- / A / A+ control.
 * Mirrored from scripts/workflows/templates/partials/css/navbar.css.
 * ------------------------------------------------------------------- */

/* Absolutely center the search inside .navbar (which is position: sticky
 * and therefore a positioning context). Keeps it visually centered
 * regardless of the brand width on the left and the .navbar-nav cluster
 * on the right. Colors track the kami parchment palette. */
.nav-search {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.6rem;
    background: var(--ivory, #faf9f5);
    border: 1px solid var(--border-cream, #f0eee6);
    /* Squircle silhouette matching .squircle-switch / .squircle-action. */
    border-radius: 6px;
    min-width: 220px;
    max-width: 360px;
    z-index: 1;
    transition: border-color 0.15s, background 0.15s;
}
.nav-search:focus-within {
    border-color: var(--wedgwood, #4e6e8e);
    background: var(--pure-white, #fff);
}
.nav-search-icon { color: var(--ink-stone, #6b6a64); flex: 0 0 auto; }
.nav-search-input {
    border: none;
    background: transparent;
    outline: none;
    font: inherit;
    font-size: 0.9rem;
    color: var(--ink-near-black, #141413);
    width: 100%;
    min-width: 0;
}
.nav-search-input::placeholder { color: var(--ink-warm-silver, #b0aea5); }
.nav-search-count {
    font-size: 0.78rem;
    color: var(--ink-stone, #6b6a64);
    flex: 0 0 auto;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

mark.page-search-hit {
    background: #fff3a3;
    color: inherit;
    padding: 0 1px;
    border-radius: 2px;
}
mark.page-search-hit.is-active {
    background: #ffb86b;
    outline: 2px solid #ff8a1f;
}

/* Font-size widget — OpenStax-style: clickable A− / A+ stepper buttons
 * flanking a native <input type="range"> with visible notches at each
 * of the 5 preset positions (0/25/50/75/100% of the track). Each notch
 * is a 2×10px vertical tick painted into the track background, so users
 * see exactly how many discrete steps are available. Default position
 * (idx 1, "2 of 5" with 1-indexing) puts the thumb one notch above the
 * smallest mark. */
.font-size-group {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
}
.font-size-step {
    border: none;
    background: transparent;
    color: var(--ink-near-black);
    cursor: pointer;
    padding: 4px 6px;
    border-radius: 6px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.12s;
}
.font-size-step:hover { background: rgba(78, 110, 142, 0.10); }
.font-size-step:focus-visible {
    outline: 2px solid var(--wedgwood-light, #7a9bbf);
    outline-offset: 2px;
}
.font-size-step-glyph {
    font-family: var(--font-serif);
    color: var(--ink-near-black);
    line-height: 1;
    user-select: none;
}
.font-size-step-glyph-small { font-size: 0.75rem; }
.font-size-step-glyph-large { font-size: 1.1rem; }

.font-size-slider {
    -webkit-appearance: none;
    appearance: none;
    width: 120px;
    height: 18px;
    background:
        /* 5 hollow circle bubbles at 0, 25, 50, 75, 100% of the track.
         * Each bubble's INTERIOR is filled with the menu background
         * (--ivory) so the rail drawn underneath is visually broken at
         * each bubble position — the line connects the bubbles in the
         * gaps but disappears inside each ring. The thumb (16px filled
         * wedgwood circle) sits on top of whichever bubble matches the
         * current value, visually "filling" the selected position while
         * the others stay hollow. */
        radial-gradient(circle, var(--ivory) 0, var(--ivory) 3.5px, var(--ink-warm-silver) 3.5px, var(--ink-warm-silver) 5px, transparent 5px) no-repeat 0%   50% / 12px 12px,
        radial-gradient(circle, var(--ivory) 0, var(--ivory) 3.5px, var(--ink-warm-silver) 3.5px, var(--ink-warm-silver) 5px, transparent 5px) no-repeat 25%  50% / 12px 12px,
        radial-gradient(circle, var(--ivory) 0, var(--ivory) 3.5px, var(--ink-warm-silver) 3.5px, var(--ink-warm-silver) 5px, transparent 5px) no-repeat 50%  50% / 12px 12px,
        radial-gradient(circle, var(--ivory) 0, var(--ivory) 3.5px, var(--ink-warm-silver) 3.5px, var(--ink-warm-silver) 5px, transparent 5px) no-repeat 75%  50% / 12px 12px,
        radial-gradient(circle, var(--ivory) 0, var(--ivory) 3.5px, var(--ink-warm-silver) 3.5px, var(--ink-warm-silver) 5px, transparent 5px) no-repeat 100% 50% / 12px 12px,
        /* Thin rail behind the bubbles — visible only in the gaps. */
        linear-gradient(var(--border-warm) 0 0) no-repeat 0 50% / 100% 2px;
    background-color: transparent;
    border-radius: 999px;
    outline: none;
    cursor: pointer;
    margin: 0;
    padding: 0;
}
.font-size-slider::-webkit-slider-runnable-track {
    background: transparent;
    height: 18px;
    border: none;
}
.font-size-slider::-moz-range-track {
    background: transparent;
    height: 18px;
    border: none;
}
.font-size-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--wedgwood, #4e6e8e);
    border: 2px solid var(--ivory, #faf9f5);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
    cursor: pointer;
    margin-top: 1px; /* center the 16px thumb against the 18px track box */
    transition: transform 0.12s, background 0.12s;
}
.font-size-slider::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--wedgwood, #4e6e8e);
    border: 2px solid var(--ivory, #faf9f5);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
    cursor: pointer;
}
.font-size-slider::-webkit-slider-thumb:hover,
.font-size-slider::-webkit-slider-thumb:active {
    transform: scale(1.15);
    background: var(--wedgwood-deep, #3d5a80);
}
.font-size-slider:focus-visible {
    outline: 2px solid var(--wedgwood-light, #7a9bbf);
    outline-offset: 4px;
    border-radius: 999px;
}

/* Reader font-size control wiring. The A−/A/A+ buttons (in the
 * settings cog menu, handled by script.js) set --reader-font-scale on
 * the <html> element. We apply it as font-size on .main-content so
 * inherited text (paragraphs, lists) scales while the layout box keeps
 * its 1120px max-width.
 *
 * `zoom` was tried (2026-05-16) and reverted same day: it scales the
 * layout box itself, which pushes wide content (KaTeX display math,
 * code blocks) past the container's max-width and produces a page-
 * level horizontal scroll bar at larger scales.
 *
 * Convention for px-pinned prose elements (h1-h4, tables, captions,
 * callout labels, definition titles, example titles, solution summary,
 * etc.): wrap the px value in
 *
 *     font-size: calc(<Npx> * var(--reader-font-scale, 1));
 *
 * This scales each rule independently without em-cascade compounding
 * (a `caption` inside a `table` would otherwise scale twice if both
 * used `em`). The original px stays self-documenting in the rule.
 * Navbar / floating-tools / .kami-* chrome stays in plain px since the
 * widget is intentionally prose-only. */
html { --reader-font-scale: 1; }
.main-content { font-size: calc(1rem * var(--reader-font-scale, 1)); }

@media (max-width: 900px) {
    /* On narrow screens drop the search back into normal flow so it doesn't
     * overlap the hamburger toggle or brand. */
    .nav-search {
        position: static;
        transform: none;
        margin: 0.4rem 0;
        min-width: 0;
        max-width: none;
        width: 100%;
    }
}

/* Dark-mode override: the parchment search box needs to flip to a dark
 * tile so it stays legible against the dark navbar. */
[data-theme="dark"] .nav-search {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.14);
}
[data-theme="dark"] .nav-search:focus-within {
    background: rgba(255, 255, 255, 0.12);
    border-color: var(--wedgwood-light, #7a9bbf);
}
[data-theme="dark"] .nav-search-input { color: var(--ink-on-dark, #faf9f5); }
[data-theme="dark"] .nav-search-input::placeholder { color: rgba(255, 255, 255, 0.55); }
[data-theme="dark"] .nav-search-icon,
[data-theme="dark"] .nav-search-count { color: rgba(255, 255, 255, 0.7); }

[data-theme="dark"] mark.page-search-hit { background: #6b5b1a; color: #fef3c7; }
[data-theme="dark"] mark.page-search-hit.is-active { background: #b58124; color: #fffbe8; outline-color: #ffb86b; }
[data-theme="dark"] .font-size-step,
[data-theme="dark"] .font-size-step-glyph { color: var(--ink-on-dark, #faf9f5); }
[data-theme="dark"] .font-size-step:hover { background: rgba(255, 255, 255, 0.08); }
[data-theme="dark"] .font-size-slider {
    background:
        /* Bubble interiors match the dark menu background (#1f1f1d, per
         * [data-theme="dark"] .nav-dropdown-menu) so the rail visually
         * breaks at each bubble in dark mode too. */
        radial-gradient(circle, #1f1f1d 0, #1f1f1d 3.5px, rgba(255, 255, 255, 0.35) 3.5px, rgba(255, 255, 255, 0.35) 5px, transparent 5px) no-repeat 0%   50% / 12px 12px,
        radial-gradient(circle, #1f1f1d 0, #1f1f1d 3.5px, rgba(255, 255, 255, 0.35) 3.5px, rgba(255, 255, 255, 0.35) 5px, transparent 5px) no-repeat 25%  50% / 12px 12px,
        radial-gradient(circle, #1f1f1d 0, #1f1f1d 3.5px, rgba(255, 255, 255, 0.35) 3.5px, rgba(255, 255, 255, 0.35) 5px, transparent 5px) no-repeat 50%  50% / 12px 12px,
        radial-gradient(circle, #1f1f1d 0, #1f1f1d 3.5px, rgba(255, 255, 255, 0.35) 3.5px, rgba(255, 255, 255, 0.35) 5px, transparent 5px) no-repeat 75%  50% / 12px 12px,
        radial-gradient(circle, #1f1f1d 0, #1f1f1d 3.5px, rgba(255, 255, 255, 0.35) 3.5px, rgba(255, 255, 255, 0.35) 5px, transparent 5px) no-repeat 100% 50% / 12px 12px,
        linear-gradient(rgba(255, 255, 255, 0.14) 0 0) no-repeat 0 50% / 100% 2px;
    background-color: transparent;
}
[data-theme="dark"] .font-size-slider::-webkit-slider-thumb {
    background: var(--wedgwood-light, #7a9bbf);
    border-color: var(--dark-surface, #30302e);
}
[data-theme="dark"] .font-size-slider::-moz-range-thumb {
    background: var(--wedgwood-light, #7a9bbf);
    border-color: var(--dark-surface, #30302e);
}
