/* ══════════════════════════════════════════════════════════════════════════════
   PPEA — Main Stylesheet
   ══════════════════════════════════════════════════════════════════════════════
   Loaded on every page.  Contains design tokens, base layout, navigation,
   and shared UI components.

   Edition-text-specific rules (toolbar, TEI annotations, line numbering,
   lightbox, combobox) live in edition_text.css.  Comparison-panel rules
   live in edition_compare.css.  Title-page rules live in titlepage.css.
   ══════════════════════════════════════════════════════════════════════════════ */


/* ── §1  Design Tokens ────────────────────────────────────────────────────────
   Semantic custom properties shared across all stylesheets.  Color tokens use
   light-dark() so they respond automatically to the user's color-scheme
   preference (or manual data-theme override — see §2).

   Tokens specific to edition text (TEI annotation colors, highlight colors,
   line-number column width) live in edition_text.css.  Comparison-panel
   tokens live in edition_compare.css.
   ────────────────────────────────────────────────────────────────────────── */
/* --main-pad-x: mobile horizontal padding on <main>.  Registered as
   typed <length> so the "1ex" value set on <main> is resolved in main's
   own font context at declaration time; otherwise descendants like
   #comparison-panel (which uses calc(-1 * var(--main-pad-x)) for its
   mobile full-bleed) would re-resolve the token against their own font
   and drift by a pixel or two away from the viewport edge. */
@property --main-pad-x {
    syntax: "<length>";
    inherits: true;
    initial-value: 0px;
}

:root {
    color-scheme: light dark;

    /* ── Backgrounds ──────────────────────────────────────────────────── */
    --color-bg:             light-dark(#fff, #1a1a1a);
    --color-bg-alt:         light-dark(#f5f5f5, #252525);
    --color-bg-subtle:      light-dark(#f0f0f0, #2a2a2a);
    --color-bg-glass:       light-dark(rgba(245, 245, 245, 0.7),  rgba(30, 30, 30, 0.7));
    --color-bg-glass-mid:   light-dark(rgba(245, 245, 245, 0.85), rgba(30, 30, 30, 0.85));
    --color-bg-glass-solid: light-dark(rgba(245, 245, 245, 0.95), rgba(30, 30, 30, 0.95));
    --color-highlight:      light-dark(yellow, #665500);

    /* ── Foreground / text ────────────────────────────────────────────── */
    --color-text:           light-dark(#000, #e0e0e0);
    --color-text-strong:    light-dark(#444, #ccc);       /* active controls */
    --color-text-secondary: light-dark(#555, #aaa);       /* indicators */
    --color-text-muted:     light-dark(#666, #999);       /* inactive controls */
    --color-text-faint:     light-dark(#888, #777);       /* eyebrows, marginalia */
    --color-text-disabled:  light-dark(#b5b5b5, #555);    /* disabled controls */
    --color-text-on-dark:   light-dark(#fff, #e0e0e0);    /* text over dark chrome */

    /* ── Borders ──────────────────────────────────────────────────────── */
    --color-border:         light-dark(#ddd, #444);
    --color-border-light:   light-dark(#d3d3d3, #3a3a3a); /* navlist separators */
    --color-border-medium:  light-dark(#a7a7a7, #555);    /* button dividers */
    --color-border-strong:  light-dark(#a9a9a9, #666);    /* panel/header dividers */

    /* ── Chrome (header, footer, nav bar) ─────────────────────────────── */
    --color-chrome:         light-dark(#a9a9a9, #333);
    --color-chrome-hover:   light-dark(#d3d3d3, #444);
    --color-chrome-submenu: light-dark(#f5f5f5, #3a3a3a);
    --color-nav-overlay:    light-dark(rgba(99, 99, 99, 0.97), rgba(20, 20, 20, 0.97));

    /* ── Links & focus ────────────────────────────────────────────────── */
    --color-link:           light-dark(#58a6bc, #7bc4d8);
    --color-link-visited:   light-dark(rgb(140, 191, 210), #9dc8d8);
    --color-focus:          light-dark(#58a6bc, #7bc4d8);

    /* ── Accent (folio combobox, selections) ──────────────────────────── */
    --color-accent:         light-dark(#4a90d9, #5a9ae0);
    --color-accent-strong:  light-dark(#3a80c9, #4a8ad0);
    --color-accent-light:   light-dark(#d0e6f8, #1a3050);
    --color-accent-ring:    light-dark(rgba(74, 144, 217, 0.25), rgba(90, 154, 224, 0.25));

    /* ── Overlays & glass ─────────────────────────────────────────────── */
    --overlay-bg:           light-dark(rgba(169, 169, 169, 0.1), rgba(80, 80, 80, 0.15));
    --overlay-bg-active:    light-dark(rgba(99, 99, 99, 0.1), rgba(120, 120, 120, 0.15));
    --overlay-border:       light-dark(rgba(0, 0, 0, 0.18), rgba(255, 255, 255, 0.15));
    --glass-blur:           blur(1.25px);
    --glass-blur-strong:    blur(3px);
    --glass-blur-heavy:     blur(5px);
    --color-backdrop:       light-dark(rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.92));
    --color-tooltip-bg:     light-dark(rgba(0, 0, 0, 0.8), rgba(50, 50, 50, 0.9));
    --color-dropdown-bg:    light-dark(rgba(39, 39, 39, 0.92), rgba(50, 50, 50, 0.95));

    /* ── Note & tag UI ────────────────────────────────────────────────── */
    --color-note-hover:     light-dark(#717946, #9aa060);

    /* ── Layout ───────────────────────────────────────────────────────── */
    --content-max-width:    1200px;
    --header-height:        50px;
    --toolbar-ribbon-h:     28px;   /* desktop toolbar height; overridden to 40px on mobile */
    --footer-height:        50px;
    /* Breathing room between fixed chrome and content.
       rem (not px) so it scales with user font-size preferences. */
    --page-top-buffer:      1.25rem;

    /* ── Responsive breakpoints ───────────────────────────────────────────
       Canonical breakpoint constants, shared by CSS and JS.  JS reads them
       via getComputedStyle(document.documentElement).getPropertyValue().
       CSS @media rules cannot reference custom properties, so each
       @media block in the project is tagged with a trailing comment
       naming the constant it corresponds to — grep for e.g. "--bp-desktop"
       to find every consumer.

       The text-page grid has four stages (see edition_text.css §25–§27):
         < --bp-phone    — Stage D, phone single-column + popover marginalia
         < --bp-tablet   — Stage C, 3-col with inline marginalia, no line nos
         < --bp-desktop  — Stage B, compact desktop (inline marginalia, single
                           line numbers, narrower text cap)
         ≥ --bp-desktop  — Stage A, wide desktop (all five streams, dual
                           line numbers)

       --bp-desktop also marks where site chrome (header nav, toolbar
       ribbon, info popover) flips between mobile and desktop modes, and
       where the side panels (search, compare, images) flip between
       overlay and sticky-sidebar modes.                                  */
    --bp-phone:             500px;
    --bp-tablet:            650px;
    --bp-desktop:           900px;
    /* --bp-banner-cutoff: 1135px — upper bound of range where #banner is
       hidden (@media max-width: 1135px); @media cannot use custom
       properties, so this is documentation/grep only. */

    /* ── Typography ───────────────────────────────────────────────────── */
    --font-text:            'Junicode2', Junicode, Times, serif;
    --font-ui:              'Raleway', sans-serif, 'Junicode2', Junicode;
    --font-heading:         'Signika', sans-serif, 'Junicode2', Junicode;

    /* ── Transitions ──────────────────────────────────────────────────── */
    --transition-fast:      0.15s ease;
    --transition-toolbar:   0.25s ease;
    --transition-medium:    0.35s cubic-bezier(0.4, 0, 0.2, 1);
    --transition-slow:      0.5s ease;

    /* ── Button / control chrome ──────────────────────────────────────── */
    /* Gradients and shadows cannot use light-dark() (non-color values).
       Light values here; dark overrides in the @media block below.     */
    --btn-gradient:          linear-gradient(#fdfdfd, #d1d1d1);
    --btn-gradient-active:   linear-gradient(#e1e1e1, #fefefe);
    --btn-gradient-disabled: linear-gradient(#dedede, #ccc);
    --btn-shadow-active:     0 1px 3px rgba(0, 0, 0, 0.4) inset;

    /* ── iOS safe-area insets (exposed to JS) ─────────────────────────
       Mirror env(safe-area-inset-*) onto CSS custom properties so JS
       can read them via getComputedStyle.  Resolve to 0px when
       viewport-fit=cover isn't active (non-iOS, or iOS on older OS). */
    --safe-area-inset-top:    env(safe-area-inset-top,    0px);
    --safe-area-inset-bottom: env(safe-area-inset-bottom, 0px);
    --safe-area-inset-left:   env(safe-area-inset-left,   0px);
    --safe-area-inset-right:  env(safe-area-inset-right,  0px);
}


/* ── §2  Dark mode — manual toggle + non-color overrides ──────────────────────
   data-theme="dark"  forces dark regardless of OS preference.
   data-theme="light" forces light.  Absence = follow OS.
   Gradient / shadow tokens are overridden here because light-dark() only
   accepts <color> values.
   ────────────────────────────────────────────────────────────────────────── */
:root[data-theme="dark"]  { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --btn-gradient:          linear-gradient(#3a3a3a, #2a2a2a);
        --btn-gradient-active:   linear-gradient(#2a2a2a, #3a3a3a);
        --btn-gradient-disabled: linear-gradient(#333, #2a2a2a);
        --btn-shadow-active:     0 1px 3px rgba(0, 0, 0, 0.6) inset;
    }
}
:root[data-theme="dark"] {
    --btn-gradient:          linear-gradient(#3a3a3a, #2a2a2a);
    --btn-gradient-active:   linear-gradient(#2a2a2a, #3a3a3a);
    --btn-gradient-disabled: linear-gradient(#333, #2a2a2a);
    --btn-shadow-active:     0 1px 3px rgba(0, 0, 0, 0.6) inset;
}


/* ── §3  Fonts ────────────────────────────────────────────────────────────────
   Junicode 2 variable (roman + italic) for medieval text, with Junicode 1
   as legacy fallback.  UI fonts (Raleway, Signika) loaded via Google Fonts
   in the HTML head.
   ────────────────────────────────────────────────────────────────────────── */

/* Junicode 2 variable font — covers all weights and widths */
@font-face {
    font-family: 'Junicode2';
    font-style: normal;
    font-weight: 100 900;
    src: url("/resources/fonts/JunicodeVF-Roman.woff2") format("woff2");
}
@font-face {
    font-family: 'Junicode2';
    font-style: italic;
    font-weight: 100 900;
    src: url("/resources/fonts/JunicodeVF-Italic.woff2") format("woff2");
}

/* Junicode 1 legacy fallback — local install first, then woff, then ttf */
@font-face {
    font-family: Junicode;
    src: local("Junicode"),
         url("/fonts/Junicode.woff") format("woff"),
         url("/fonts/Junicode.ttf") format("truetype");
}
@font-face {
    font-family: Junicode;
    font-weight: bold;
    src: local("Junicode Bold"),
         local("Junicode-Bold"),
         url("/fonts/Junicode-Bold.woff") format("woff"),
         url("/fonts/Junicode-Bold.ttf") format("truetype");
}
@font-face {
    font-family: Junicode;
    font-style: italic;
    src: local("Junicode Italic"),
         local("Junicode-Italic"),
         url("/fonts/Junicode-Italic.woff") format("woff"),
         url("/fonts/Junicode-Italic.ttf") format("truetype");
}
@font-face {
    font-family: Junicode;
    font-weight: bold;
    font-style: italic;
    src: local("Junicode Bold Italic"),
         local("Junicode-BoldItalic"),
         url("/fonts/Junicode-BoldItalic.woff") format("woff"),
         url("/fonts/Junicode-BoldItalic.ttf") format("truetype");
}

.scholarly-text,
.medieval-text {
    font-size: 12pt;
    font-family: var(--font-text);
}


/* ── §4  Visually-hidden utility ──────────────────────────────────────────────
   Hides content visually while keeping it accessible to screen readers.
   Used for .aria-text spans throughout the site.  Edition-specific uses
   (radio buttons, toggle checkboxes) are in edition_text.css.
   ────────────────────────────────────────────────────────────────────────── */
.aria-text {
    border: 0;
    clip: rect(0, 0, 0, 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
}


/* ── §5  Base styles ──────────────────────────────────────────────────────────
   Document-level resets and defaults.
   ────────────────────────────────────────────────────────────────────────── */
*, *::before, *::after {
    box-sizing: border-box;
}

html, body {
    width: 100%;
    /* Prevent a horizontal scrollbar from appearing when the vertical scrollbar
       reduces the available width below the article's content width.  overflow-x:
       clip does not create a scroll container (unlike hidden/auto), so it leaves
       position:sticky and position:fixed behaviour unaffected. */
    overflow-x: clip;
    /* Lock iOS Safari's automatic text inflation.  Without this, landscape
       orientation and some "small text" heuristics can blow up headings
       beyond what the CSS specifies, even with a correct viewport meta. */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

body {
    margin: 0;
    font-family: var(--font-ui);
    background-color: var(--color-bg);
    color: var(--color-text);
    position: relative;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

sup { line-height: 0; }

h1 { text-align: center; }

h1, h2 { font-family: var(--font-heading); }

/* On narrow viewports the default browser sizes for h1/h2 (2em / 1.5em) —
   especially rendered in the heavy Signika display face — eat most of the
   screen on real iOS Safari.  Scale them down with clamp() on mobile.
   Scoped to .site-page so text-page headings (which carry their own
   sizing) are unaffected. */
@media (max-width: 649px) {
    .site-page h1 {
        font-size: clamp(1.25rem, 5.5vw, 2rem);
    }
    .site-page h2 {
        font-size: clamp(1rem, 4.5vw, 1.5rem);
    }
}

a[href] { color: var(--color-link); }

a:visited { color: var(--color-link-visited); }

/* Offset for ID jump with fixed header.
   scroll-margin-top replaces the old display:block ::before hack, which broke
   text-indent in Safari by creating a block-in-inline formatting context. */
main [id] {
    scroll-margin-top: var(--header-height);
}


/* ── §5a  Z-index scale ──────────────────────────────────────────────────────
   Root stacking context layers (elements in <body>), sorted bottom→top:
     1   <main>              — content root; internal content layers within
     2   grid internals      — note markers, subgrid cols
     8   .search-match-nav   — floating in-text match navigator (below chrome)
    20   .toolbar-ribbon     — edition toolbar, desktop (top) + mobile (bottom)
    25   header (desktop)    — fixed site header (above toolbar so hover
                               submenus from the nav paint over it)
    25   nav submenus        — trapped in header's stacking context
    30   nav.contents        — slide-in TOC sidebar (overlays header + toolbar)
    35   #contents-button    — TOC open/close tab (must stay above sidebar)
         footer              — absolute-positioned site footer, no z-index
                                (sits at doc bottom, never overlaps chrome)
   150   .toolbar-submenu    — toolbar dropdown menus
   200   #comparison-panel   — bottom comparison strip
   200   #passage-listbox     — mobile bottom-toolbar dropdowns (separate context
         #folio-listbox        from comparison panel; no overlap)
   220   #dict-toolbar       — dictionary lookup pill (all contexts)
   250   .info-popover       — floating notes/apparatus panel
   300   mobile nav overlay  — slide-out hamburger menu panel
   400   mobile header       — header + hamburger toggle at < --bp-desktop
   500   #image-panel        — IIIF side panel (desktop)
   500   #search-results-panel — in-text search results panel (tablet overlay)
   550   .info-popover.pinned— pinned popover (position:fixed, above image panel)
   600   #image-panel mob    — full-viewport image panel (mobile)
   600   #search-results-panel — full-viewport search panel (phone)
   700   #image-popover      — modal image lightbox
   ────────────────────────────────────────────────────────────────────────── */

/* ── §6  Site chrome — header, banner, footer ────────────────────────────────
   Fixed header bar with logo, navigation, and sticky footer.
   ────────────────────────────────────────────────────────────────────────── */
header {
    height: var(--header-height);
    width: 100%;
    background: var(--color-chrome);
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    position: fixed;
    /* 25 — above toolbar-ribbon (20) so hover submenus from the nav
       paint over the toolbar.  Header creates a stacking context,
       so its descendant submenus are trapped within this level. */
    z-index: 25;
    left: 0;
}

section#banner { height: var(--header-height); }

section#banner img { height: 100%; }

main {
    flex-grow: 1;
    display: flex;
    flex-direction: column;
    padding-top: calc(var(--header-height) + var(--page-top-buffer));
    padding-bottom: calc(var(--footer-height) + var(--page-top-buffer));
    width: 100%;
    /* No overflow-x set (= visible).  Do NOT use auto or hidden here:
       those create a scroll container, which scopes position:sticky on
       child elements to <main>'s height rather than the viewport.  clip
       also works but clips position:fixed descendants in some browsers
       (e.g. Safari), hiding the pinned info-popover at the OSD edge. */
    overflow-wrap: break-word;
    /* Stacking context: keeps all content (note markers, grid panels,
       intro sidebar) below the fixed header (z-index: 25) and toolbar
       ribbon (z-index: 20).  Internal z-indexes still layer correctly
       within this context.  The info-popover is a child of <main>,
       so it shares this stacking context when floating (position:
       absolute) and escapes it when pinned (position: fixed). */
    position: relative;
    z-index: 1;
}

/* Default reading-width centering for all page articles.
   Specialized types (passage-container, titlepage, materials-page) override
   max-width via their own CSS; margin: auto is inherited for centering. */
article {
    max-width: var(--content-max-width);
    margin-left: auto;
    margin-right: auto;
    width: 100%;
}

/* Prose pages (help, about/*, contact, workProgress, resources/*) opt in
   with `class="site-page prose"` to get a scholarly-prose reading column
   that matches the intro-page cap in edition_text.css §19a.  Listing and
   home pages (index, texts, search, preview, about/credits) stay wide
   without the modifier.  WCAG 1.4.8 (no-justify) is AAA — not our AA
   target — and `hyphens: auto` mitigates rivers; `text-align-last: left`
   keeps the final line of each paragraph ragged. */
article.site-page.prose {
    max-width: 42em;
    text-align: justify;
    hyphens: auto;
    text-align-last: left;
}

article.passage-container {
    position: relative;
}

footer {
    background: var(--color-chrome);
    color: var(--color-text-on-dark);
    text-align: center;
    width: 100%;
    max-height: var(--footer-height);
    overflow-y: hidden;
    /* flex-column body pushes footer to viewport bottom on short pages
       without position: absolute, so footer doesn't need absolute positioning.
       No z-index needed: footer is never overlapped by fixed chrome. */
}

footer p {
    margin: 0;
    line-height: 1.5;
}

/* On narrow viewports the copyright line wraps and the 50px fixed-height
   footer clips most of its content.  Scale font-size and tighten
   line-height so everything fits within the box at any mobile width. */
@media (max-width: 649px) {
    footer p {
        font-size: clamp(0.55rem, 2.5vw, 0.8125rem);
        line-height: 1.2;
    }
}


/* ── §7  Navigation ───────────────────────────────────────────────────────────
   Top nav bar, menu items, submenus.  Hamburger toggle at ≤ 860px in §12.
   ────────────────────────────────────────────────────────────────────────── */
nav#top-nav {
    width: 100%;
    height: 100%;
}

nav#top-nav > ul {
    display: flex;
    flex-wrap: nowrap;
    flex-direction: row;
    justify-content: space-evenly;
    height: 100%;
    font-family: var(--font-heading);
}

nav#top-nav ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

nav#top-nav ul a {
    text-decoration: none;
    color: var(--color-text-on-dark);
}

nav#top-nav > ul > li {
    display: block;
    position: relative;
    height: 100%;
}

nav#top-nav > ul > li > div { height: 100%; }

nav#top-nav > ul > li.menuitem { text-transform: uppercase; }

nav#top-nav .menuitem:hover a,
nav#top-nav .menuitem a:focus {
    background: var(--color-chrome-hover);
    color: var(--color-text);
}

nav#top-nav .menuitem > a {
    height: 100%;
    padding: 0 1em;
    display: flex;
    align-items: center;
}

nav#top-nav .menuitem ul.submenu {
    display: none;
    background: var(--color-chrome-hover);
    flex-direction: column;
    position: absolute;
    width: 200px;
}

nav#top-nav .menuitem:hover ul.submenu {
    display: block;
    z-index: 10;
}

nav#top-nav .menuitem > ul.submenu > li > a { padding-left: 1em; }

nav#top-nav .menuitem > ul.submenu a {
    padding-right: 1em;
    padding-top: 0.5ex;
    padding-bottom: 0.5ex;
    color: var(--color-text);
    display: block;
}

nav#top-nav .menuitem > ul.submenu li a:hover {
    background: var(--color-chrome-submenu);
}

/* Third-level inset: default for About, Resources, etc. */
nav#top-nav .menuitem > ul.submenu > li > ul > li > a {
    padding-left: 2em;
}

/* Third-level flyout: texts list emerges from the side */
nav#top-nav .menuitem > ul.submenu--flyout > li {
    position: relative;
}

nav#top-nav .menuitem > ul.submenu--flyout > li > ul {
    display: none;
    position: absolute;
    left: 100%;
    top: 0;
    min-width: 120px;
    width: auto;
    z-index: 11;
}

nav#top-nav .menuitem > ul.submenu--flyout > li:hover > a {
    background: var(--color-chrome-submenu);
}

nav#top-nav .menuitem > ul.submenu--flyout > li:hover > ul {
    display: block;
    background: var(--color-chrome-submenu);
}

nav#top-nav .menuitem > ul.submenu--flyout > li > ul > li > a {
    padding-left: 1em;
}

/* Fourth level: family groups within flyout type panel.
   Family labels serve as non-hoverable headers; texts indent beneath them. */
nav#top-nav .menu-family-group > .menu-family-label {
    display: block;
    padding: 0.3em 1em;
    font-style: italic;
    font-size: 0.85em;
    color: var(--color-text-muted);
    text-decoration: none;
    pointer-events: auto;
}
nav#top-nav .menu-family-group > .menu-family-label:hover {
    text-decoration: underline;
    background: none;
}

/* Family text list: always visible within the flyout (not another flyout) */
nav#top-nav .menu-family-group > ul {
    display: block;
    position: static;
    background: inherit;
    width: auto;
}
nav#top-nav .menu-family-group > ul > li > a {
    padding-left: 1.5em;
}

/* Spacing between family groups */
nav#top-nav .menu-family-group + .menu-family-group {
    margin-top: 0.3em;
}

/* Sigils: preserve natural case regardless of parent text-transform */
.sigil {
    text-transform: none;
}


/* ── §8  Front page ───────────────────────────────────────────────────────────
   Banner image and contributor lists on the site home page.
   ────────────────────────────────────────────────────────────────────────── */
div#front-banner {
    max-width: 100%;
    margin-top: 1em;
    padding-bottom: 1em;
}

div#front-banner img { max-width: 100%; }

ul.contributors {
    column-count: auto;
    list-style: none;
    padding: 0;
}

ul.contributors.longnames  { columns: 20em 3; }
ul.contributors.shortnames { columns: 10em 5; }
ul.contributors.mainnames  { columns: auto 1; text-align: center; }

li.featured { font-size: larger; }

ul.contributors li {
    padding: 0.5ex;
    break-inside: avoid;
    page-break-inside: avoid;
}


/* ── §9  Navlist ──────────────────────────────────────────────────────────────
   Inline horizontal nav used on text listing pages and callout boxes.
   ────────────────────────────────────────────────────────────────────────── */
.navlist {
    display: flex;
    flex-direction: row;
    align-content: center;
    align-items: center;
    width: auto;
}

.navlist label {
    font-size: inherit;
    font-style: italic;
    align-content: center;
    margin: 0;
    margin-right: 1ex;
}

.navlist ul {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    width: auto;
}

.navlist li {
    display: inline-block;
    align-self: center;
    font-size: 95%;
}

.navlist li:not(:first-child) {
    border-left: 1px var(--color-border-light) solid;
}

.navlist li a {
    display: inline-block;
    min-width: 2em;
    padding-left: 1ex;
    padding-right: 1ex;
    text-align: center;
    text-decoration: none;
}

.navlist li a:hover,
.navlist li a:focus {
    background: var(--color-bg-alt);
}


/* ── §10  Text heading links ──────────────────────────────────────────────────
   Heading links on text listing pages (.text class on the container).
   ────────────────────────────────────────────────────────────────────────── */
.text h3 {
    font-weight: normal;
    margin: 1em 0 0 0;
}

.text h3 a:not(:hover) {
    color: var(--color-text);
    text-decoration: none;
}


/* ── §11  Collapsible section nav (details.text-nav) ──────────────────────────
   Used by the edition TOC (title page), text listing (texts.html /
   preview.html), and reading-page sidebar nav.  Two progressive
   enhancement tiers:

   Tier 1 — @supports selector(::details-content) (Chrome/Edge/Safari):
     display:flex on <details> puts summary and ::details-content as flex
     siblings.  Asymmetric transitions: open jumps to full height instantly
     so only the left-to-right item fan plays; close collapses after a
     delay to let items animate out first.  Per-item stagger uses
     sibling-index() / sibling-count() (CSS Values Level 5).

   Tier 2 — @supports not selector(::details-content) (Firefox):
     Float layout: summary floats left, ul is a BFC block beside it.
     display:flex !important overrides UA display:none on close so the
     ul stays in layout.  State-dependent transition timing for open/close.
   ────────────────────────────────────────────────────────────────────────── */
details.text-nav {
    margin-bottom: 0.4em;
}

details.text-nav summary {
    cursor: pointer;
    font-style: italic;
    font-weight: normal;
    white-space: nowrap;
    margin-right: 1ex;
    padding: 0;
    list-style: none;
}

details.text-nav summary::-webkit-details-marker { display: none; }
details.text-nav summary::marker               { display: none; }

/* Collapsed: downward-pointing triangle */
details.text-nav:not([open]) summary::after {
    width: 0;
    height: 0;
    border-left: 0.5ex solid transparent;
    border-right: 0.5ex solid transparent;
    border-top: 1ex solid var(--color-border-strong);
    display: inline-block;
    content: "";
    margin-left: 0.5ex;
}

/* Expanded: rightward-pointing triangle */
details.text-nav[open] summary::after {
    width: 0;
    height: 0;
    border-top: 0.5ex solid transparent;
    border-left: 1ex solid var(--color-border-strong);
    border-bottom: 0.5ex solid transparent;
    display: inline-block;
    content: "";
    margin-left: 0.5ex;
}

details.text-nav ul {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}

/* Tier 1: Chrome/Edge/Safari (::details-content) */
@supports selector(::details-content) {
    details.text-nav {
        display: flex;
        flex-direction: row;
        align-items: baseline;
        interpolate-size: allow-keywords;
    }
    details.text-nav summary { flex-shrink: 0; }
    details.text-nav::details-content {
        flex: 1;
        overflow: clip;
        height: 0;
        transition: height 0.15s ease 0.35s,
                    content-visibility 0.5s ease allow-discrete;
    }
    details.text-nav[open]::details-content {
        height: auto;
        transition: content-visibility 0s allow-discrete;
    }

    @keyframes text-nav-item-in {
        from { opacity: 0; transform: translateX(-1em); }
        to   { opacity: 1; transform: translateX(0); }
    }
    @keyframes text-nav-item-out {
        from { opacity: 1; transform: translateX(0); }
        to   { opacity: 0; transform: translateX(-1em); }
    }

    details.text-nav[open] ul li {
        animation: text-nav-item-in 0.2s ease-out both;
        animation-delay: calc((sibling-index() - 1) * 0.025s);
    }
    details.text-nav:not([open]) ul li {
        animation: text-nav-item-out 0.2s ease-in both;
        animation-delay: calc((sibling-count() - sibling-index()) * 0.025s);
    }
}

/* Tier 2: Firefox and other browsers */
@supports not selector(::details-content) {
    details.text-nav { display: flow-root; }
    details.text-nav summary { float: left; }
    details.text-nav ul {
        overflow: hidden;
        display: flex !important;
        max-height: 0;
        opacity: 0;
        transition: opacity 0.3s ease, max-height 0s 0.3s;
    }
    details.text-nav[open] > ul {
        max-height: 8em;
        opacity: 1;
        transition: max-height 0s, opacity 0.3s ease;
    }
}

details.text-nav li {
    display: inline-block;
    align-self: center;
    font-size: 95%;
}

/* Separator on the right so it sits at the end of each wrapped line */
details.text-nav li:not(:last-child) {
    border-right: 1px var(--color-border-light) solid;
}

details.text-nav li a {
    display: inline-block;
    min-width: 2.5em;
    padding-left: 1ex;
    padding-right: 1ex;
    text-align: center;
    text-decoration: none;
}

details.text-nav li a:hover,
details.text-nav li a:focus {
    background: var(--color-bg-alt);
}


/* ── §12  Callout boxes ───────────────────────────────────────────────────────
   Used on technical materials pages.
   ────────────────────────────────────────────────────────────────────────── */
.callout {
    display: table;
    margin: 1em 0;
    padding: 0.5ex;
    border-radius: 5px;
}

.callout.external { background-color: var(--color-bg-alt); }
.callout.example  { background-color: var(--color-bg-alt); }

.callout.warning {
    background-color: var(--color-bg-alt);
    display: block;
    border: 2px var(--color-border-strong) solid;
}

.callout h1 {
    font-size: inherit;
    text-align: left;
    margin: 0;
}

.callout .navlist li:not(:first-child) {
    border-left-color: var(--color-border-strong);
}


/* ── §13  Highlight utility ───────────────────────────────────────────────────
   Applied by JS to mark search terms — both on the search results page and
   when navigating from search results to a passus page (where the search term
   should be highlighted in context).  Not yet implemented on passus pages;
   the rule is here so the style is available when that feature is added.
   ────────────────────────────────────────────────────────────────────────── */
.highlight {
    background-color: var(--color-highlight);
}

/* Search hit highlight token — shared by edition_search.css (panel results and
   passage highlights) so both contexts use the same colour. */
:root {
    --color-search-hit:        light-dark(#ffff33, #665500);
    --color-search-hit-settle: light-dark(#fff9c4, #3a3000);
    --color-search-hit-strong: light-dark(#ff9900, #996600);
}

/* ── §13b  Scroll-fade utility ────────────────────────────────────────────────
   Gradient hint that more scrollable content is below. Container sets
   --scroll-fade-bg to the container's background colour.
   JS toggles .at-bottom when the user scrolls to the end. Used in
   edition_compare.css (#comparison-panel) and edition_passage.css (.contents-scroll).
   ────────────────────────────────────────────────────────────────────────── */
.scroll-fade {
    position: sticky;
    bottom: 0;
    height: 50px;
    margin-top: -50px;       /* collapse so it doesn't expand scroll area */
    background: linear-gradient(to bottom, transparent, var(--scroll-fade-bg, transparent));
    pointer-events: none;
    z-index: 5;
    transition: opacity var(--transition-fast);
    opacity: 0.7;
}

.scroll-fade.at-bottom { opacity: 0; }


/* ── §13c  Panel loading spinner ──────────────────────────────────────────────
   Composite spinner: conic-gradient "comet" ring (CSS div) + PPEA graph logo
   (SVG, per-element staggered animation).
   Emitted by lib/spinner.js into any async panel (comparison, search, image).
   spinner.js fetches piers-spinner.svg, extracts the <symbol> innerHTML, and
   injects it directly into each .spinner-logo <svg> so that these CSS
   animations apply without a shadow-DOM boundary (external SVG <use> CSS
   animations do not run in Safari).

   The tree is drawn as 14 separate <line>/<circle> elements with structured
   group delays: each group fires exactly when its parent junction finishes
   drawing (delay = group_index × 114 ms, where 114 ms = 3% of 3.8 s cycle).
   This gives a clean junction handoff with no gap, and erase order mirrors
   draw order exactly.

   The .spinner-ring div is always present in the DOM (emitted before the SVG).
   It serves as a CSS-only fallback while the SVG is fetching, and then runs
   alongside the tree once the SVG is injected. z-index:1 places the ring
   above the SVG so it paints over the trunk-bottom overlap.
   ────────────────────────────────────────────────────────────────────────── */
.panel-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 7em;
    padding: 1.5em;
}

.spinner-piers {
    position: relative;
    width: 5em;
    height: 5em;
    flex-shrink: 0;
}

/* Comet ring.
   inset:-2% extends the element ~1.6px beyond .spinner-piers on each side,
   giving the ring stroke clearance at the circle-frame edge.  Because the
   ring element and its containing block are nearly the same size, any browser
   quirk that resolves mask %-sizes against the containing block instead of
   the element produces the same result — the Safari mask-centering bug is
   neutralised.
   rgb(from currentColor r g b / alpha) preserves the hue when fading to
   transparent; plain `transparent` = rgba(0,0,0,0) would darken the tail.
   Rotates at 3.8s ÷ 3 (exactly 3 rev per tree cycle) so they never drift. */
.spinner-ring {
    position: absolute;
    inset: -2%;
    border-radius: 50%;
    z-index: 1;
    color: light-dark(#888, #ebebeb);
    background: conic-gradient(
        from 0deg,
        rgb(from currentColor r g b / 0.15)   0deg,
        rgb(from currentColor r g b / 0)       8deg,
        rgb(from currentColor r g b / 0)      70deg,
        rgb(from currentColor r g b / 0.02)   70deg,
        rgb(from currentColor r g b / 0.07)  130deg,
        rgb(from currentColor r g b / 0.18)  210deg,
        rgb(from currentColor r g b / 0.40)  280deg,
        rgb(from currentColor r g b / 0.70)  330deg,
        rgb(from currentColor r g b / 0.90)  354deg,
        currentColor                          360deg
    );
    -webkit-mask: radial-gradient(ellipse closest-side at 50% 50%,
        transparent 87%, black 89%, black 95%, transparent 97%);
    mask: radial-gradient(ellipse closest-side at 50% 50%,
        transparent 87%, black 89%, black 95%, transparent 97%);
    animation: comet-spin calc(3.8s / 3) linear infinite;
}

/* Inner SVG: the PPEA graph logo.  inset:0 fills the full .spinner-piers box;
   the circle-frame element sits at 96% of the element half-width, which the
   ring mask is calibrated to match. */
.spinner-logo {
    position: absolute;
    inset: 0;
    color: var(--color-accent);
    overflow: visible;
}

/* Tree segment lines.  All segments use stroke-linecap:butt throughout —
   no round-cap pre-arrival dots during the invisible phase, and no floating
   cap dots approaching junctions during the draw phase.  Junction gaps are
   covered by animated .junction-cap circles (see below). */
.spinner-logo .tree-seg {
    fill: none;
    stroke: currentColor;
    stroke-width: 7;
    stroke-linecap: butt;
    stroke-dasharray: 0 1;
    stroke-dashoffset: 0;
    animation: logo-seg 3.8s linear infinite;
}
.spinner-logo .tree-seg-leaf {
    animation-name: logo-seg-leaf;
    stroke-linecap: butt;
}

/* Node circles: appear/disappear via opacity. */
.spinner-logo .tree-node {
    fill: none;
    stroke: currentColor;
    stroke-width: 4;
    opacity: 0;
    animation: logo-node 3.8s linear infinite;
}

.spinner-logo .circle-frame {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    opacity: 0.3;
}

/* Junction cap circles: r = stroke-width/2 = 3.5, fill only.
   Each cap snaps visible when the first spine segment tip arrives at the
   junction, and snaps off when the last segment's x1 begins erasing.
   This fills the butt-cap gap without any pre-arrival round-cap artifacts.
   Cycle = 3800ms; draw phase = 0%→3% (114ms); erase phase = 50%→53%.
   ON  = spine_segment_delay + 3%;  OFF = 50% + last_x1_segment_delay.
     jc1 (89,147):    ON=3%   (s1 delay 0+114ms),   OFF=57.5% (s4 delay 285ms)
     jc2 (89,112):    ON=10.5% (s4 delay 285+114ms), OFF=65%   (s7 delay 570ms)
     jc3 (106,100.5): ON=18%  (s7 delay 570+114ms), OFF=72.5% (s10 delay 855ms)
     jc4 (93,81):     ON=25.5% (s10 delay 855+114ms),OFF=80%  (s13 delay 1140ms)
   animation-timing-function:step-end makes each transition a snap, not a fade. */
.spinner-logo .junction-cap {
    fill: currentColor;
    opacity: 0;
}
.spinner-logo .jc0 { animation: jcap_root 3.8s linear infinite; }
.spinner-logo .jc1 { animation: jcap1 3.8s linear infinite; }
.spinner-logo .jc2 { animation: jcap2 3.8s linear infinite; }
.spinner-logo .jc3 { animation: jcap3 3.8s linear infinite; }
.spinner-logo .jc4 { animation: jcap4 3.8s linear infinite; }

/* Per-element animation delays — segments use 95ms step;
   node circles fire when their branch finishes drawing
   (branch_delay + 114ms draw duration). */
.spinner-logo .s1  { animation-delay:    0ms; }
.spinner-logo .s2  { animation-delay:   95ms; }
.spinner-logo .s3  { animation-delay:  209ms; }
.spinner-logo .s4  { animation-delay:  285ms; }
.spinner-logo .s5  { animation-delay:  380ms; }
.spinner-logo .s6  { animation-delay:  494ms; }
.spinner-logo .s7  { animation-delay:  570ms; }
.spinner-logo .s8  { animation-delay:  665ms; }
.spinner-logo .s9  { animation-delay:  779ms; }
.spinner-logo .s10 { animation-delay:  855ms; }
.spinner-logo .s11 { animation-delay:  950ms; }
.spinner-logo .s12 { animation-delay: 1064ms; }
.spinner-logo .s13 { animation-delay: 1140ms; }
.spinner-logo .s14 { animation-delay: 1254ms; }

@keyframes comet-spin {
    to { transform: rotate(360deg); }
}

@keyframes logo-seg {
    0%   { stroke-dasharray: 0 1; stroke-dashoffset: 0; }
    3%   { stroke-dasharray: 1 0; stroke-dashoffset: 0; }
    50%  { stroke-dasharray: 1 0; stroke-dashoffset: 1; }
    53%  { stroke-dasharray: 0 1; stroke-dashoffset: 0; }
    100% { stroke-dasharray: 0 1; stroke-dashoffset: 0; }
}
@keyframes logo-seg-leaf {
    0%   { stroke-dasharray: 0 1; stroke-dashoffset: 0; }
    3%   { stroke-dasharray: 1 0; stroke-dashoffset: 0; }
    50%  { stroke-dasharray: 1 0; stroke-dashoffset: 1; }
    53%  { stroke-dasharray: 0 1; stroke-dashoffset: 0; }
    100% { stroke-dasharray: 0 1; stroke-dashoffset: 0; }
}

@keyframes logo-node {
    0%    { opacity: 0; }
    3%    { opacity: 1; }
    50%   { opacity: 1; }
    53%   { opacity: 0; }
    100%  { opacity: 0; }
}

@keyframes jcap_root {
    /* Root of tree (89,160): visible while s1 exists (0%→50%), then gone. */
    0%   { opacity: 1; animation-timing-function: step-end; }
    50%  { opacity: 0; }
    100% { opacity: 0; }
}
@keyframes jcap1 {
    0%    { opacity: 0; animation-timing-function: step-end; }
    3%    { opacity: 1; animation-timing-function: step-end; }
    57.5% { opacity: 0; }
    100%  { opacity: 0; }
}
@keyframes jcap2 {
    0%    { opacity: 0; animation-timing-function: step-end; }
    10.5% { opacity: 1; animation-timing-function: step-end; }
    65%   { opacity: 0; }
    100%  { opacity: 0; }
}
@keyframes jcap3 {
    0%    { opacity: 0; animation-timing-function: step-end; }
    18%   { opacity: 1; animation-timing-function: step-end; }
    72.5% { opacity: 0; }
    100%  { opacity: 0; }
}
@keyframes jcap4 {
    0%    { opacity: 0; animation-timing-function: step-end; }
    25.5% { opacity: 1; animation-timing-function: step-end; }
    80%   { opacity: 0; }
    100%  { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .spinner-ring                { animation: none; opacity: 0; }
    .spinner-logo .tree-seg      { animation: none; stroke-dasharray: 1 0; stroke-dashoffset: 0; stroke-linecap: round; }
    .spinner-logo .tree-seg-leaf { animation: none; stroke-dasharray: 1 0; stroke-dashoffset: 0; stroke-linecap: butt; }
    .spinner-logo .tree-node     { animation: none; opacity: 1; }
    .spinner-logo .junction-cap  { animation: none; opacity: 1; }
    .spinner-logo .jc0           { animation: none; opacity: 1; }
}


/* ── §13d  Full-page loading overlay ──────────────────────────────────────────
   Shown during full-page navigations by lib/page-loading.js.  The element
   is a single <div id="page-loading-overlay" hidden> placed at the end of
   <body> in each top-level template wrapper.  When revealed, the module
   adds class "is-visible" and injects the shared PPEA spinner.

   Position: fixed full viewport, above all page chrome (z-index above
   toolbars/panels).  Background uses --overlay-bg + --glass-blur to
   dim/blur the underlying page just enough to communicate "in transit"
   without being heavy-handed.

   Fades in via opacity transition so a same-tick reveal doesn't pop;
   the new page replaces this DOM entirely, so no fade-out is needed.
   ────────────────────────────────────────────────────────────────────────── */
#page-loading-overlay {
    position: fixed;
    inset: 0;
    z-index: 9000;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Stronger than the chrome-button --overlay-bg: needs to read as a
       clear "in-transit" state, not a subtle hint.  Same idea as the
       --color-backdrop modal scrim but lighter — we're pausing the page,
       not blocking it from view. */
    background-color: light-dark(rgba(255, 255, 255, 0.45), rgba(0, 0, 0, 0.45));
    -webkit-backdrop-filter: var(--glass-blur-heavy);
    backdrop-filter: var(--glass-blur-heavy);
    opacity: 0;
    transition: opacity 120ms ease-out;
    /* pointer-events:none until the overlay is actually visible so it
       never intercepts clicks while sitting at opacity:0. */
    pointer-events: none;
}

/* Honour the HTML [hidden] attribute.  Without this rule, the ID-selector's
   display:flex above wins on specificity over the UA [hidden]{display:none}
   stylesheet rule, leaving the overlay laid out (and blocking pointer
   events on iOS where pointer-events:none still doesn't suppress
   touch-action in some edge cases). */
#page-loading-overlay[hidden] { display: none; }

#page-loading-overlay.is-visible {
    opacity: 1;
    pointer-events: auto;
}

/* The injected .panel-loading inside the overlay shouldn't enforce its
   own min-height — the overlay already fills the viewport. */
#page-loading-overlay .panel-loading {
    min-height: 0;
    padding: 0;
}

/* Make the spinner itself a touch larger for a full-page context. */
#page-loading-overlay .spinner-piers {
    width: 7em;
    height: 7em;
}

@media (prefers-reduced-motion: reduce) {
    #page-loading-overlay { transition: none; }
}


/* ── §13d  SVG sprite icons ──────────────────────────────────────────────────
   Shared utility class for icons sourced from /img/ui_sprites.svg.
   Sized to 1em × 1em so they scale with the surrounding font-size (toolbar
   uses 0.85em base; fullscreen toolbar uses 1em).  vertical-align:middle
   aligns them with adjacent text or button labels.
   overflow:hidden clips any stray symbol geometry outside the viewBox.
   ─────────────────────────────────────────────────────────────────────────── */
.icon {
    display: inline-block;
    width:  1em;
    height: 1em;
    vertical-align: middle;
    overflow: hidden;
}


/* ── §14  Chrome buttons (shared glass-overlay appearance) ────────────────────
   Hamburger, line-number FAB, and comparison panel close share this
   glass-overlay style.  Size and positioning are set per-button below
   and in edition_text.css / edition_compare.css / edition_images.css.
   ────────────────────────────────────────────────────────────────────────── */
#menu-toggle .icon-hamb,
#comparison-panel .close-button {
    padding: 0;
    appearance: none;
    background-color: var(--overlay-bg);
    backdrop-filter: var(--glass-blur);
    border: 1px solid var(--overlay-border);
    border-radius: 5px;
    cursor: pointer;
    color: var(--color-text);
}

/* ── §14b  Hamburger toggle & icon ───────────────────────────────────────────
   Hidden at > 860px; revealed in the responsive block (§15).
   ────────────────────────────────────────────────────────────────────────── */
.icon-hamb {
    height: 36px;
    width: 36px;
}

#menu-toggle .icon-hamb {
    transition: background-color 1s, color 0.5s;
}

#menu-check:checked ~ #menu-toggle svg {
    background-color: var(--overlay-bg-active);
    transition: background-color 0.5s;
}

#menu-check:checked ~ #menu-toggle .icon-hamb {
    color: var(--color-text-on-dark);
    transition: color 1s;
}

#menu-check, #menu-toggle { display: none; }


/* ── §15  Responsive — < --bp-desktop (site-wide) ─────────────────────────────
   Mobile/tablet layout: hamburger menu replaces top nav bar.
   Text-page-specific responsive overrides are in edition_text.css.
   ────────────────────────────────────────────────────────────────────────── */

/* Banner hidden between --bp-desktop and 1135px (horizontal nav needs the
   space once it replaces the hamburger).  The upper bound (1135) is the
   width at which there is finally room for banner + nav side by side. */
@media screen and (min-width: 900px) and (max-width: 1135px) /* --bp-desktop to 1135 */ {
    #banner { display: none; }
}

@media screen and (max-width: 899px) /* < --bp-desktop */ {
    /* ── Header ──────────────────────────────────────────────────── */
    header {
        width: 100%;
        justify-content: space-between;
        flex-wrap: nowrap;
        position: relative;
        z-index: 400;   /* mobile header tier */
    }

    section#banner { max-width: 100%; }

    section#banner > img {
        max-height: 100%;
        max-width: 100%;
        height: auto;
        position: relative;
        top: 50%;
        transform: translateY(-50%);
    }

    header > label {
        height: 100%;
        width: 40px;
        font-size: var(--header-height);
        line-height: var(--header-height);
        fill: var(--color-text-on-dark);
        margin: 0 5px;
    }

    label:active svg {
        background-color: var(--overlay-bg-active);
    }

    /* ── Mobile nav overlay ──────────────────────────────────── */
    nav#top-nav { width: initial; }

    nav#top-nav > ul {
        position: fixed;
        /* 100dvh tracks the visual viewport as iOS Safari's URL bar
           expands/contracts, matching the drawer's height to whatever
           page area Safari allots.  Menu items stay clear of hardware
           cutouts via env(safe-area-inset-*) padding below; those
           resolve to 0 when viewport-fit=cover isn't active. */
        top: 0;
        height: 100dvh;
        right: 0;
        width: min(75vw, 300px);
        overflow-x: hidden;
        z-index: 300;   /* mobile nav overlay tier */
        background-color: var(--color-nav-overlay);
        -webkit-backdrop-filter: var(--glass-blur-heavy);
        backdrop-filter: var(--glass-blur-heavy);
        /* Additional vertical padding for iOS safe areas (notch/status
           bar on top, home indicator on bottom) so menu items don't
           render behind hardware cutouts.  env() resolves to 0 when
           viewport-fit=cover isn't active. */
        padding:
            calc(var(--header-height) + env(safe-area-inset-top)) 0
            calc(var(--header-height) + env(safe-area-inset-bottom));
        margin-bottom: var(--header-height);
        overflow-y: auto;
        display: flex;
        flex-direction: column;
        gap: 0.5em;
        transition: transform 0.75s, visibility 0s;
        visibility: visible;
    }

    nav#top-nav > ul > li {
        height: initial;
        margin: 1ex 0;
    }

    li.menuitem {
        font-size: larger;
        margin: 0;
    }

    nav#top-nav .menuitem .menuitem {
        font-size: initial;
    }

    li.menuitem a {
        padding: 0;
    }

    nav#top-nav .menuitem > a {
        height: auto;
        display: block;
    }

    nav#top-nav .menuitem > a,
    nav#top-nav li > div:not(#view-component) {
        padding: 0 1ex;
    }

    /* ── Mobile Texts submenu ─────────────────────────────────
       Design goals:
       • Suppress all desktop :hover flyout/background behaviour
       • JS toggles .mobile-expanded; accordion (one sibling at a time)
       • Expanded section gets full-bleed gray background (header + children)
       • Type headings (Critical, Documentary, Preview): full-width block links
       • Sigils: compact inline row within the gray expanded area
       • Family headers: italic labels above their sigil row
       • Individual sigil hover: slightly darker on top of the gray band
       ─────────────────────────────────────────────────────────── */

    /* 1. Kill desktop :hover rules that cascade into submenus on Safari tap.
          .menuitem:hover > a is fine (highlights the item itself).
          .menuitem:hover ul a is the cascade we must stop.
          Individual a:hover is kept for per-link feedback. */
    nav#top-nav .menuitem ul.submenu { display: none; }
    nav#top-nav .menuitem:hover ul.submenu { display: none; }
    nav#top-nav .menuitem:hover ul a { background: none; }
    nav#top-nav .menuitem > ul.submenu--flyout > li:hover > ul { display: none; }
    nav#top-nav .menuitem > ul.submenu--flyout > li:hover > a { background: none; }

    /* 1b. Mobile submenu link hover.
           Must match the desktop selector's specificity (0,1,3,4) and come
           later in source order so it wins.  Uses --color-chrome-hover (#444)
           which is visibly lighter than the parent --color-chrome-submenu (#3a3a3a). */
    nav#top-nav .menuitem > ul.submenu li a:hover {
        background: var(--color-chrome-hover);
    }

    /* 1c. Gray highlight on the entire expanded section (e.g. "Texts" + all children).
           Single color for the whole block — no layered shades. */
    nav#top-nav .menuitem.mobile-expanded {
        background: var(--color-chrome-submenu);
    }

    /* 1d. Lock top-level label to dark text while expanded (light background). */
    nav#top-nav .menuitem.mobile-expanded > a {
        color: var(--color-text);
    }

    /* 2. Expanded top-level submenu (Texts → shows type list). */
    nav#top-nav .menuitem.mobile-expanded > ul.submenu {
        display: block !important;
        position: static;
        width: auto;
        background: transparent;
        padding: 0;
    }

    /* 3. Type sections inherit the parent's gray background.
          No additional background needed — the .menuitem.mobile-expanded
          provides the uniform gray for the entire block. */

    /* 4. Type heading links (Critical Editions, Preview, etc.).
          Full-width block for full-bleed hover highlight.
          Specificity beats desktop nav#top-nav .menuitem > ul.submenu > li > a. */
    nav#top-nav .menuitem > ul.submenu--flyout > li > a {
        display: block;
        padding: 0.3em 1em 0.3em 2em;
        font-size: initial;
    }

    /* 5. Expanded type section's child list.
          Flat lists (no family groups): inline flex row.
          Family-containing lists: block (family groups stack vertically).
          Both: transparent background (parent <li> provides the gray). */
    nav#top-nav .menuitem > ul.submenu--flyout > li.mobile-expanded > ul {
        position: static;
        width: auto;
        background: transparent;
    }
    nav#top-nav .menuitem > ul.submenu--flyout > li.mobile-expanded > ul:not(:has(.menu-family-group)) {
        display: flex !important;
        flex-wrap: wrap;
        padding: 0.2em 1em 0.2em 2em;
    }
    nav#top-nav .menuitem > ul.submenu--flyout > li.mobile-expanded > ul:has(.menu-family-group) {
        display: block !important;
        padding: 0;
    }

    /* 6. Sigil links within type lists: inline items. */
    nav#top-nav .submenu--flyout > li > ul > li {
        margin: 0;
        list-style: none;
    }
    nav#top-nav .submenu--flyout > li > ul > li > a {
        padding: 0.2em 0.5em;
        font-size: initial;
    }

    /* 7. Family group headers (A-Version, B-Version, etc.).
          Full-width block labels, not expandable. */
    nav#top-nav .menuitem .menu-family-group > .menu-family-label {
        display: block;
        padding: 0.2em 1em 0.2em 2.5em;
        font-style: italic;
        font-size: 0.75em;
        text-transform: none;
        background: transparent;
    }

    /* 8. Family sigil rows: inline flex, indented under the header.
          Explicit transparent background to prevent desktop inherit layering. */
    nav#top-nav .menu-family-group > ul {
        display: flex !important;
        flex-wrap: wrap;
        padding: 0 1em 0.2em 2.5em;
        background: transparent;
    }
    nav#top-nav .menu-family-group > ul > li {
        margin: 0;
        list-style: none;
    }
    nav#top-nav .menuitem .menu-family-group > ul > li > a {
        padding: 0.2em 0.5em;
        font-size: initial;
    }

    /* 10. Disclosure indicators (progressive: requires :has). */
    nav#top-nav .menuitem:has(> ul.submenu) > a::after,
    nav#top-nav .submenu--flyout > li:has(> ul) > a::after {
        content: " \25B8";  /* ▸ */
        font-size: 0.8em;
    }
    nav#top-nav .mobile-expanded > a::after {
        content: " \25BE" !important;  /* ▾ */
    }

    .menubar li:first-of-type { margin-top: var(--header-height); }
    .menubar li:last-of-type  { margin-bottom: var(--header-height); }

    /* ── Hamburger checkbox toggle ────────────────────────────── */
    input#menu-check {
        border: 0;
        clip: rect(0, 0, 0, 0);
        height: 1px;
        margin: -1px;
        overflow: hidden;
        padding: 0;
        position: fixed;
        width: 1px;
    }

    #menu-check, #menu-toggle { display: block; }
    #menu-toggle { cursor: pointer; }

    #top-nav > label {
        z-index: 400;   /* mobile header tier */
        position: fixed;
        right: 0;
        top: 0;
        margin: 7px;
    }

    nav#top-nav > input:not(:checked) ~ ul {
        transform: translate3d(calc(100% + 1px), 0, 0);
        visibility: hidden;
        transition: transform 0.75s, visibility 0s linear 0.75s;
    }

    /* ── Main content ────────────────────────────────────────── */
    main {
        /* --main-pad-x exposes the mobile horizontal padding so
           descendants (e.g. #comparison-panel's full-bleed negative
           margin) can stay in sync without duplicating the magic
           number.  Registered as a typed <length> via @property below
           so "1ex" resolves in main's font context at declaration time,
           not in each consumer's own context. */
        --main-pad-x: 1ex;
        padding: 0 var(--main-pad-x) calc(var(--footer-height) + var(--page-top-buffer));
        width: 100%;
    }
    body {
        width: 100%;
    }
}


/* ── §16  Print ───────────────────────────────────────────────────────────────
   Hide chrome, expand content to full width.
   ────────────────────────────────────────────────────────────────────────── */
@media print {
    header, footer, nav { display: none; }

    main {
        width: 100%;
        margin-top: 0;
    }
}
