/* 
  style.css
  Enhanced with clean Merkava-inspired design patterns.
  Base styles provided here; most layout handled by Tailwind CSS in index.html.
*/

/* ═══════════════════════════════════════════════════════════════════ */
/* TYPOGRAPHY & HEBREW SUPPORT */
/* ═══════════════════════════════════════════════════════════════════ */

html {
    scroll-behavior: smooth;
    -webkit-tap-highlight-color: transparent;
}

/* Thin scrollbars tinted from the text colour (35%, 60% under the pointer)
   in light and dark alike. These two rules came with the daisyUI stylesheet
   this page used to load from a CDN (138 KiB, render-blocking, none of its
   components in use); they are kept here so the scrollbars do not change. */
* {
    scrollbar-color: color-mix(in oklch, currentColor 35%, transparent) transparent;
}
:hover {
    scrollbar-color: color-mix(in oklch, currentColor 60%, transparent) transparent;
}

/* A Hebrew first paint: the head script in index.html sets lang/dir (and
   data-lang-pending) before the body script swaps the [data-he] texts in, so
   the English ones hold their place unseen instead of flashing (visibility,
   not display: no box changes size). toggleLanguage clears the flag. Pages
   without that head script never set it. A region swapped early
   (swapPendingLanguage, data-lang-ready) already shows its Hebrew. */
html[data-lang-pending][lang="he"] [data-he]:not([data-lang-ready] *) {
    visibility: hidden;
}

/* The topbar's auth slot (index.html #authControls) is laid out from the
   first paint at its likely shape -- Sign In, or the profile button when
   Clerk's cookie says a session exists (html.auth-likely-in) -- and its
   content only fades in once refreshAuthUi knows who is here and drops
   aria-busy. Held with visibility, never display:none, so the topbar never
   grows under the reader. */
#authControls > * {
    transition: opacity var(--motion-dur-base, 200ms) var(--motion-ease-out, ease-out);
}
#authControls[aria-busy="true"] > * {
    visibility: hidden;
    opacity: 0;
}
html.auth-likely-in #authControls[aria-busy="true"] #signInBtn {
    display: none;
}
html.auth-likely-in #authControls[aria-busy="true"] #userProfileMenuContainer {
    display: flex;
}

/* The language buttons keep one width whether or not their web font
   (Cardo / the Hebrew face) has arrived. */
.lang-btn {
    min-inline-size: 3.5rem;
    justify-content: center;
}

:root {
    /* Reader layout — not in tokens.css */
    --reader-topbar-offset: 3.2rem;
    --reader-topbar-left-gap: 0px;
    --reader-topbar-right-gap: 0px;
    --reader-outer-max-width: 56rem;
    --reader-shul-max-width: 76rem;
    --reader-inline-padding: 1rem;

    /* Legacy spacing scale aliases — not in tokens.css */
    --space-xs: 0.25rem;
    --space-sm: 0.5rem;
    --space-md: 1rem;
    --space-lg: 1.5rem;
    --space-xl: 2rem;
}

body {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    background: var(--surface-base);
    /* Positioned containing block for #readerTopBar (position: absolute) below. */
    position: relative;
}

/* Popovers and panels marked up as an always-open <dialog> (shown and hidden
   by their own classes, never show()/showModal()): undo the browser's dialog
   box so they lay out like the plain blocks their own rules expect. :where()
   keeps this at zero specificity, so any of their rules wins. */
:where(dialog.dialog-box-reset) {
    position: static;
    inset: auto;
    width: auto;
    height: auto;
    max-width: none;
    max-height: none;
    margin: 0;
    padding: 0;
    border: 0 solid;
    background: transparent;
    color: inherit;
    unicode-bidi: isolate;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    overflow-wrap: break-word;
}

@font-face {
    font-family: 'Ezra SIL';
    src: url('/static/fonts/SILEOT.woff2') format('woff2'),
         url('/static/fonts/SILEOT.woff') format('woff');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

/* Hebrew text support */
[lang="he"],
.font-hebrew {
    font-family: 'Ezra SIL', 'Ezra SIL Fallback', 'Cardo', 'Cardo Fallback', serif;
    direction: rtl;
    text-align: right;
}

/* No fake bold. Ezra SIL ships a single weight, so a bold request on it made
   the browser smear one on: about 40% more ink, on a face that already sets
   darker than Cardo (a Hebrew prayer heading came out half again as heavy as
   the English heading beside it). Every other face the page uses has a real
   bold, so only Ezra SIL is affected. */
html {
    font-synthesis-weight: none;
}

/* Emphasis in Hebrew (a commentary's opening words, a bolded term in a source)
   is a thin stroke in the text colour over the regular face: about 35% more
   ink, the same step up as English bold, and niqqud and te'amim stay where
   they are. The rule used to ask for bold as well, so the stroke came on top
   of the fake bold (twice the ink of the regular text). */
:is(.font-hebrew, .reader-text-he, .source-he, .ai-src-box-he, html.rtl #readerTitle) :is(b, strong),
:is(.font-hebrew, .reader-text-he, .source-he, .ai-src-box-he):is(b, strong) {
    -webkit-text-stroke: var(--he-emphasis-stroke, 0.025em) currentColor;
}

/* Hebrew titles set in Cardo. Its bold carries only part of the Hebrew block,
   so a title came out with a few heavy letters among regular ones. The regular
   face with a thin stroke gives every letter the same weight. */
html.rtl :is(.home-topic-title, .home-library-title, .ai-tip__title, .conv-empty__title, .prose h1, .prose h2) {
    font-weight: 400;
    -webkit-text-stroke: var(--he-emphasis-stroke, 0.025em) currentColor;
}

/* Proper line height for Hebrew */
[dir="rtl"] {
    line-height: 1.8;
}

/* ═══════════════════════════════════════════════════════════════════ */
/* CARD & CONTAINER STYLING (Merkava-inspired) */
/* ═══════════════════════════════════════════════════════════════════ */

.source-card {
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    background: #ffffff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
    transition: border-color var(--motion-dur-base) var(--motion-ease-out);
}

.source-card:hover {
    border-color: #d4af37;
    box-shadow: 0 4px 12px rgba(212, 175, 55, 0.1);
}

.source-card.featured {
    border-inline-start: 4px solid #002147;
    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
}

/* ═══════════════════════════════════════════════════════════════════ */
/* HALACHA SECTIONS WITH VISUAL HIERARCHY */
/* ═══════════════════════════════════════════════════════════════════ */

.halacha-section {
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    border-radius: 8px;
    border-inline-start: 4px solid transparent;
}

.halacha-section.ruling {
    border-inline-start-color: #002147;
    background-color: #f0f4f8;
}

.halacha-section.custom {
    border-inline-start-color: #7c3aed;
    background-color: #f5f3ff;
}

.halacha-section.source {
    border-inline-start-color: #d4af37;
    background-color: #fffbf0;
}

.halacha-title {
    font-weight: 700;
    color: #002147;
    margin-bottom: 0.75rem;
    font-size: 1rem;
}

.halacha-text {
    color: #334155;
    line-height: 1.6;
    margin-bottom: 0.5rem;
    font-size: 0.9rem;
}

/* ═══════════════════════════════════════════════════════════════════ */
/* SOURCE REFERENCE STYLING */
/* ═══════════════════════════════════════════════════════════════════ */

.source-ref {
    display: inline-block;
    background: #f1f5f9;
    color: #0c4a6e;
    padding: 0.25rem 0.65rem;
    border-radius: 4px;
    font-size: 0.875rem;
    font-weight: 500;
    margin: 0 0.25rem;
    font-family: 'Courier New', monospace;
}

.source-ref:hover {
    background: #e2e8f0;
    cursor: pointer;
}

/* ═══════════════════════════════════════════════════════════════════ */
/* Sh'elah LAYOUT POLISH (Sefaria/Merkava-inspired) */
/* ═══════════════════════════════════════════════════════════════════ */

.library-shell {
    background: var(--surface-base);
}

/* No backdrop-filter: at 97% opacity the blur was invisible, but it still
   made the sticky bar re-blur whatever scrolled or animated under it on
   every frame (costly in Safari). */
.topbar {
    background: linear-gradient(180deg, rgba(248, 244, 236, 0.97) 0%, rgba(245, 240, 232, 0.97) 100%);
    border-bottom: 1px solid var(--surface-border);
    box-shadow: 0 2px 8px rgba(78, 64, 45, 0.06);
    position: sticky;
    top: 0;
    z-index: 200;
    overflow: visible;
    min-height: 0;
}

/* Topbar flat icon/text buttons (no button-look border/bg) */
.topbar-flat-btn {
    background: transparent !important;
    border: none !important;
    box-shadow: none;
    padding: 0.2rem 0.32rem;
    border-radius: 0.35rem;
    color: #5a4f3e;
    cursor: pointer;
    transition: background var(--motion-dur-fast) var(--motion-ease-out), color var(--motion-dur-fast) var(--motion-ease-out);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.3rem;
    font-size: 0.75rem;
}

.topbar-flat-btn:hover,
.topbar-flat-btn:focus-visible {
    background: rgba(0, 0, 0, 0.06) !important;
    color: #3a3128;
}

:is([data-theme="dark"], body.theme-dark) .topbar-flat-btn {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .topbar-flat-btn:hover,
:is([data-theme="dark"], body.theme-dark) .topbar-flat-btn:focus-visible {
    background: var(--control-bg) !important;
    /* !important needed: at (0,3,1) this already outranks
       .library-shell .lang-btn's always-on (0,2,0) color rule on
       specificity alone, but importance is compared before specificity,
       so a plain (non-important) color here still lost outright. */
    color: var(--control-text-strong) !important;
}

/* ─── TOPBAR LIBRARY BUTTON ─────────────────────────────────── */
.topbar-library-btn {
    opacity: 0.85;
    color: var(--text-navy, #002147);
    border: 1px solid transparent !important;
    border-radius: 0.4rem;
    padding: 0.22rem 0.6rem;
    gap: 0.35rem;
    transition: opacity var(--motion-dur-fast) var(--motion-ease-out), background var(--motion-dur-fast) var(--motion-ease-out), border-color var(--motion-dur-fast) var(--motion-ease-out);
}

.topbar-library-btn:hover,
.topbar-library-btn:focus-visible {
    opacity: 1;
    background: rgba(0, 33, 71, 0.07) !important;
    border-color: rgba(0, 33, 71, 0.15) !important;
}

:is([data-theme="dark"], body.theme-dark) .topbar-library-btn {
    color: var(--accent-cream, #f3eadd);
    border-color: transparent !important;
}

:is([data-theme="dark"], body.theme-dark) .topbar-library-btn:hover,
:is([data-theme="dark"], body.theme-dark) .topbar-library-btn:focus-visible {
    background: rgba(255, 255, 255, 0.09) !important;
    border-color: rgba(255, 255, 255, 0.12) !important;
}


.delayed-tooltip {
    position: fixed;
    z-index: 9999;
    max-width: 20rem;
    padding: 0.42rem 0.6rem;
    border-radius: 0.75rem;
    background: rgba(15, 23, 42, 0.92);
    border: 1px solid rgba(148, 163, 184, 0.18);
    color: #f8fafc;
    font-size: 0.82rem;
    line-height: 1.35;
    pointer-events: none;
    opacity: 0;
    transform: translate(-50%, -0.45rem) scale(0.98);
    transition: opacity var(--motion-dur-fast) var(--motion-ease-out), transform var(--motion-dur-fast) var(--motion-ease-out);
    box-shadow: 0 16px 32px rgba(15, 23, 42, 0.22);
    white-space: normal;
    overflow-wrap: break-word;
    backdrop-filter: blur(8px);
}

:is([data-theme="dark"], body.theme-dark) .delayed-tooltip {
    background: rgba(15, 23, 42, 0.96);
    border-color: rgba(148, 163, 184, 0.2);
    color: var(--tooltip-text);
}

.delayed-tooltip.visible {
    opacity: 1;
    transform: translate(-50%, -0.45rem) scale(1);
}

@media (min-width: 1024px) {

    /* Sticky sidebars - stay in place while main content scrolls */
    #leftSidebar,
    #rightSidebar {
        position: sticky;
        top: var(--topbar-height, 3.4rem);
        min-height: 0;
        height: calc(100vh - var(--topbar-height, 3.4rem));
        max-height: calc(100vh - var(--topbar-height, 3.4rem));
        overflow-y: auto;
        overscroll-behavior: contain;
        z-index: 40;
        padding-bottom: 1rem;
    }
}

.topbar-search-wrap {
    position: relative;
    z-index: 40;
}

#topbarControls {
    position: relative;
    z-index: 110;
    flex-shrink: 0;
}

/* .topbar-brand-title's line-height is set on the element itself via
   Tailwind's text-sm/none + sm:text-base/none (index.html) -- those
   bundled font-size/line-height utilities load after this stylesheet
   and always win the cascade tie, so a rule here would be dead weight
   regardless of its value. */

/* Touch: the brand link is 34px tall. An invisible layer stretches its tap
   area to --hit-min (44px) without changing the topbar's size. Lives here
   because the legal pages share this topbar and do not load ai.css. */
@media (pointer: coarse) {
    .topbar-brand {
        position: relative;
    }

    .topbar-brand::before {
        content: "";
        position: absolute;
        top: 50%;
        left: 0;
        right: 0;
        height: max(100%, var(--hit-min));
        transform: translateY(-50%);
    }
}

/* Scales in step with .topbar-brand-title's own text-sm -> sm:text-base
   jump (index.html) so the icon:text proportion stays constant across
   that breakpoint. Below sm, the topbar's search bar is hidden (see the
   max-width:1023px block below), so nothing else in the row is taller
   than the brand lockup -- the topbar shrinks to fit it exactly, leaving
   far less vertical slack than on wider screens where the search input
   sets a taller row. A flat enlarged size looked fine on desktop but
   cramped on mobile for that reason; keeping mobile at the smaller size
   restores the breathing room without shrinking the desktop version. */
.topbar-brand-icon {
    font-size: 1.7rem;
}

@media (min-width: 640px) {
    .topbar-brand-icon {
        font-size: 1.9rem;
    }
}

.topbar-brand-subtitle {
    margin-top: 0.0625rem;
    line-height: 1;
}

#userProfileMenuContainer {
    position: relative;
    z-index: 130;
    flex-shrink: 0;
}

#settingsMenuContainer {
    position: relative;
    z-index: 120;
    flex-shrink: 0;
}

/* Settings panel: absolute relative to its container button, RTL-aware via logical inset */
#settingsPanel {
    position: absolute;
    top: calc(100% + 0.35rem);
    inset-inline-start: 50%;
    transform: translateX(-50%);
    width: min(22rem, calc(100vw - 1rem));
    max-width: min(22rem, calc(100vw - 1rem));
    max-height: min(calc(100vh - 5rem), 32rem);
    overflow-y: auto;
}

/* Light-mode background/border/color for this button are NOT set here --
   `.library-shell #settingsMenuBtn` (search that selector further down)
   has one extra class of specificity and wins the cascade for all three,
   via --control-bg/--control-border/--control-text. Those tokens (tokens.css
   --ctrl-*) are what actually renders; this block only owns the structural
   properties nothing else touches. (--ctrl-text used to be a stray navy
   blue -- see tokens.css's comment on that token for the fix.) */
#settingsMenuBtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: relative; /* anchors the ::after touch-target hit-slop below */
    border-radius: 0.35rem;
}

/* 2026-09 revision: the translucent warm-stone chip this rule used to draw
   (rgba(168,162,158,...) fill+border) is removed on purpose, to match the
   light-mode version of this button, which has never had a chip --
   `.library-shell #settingsMenuBtn` (light mode) just tints --control-text
   on a --control-bg fill so close in value to the light topbar that it
   reads as flat/blended, not a distinct chip. Dark mode now blends the
   same way: falls back to transparent -- note this needs an *explicit*
   `transparent` below, not just deleting the old declarations. Deleting
   them would resurface the unguarded `.library-shell #settingsMenuBtn`
   rule further down (background: var(--control-bg), border-color:
   var(--control-border)), which beats .topbar-flat-btn's own
   `background: transparent` on specificity -- putting back the ~1:1-
   contrast --control-bg fill that was the original reason this chip
   existed. Legibility without a chip rests on the glyph color instead:
   color stays --accent-cream (#ddd5c8, bold icon weight), which measures
   11.58:1 against this topbar's dark background (--surface-2 #1e1d1a, via
   the .bg-white dark override) -- far past the 3:1 WCAG 1.4.11 floor for a
   graphical/icon control and past 4.5:1 too, so no token change was
   needed. :hover/:focus-visible keep a --control-bg tint (~1.05:1 against
   the topbar -- a deliberately subtle Fitts's-law affordance, not a chip)
   so interaction still gets feedback; border-color stays pinned to
   transparent even there because the unguarded
   `.library-shell #settingsMenuBtn:hover` rule further down would
   otherwise win that property (extra class selector outranks us at equal
   id count). Keep #settingsMenuBtn and #mobileLangToggle in sync (mirrored
   rules right below). See docs/ACCESSIBILITY_AUDIT.md for the chip
   rationale this supersedes. */
:is([data-theme="dark"], body.theme-dark) #settingsMenuBtn {
    background: transparent !important;
    border-color: transparent !important;
    color: var(--accent-cream) !important;
}

:is([data-theme="dark"], body.theme-dark) #settingsMenuBtn:hover,
:is([data-theme="dark"], body.theme-dark) #settingsMenuBtn:focus-visible {
    background: var(--control-bg) !important;
    border-color: transparent !important;
    color: var(--control-text-strong) !important;
}

/* Mobile language toggle: mirrors #settingsMenuBtn exactly (see the long
   comment above) -- transparent at rest, a subtle --control-bg tint on
   hover/focus only, no border at any state. Keep both in sync. */
:is([data-theme="dark"], body.theme-dark) #mobileLangToggle {
    background: transparent !important;
    border-color: transparent !important;
    color: var(--accent-cream) !important;
}

:is([data-theme="dark"], body.theme-dark) #mobileLangToggle:hover,
:is([data-theme="dark"], body.theme-dark) #mobileLangToggle:focus-visible {
    background: var(--control-bg) !important;
    border-color: transparent !important;
    color: var(--control-text-strong) !important;
}

#settingsMenuBtn svg {
    position: relative;
    top: 1px;
}

/* Touch-target minimum (44x44, this project's a11y bar) via an invisible
   hit-slop pseudo-element rather than resizing the visible button --
   growing the button itself would break this topbar's tight packing.
   Measured live at 1280px width: #settingsMenuBtn renders 28x24 with only
   ~6px of gap to the next control (#authControls); width could only be
   safely grown to 38px without the hit-zone reaching into that neighbor's
   own box. Vertically the 55px-tall topbar has ample headroom, so height
   reaches the full 44px target. Width is a documented partial mitigation,
   not a full 44x44 -- the topbar has no more horizontal room to give at
   this breakpoint. */
#settingsMenuBtn::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 38px;
    height: 44px;
    transform: translate(-50%, -50%);
}

/* #citySearchBtn (20x20) sits inside the Zmanim card, not a crowded
   toolbar -- measured clearance above/below/right is well over 12px each
   way, so this one reaches the full 44x44 target. */
#citySearchBtn {
    position: relative;
}

#citySearchBtn::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
}

html.rtl #hebrewDateDisplay {
    direction: rtl;
    unicode-bidi: plaintext;
    text-align: right;
}

.topbar-user-menu-btn {
    font-family: Georgia, "Times New Roman", serif;
    color: var(--control-text-strong);
}

/* Same 18px line box as the other top-bar buttons (Tailwind's text-xs,
   which loads last, gave 16px, so this one sat 2px short). Its container is
   flex (index.html) so the button isn't placed on a text baseline, which
   dropped it ~1px below its neighbours. */
.topbar-flat-btn.topbar-user-menu-btn {
    line-height: 1.5;
}

.topbar-user-menu-btn:hover,
.topbar-user-menu-btn:focus-visible {
    color: var(--control-text-strong);
}

/* These are a CSS-only fallback for the dropdown's resting position — the
   inline styles set by positionFloatingMenu()/positionUserProfileMenu() (in
   templates/index.html and templates/components/legal_scripts.html) use
   `!important` too and always win once JS runs, anchoring the menu directly
   under the topbar. This fallback used to be `position: fixed; top: 0;
   inset-inline-start: 0`, which pinned the menu to the page's top-left
   corner on any page where that JS hadn't run yet — keep this one resolving
   to something sane (just under the trigger button) on its own. */
#userProfileMenu {
    background: #fffaf3;
    border-color: #ddd4c3;
    z-index: 9999;
    position: absolute;
    top: 100%;
    inset-inline-end: 0;
    inset-inline-start: auto;
    margin-top: 0.375rem;
    padding: var(--sp-1);
    width: max-content;
    min-width: 7rem;
}

/* Every row (links and buttons alike) shares one size: the same inset,
   type and height, with the hover fill inset as a rounded row. */
.topbar-user-menu-item {
    font-family: Georgia, "Times New Roman", serif;
    line-height: 1.25;
    color: #334155;
    align-items: center;
    min-height: 1.5rem;
    border-radius: var(--radius-sm);
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    background: transparent;
    text-decoration: none;
}

/* Layout and hover fill are qualified by the element type: the rows also
   carry the block / px-3 / py-1.5 / hover:bg-slate-100 utilities, which load
   after this sheet and would win a tie with the bare class. */
a.topbar-user-menu-item,
button.topbar-user-menu-item {
    display: flex;
    padding: var(--sp-1) var(--sp-3);
}

@media (pointer: coarse) {
    .topbar-user-menu-item { min-height: var(--hit-min); }
}

.topbar-user-menu-item:hover,
.topbar-user-menu-item:focus-visible {
    color: #223e5a;
}

a.topbar-user-menu-item:hover,
a.topbar-user-menu-item:focus-visible,
button.topbar-user-menu-item:hover,
button.topbar-user-menu-item:focus-visible {
    background: #f4eee2;
}

:is([data-theme="dark"], body.theme-dark) #userProfileMenu {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) .topbar-user-menu-item {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .topbar-user-menu-item:hover,
:is([data-theme="dark"], body.theme-dark) .topbar-user-menu-item:focus-visible {
    background: var(--control-bg-hover) !important;
    color: var(--control-text-strong);
}

/* Settings Panel & General Button Styling for Tailwind Compatibility */
#settingsPanel button {
    color: #334155;
    display: inline-block;
    visibility: visible;
    border-radius: 0.6rem;
    padding: 0.42rem 0.62rem;
    font-size: var(--text-xs);
    line-height: 1.6;
}

/* #settingsPanel button's display:inline-block above outranks the .hidden
   utility on any button inside the panel (an id in its selector); these
   rules out-specify both so the export-only controls
   (updateExportControlsVisibility() / syncSettingsExportControls()) can
   still be toggled off outside text pages. */
#settingsPanel button.hidden,
#settingsPanel .export-text-only.hidden {
    display: none;
}

/* Quick Settings' community (minhag) radio group: static/js/minhag-setting.js. */
.minhag-setting {
    margin: 0;
    padding: 0;
    border: 0;
    min-inline-size: 0;
    display: grid;
    gap: var(--sp-1);
}

.minhag-setting__legend {
    padding: 0;
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--ink-heading);
}

.minhag-setting__hint {
    margin: 0 0 var(--sp-1);
    font-size: var(--text-xs);
    line-height: 1.5;
    color: var(--ink-secondary);
}

.minhag-option {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-2);
    min-height: var(--hit-min);
    padding: var(--sp-2);
    border: 1px solid var(--control-border);
    border-radius: var(--radius-md);
    background: var(--control-bg);
    color: var(--control-text);
    cursor: pointer;
    text-align: start;
    transition: background-color 180ms ease-out, border-color 180ms ease-out;
}

.minhag-option:hover {
    background: var(--control-bg-hover);
}

.minhag-option:has(.minhag-option__input:checked) {
    border-color: var(--control-accent);
    box-shadow: inset 0 0 0 1px var(--control-accent);
}

.minhag-option:has(.minhag-option__input:focus-visible) {
    outline: 2px solid var(--control-accent);
    outline-offset: 2px;
}

.minhag-option__input {
    flex-shrink: 0;
    inline-size: 1rem;
    block-size: 1rem;
    margin: 0.125rem 0 0;
    accent-color: var(--control-accent);
}

.minhag-option__text {
    display: grid;
    gap: 0.125rem;
    min-width: 0;
}

.minhag-option__name {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--control-text-strong);
}

.minhag-option__desc {
    font-size: var(--text-xs);
    line-height: 1.45;
    color: var(--ink-secondary);
}

@media (prefers-reduced-motion: reduce) {
    .minhag-option {
        transition: none;
    }
}

/* Quick Settings' "AI settings" row: icon, two-line label, caret. */
#settingsPanel #openAiSettingsBtn {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-height: 44px;
}

[dir="rtl"] #openAiSettingsBtn .ai-settings-caret {
    transform: scaleX(-1);
}

#settingsPanel button:not(#bookmarkCurrentBtn) {
    background: #e2e8f0 !important;
    border-color: #cbd5e1 !important;
}

#settingsPanel button:hover:not(#bookmarkCurrentBtn) {
    background: #cfd8e9 !important;
}

#semanticBookmarkBtn {
    border-color: #dacdb8;
}

/* #searchIcon's `top-2` utility (templates/index.html) is a fixed 8px
   offset that doesn't track #searchInput's actual height (which varies
   with the sm: breakpoint's text-sm/text-base font-size change), so the
   icon read as sitting a bit high inside the pill. True vertical
   centering via top/transform tracks the input's height at any
   breakpoint instead of guessing a fixed offset.

   .search-icon-glass and .search-ai-sparkle (below) are separate inline
   children of this box rather than being animated directly on #searchIcon
   itself -- an earlier version put the loading spin on #searchIcon, which
   overwrote this translateY(-50%) with the keyframe's own transform and
   made the icon visibly jump out of vertical center for the whole loading
   window. Splitting them means #searchIcon's own transform is never
   touched by either child's animation. */
#searchIcon {
    color: #a5947d !important;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    gap: var(--sp-1);
}

/* In Hebrew the icon sits at the input's left and the input keeps its room
   there, keyed off dir so it's right from the head script's first paint
   (toggleLanguage used to swap the utility classes after it, shifting both). */
html[dir="rtl"] #searchIcon {
    right: auto;
    left: var(--sp-3);
}

html[dir="rtl"] #searchInput {
    padding-left: calc(var(--sp-12) + var(--sp-2));
    padding-right: var(--sp-4);
}

/* On-screen keyboard (static/js/hebrew-keyboard.js). The button sits just
   inside the bar, before the search icon; it draws 32px but its ::before
   reaches the 44px touch minimum. It shows only on a keyboard-less touch
   screen (the script sets .kbd-available on the form), and the input only
   makes room for it then. */
#searchForm.kbd-available #searchInput {
    padding-right: calc(var(--sp-12) * 2);
}

html[dir="rtl"] #searchForm.kbd-available #searchInput {
    padding-left: calc(var(--sp-12) * 2);
    padding-right: var(--sp-4);
}

.search-kbd-btn {
    position: absolute;
    top: 50%;
    right: calc(var(--sp-12) + var(--sp-2));
    width: var(--sp-8);
    height: var(--sp-8);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-full);
    color: var(--ink-secondary);
    background: transparent;
    transform: translateY(-50%);
    transition: background-color var(--motion-dur-fast) var(--motion-ease-out),
        color var(--motion-dur-fast) var(--motion-ease-out);
}

.search-kbd-btn[hidden] {
    display: none;
}

.search-kbd-btn::before {
    content: "";
    position: absolute;
    inset: calc((var(--sp-8) - var(--hit-min)) / 2);
}

html[dir="rtl"] .search-kbd-btn {
    right: auto;
    left: calc(var(--sp-12) + var(--sp-2));
}

.search-kbd-btn:hover,
.search-kbd-btn[aria-expanded="true"] {
    background: var(--control-bg-hover);
    color: var(--ink-primary);
}

.search-kbd-btn[aria-expanded="true"] {
    color: var(--control-accent);
}

.search-kbd-btn:active {
    transform: translateY(-50%) scale(0.94);
}

/* The panel: under the bar, its full width and left edge. A flat tray with
   raised keys: letters on the light key surface, function keys (Shift, Caps,
   Delete, the menus, Enter) a step darker, Enter's glyph in the accent. */
.hebrew-kbd {
    position: absolute;
    top: calc(100% + var(--sp-2));
    left: 0;
    right: 0;
    z-index: 81;
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    padding: var(--sp-2);
    background: var(--surface-subtle);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-md);
    transform-origin: top center;
    /* Keys sit where they are on a physical keyboard (ק under E, as on an
       Israeli one) whatever the page direction. */
    direction: ltr;
}

.hebrew-kbd.hidden {
    display: none;
}

.kbd-row {
    display: flex;
    justify-content: center;
    gap: var(--sp-1);
}

.kbd-key {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    max-width: var(--sp-12);
    height: var(--hit-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Transparent, so forced-colors mode still draws an outline. */
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: var(--surface-elevated);
    box-shadow: var(--shadow-sm);
    color: var(--control-text-strong);
    font-size: clamp(1rem, 0.9rem + 0.4vw, 1.2rem);
    font-weight: 500;
    line-height: 1;
    user-select: none;
    -webkit-user-select: none;
    touch-action: manipulation;
    transition: background-color var(--motion-dur-fast) var(--motion-ease-out),
        transform var(--motion-dur-fast) var(--motion-ease-out);
}

.kbd-key[lang="he"] {
    font-family: var(--font-hebrew);
}

.kbd-key:hover {
    background: var(--control-bg-hover);
}

.kbd-key:active {
    transform: scale(0.94);
}

.kbd-key:focus-visible {
    outline: 2px solid var(--control-accent);
    outline-offset: 1px;
}

/* A Hebrew key's Latin letter, small in the corner as on a printed
   Israeli keyboard. */
.kbd-sub {
    position: absolute;
    right: var(--sp-1);
    bottom: 2px;
    font-family: var(--font-sans, sans-serif);
    font-size: 0.625rem;
    font-weight: 400;
    line-height: 1;
    color: var(--ink-secondary);
}

.kbd-key-wide {
    flex: 1.6 1 0;
    max-width: calc(var(--sp-12) * 1.6);
    background: var(--control-bg);
    color: var(--ink-secondary);
    font-size: 0.875rem;
    font-weight: 600;
}

.kbd-key-wide:hover {
    color: var(--ink-primary);
}

/* Shift / Caps Lock while on: never colour alone, a ring marks it too. */
.kbd-key[aria-pressed="true"] {
    background: var(--control-bg-hover);
    box-shadow: inset 0 0 0 2px var(--control-accent);
    color: var(--ink-primary);
}

/* Enter (search) stands out by its accent colour and weight; a filled
   accent key falls under 4.5:1 for its glyph in dark mode. */
.kbd-enter,
.kbd-enter:hover {
    color: var(--control-accent);
    font-size: 1.125rem;
}

.kbd-key-space {
    flex: 4 1 0;
    max-width: calc(var(--sp-12) * 6);
    font-size: 0.8125rem;
    color: var(--ink-secondary);
}

/* While the panel is open the suggestions sit below it, never under it. */
#searchForm.kbd-open #searchSuggestions {
    margin-top: calc(var(--hebrew-kbd-h, 0px) + var(--sp-2) * 2);
}

@media (prefers-reduced-motion: reduce) {
    .kbd-key,
    .search-kbd-btn {
        transition: none;
    }

    .search-kbd-btn:active {
        transform: translateY(-50%);
    }

    .kbd-key:active {
        transform: none;
    }
}

.search-icon-glass {
    display: inline-flex;
    transition: opacity var(--motion-dur-base) var(--motion-ease-out);
}

/* Small gold 4-point star sitting inline next to the magnifying glass -- a
   subtle, always-on hint that the search bar is also the "Ask Sh'elah" AI
   entry point, not just plain text search. Previously an absolutely
   positioned badge on the glass icon's corner, which read as clutter/
   overlap rather than a companion icon -- now a plain flex sibling (see
   #searchIcon's `gap` above), vertically centered alongside the glass icon
   instead of layered on top of it. Reuses .ai-hint-icon's color/opacity
   (see below) plus tokens.css's shelah-warm-pulse keyframe (already used
   for the loading overlay's logo, ENGINEERING_RULES.md: "zero new
   @keyframes outside the token layer") for the same ambient "something AI
   is here" glow used elsewhere, rather than a new animation style. Kept
   small and low-contrast at rest on purpose -- a hint, not a loading
   spinner; body.search-loading (static/css/ai.css) swaps this to an actual
   spin for the "asking AI" state.

   Duration overridden to 3.4s here (vs. the 2.6s baseline the shared
   keyframe is authored for): a solid filled star carries more "ink" than
   the keyframe's original thin outline target, so the same opacity/scale
   swing at the default pace reads more like an on/off blink than a gentle
   fade. Slowing just this selector's pace (same keyframe, same 0.7
   opacity floor) fixes that without touching sidebar.css's own separate
   1.6s override of the same keyframe for an unrelated element. */
.search-ai-sparkle {
    display: inline-flex;
    filter: drop-shadow(0 0 10px rgba(201, 168, 78, 0.4));
    animation: shelah-warm-pulse 3.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .search-ai-sparkle {
        animation: none !important;
    }
}

/* Small gold star badge next to "Mode"/"Community" in Quick Settings,
   signaling that those two controls shape the AI's answers (as opposed to
   the plain display/appearance controls elsewhere in the panel). Same
   'sparkle' icon and gold accent as the search bar's hint so the whole
   site reads as one consistent "AI" visual language. */
.ai-hint-icon {
    display: inline-flex;
    flex-shrink: 0;
    color: var(--accent-gold);
    opacity: 0.85;
}

.library-shell button svg,
.library-shell [role="button"] svg {
    color: currentColor;
    opacity: 0.92;
}

.library-shell button:hover svg,
.library-shell [role="button"]:hover svg,
.library-shell button:focus-visible svg,
.library-shell [role="button"]:focus-visible svg {
    color: currentColor;
    opacity: 1;
}

#searchInput {
    background: #fbf8f1;
    border-color: #d8d0c2;
    /* The placeholder is longer than the field on a phone; the default `clip`
       cut it off mid-letter under the search/AI icons. */
    text-overflow: ellipsis;
}

/* #64748b (slate-500) against this input's #fbf8f1 background measured
   4.49:1 -- just under WCAG AA's 4.5:1 for text. Bumped one step to
   slate-600 (#475569), same family/hue, now 7.14:1. */
#searchInput::placeholder {
    color: #475569;
    opacity: 1;
}

#searchInput:focus {
    border-color: #b8aa90 !important;
    box-shadow: 0 0 0 2px rgba(217, 205, 184, 0.78);
}

#searchSuggestions {
    border-color: #ddd4c3 !important;
    background: #fffaf1 !important;
}

/* #searchForm's hidden submit button (templates/index.html, the WCAG SC
   3.2.2 / H32.2 fix documented there) is the only focusable .sr-only
   element on the page. Tailwind's sr-only clip:rect(0,0,0,0) clips its
   entire box -- including the global :focus-visible outline from
   typography.css -- so a sighted keyboard user tabbing to it saw no focus
   indicator at all (measured live: outline was present in computed style
   but invisible on a 1x1px clipped box). Un-hidden on :focus-visible the
   same way .skip-to-content already does elsewhere on this page. */
#searchForm button[type="submit"].sr-only:focus-visible {
    position: absolute;
    width: auto;
    height: auto;
    padding: 0.4rem 0.9rem;
    margin: 0;
    overflow: visible;
    clip: auto;
    top: calc(100% + 0.5rem);
    left: 0;
    z-index: 90;
    background: var(--ink, #002147);
    color: #fff;
    border-radius: var(--radius-md, 0.5rem);
    font-size: 0.8rem;
    font-weight: 600;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

:is([data-theme="dark"], body.theme-dark) #searchForm button[type="submit"].sr-only:focus-visible {
    background: var(--accent-cream, #efe6d8);
    color: var(--surface-base, #090a0c);
}

.navigator-pane {
    background:
        linear-gradient(180deg, rgba(250, 247, 239, 0.98) 0%, rgba(246, 241, 232, 0.98) 100%),
        repeating-linear-gradient(45deg,
            rgba(115, 94, 67, 0.015) 0,
            rgba(115, 94, 67, 0.015) 4px,
            transparent 4px,
            transparent 10px);
}

.pulse-pane {
    background:
        linear-gradient(180deg, #fbf7ef 0%, #f6f0e5 100%),
        radial-gradient(circle at 85% 10%, rgba(125, 108, 85, 0.035) 0%, transparent 44%);
}

.menu-parasha-quick-link {
    border: 1px solid #c8b79d;
    background: linear-gradient(180deg, #fffaf1 0%, #f4ebdb 100%);
    border-radius: 0.55rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45);
}

/* Colour and padding sit one id higher than the class above: the link also
   carries the text-[#1f3f63] / hover:text-[#102b45] / py-0.5 utilities, which
   load after this sheet and would otherwise win the tie. */
#leftSidebar .menu-parasha-quick-link {
    color: #1f3f63;
    padding: 0.28rem 0.55rem;
}

.menu-parasha-quick-link:hover,
.menu-parasha-quick-link:focus-visible {
    background: #efe3d0;
    border-color: #a59072;
}

/* The lift is a mouse gesture: a tap on a touch screen would leave it stuck. */
@media (hover: hover) and (pointer: fine) {
    .menu-parasha-quick-link:hover { transform: translateY(-1px); }
}

#leftSidebar .menu-parasha-quick-link:hover,
#leftSidebar .menu-parasha-quick-link:focus-visible {
    color: #16324f;
}

.segment-row {
    position: relative;
}

.segment-label {
    display: inline-block;
    min-width: 1.15rem;
    text-align: center;
    font-size: var(--text-xs);
    letter-spacing: 0;
    text-transform: none;
    /* Was a hardcoded slate-400 (#94a3b8): only 2.4:1 against the light
       surfaces this renders on (verse-number labels are real text, not
       decorative icons) — well under the 4.5:1 AA text threshold. Token
       is tuned to clear every light AND dark surface (4.64-5.18:1 light,
       5.17-6.30:1 dark via the [data-theme="dark"] remap below). */
    color: var(--ink-secondary);
    background: transparent;
    border: 0;
    border-radius: 0;
    padding: 0;
    margin-bottom: 0;
    font-family: 'Inter', sans-serif;
    font-weight: 600;
}

.segment-label.inline-label {
    white-space: nowrap;
    line-height: 1.15;
    margin-top: 0.22rem;
}

#reader .reader-source-clean {
    background: transparent;
    border: 0;
    box-shadow: none;
}

#reader .reader-source-title {
    margin-bottom: 0;
}

#reader .reader-source-lines {
    margin-top: 0.42rem;
    padding-top: 0;
    border-top: none;
}

#reader .reader-text-row {
    background: transparent;
    border-color: var(--reader-divider-color);
}

#reader .reader-side-row,
#reader .reader-interleaved-row,
#reader .reader-single-row {
    position: relative;
}

#reader .reader-row-mid-label {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: 0.72rem;
    z-index: 2;
    padding: 0 0.18rem;
    background: var(--reader-label-bg);
    line-height: 1;
    pointer-events: none;
}

#reader .reader-row-right-label {
    position: absolute;
    right: 0.2rem;
    top: 0.72rem;
    z-index: 2;
    line-height: 1;
}

#reader .reader-text-he,
#reader .reader-text-en {
    background: transparent;
    border-inline-end: 0;
    border-inline-start: 0;
}

#reader .reader-side-row .reader-text-he,
#reader .reader-side-row .reader-text-en,
#reader .reader-interleaved-row .reader-text-he,
#reader .reader-interleaved-row .reader-text-en,
#reader .reader-single-row .reader-text-he,
#reader .reader-single-row .reader-text-en {
    padding-inline-end: 1.15rem;
}

/* The verse number is absolutely positioned at the physical right edge (see
   .reader-row-right-label). English (ltr) reserves that room with the
   padding-inline-end above, but the Hebrew block is dir="rtl", where
   inline-end is the LEFT side -- so its first line used to run underneath the
   number. Reserve the room on the Hebrew block's start (right) side instead:
   min-width 1.15rem + the label's 0.2rem inset + a little air. */
#reader .reader-interleaved-row .reader-text-he,
#reader .reader-single-row .reader-text-he {
    padding-inline-end: 0;
    padding-inline-start: 1.7rem;
}

#reader .reader-side-row .reader-text-he {
    padding-inline-end: 0.35rem;
}

#reader .reader-side-row .reader-text-en {
    padding-inline-start: 0.35rem;
}

#reader .reader-side-row .reader-text-he,
#reader .reader-side-row .reader-text-en {
    min-height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
}

.reader-nav-floating {
    position: fixed;
    right: 1rem;
    bottom: 6.25rem;
    z-index: 92;
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.reader-nav-floating-btn {
    border: 1px solid #24405f;
    background: #193754;
    color: #f8fafc;
    border-radius: 0.6rem;
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    padding: 0.6rem 0.85rem;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.22);
}

.reader-nav-floating-btn:hover,
.reader-nav-floating-btn:focus-visible {
    background: #102b45;
}

.reader-nav-floating-btn:disabled {
    opacity: 0.5;
    pointer-events: none;
}

.chapter-grid-items {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
    gap: 0.65rem;
}

.chapter-grid-items-sectioned {
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}

.chapter-grid-section-block {
    margin-bottom: 0.95rem;
}

.chapter-grid-section-items {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
    gap: 0.65rem;
}

.chapter-grid-header {
    background: linear-gradient(180deg, #f7f1e6 0%, #f0e8d9 100%);
    color: #1f3f63;
    border-bottom-color: #d7cebc;
}

.chapter-grid-subtitle {
    color: #6c7078;
}

.chapter-grid-parasha-strip {
    /* Use a wrapping flex layout so parasha buttons size to their text content
       instead of being forced into equal-width grid columns which can cut
       longer names. Flex allows items to grow/shrink naturally and wrap. */
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin-bottom: 0.85rem;
    padding-bottom: 0.65rem;
    border-bottom: 1px solid #ded4c4;
}

.chapter-grid-parasha-link {
    border: 1px solid #d7ceb9;
    background: #fbf7ee;
    color: #2c4868;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.14rem;
    font-family: 'Cardo', 'Cardo Fallback', serif;
    font-size: 0.91rem;
    font-weight: 700;
    line-height: 1.22;
    padding: 0.42rem 0.58rem;
    text-decoration: none;
    border-radius: 0.7rem;
    text-align: left;
    /* Allow the parasha link to size to content (auto width) and wrap text.
       Prevent forcing equal widths by grid; flex will handle wrapping. */
    flex: 0 1 auto;
}

.chapter-grid-parasha-link:hover,
.chapter-grid-parasha-link:focus-visible {
    background: #f0eadc;
    border-color: #bba888;
    color: #17324f;
}

.chapter-grid-parasha-name {
    white-space: normal;
    overflow-wrap: anywhere;
}

.chapter-grid-parasha-meta {
    font-size: var(--text-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #7f735f;
}

.chapter-grid-group-label {
    grid-column: 1 / -1;
    font-size: var(--text-xs);
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: #7d705c;
    font-weight: 700;
    padding-top: 0.25rem;
}

.chapter-grid-item {
    min-height: 3.1rem;
    border: 1px solid #d8d0c1;
    border-radius: 0.75rem;
    background: #fbf7ee;
    color: #1f3f63;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.1rem;
}

.chapter-grid-items-prayer {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 0.55rem;
}

.chapter-grid-items-prayer .chapter-grid-item {
    min-height: 2.6rem;
}

.chapter-grid-item:hover,
.chapter-grid-item:focus-visible {
    border-color: #bba88a;
    background: #f0eadc;
}

.chapter-grid-item-number {
    font-family: 'Cardo', 'Cardo Fallback', serif;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 0 0.2rem;
}

/* Book-name tiles (library category modal): the name scales with the tile's own
   width so "Deuteronomy" fits on narrow phones, and multi-word names wrap,
   instead of being ellipsised. Scoped here because the chapter-number grid shares the class and
   must keep its 1rem numerals. */
#libraryCategoryBody .chapter-grid-item {
    container-type: inline-size;
}

#libraryCategoryBody .chapter-grid-item-number {
    font-size: clamp(0.625rem, 14cqw, 1rem);
    /* Multi-word names ("Kitzur Shulchan Arukh") wrap instead of clipping. */
    white-space: normal;
    overflow-wrap: break-word;
    text-wrap: balance;
    text-align: center;
    line-height: 1.15;
    padding-block: 0.05em 0.12em; /* keeps descenders inside the overflow clip */
}

.chapter-grid-item-label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: #64748b;
}

/* Table-of-Contents accordion (#leftSidebar) — one consistent chevron for every
   <summary>, replacing each browser's own native disclosure-triangle glyph
   (previously shown, unstyled, on any summary missing list-none) and filling
   in the ones that suppressed it with no replacement icon at all. */
#leftSidebar .space-y-4 summary {
    list-style: none;
    cursor: pointer;
}

#leftSidebar .space-y-4 summary::-webkit-details-marker {
    display: none;
}

#leftSidebar .space-y-4 summary::after {
    content: '';
    display: inline-block;
    inline-size: 0.75em;
    block-size: 0.75em;
    margin-inline-start: 0.35rem;
    vertical-align: -0.05em;
    background: var(--text-muted);
    -webkit-mask: var(--icon-caret-right) center / contain no-repeat;
    mask: var(--icon-caret-right) center / contain no-repeat;
    transition: transform var(--motion-dur-fast) var(--motion-ease-out);
}

/* The chevron points toward the content, so it turns around in RTL. */
#leftSidebar .space-y-4 summary:dir(rtl)::after {
    transform: scaleX(-1);
}

#leftSidebar .space-y-4 details[open]>summary::after,
#leftSidebar .space-y-4 details[open]>summary:dir(rtl)::after {
    transform: rotate(90deg);
}

.library-index-sidebar-tree {
    margin-inline-start: 0.5rem;
    padding-inline-start: 0.75rem;
    border-inline-start: 2px solid rgba(0, 33, 71, 0.3);
}

.library-tree-summary {
    text-align: start;
}

.library-tree-children {
    margin-inline-start: 0.75rem;
    padding-inline-start: 0.5rem;
    border-inline-start: 1px solid #d7d2c6;
}

.library-node-open {
    text-align: start;
}

#reader .prayer-clean-lines {
    background: transparent;
    border: 0;
    box-shadow: none;
}

#reader .prayer-clean-row {
    background: transparent;
}

#reader .prayer-clean-he,
#reader .prayer-clean-en {
    background: transparent;
}

#reader .prayer-clean-row-dual .prayer-clean-he {
    text-align: right;
}

#reader .prayer-clean-row-dual .prayer-clean-en {
    text-align: left;
}

/* Sefaria wraps siddur rubrics/instructions ("Take the cup and say:") in
   <b><small>...</small></b>, mixed inline with ordinary prayer text in the
   same line. WCAG 1.4.1 (no color-only state): style survives on ITS OWN
   without any surrounding color, using three non-color cues together --
   size, italic slant, and a dotted underline -- so it reads distinctly in
   light and dark theme alike, and even in a high-contrast/forced-colors
   mode that strips background/foreground color entirely.
   !important is required: renderPrayerDisplayByLayout() force-sets
   `el.style.fontSize = 'inherit'` as an inline style on every descendant
   of #prayer-display after each render (so the reader's font-size control
   reaches nested markup), which would otherwise always beat this rule. */
#reader .prayer-clean-lines small {
    font-size: 0.83em;
    font-style: italic;
    text-decoration: underline dotted;
    text-underline-offset: 0.15em;
}

@media (max-width: 1023px) {
    #reader .reader-row-mid-label {
        left: auto;
        right: 0.2rem;
        transform: none;
        background: transparent;
    }
}

.segment-translit {
    font-family: 'Cardo', 'Cardo Fallback', serif;
    letter-spacing: 0.02em;
    /* Was a hardcoded slate-500 (#64748b): 4.07-4.45:1 against 4 of the 5
       light surfaces (fails 4.5:1 AA text threshold on all but surface-2).
       --ink-secondary clears every light and dark surface (see .segment-label
       above for the same fix). */
    color: var(--ink-secondary);
}

/* ═══════════════════════════════════════════════════════════════════ */
/* CUSTOM SCROLLBAR (Modern look) */
/* ═══════════════════════════════════════════════════════════════════ */

::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

/* Light mode scrollbar */
::-webkit-scrollbar-track {
    background: #f1f5f9;
    border-radius: 10px;
}

::-webkit-scrollbar-thumb {
    background: #cbd5e1;
    border-radius: 10px;
}

::-webkit-scrollbar-thumb:hover {
    background: #94a3b8;
}

/* Inverted scrollbar theming for sidebars */
#leftSidebar,
#rightSidebar {
    scrollbar-width: thin;
}

/* #readerTopBar is position: absolute (see #readerTopBar below), so it no
   longer sits in flow above this row — the sidebars start flush under the
   main site topbar with no extra offset needed here. */

/* Light mode: light shade of white for sidebar scrollbars */
#leftSidebar::-webkit-scrollbar-track,
#rightSidebar::-webkit-scrollbar-track {
    background: #fafafa;
    border-radius: 10px;
}

#leftSidebar::-webkit-scrollbar-thumb,
#rightSidebar::-webkit-scrollbar-thumb {
    background: #e8e8e8;
    border-radius: 10px;
}

#leftSidebar::-webkit-scrollbar-thumb:hover,
#rightSidebar::-webkit-scrollbar-thumb:hover {
    background: #d0d0d0;
}

/* Dark mode scrollbar */
html.theme-dark::-webkit-scrollbar,
:is([data-theme="dark"], body.theme-dark)::-webkit-scrollbar,
:is([data-theme="dark"], body.theme-dark) ::-webkit-scrollbar {
    width: 10px;
    height: 10px;
    background: var(--surface-base);
}

html.theme-dark::-webkit-scrollbar-track,
:is([data-theme="dark"], body.theme-dark)::-webkit-scrollbar-track,
:is([data-theme="dark"], body.theme-dark) ::-webkit-scrollbar-track {
    background: var(--surface-subtle);
    border-radius: 10px;
}

html.theme-dark::-webkit-scrollbar-thumb,
:is([data-theme="dark"], body.theme-dark)::-webkit-scrollbar-thumb,
:is([data-theme="dark"], body.theme-dark) ::-webkit-scrollbar-thumb {
    background: var(--control-border);
    border-radius: 10px;
    border: 2px solid var(--surface-subtle);
}

html.theme-dark::-webkit-scrollbar-thumb:hover,
:is([data-theme="dark"], body.theme-dark)::-webkit-scrollbar-thumb:hover,
:is([data-theme="dark"], body.theme-dark) ::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--control-border) 150%, var(--surface-elevated));
}

/* Dark mode: sidebar scrollbars use a lighter thumb for contrast */
:is([data-theme="dark"], body.theme-dark) #leftSidebar,
:is([data-theme="dark"], body.theme-dark) #rightSidebar {
    scrollbar-color: var(--control-border) transparent;
    scrollbar-width: thin;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar::-webkit-scrollbar-track,
:is([data-theme="dark"], body.theme-dark) #rightSidebar::-webkit-scrollbar-track {
    background: transparent;
    border-radius: 10px;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar::-webkit-scrollbar-thumb,
:is([data-theme="dark"], body.theme-dark) #rightSidebar::-webkit-scrollbar-thumb {
    background: var(--control-border);
    border-radius: 10px;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar::-webkit-scrollbar-thumb:hover,
:is([data-theme="dark"], body.theme-dark) #rightSidebar::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--text-muted) 60%, var(--control-border));
}

/* ═══════════════════════════════════════════════════════════════════ */
/* FullCalendar Overrides */
/* ═══════════════════════════════════════════════════════════════════ */

.fc {
    font-family: 'Inter', sans-serif;
}

.fc .fc-toolbar-title {
    font-size: 1.25em;
    font-weight: 600;
    color: #002147;
}

.fc-event {
    cursor: pointer;
    border: none !important;
    border-radius: 4px;
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.fc-col-header-cell-cushion,
.fc-daygrid-day-number {
    color: #475569;
    text-decoration: none;
}

.fc-day-today {
    background: #F0F9FF;
}

/* ═══════════════════════════════════════════════════════════════════ */
/* MARKDOWN RENDERING (marked.js) */
/* ═══════════════════════════════════════════════════════════════════ */

.prose {
    max-width: none;
}

/* Single source of truth for paragraph rhythm (was previously declared
   twice in a row with drifting margin/line-height values). */
.prose p {
    margin: var(--sp-4) 0;
    font-size: 0.95rem;
    line-height: 1.7;
    color: var(--ink-primary);
}

/* Lists and <hr> previously fell through to @tailwindcss/typography's own
   em-based default scale (ul/ol/li/hr had no override here), which does not
   share a rhythm with the rem-based p/h2/h3 rules above -- that mismatch is
   what read as "spacing is all over the place". These pin lists/hr to the
   same --sp-* rem scale as the rest of this block. */
.prose ul,
.prose ol {
    margin: var(--sp-4) 0;
    padding-inline-start: var(--sp-6);
}

.prose li {
    margin: var(--sp-2) 0;
}

.prose hr {
    margin: var(--sp-6) 0;
    border: none;
    border-top: 1px solid var(--surface-border);
}

.prose blockquote {
    margin: 0 0 var(--sp-6);
    padding-inline-start: var(--sp-4);
    font-style: italic;
    color: var(--ink-secondary);
}

.prose strong {
    color: var(--ink-heading);
    font-weight: 700;
}

.prose em {
    font-style: italic;
    color: #475569;
}

.prose code {
    background: #f1f5f9;
    color: #0c4a6e;
    padding: 0.2rem 0.5rem;
    border-radius: 3px;
    font-family: 'Courier New', monospace;
    font-size: 0.9em;
}

.prose h2 {
    color: var(--ink-heading);
    font-size: 1.25rem;
    font-weight: 700;
    margin-top: 1.5rem;
    margin-bottom: 0.75rem;
}

.prose h3 {
    color: #1e293b;
    font-size: 1.1rem;
    font-weight: 600;
    margin-top: 1.25rem;
    margin-bottom: 0.5rem;
}

/* ═══════════════════════════════════════════════════════════════════ */
/* AI MODAL & SYNTHESIS STYLING */
/* ═══════════════════════════════════════════════════════════════════ */

.ai-synthesis {
    background: linear-gradient(135deg, #f0f4f8 0%, #f4f8fc 100%);
    border: 1px solid #cbd5e1;
    border-radius: 12px;
    padding: 2rem;
    margin-bottom: 2rem;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

.ai-sources {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.5rem;
    margin: 2rem 0;
}

/* .ai-source-card, .ai-wiki-card, .ai-custom-card — owned by static/css/ai.css */

/* Omnibox suggestion list */
#searchSuggestions .suggestion-item {
    transition: background-color var(--motion-dur-base) var(--motion-ease-out);
}

#searchSuggestions .suggestion-item {
    cursor: pointer;
    min-height: var(--hit-min);
}

#searchSuggestions .suggestion-item:not([aria-selected="true"]):hover {
    background: var(--surface-subtle);
}

/* Verse results (backend/verse_search.py): the group's heading, the verse
   as a two-line snippet in its own script, matched words marked by weight
   and a tint (never the tint alone), and a skeleton of the same height
   while they load. */
#searchSuggestions .suggestion-group-heading {
    padding-block: var(--sp-2) var(--sp-1);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    border-top: 1px solid var(--surface-border);
}

#searchSuggestions .suggestion-verse-snippet {
    color: var(--text-muted);
    line-height: 1.5;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}

#searchSuggestions .suggestion-verse-snippet[dir="rtl"] {
    text-align: right;
    font-family: var(--font-hebrew);
    font-size: 0.875rem;
}

#searchSuggestions .suggestion-verse-snippet[dir="ltr"] {
    text-align: left;
}

#searchSuggestions .suggestion-verse-match {
    background: color-mix(in srgb, var(--accent-gold) 22%, transparent);
    color: var(--ink-primary);
    font-weight: 600;
    border-radius: var(--radius-sm);
    padding-inline: 1px;
}

#searchSuggestions .suggestion-skeleton {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    min-height: 4.25rem;
    justify-content: center;
}

#searchSuggestions .suggestion-skeleton-title {
    display: block;
    height: 0.75rem;
    width: 30%;
}

#searchSuggestions .suggestion-skeleton-text {
    display: block;
    height: 0.75rem;
    width: 85%;
}

#searchSuggestions .suggestion-item:focus {
    outline: none;
    background: #f4efe3;
}

/* Reader personalization */
#reader {
    --reader-font-size: 18px;
    --reader-line-height: 1.8;
    --reader-hebrew-size-offset: 2px;
    --reader-divider-color: #ddd5c8;
    --reader-label-bg: #f6f1e6;
    /* The p-4/sm:p-6/lg:p-12 utility classes give #reader the same generous
       top padding on every side, sized for when nothing sat above the
       article. With the reader topbar now always present above the text
       view, that top padding stacked with #reader>header's own margin to
       leave a large dead gap between the topbar and the title. Only the
       top inset needs trimming — left/right/bottom padding is untouched. */
    padding-top: clamp(0.6rem, 1.6vw, 1.1rem);
}

/* Removed responsive reader max-width overrides to keep layout stable and prevent inward/outward jumping */

@media (min-width: 1024px) and (max-width: 1420px) {

    #leftSidebar,
    #rightSidebar {
        width: 16rem;
        min-width: 16rem;
        padding-inline-start: 0.9rem;
        padding-inline-end: 0.9rem;
    }
}

@media (min-width: 1024px) and (max-width: 1260px) {

    #leftSidebar,
    #rightSidebar {
        width: 14.75rem;
        min-width: 14.75rem;
    }
}

#readerSettingsPanel {
    max-height: min(70vh, 32rem);
    overflow-y: auto;
}

#readerSettingsPanel.reader-settings-dropdown {
    /* Centred on its anchor with arithmetic, not translateX(-50%): `transform`
       stays free for the open/close animation (ShelahMotion.present). Same in
       LTR and RTL, since `left` is physical. Keep in step with the Tailwind
       w-[min(92vw,24rem)] on the element. */
    --reader-settings-w: min(92vw, 24rem);
    width: var(--reader-settings-w);
    left: calc(50% - var(--reader-settings-w) / 2);
    right: auto;
    background: var(--surface-elevated);
    border: 1px solid var(--surface-border);
    box-shadow: 0 14px 32px color-mix(in srgb, var(--surface-base) 35%, transparent);
    color: var(--text-main);
}

/* The input's own box is the 44px touch area; the visible track is drawn by the
   pseudo-elements, so the hit area is generous without a thick bar. Track and thumb
   sizes come from tokens.css (4px capsule, 14px knob that grows to 16px under
   the finger); the 44px input height keeps the hit area. The fill uses --control-accent, the same colour a
   checked .reader-switch uses, so the two controls in a panel read as one family.
   The thumb keeps a 2px ring in the accent so its edge stays >= 3:1 against the panel
   (WCAG 1.4.11) rather than relying on a shadow alone. */
.reader-range-slider {
    -webkit-appearance: none;
    appearance: none;
    height: var(--hit-min);
    padding: 0;
    background: transparent;
    --range-progress: 50%;
    --range-track: var(--slider-track-h);
    --range-thumb: var(--slider-thumb);
    --range-thumb-scale: 1;
    --range-complete: var(--control-accent);
    --range-incomplete: #d7cebc;
    --range-thumb-bg: #fffaf2;
    --range-thumb-border: var(--control-accent);
    outline: none;
    cursor: pointer;
    touch-action: pan-y;
}

.reader-range-slider:active {
    --range-thumb-scale: var(--slider-thumb-press-scale);
}

.reader-range-slider::-webkit-slider-runnable-track {
    box-sizing: border-box;
    height: var(--range-track);
    border-radius: 9999px;
    background: linear-gradient(to right,
            var(--range-complete) 0%,
            var(--range-complete) var(--range-progress),
            var(--range-incomplete) var(--range-progress),
            var(--range-incomplete) 100%);
}

.reader-range-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    box-sizing: border-box;
    width: var(--range-thumb);
    height: var(--range-thumb);
    /* WebKit does not centre the thumb on the track by itself. */
    margin-top: calc((var(--range-track) - var(--range-thumb)) / 2);
    border-radius: 50%;
    border: 2px solid var(--range-thumb-border);
    background: var(--range-thumb-bg);
    box-shadow: 0 1px 3px rgba(31, 63, 99, 0.26), 0 0 1px rgba(31, 63, 99, 0.4);
    cursor: pointer;
    /* The press-grow is a scale (audit M-9): tweening width, height and
       margin-top re-laid the thumb out every frame. */
    transform: scale(var(--range-thumb-scale));
    transition: transform var(--motion-dur-fast) var(--motion-ease-out);
}

.reader-range-slider::-moz-range-track {
    box-sizing: border-box;
    height: var(--range-track);
    border-radius: 9999px;
    background: var(--range-incomplete);
}

.reader-range-slider::-moz-range-progress {
    height: var(--range-track);
    border-radius: 9999px;
    background: var(--range-complete);
}

.reader-range-slider::-moz-range-thumb {
    box-sizing: border-box;
    width: var(--range-thumb);
    height: var(--range-thumb);
    border-radius: 50%;
    border: 2px solid var(--range-thumb-border);
    background: var(--range-thumb-bg);
    box-shadow: 0 1px 3px rgba(31, 63, 99, 0.26), 0 0 1px rgba(31, 63, 99, 0.4);
    cursor: pointer;
    transform: scale(var(--range-thumb-scale));
    transition: transform var(--motion-dur-fast) var(--motion-ease-out);
}

.reader-range-slider:focus-visible::-webkit-slider-thumb {
    outline: 2px solid var(--control-accent);
    outline-offset: 2px;
}

.reader-range-slider:focus-visible::-moz-range-thumb {
    outline: 2px solid var(--control-accent);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .reader-range-slider::-webkit-slider-thumb,
    .reader-range-slider::-moz-range-thumb {
        transition: none;
    }
}

.reader-switch {
    -webkit-appearance: none;
    appearance: none;
    position: relative;
    width: 2.2rem;
    height: 1.2rem;
    border-radius: 9999px;
    border: 1px solid #c4b9a4;
    background: #e8dfd0;
    transition: background var(--motion-dur-fast) var(--motion-ease-out), border-color var(--motion-dur-fast) var(--motion-ease-out);
    cursor: pointer;
}

.reader-switch::after {
    content: "";
    position: absolute;
    top: 0.1rem;
    left: 0.12rem;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: 50%;
    background: #fffaf2;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
    transition: transform var(--motion-dur-fast) var(--motion-ease-out);
}

.reader-switch:checked {
    background: var(--control-accent);
    border-color: var(--control-accent);
}

.reader-switch:checked::after {
    transform: translateX(1rem);
}

.sidebar-show-tab {
    backdrop-filter: blur(10px);
    letter-spacing: 0.02em;
    opacity: 0.85;
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .topbar {
        background: rgba(246, 241, 232, 0.98);
    }

    .sidebar-show-tab {
        background: rgba(255, 255, 255, 0.95);
    }
}

.sidebar-show-tab:hover {
    opacity: 1;
    /* The raised shadow is a fading layer (ai.css, audit M-9). */
}

html.rtl #leftSidebar {
    direction: rtl;
}

html.rtl #leftSidebar summary,
html.rtl #leftSidebar button,
html.rtl #leftSidebar h3,
html.rtl #leftSidebar p {
    text-align: right;
}

html.rtl #leftSidebar .border-l-2 {
    border-left-width: 0;
    border-right-width: 2px;
    padding-inline-start: 0;
    padding-inline-end: 0.75rem;
}

html.rtl #leftSidebar .pl-3 {
    padding-inline-start: 0;
    padding-inline-end: 0.75rem;
}

html.rtl #leftSidebar .ml-2,
html.rtl #leftSidebar .ml-3 {
    margin-inline-start: 0;
}

html.rtl #leftSidebar .ml-2 {
    margin-inline-end: 0.5rem;
}

html.rtl #leftSidebar .ml-3 {
    margin-inline-end: 0.75rem;
}

html.rtl #leftSidebar .library-sidebar-header {
    direction: rtl;
}

html.rtl #leftSidebar .library-sidebar-header h3 {
    order: 2;
}

html.rtl #leftSidebar .library-sidebar-header button {
    order: 1;
}

html.rtl #personalShelf button,
html.rtl #searchSuggestions .suggestion-item,
html.rtl #popularTextsGrid button {
    text-align: right;
}

html.rtl #searchSuggestions .suggestion-item .flex {
    flex-direction: row-reverse;
}

html.rtl .chapter-grid-parasha-link {
    text-align: right;
    align-items: flex-end;
}

html.rtl .chapter-grid-items,
html.rtl .chapter-grid-section-items {
    direction: rtl;
}

html.rtl .chapter-grid-group-label {
    direction: rtl;
    unicode-bidi: plaintext;
    text-align: right;
}

html.rtl .chapter-grid-item-number {
    direction: rtl;
    unicode-bidi: plaintext;
}

html.rtl #readerTopBar .reader-topbar-track {
    direction: ltr;
}

html.rtl #readerTopBar .reader-topbar-settings-label {
    direction: rtl;
    text-align: center;
}

#reader #readerContent,
#reader .source-en {
    font-size: var(--reader-font-size);
    line-height: var(--reader-line-height);
}

#reader .source-he {
    font-size: calc(var(--reader-font-size) + var(--reader-hebrew-size-offset));
    line-height: var(--reader-line-height);
}

#reader .source-grid.layout-reverse .source-he:not(.reader-text-he) {
    order: 2;
    border-inline-end: 0;
    border-inline-start: 1px solid #e2e8f0;
}

#readerTopBar {
    /* Taken out of document flow (overrides the Tailwind "sticky" utility
       class on this element) so it no longer pushes #leftSidebar/#rightSidebar
       and the reader row down by its own height. It used to be an in-flow
       sticky sibling before that row, which forced the sidebars to fake their
       way back up to the main topbar via a negative margin-top — but Chrome
       would compute that shifted position correctly (getBoundingClientRect,
       hit-testing math) while still painting the sidebar at its old,
       un-shifted position, leaving a dead-looking gap at the top of the
       sidebar. Positioning this bar absolutely (relative to body, see
       `position: relative` on body above) sidesteps that repaint bug
       entirely: the row below now naturally starts flush under the main
       topbar with no margin hack needed. #mainContainer's padding-top makes
       up the space this bar now occupies over the reader column only. */
    position: absolute;
    top: var(--reader-topbar-offset, 4.35rem);
    border-top: 1px solid #d8cfbe;
    border-bottom: 1px solid #d8cfbe;
    border-inline-start: 0;
    border-inline-end: 0;
    /* Very subtle translucency: the reader column scrolls underneath this
       bar (#mainContainer's padding-top sits under it), so a ~93% surface
       mix plus a soft blur lets the text shadow through without costing
       legibility. Dark mode uses the same mix (reader.css). */
    background: color-mix(in srgb, var(--surface-topbar) 93%, transparent);
    /* Slim bar: no vertical padding (overrides the py-1 utility); the track
       sets the visual height and the buttons keep a 44px hit area. */
    padding-block: 0;
    margin-top: 0;
    margin-bottom: 0;
    border-radius: 0;
    box-shadow: none;
    z-index: 55;
    box-sizing: border-box;
    /* --reader-topbar-left-gap/--reader-topbar-right-gap are the live widths
       of any anchored left/right sidebar (measured in syncReaderTopBarOffset()
       in templates/index.html). When a sidebar is open this shrinks and
       shifts the bar so it starts at the sidebar's edge instead of running
       underneath it; when no sidebar is anchored both gaps are 0px and the
       bar spans the full width exactly as before. */
    width: calc(100% - var(--reader-topbar-left-gap, 0px) - var(--reader-topbar-right-gap, 0px));
    margin-left: var(--reader-topbar-left-gap, 0px);
    margin-right: var(--reader-topbar-right-gap, 0px);
    -webkit-backdrop-filter: blur(12px) saturate(1.3);
    backdrop-filter: blur(12px) saturate(1.3);
}

.reader-topbar-shell {
    width: 100%;
    min-width: 0;
    padding-inline: clamp(0.35rem, 0.8vw, 0.9rem);
    box-sizing: border-box;
    display: flex;
    align-items: center;
}

.reader-topbar-track {
    flex: 1;
    width: 100%;
    max-width: var(--reader-outer-max-width, 62rem);
    margin: 0 auto;
    padding-inline: var(--reader-inline-padding, 1rem);
    display: flex;
    align-items: center;
    gap: 0.35rem;
    /* Visual height of the reader bar (36px + 1px borders = 38px, was 54px).
       syncReaderTopBarOffset() measures the bar, so #mainContainer's
       padding and the sidebar offsets follow automatically. */
    min-height: var(--reader-topbar-track-h, 2.25rem);
}

/* Buttons keep the full 44px hit area (ENGINEERING_RULES) but give back the
   overhang with negative block margins, so they don't inflate the slim track;
   the extra 4px of hit area simply extends past the track edges. */
.reader-topbar-track .reader-topbar-icon-btn {
    margin-block: calc((var(--reader-topbar-track-h, 2.25rem) - var(--hit-min, 44px)) / 2);
}

/* #readerTopBar is position: absolute and no longer reserves flow height
   above the sidebar+content row (see #readerTopBar above), so the reader
   column needs its own top padding to clear the bar instead. This is exactly
   the bar's height when showing, and 0px when it's hidden. */
#mainContainer {
    padding-top: calc(var(--right-sidebar-top-offset, 0px) - var(--reader-topbar-offset, 0px));
}

/* Library button: leftmost, flex-shrink-0 */
.reader-topbar-library-track {
    flex-shrink: 0;
    margin-inline-end: 0.1rem;
    opacity: 0.8;
}

.reader-topbar-library-track:hover,
.reader-topbar-library-track:focus-visible {
    opacity: 1;
}

#readerPrevTopBarBtn {
    flex-shrink: 0;
}

/* Settings wrapper expands to fill middle, centering the button */
.reader-topbar-settings-wrap {
    flex: 1;
    display: flex;
    justify-content: center;
    min-width: 0;
}

#readerNextTopBarBtn {
    flex-shrink: 0;
}

/* Keep hidden prev/next visible in layout so the track doesn't shift */
#readerPrevTopBarBtn.hidden,
#readerNextTopBarBtn.hidden {
    display: flex;
    visibility: hidden;
    pointer-events: none;
}

.reader-topbar-icon-btn {
    /* 44px hit target (WCAG 2.1 AA / ENGINEERING_RULES) without growing the
       glyph itself -- padding/font-size stay the same, min-height/min-width
       just pad out the box around them. */
    min-height: var(--hit-min, 44px);
    min-width: var(--hit-min, 44px);
    border: none;
    background: transparent;
    color: var(--control-text);
    border-radius: 0;
    font-size: 1.1rem;
    font-weight: 500;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem 0.4rem;
    cursor: pointer;
    transition: none;
}

.reader-topbar-icon-btn:hover,
.reader-topbar-icon-btn:focus-visible {
    background: transparent;
    border-color: transparent;
    color: var(--control-text-strong);
}

.reader-topbar-icon-btn:active {
    transform: none;
}

.reader-topbar-icon-btn:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--control-border) 70%, transparent);
    outline-offset: 2px;
}

.reader-topbar-icon-btn:disabled {
    opacity: 0.3;
    pointer-events: none;
}

/* Commentary sidebar entry point: rightmost, flex-shrink:0 like Prev/Next so
   it doesn't get squeezed by the centered settings button. The hint dot is
   a one-time "there's something here" cue (localStorage-gated in JS, see
   READER_COMMENTARY_HINT_KEY) -- hidden by default, only shown via the
   .has-hint class until the user opens the sidebar or makes a selection
   with commentary once. */
.reader-topbar-commentary-btn {
    position: relative;
    flex-shrink: 0;
}

.reader-topbar-commentary-hint-dot {
    display: none;
    position: absolute;
    top: 0.2rem;
    right: 0.2rem;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent-gold);
    pointer-events: none;
}

.reader-topbar-commentary-btn.has-hint .reader-topbar-commentary-hint-dot {
    display: block;
    animation: shelah-warm-pulse 2.2s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .reader-topbar-commentary-btn.has-hint .reader-topbar-commentary-hint-dot {
        animation: none !important;
    }
}

.reader-topbar-settings-wrap {
    display: flex;
    justify-content: center;
    min-width: 0;
    width: 100%;
}

/* Full-width anchor so left:50% + translateX(-50%) centres the dropdown over the whole topbar in both LTR and RTL */
.reader-topbar-settings-anchor {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
}

.reader-topbar-settings-btn {
    width: min(100%, clamp(9.8rem, 34vw, 15rem));
    min-width: 0;
    justify-content: center;
    gap: 0.45rem;
    padding-inline: 0.85rem;
    letter-spacing: 0.02em;
}

.reader-topbar-settings-icon {
    font-size: 0.9rem;
    line-height: 1;
}

.reader-topbar-settings-label {
    font-family: 'Inter', sans-serif;
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Reader topbar buttonless styling */
.library-shell .reader-topbar-icon-btn,
.library-shell #readerPrevTopBarBtn,
.library-shell #readerNextTopBarBtn {
    border: none;
    background: transparent;
    /* Was #8b7868 (3.84:1 against the reader topbar's light bg #f9f4ea) —
       fails the 4.5:1 AA text threshold (these render text labels like
       "Reader Settings", not just icons). Darkened within the same warm
       brown family, kept clear of the :hover/:focus-visible #5a4a3a
       (7.74:1) so the two states stay visually distinct. New value: 5.02:1. */
    color: #786650;
}

.library-shell .reader-topbar-icon-btn:hover,
.library-shell .reader-topbar-icon-btn:focus-visible,
.library-shell #readerPrevTopBarBtn:hover,
.library-shell #readerNextTopBarBtn:hover {
    background: transparent;
    border: none;
    color: #5a4a3a;
}

.library-shell .reader-topbar-shell #readerSettingsBtn {
    background: transparent !important;
    border: none !important;
    /* Was #8b7868 (3.84:1 against the reader topbar's light bg #f9f4ea) —
       fails the 4.5:1 AA text threshold (these render text labels like
       "Reader Settings", not just icons). Darkened within the same warm
       brown family, kept clear of the :hover/:focus-visible #5a4a3a
       (7.74:1) so the two states stay visually distinct. New value: 5.02:1. */
    color: #786650 !important;
}

.library-shell .reader-topbar-shell #readerSettingsBtn:hover,
.library-shell .reader-topbar-shell #readerSettingsBtn:focus-visible {
    background: transparent !important;
    border: none !important;
    color: #5a4a3a !important;
}

/* Prev/Next/Library at the ends of a text. 0.45 left the glyph at 2.3:1 on the
   dark top bar and 1.9:1 on the light one, close to invisible; 0.62 is still
   plainly off but legible (3.3:1 dark, 3.0:1 light). */
#readerTopBar button:disabled {
    opacity: 0.62;
    pointer-events: none;
}

@media (min-width: 640px) {
    :root {
        --reader-inline-padding: 1.5rem;
    }
}

@media (min-width: 1024px) {
    :root {
        --reader-inline-padding: 3rem;
    }
}

#reader .source-grid.layout-reverse .source-en {
    order: 1;
}

#reader .source-grid.source-grid-interleaved .source-he:not(.reader-text-he),
#reader .source-grid.source-grid-interleaved .source-en:not(.reader-text-en) {
    background: transparent;
    padding: 0;
}

#reader .source-he {
    letter-spacing: normal;
    word-spacing: normal;
    font-kerning: normal;
}

#rightSidebar {
    align-self: flex-start;
}

@media (min-width: 1024px) {
    #rightSidebar {
        position: sticky;
        top: var(--topbar-height, 3.4rem);
        height: calc(100vh - var(--topbar-height, 3.4rem));
        max-height: calc(100vh - var(--topbar-height, 3.4rem));
        overflow-y: auto;
        overscroll-behavior: contain;
        padding-bottom: 1rem;
    }
}

body.shul-mode .topbar {
    opacity: 0.15;
    transition: opacity var(--motion-dur-base) var(--motion-ease-out);
}

body.shul-mode .topbar:hover {
    opacity: 1;
}

body.shul-mode #readerTopBar {
    opacity: 0.15;
    transition: opacity var(--motion-dur-base) var(--motion-ease-out);
}

body.shul-mode #readerTopBar:hover {
    opacity: 1;
}

/* Same auto-hide treatment as #readerTopBar — if the settings dropdown is
   left open while Shul mode is active, it shouldn't stay fully opaque and
   distracting while everything else around it fades. */
body.shul-mode #readerSettingsPanel {
    opacity: 0.15;
    transition: opacity var(--motion-dur-base) var(--motion-ease-out);
}

body.shul-mode #readerSettingsPanel:hover {
    opacity: 1;
}

body.shul-mode #reader {
    max-width: var(--reader-shul-max-width);
    padding-top: 1.25rem;
}

/* Auto Scroll + Scroll Speed controls only matter once Shul Mode is on
   (see applyShulMode() in templates/index.html). A grid-rows 0fr->1fr
   collapse animates height without knowing the content's pixel height and
   without touching any layout property via JS (transform/opacity only, per
   ENGINEERING_RULES.md) — the "inner" wrapper is required for the trick and
   is what actually clips the content while collapsed. */
.shul-sub-controls {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    transition: grid-template-rows var(--motion-dur-base, 200ms) var(--motion-ease-out, ease-out),
                opacity var(--motion-dur-base, 200ms) var(--motion-ease-out, ease-out);
}

.shul-sub-controls.is-open {
    grid-template-rows: 1fr;
    opacity: 1;
}

.shul-sub-controls-inner {
    min-height: 0;
    overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
    .shul-sub-controls {
        transition: none;
    }
}

/* Keep the reader-settings top bar's inner track in step with the widened
   Shul-mode reading column above (#reader, same var) — otherwise the bar
   stays pinned to the default --reader-outer-max-width and renders as a
   narrow floating pill against the now-wider text below it. */
body.shul-mode .reader-topbar-track {
    max-width: var(--reader-shul-max-width);
}

body.shul-mode #reader #readerContent,
body.shul-mode #reader .source-he,
body.shul-mode #reader .source-en,
body.shul-mode #reader #prayer-display {
    font-size: calc(var(--reader-font-size) + 6px);
    line-height: calc(var(--reader-line-height) + 0.15);
}

@media (max-width: 1024px) {

    #reader .source-en {
        font-size: calc(var(--reader-font-size) - 1px);
    }

    #reader .source-he {
        font-size: calc(var(--reader-font-size) + var(--reader-hebrew-size-offset) - 1px);
    }
}

/* ═══════════════════════════════════════════════════════════════════ */
/* MOBILE ACCESSIBILITY & DRAWERS */
/* ═══════════════════════════════════════════════════════════════════ */

body.mobile-panel-open {
    overflow: hidden;
    overscroll-behavior: none;
}

@media (max-width: 1023px) {
    .topbar {
        align-items: flex-start;
        padding-inline-start: max(0.5rem, env(safe-area-inset-left));
        padding-inline-end: max(0.5rem, env(safe-area-inset-right));
    }

    .topbar-search-wrap,
    .topbar-controls {
        min-width: 0;
        max-width: 100%;
    }

    .topbar-controls {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        -ms-overflow-style: none;
    }

    .topbar-controls::-webkit-scrollbar {
        display: none;
    }

    #settingsPanel {
        width: min(22rem, calc(100vw - 1rem));
        max-width: calc(100vw - 1rem);
        max-height: calc(100vh - 5.5rem);
        max-height: calc(100dvh - var(--topbar-height, 3.4rem) - var(--mobile-tabs-height, 3.1rem) - 0.5rem);
    }

    /* Absolute inside the content row (`.flex.flex-1.min-h-0.relative`
       under <body>), not fixed to the viewport: that row sits between the
       top bar and the bottom tabs, so a drawer bounded by it can never run
       underneath either bar (it used to be fixed with bottom: 0 and lose
       its last ~50px behind the z-96 tab bar). */
    .mobile-drawer {
        position: absolute;
        top: 0;
        bottom: 0;
        height: auto;
        max-height: none;
        width: min(90vw, 22rem);
        max-width: 22rem;
        overflow-y: auto;
        overflow-x: hidden;
        -webkit-overflow-scrolling: touch;
        touch-action: pan-y;
        overscroll-behavior: contain;
        z-index: 95;
        box-shadow: 0 12px 34px rgba(15, 23, 42, 0.3);
    }

    #leftSidebar.mobile-drawer,
    #rightSidebar.mobile-drawer {
        padding-bottom: max(1.5rem, env(safe-area-inset-bottom));
    }

    .mobile-drawer-left {
        inset-inline-start: 0;
        border-inline-end: 1px solid #e2e8f0;
        transform: translateX(-105%);
        /* Same quick, overshoot-free settle as the menus/calendar (was 400ms
           plus a box-shadow transition); transform only. */
        transition: transform var(--motion-dur-base) var(--motion-ease-decel);
    }

    .mobile-drawer-right {
        inset-inline-end: 0;
        border-inline-start: 1px solid #e2e8f0;
        transform: translateX(105%);
        transition: transform var(--motion-dur-base) var(--motion-ease-decel);
    }

    .mobile-drawer.mobile-open {
        transform: translateX(0);
        box-shadow: 0 20px 60px rgba(15, 23, 42, 0.28);
    }

    /* #reader / #readerTopBar / #mainContainer spacing for phones is set in
       the "MOBILE LAYOUT" block below: both bars are in-flow there, so no
       offsets or overlay-clearing padding are needed here. */

    .reader-topbar-settings-wrap {
        min-width: 0;
    }

    .reader-topbar-settings-btn {
        min-width: 0;
        width: min(100%, min(12.5rem, 62vw));
        max-width: min(12.5rem, 62vw);
        padding-inline: 0.65rem;
        gap: 0.35rem;
    }

    .reader-topbar-settings-label {
        font-size: var(--text-xs);
    }

    #reader header .flex.flex-wrap.justify-center.items-center {
        justify-content: flex-start;
    }

    #mobileNavBtn,
    #mobileLangToggle,
    #settingsMenuBtn,
    #userProfileMenuBtn {
        min-height: 2rem;
        min-width: 2rem;
    }
}

/* ═══════════════════════════════════════════════════════════════════ */
/* HOMEPAGE TYPOGRAPHY-ONLY REDESIGN */
/* ═══════════════════════════════════════════════════════════════════ */

.home-typography {
    background: transparent;
    max-width: 1200px;
    margin-inline: auto;
    padding-inline: clamp(1.25rem, 3.5vw, 2.2rem);
}

.home-section-label {
    font-size: var(--text-xs);
    letter-spacing: 0.17em;
    text-transform: uppercase;
    font-variant: small-caps;
    /* Was a hardcoded #64748b (the pre-2026-08-15 --ink-secondary value,
       see docs/ACCESSIBILITY_AUDIT.md finding 3) that never picked up the
       token fix, leaving this at 4.45:1 on --surface-0 -- WCAG 2.1 AA
       needs 4.5:1. Caught by the automated pa11y-ci check; switched to the
       token so it now tracks the fixed value (and the dark-theme override
       below). */
    color: var(--ink-secondary);
    font-weight: 700;
    margin-bottom: 0.85rem;
}

.home-topic-title {
    font-family: 'Cardo', 'Cardo Fallback', serif;
    font-weight: 700;
}

.home-library-link {
    border: 0;
    background: transparent;
    display: block;
}

html.rtl .home-main-layout {
    direction: rtl;
}

html.rtl .home-main-layout .home-library-link,
html.rtl .home-main-layout .home-topic-title,
html.rtl .home-main-layout .home-library-title,
html.rtl .home-main-layout .home-library-description,
html.rtl .home-main-layout .home-section-label,
html.rtl .home-main-layout .home-daily-link,
html.rtl .home-main-layout #popularTextsGrid {
    text-align: right;
}

.home-library-title {
    display: block;
    font-family: 'Cardo', 'Cardo Fallback', serif;
    font-size: clamp(1.6rem, 2.2vw, 2.1rem);
    line-height: 1.1;
    font-weight: 700;
}

.home-library-description {
    display: block;
    margin-top: 0.5rem;
    max-width: 46ch;
    /* Same stale-hardcoded-hex issue as .home-section-label above. */
    color: var(--ink-secondary);
    font-size: 0.95rem;
    line-height: 1.5;
}

.home-link-tanakh .home-library-title {
    color: #004e5f;
}

.home-link-mishnah .home-library-title {
    color: #1f6f9f;
}

.home-link-talmud .home-library-title {
    color: #8c6e2b;
}

.home-link-halakhah .home-library-title {
    color: #7a2435;
}

.home-link-customs .home-library-title {
    color: #4d3866;
}

.home-link-thought .home-library-title {
    color: #006d6a;
}

.home-library-link:hover .home-library-title,
.home-topic-title:hover,
.home-daily-link:hover,
.home-stat-link:hover {
    text-decoration: underline;
    text-underline-offset: 0.18em;
}

.home-today-section {
    background: transparent;
    border: 0;
}

.home-main-layout {
    column-gap: clamp(2rem, 4vw, 3rem);
}

#dailyPulseColumn .home-section-label,
.home-main-layout>section>.home-section-label {
    margin-bottom: 1rem;
}

.home-calendar-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: 1rem;
    padding: 0.5rem 1rem;
    border: 1.5px solid #c4ab6e;
    background: linear-gradient(135deg, #fffaf0 0%, #f7f1e1 100%);
    border-radius: 0.45rem;
    color: #1f3f63;
    font-weight: 700;
    font-size: 0.82rem;
    letter-spacing: 0.04em;
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(78, 64, 30, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.6);
    transition: background var(--motion-dur-fast) var(--motion-ease-out), border-color var(--motion-dur-fast) var(--motion-ease-out), transform var(--motion-dur-fast) var(--motion-ease-out);
}

.home-calendar-btn__icon {
    flex: none;
    width: 1.1em;
    height: 1.1em;
}

.home-calendar-btn:hover {
    background: linear-gradient(135deg, #fff5e0 0%, #f2e8c8 100%);
    border-color: #b09050;
}

/* The raised shadow is a fading layer (ai.css, audit M-9). */
@media (hover: hover) and (pointer: fine) {
    .home-calendar-btn:hover { transform: translateY(-1px); }
}

.home-daily-entry {
    padding: 0;
}

.sk-daily-label {
    display: block;
    width: 6rem;
    height: 0.72rem;
}

.sk-daily-link {
    display: block;
    width: 9rem;
    height: 1.05rem;
    margin-top: 0.4rem;
}

.home-daily-label {
    display: block;
    font-size: var(--text-xs);
    letter-spacing: 0.17em;
    text-transform: uppercase;
    /* Same stale-hardcoded-hex issue as .home-section-label above. */
    color: var(--ink-secondary);
    font-weight: 700;
}

/* Real WCAG 2.1 AA fixes (pa11y-ci):
   the zmanim/daily-pulse widget uses Tailwind's default .text-slate-500
   utility (#64748b) and a one-off custom hex for row labels and the "next
   zman" countdown -- both fail 4.5:1 against this widget's cream card
   background (computed 4.43-4.45:1, confirmed with pa11y-ci against a live
   page, not just the token layer -- see docs/ACCESSIBILITY_AUDIT.md's own
   "not covered here" note re: individual component pairs). Scoped to
   #dailyPulseColumn / #nextZmanBadge rather than redefining .text-slate-500
   globally, since that utility is reused elsewhere in this file against
   different, already-compliant backgrounds. !important is required because
   static/css/tailwind.css loads after this file (see load order in
   templates/index.html), so the utility class would otherwise win. */
#dailyPulseColumn .text-slate-500 {
    color: var(--ink-secondary) !important;
}

#nextZmanBadge span span {
    color: var(--accent-primary);
}

.home-daily-link {
    margin-top: 0.22rem;
    background: transparent;
    border: 0;
    padding: 0;
    color: #1e293b;
    font-size: 1.05rem;
    font-family: 'Cardo', 'Cardo Fallback', serif;
    font-weight: 700;
    text-align: left;
}

/* Reset button chrome for a value that's now a link (holidayName,
   shabbatWeekName) while keeping the Tailwind utility classes it already
   carries (.text-slate-700, .text-end, .max-w-[60%]) in control of color,
   alignment and truncation -- only the browser's own button styling needs
   overriding here. */
.home-stat-link {
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    cursor: pointer;
}

.today-zmanim-list [data-zman-row] {
    background: transparent;
    border-radius: 0;
    padding-inline-start: 0;
    padding-inline-end: 0;
}

.today-zmanim-list [data-zman-row].zman-next-highlight {
    background: #f2eadb;
    border: 1px solid #d7c7ae;
    border-radius: 0.45rem;
    padding-inline-start: 0.45rem;
    padding-inline-end: 0.45rem;
}

.today-zmanim-list [data-zman-row].zman-next-highlight b {
    color: #5b4832;
}

/* ═══════════════════════════════════════════════════════════════════ */
/* MOBILE LAYOUT: TOP BAR + BOTTOM TABS + COMMENTARY SHEET */
/* ═══════════════════════════════════════════════════════════════════ */

.mobile-bottom-tabs {
    display: none;
}

@media (max-width: 1023px) {
    .topbar {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
        gap: 0.5rem;
        padding-inline-start: max(0.5rem, env(safe-area-inset-left));
        padding-inline-end: max(0.5rem, env(safe-area-inset-right));
    }

    .topbar .topbar-search-wrap {
        display: none;
    }

    body.mobile-search-open .topbar .topbar-search-wrap {
        display: flex;
        grid-column: 1 / -1;
        order: 5;
        margin-top: 0.35rem;
    }

    .topbar-brand {
        grid-column: 1;
        justify-self: start;
    }

    .topbar-brand-title {
        display: block;
    }

    #topbarControls {
        grid-column: 2;
        justify-self: end;
        width: auto;
        order: 0;
        justify-content: flex-end;
        gap: 0.35rem;
        padding-top: 0;
        flex-wrap: nowrap;
        overflow: visible;
    }

    /* Escapes #topbarControls' own flex row (which is pinned to the right
       edge) so the date can sit in the open space between the brand and
       the controls cluster, regardless of where it's nested in the DOM.
       position:fixed is relative to the viewport, not any ancestor --
       .topbar's position:sticky/z-index do not change that. Hidden by
       default: that gap's width varies (auth state, language, viewport),
       so syncHebrewDateMobilePosition() in index.html measures it and
       only shows this + sets `left` (the horizontal center of the gap,
       matching the translateX(-50%) below) when the date actually fits. */
    #hebrewDateDisplay {
        display: none;
        position: fixed;
        top: calc(var(--topbar-height, 3.4rem) / 2);
        transform: translate(-50%, -50%);
        pointer-events: none;
        white-space: nowrap;
        z-index: 5;
    }

    #authControls {
        max-width: 100%;
    }

    #authControls #userProfileMenuLabel {
        max-width: 8rem;
    }

    #settingsMenuBtn,
    #authControls button:not(.topbar-user-menu-item),
    #mobileLangToggle {
        font-size: 11px;
        line-height: 1.2;
        padding: 0.24rem 0.5rem;
    }

    body.mobile-search-open .topbar-brand,
    body.mobile-search-open #topbarControls {
        display: none;
    }

    /* The body is a full-height flex column (top bar / content row / this
       tab bar), so the tab bar is a real row: the content row above it is
       exactly the space between the two bars, and the scroll pane inside
       it reaches its true top and bottom. It used to be position: fixed,
       an overlay covering the bottom of the pane, and every screen paid for
       that with its own hand-tuned bottom padding.
       `relative` (not static) only so z-index still lifts it above the
       drawer backdrop and taps on it keep working while a drawer is open. */
    body.library-shell {
        height: 100vh;
        /* dvh tracks the *visible* viewport as the mobile browser's own
           toolbar shows/hides; plain vh is the largest one, which pushed the
           bottom of the layout under that toolbar. */
        height: 100dvh;
    }

    .mobile-bottom-tabs {
        position: relative;
        flex: 0 0 auto;
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        /* Equal columns with a gutter, so neighbouring pills never touch. */
        column-gap: var(--sp-1);
        /* The page's own surface (not a warmer one-off tint), so the bar
           reads as the same material as the content above it. */
        background: color-mix(in srgb, var(--surface-base) 97%, transparent);
        border-top: 1px solid var(--surface-border);
        padding: var(--sp-1) max(var(--sp-2), env(safe-area-inset-right)) max(var(--sp-1), env(safe-area-inset-bottom)) max(var(--sp-2), env(safe-area-inset-left));
        z-index: 96;
    }

    /* Icon stacked over label, both centered in the column: the icons sit
       on an even rhythm whatever each label's width. */
    .mobile-tab-btn {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: var(--sp-1);
        border: 0;
        background: transparent;
        font-size: var(--text-xs);
        font-weight: 700;
        letter-spacing: 0.08em;
        line-height: 1;
        text-transform: uppercase;
        color: #645a49;
        padding: var(--sp-2) var(--sp-1);
        border-radius: var(--radius-md);
        min-width: 0;
        min-height: var(--hit-min);
        position: relative;
        z-index: 1;
    }

    .mobile-tab-btn__icon {
        position: relative;
        display: inline-flex;
    }

    .mobile-tab-btn__label {
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    @media (hover: hover) {
        .mobile-tab-btn:not(.mobile-tab-active):hover {
            background: var(--ctrl-bg-hover);
        }
    }

    /* Small controls in the top bars: keep their drawn size but extend the
       tappable area to 44px tall with an invisible hit-slop, the same
       partial mitigation #settingsMenuBtn uses (height only -- the bars have
       no spare width, and a wider slop would overlap the neighbouring
       button). .reader-topbar-icon-btn is excluded: its own box is already
       44x44 (min-height/min-width: var(--hit-min)), so it needs no slop. */
    #signInBtn,
    #mobileLangToggle {
        position: relative;
    }

    #signInBtn::after,
    #mobileLangToggle::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 0;
        width: 100%;
        height: 44px;
        transform: translateY(-50%);
    }

    /* Phone Ask button: drawn 32px tall so it doesn't make the bar taller
       than its other controls; the same 44px hit-slop, on ::before because
       the discovery tip's .ai-attention ring owns ::after. Width is already
       44px. */
    #mobileTopbarAskBtn {
        min-height: var(--sp-8);
        height: var(--sp-8);
        /* The controls row's own gap already spaces it. */
        margin-inline-start: 0;
    }

    #mobileTopbarAskBtn::before {
        content: "";
        position: absolute;
        top: 50%;
        left: 0;
        width: 100%;
        height: var(--hit-min);
        transform: translateY(-50%);
    }

    /* Smallest phones: brand + settings + Ask + Sign In + language toggle
       overflow one row by a few px, so drop the brand's subtitle rather than
       wrap the controls onto a second row. (Two classes: Tailwind's .block,
       loaded after this sheet, would win a single-class tie.) */
    @media (max-width: 359px) {
        .topbar-brand .topbar-brand-subtitle {
            display: none;
        }
    }

    /* Search tab: a small AI sparkle (same mark as the search field's own
       hint) tucked on the icon's corner, so it never shifts the label off
       the column's center. */
    .mobile-tab-btn__ai {
        position: absolute;
        top: calc(var(--sp-1) * -1);
        inset-inline-end: calc(var(--sp-2) * -1);
    }

    .mobile-tab-btn.mobile-tab-active {
        background: #ede3d1;
        color: #473d2f;
        box-shadow: inset 0 0 0 1px #d8c9af;
    }

    /* The active pill is one sliding element (#mobileTabIndicator), positioned
       by JS with a spring. Once it is placed (.has-indicator) it supplies the
       fill, so the active button drops its own background; without JS the
       button styling above still marks the tab. */
    .mobile-tab-indicator {
        position: absolute;
        top: 0;
        left: 0;
        width: 0;
        height: 0;
        border-radius: 0.6rem;
        background: #ede3d1;
        box-shadow: inset 0 0 0 1px #d8c9af;
        pointer-events: none;
        z-index: 0;
        opacity: 0;
    }

    .mobile-bottom-tabs.has-indicator .mobile-tab-indicator {
        opacity: 1;
    }

    .mobile-bottom-tabs.has-indicator .mobile-tab-btn.mobile-tab-active {
        background: transparent;
        box-shadow: none;
    }

    .mobile-tab-btn:active {
        background: #e9dfcc;
    }

    /* The reader's own bar is a normal row between the top bar and the
       content (it is `position: absolute` on desktop, where #mainContainer
       pads itself down to clear it -- neither applies here), so the
       scroll pane starts below it and needs no top offset. */
    #readerTopBar {
        position: relative;
        top: auto !important;
        flex: 0 0 auto;
        width: 100%;
        margin-left: 0;
        margin-right: 0;
    }

    /* The Reader Settings dropdown is anchored to the whole bar, not to its
       button: the button sits off-centre between the prev/next and comment
       icons, so centring on it (left: 50% of the button's own anchor) pushed
       a 92vw panel past the left edge. Made static, the anchor stops being
       the containing block and the panel positions against #readerTopBar
       (full width); it fills the bar minus a gutter, capped at 24rem and
       centred by auto margins. The doubled selector out-ranks the centring
       rule above (#readerSettingsPanel.reader-settings-dropdown). */
    #readerTopBar .reader-topbar-settings-anchor {
        position: static;
    }

    html #readerTopBar #readerSettingsPanel.reader-settings-dropdown {
        left: var(--sp-2);
        right: var(--sp-2);
        width: auto;
        max-width: 24rem;
        margin-inline: auto;
        max-height: min(70dvh, 32rem);
    }

    #mainContainer {
        padding-top: 0;
    }

    /* Nothing overlays the bottom of the scroll pane any more, so content
       only needs ordinary end padding -- not a bar-height's worth of it. */
    #reader {
        padding-bottom: var(--sp-8);
    }

    #homeGrid {
        padding-bottom: var(--sp-6);
    }

    #leftSidebar.mobile-drawer {
        width: min(88vw, 20rem);
        max-width: 20rem;
    }

    #rightSidebar.mobile-drawer-right {
        inset-inline-start: 0;
        inset-inline-end: 0;
        top: auto;
        bottom: 0;
        width: 100%;
        max-width: none;
        /* % of the content row (the space between the two bars), so the
           sheet's bottom edge sits on the tab bar, not behind it. */
        height: min(70%, 34rem);
        max-height: 70%;
        border-inline-start: 0;
        border-top: 1px solid #cbd5e1;
        border-radius: 1rem 1rem 0 0;
        transform: translateY(106%);
        transition: transform var(--motion-dur-base) var(--motion-ease-decel);
        padding-bottom: max(1rem, env(safe-area-inset-bottom));
    }

    #rightSidebar.mobile-drawer-right.mobile-open {
        transform: translateY(0);
        box-shadow: 0 -12px 40px rgba(15, 23, 42, 0.18);
    }

    #dailyPulseColumn {
        margin-top: 0.5rem;
    }

    .home-library-title {
        font-size: clamp(1.45rem, 7.2vw, 1.9rem);
    }

    .home-library-description {
        font-size: 0.9rem;
    }
}

/* Modal cards cap their height in `vh` via Tailwind utilities
   (max-h-[85vh] etc.). On phones `vh` is the LARGEST viewport, so a card can
   extend under the mobile browser's own toolbar and lose its bottom edge.
   Same percentages, in `dvh` (the currently visible viewport). Scoped by id
   so it out-ranks the utility classes (tailwind.css loads after this file);
   @supports keeps browsers without dvh on the existing vh caps. */
@supports (height: 100dvh) {
    #calendarModal > div {
        max-height: 90dvh;
    }

    #textsMenuModal > div,
    #privacyDataModal > div,
    #devtoolsInspectorModal > div {
        max-height: 85dvh;
    }

    #chapterGridModal > div,
    #libraryCategoryModal > div {
        max-height: 88dvh;
    }
}

/* ═══════════════════════════════════════════════════════════════════ */
/* WARM THEME NORMALIZATION OVERRIDES */
/* ═══════════════════════════════════════════════════════════════════ */

.library-shell,
.library-shell #mainContainer,
.library-shell .content-canvas {
    background: var(--surface-base) !important;
}

.library-shell .bg-white {
    background-color: var(--surface-elevated) !important;
}

.library-shell .bg-slate-50 {
    background-color: var(--surface-subtle);
}

.library-shell .bg-slate-100 {
    background-color: var(--surface-pill);
}

.library-shell .border-slate-100,
.library-shell .border-slate-200,
.library-shell .border-slate-300 {
    border-color: var(--surface-border) !important;
}

.library-shell .text-blue-100 {
    color: #f8edd8;
}

.library-shell .text-blue-500,
.library-shell .text-blue-600,
.library-shell .text-blue-700,
.library-shell .text-blue-800,
.library-shell .text-blue-900 {
    color: #6a5840;
}

.library-shell .bg-blue-50,
.library-shell .bg-blue-100,
.library-shell .bg-indigo-50 {
    background-color: #f4efe3;
}

.library-shell .border-blue-200,
.library-shell .border-indigo-200 {
    border-color: #d9cfbe;
}

.library-shell .text-indigo-700,
.library-shell .text-indigo-800,
.library-shell .text-indigo-900 {
    color: #5f4f3a;
}

.library-shell .hover\:bg-blue-100:hover,
.library-shell .hover\:bg-slate-100:hover,
.library-shell .hover\:bg-slate-200:hover,
.library-shell .hover\:bg-blue-50:hover {
    background-color: #f4efe3 !important;
}

.library-shell .focus\:ring-blue-300:focus,
.library-shell .focus\:ring-blue-400:focus,
.library-shell .focus\:ring-blue-500:focus {
    --tw-ring-color: rgba(183, 167, 138, 0.65);
}

.library-shell .focus\:border-blue-300:focus,
.library-shell .focus\:border-blue-400:focus,
.library-shell .focus\:border-blue-500:focus {
    border-color: #b8aa90;
}

.library-shell .lang-btn {
    background-color: var(--control-bg) !important;
    border-color: var(--control-border) !important;
    color: var(--control-text) !important;
    position: relative; /* anchors the ::before touch-target hit-slop below */
}

/* Without this, :hover/:focus-visible feedback on these two buttons was
   silently cancelled: .topbar-flat-btn:hover's color has no !important,
   so it always lost to this rule's always-on `color: ... !important`
   above at equal (0,2,0) specificity by losing the source-order tie
   (this rule comes later in the file). #settingsMenuBtn/#mobileLangToggle
   don't have this problem -- they get a dedicated, higher-specificity
   :hover override further down (search ".library-shell #settingsMenuBtn:hover")
   that .lang-btn never had. Mirrors that same pattern instead of just
   adding !important to the low-specificity rule, which would still lose
   the source-order tie.
   Theme tokens, not a translucent black overlay + a literal brown: that
   literal was only readable in light theme (#3a3128 over the dark control
   surface is 1.29:1) and stayed correct in dark solely because the
   higher-specificity .topbar-flat-btn dark rule happened to override it.
   The tokens hold in both themes on their own: light #4c3924 on #ece5d8
   8.74:1, dark #b8b0a0 on #2d2b28 6.56:1. */
.library-shell .lang-btn:hover,
.library-shell .lang-btn:focus-visible {
    background-color: var(--control-bg-hover) !important;
    color: var(--control-text-strong) !important;
}

.library-shell .lang-btn.lang-btn-active {
    background-color: rgba(0, 0, 0, 0.06) !important;
    color: #4d3d2a !important;
    font-weight: 700;
}

/* Touch-target minimum via invisible hit-slop (see #settingsMenuBtn above
   for the same technique/rationale). Uses ::before, not ::after -- the
   active language button already uses ::after for its underline indicator
   (ai.css's .lang-btn-active::after), and both rules share this element's
   only ::after box, so reusing it here clobbered the underline's
   transform/opacity (confirmed live: computed transform came back as the
   underline's scale-in keyframe instead of ours). English/עברית sit side
   by side with only ~6px between them, so width can only safely grow +3px
   each side (calc(100% + 6px), centered) without the two buttons' hit-zones
   overlapping each other. Height reaches the full 44px target since the
   55px-tall topbar has the room. Measured 52x24 (English) / 45x24
   (עברית) -> hit-zone 58x44 / 51x44: a documented partial mitigation on
   width, full compliance on height. */
.library-shell .lang-btn::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: calc(100% + 6px);
    height: 44px;
    transform: translate(-50%, -50%);
}

.library-shell #settingsMenuBtn,
.library-shell #mobileLangToggle,
.library-shell #readerSettingsBtn,
.library-shell #bookmarkCurrentBtn,
.library-shell #openReaderSettingsFromMenu,
.library-shell #importShelfBtn,
.library-shell #exportCitationBtn,
.library-shell #themeToggleBtn {
    background-color: var(--control-bg) !important;
    border-color: var(--control-border) !important;
    color: var(--control-text) !important;
}

.library-shell #bookmarkCurrentBtn {
    background-color: var(--control-strong-bg) !important;
    border-color: var(--control-strong-bg) !important;
    color: #f5f8fd !important;
}

.library-shell #bookmarkCurrentBtn:hover {
    background-color: var(--control-strong-bg-hover) !important;
}

.library-shell #settingsMenuBtn:hover,
.library-shell #settingsMenuBtn:focus-visible,
.library-shell #mobileLangToggle:hover,
.library-shell #mobileLangToggle:focus-visible,
.library-shell #readerSettingsBtn:hover,
.library-shell #openReaderSettingsFromMenu:hover,
.library-shell #importShelfBtn:hover,
.library-shell #exportCitationBtn:hover,
.library-shell #themeToggleBtn:hover {
    background-color: var(--control-bg-hover) !important;
    border-color: #ccbca2 !important;
    color: var(--control-text-strong) !important;
}

.library-shell #settingsPanel,
.library-shell #readerSettingsPanel,
.library-shell #selectionInsights {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
}

/* These modal headers carry a .text-blue-100 subtitle (color #f8edd8,
   see the .text-blue-100 rule above) directly on this gradient. The
   original stops (#756d61 / #867d70) only cleared 3.49-4.40:1 against that
   text -- failing 4.5:1 AA everywhere along the gradient, not just at one
   end (the .text-white h2 title is large/bold text and was already fine
   at 3:1). Darkened both stops ~17% in place, preserving the same hue and
   gradient shape; now 4.75-5.63:1 against the subtitle and 5.52-6.76:1
   against the white title. */
.library-shell #textsMenuModal .bg-linear-to-r.from-navy.to-blue-900,
.library-shell #devtoolsInspectorModal .bg-linear-to-r.from-navy.to-blue-900 {
    background-image: linear-gradient(to right, #615a51, #6f685d);
}

.library-shell #searchSuggestions .suggestion-item[aria-selected="true"] {
    background: var(--control-bg-hover);
    /* Not colour alone: the highlighted option also carries an inline bar. */
    box-shadow: inset 3px 0 0 var(--control-accent);
}

html.rtl .library-shell #searchSuggestions .suggestion-item[aria-selected="true"] {
    box-shadow: inset -3px 0 0 var(--control-accent);
}

.library-shell .library-node-open.library-node-active {
    background: #f2eadc;
    border: 1px solid #d7c8ad;
    color: #4f4130;
}

.library-shell .library-node-open.library-node-active:hover {
    background: #ede2d0;
    color: #433728;
}

@media (max-width: 768px) {

    .library-shell #settingsMenuBtn,
    .library-shell #mobileLangToggle,
    .library-shell #readerSettingsBtn,
    .library-shell #themeToggleBtn,
    .library-shell .lang-btn {
        min-height: 1.9rem;
        padding-top: 0.22rem;
        padding-bottom: 0.22rem;
    }
}

.library-shell :where(button, [role="button"], input, select, textarea, .mobile-tab-btn, .sidebar-show-tab, .suggestion-item, .conv-mode-opt) {
    transition:
        background-color var(--motion-dur-base) var(--motion-ease-out),
        color var(--motion-dur-base) var(--motion-ease-out),
        border-color var(--motion-dur-base) var(--motion-ease-out),
        transform var(--motion-dur-fast) var(--motion-ease-out),
        scale var(--motion-dur-fast) var(--motion-ease-out),
        opacity var(--motion-dur-fast) var(--motion-ease-out);
    -webkit-tap-highlight-color: rgba(221, 201, 168, 0.36);
}

.library-shell .shelf-open:focus-visible,
.library-shell .library-node-open:focus-visible,
.library-shell #leftSidebar button:focus-visible,
.library-shell #topbarControls button:focus-visible,
.library-shell #searchSuggestions .suggestion-item:focus-visible {
    /* --control-accent is 5:1+ against the page in both themes; the old
       translucent tan measured 1.67:1 (light) / 2.98:1 (dark), under the
       3:1 WCAG 1.4.11 minimum for a focus indicator. */
    outline: 2px solid var(--control-accent);
    outline-offset: 2px;
    background-color: #f4efe3 !important;
}

/* ═══════════════════════════════════════════════════════════════════ */
/* SOFT DARK MODE */
/* Token values are set by tokens.css [data-theme="dark"] / body.theme-dark.
   Only presentational non-token properties live here. */
/* ═══════════════════════════════════════════════════════════════════ */

/* Corpus accent tokens (--accent-menu, --accent-tanakh, etc.) defined in tokens.css dark block */
:is([data-theme="dark"], body.theme-dark) {
    background: radial-gradient(circle at 50% -40%, rgba(255, 255, 255, 0.06), transparent 48%), var(--surface-0);
    color: var(--ink-primary);
    color-scheme: dark;
}

:is([data-theme="dark"], body.theme-dark),
:is([data-theme="dark"], body.theme-dark) #mainContainer,
:is([data-theme="dark"], body.theme-dark) .content-canvas,
:is([data-theme="dark"], body.theme-dark) .library-shell {
    background: var(--surface-base) !important;
    color: var(--accent-cream) !important;
}

:is([data-theme="dark"], body.theme-dark) .topbar {
    background: linear-gradient(180deg,
            color-mix(in srgb, var(--surface-topbar) 98%, transparent) 0%,
            color-mix(in srgb, var(--surface-base) 98%, transparent) 100%);
    border-color: var(--surface-border);
    box-shadow: 0 10px 28px color-mix(in srgb, var(--surface-base) 68%, transparent);
}

:is([data-theme="dark"], body.theme-dark) #searchInput {
    background: var(--surface-pill);
    border-color: var(--surface-border);
    color: var(--accent-cream);
    -webkit-text-fill-color: var(--accent-cream);
    caret-color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #searchInput::placeholder {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) #searchInput:-webkit-autofill,
:is([data-theme="dark"], body.theme-dark) #searchInput:-webkit-autofill:hover,
:is([data-theme="dark"], body.theme-dark) #searchInput:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--accent-cream);
    box-shadow: 0 0 0 1000px var(--surface-pill) inset;
}

html.theme-dark,
:is([data-theme="dark"], body.theme-dark),
:is([data-theme="dark"], body.theme-dark) .library-shell,
:is([data-theme="dark"], body.theme-dark) #mainContainer,
:is([data-theme="dark"], body.theme-dark) .topbar,
:is([data-theme="dark"], body.theme-dark) .navigator-pane,
:is([data-theme="dark"], body.theme-dark) .pulse-pane,
:is([data-theme="dark"], body.theme-dark) .mobile-bottom-tabs {
    transition: none !important;
}

:is([data-theme="dark"], body.theme-dark) #searchSuggestions {
    background: var(--surface-elevated) !important;
    border-color: var(--surface-border) !important;
    box-shadow: 0 20px 32px color-mix(in srgb, var(--surface-base) 74%, transparent);
}

:is([data-theme="dark"], body.theme-dark) #searchSuggestions .suggestion-item[aria-selected="true"] {
    background: var(--control-bg-hover);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .navigator-pane,
:is([data-theme="dark"], body.theme-dark) .pulse-pane {
    background:
        linear-gradient(180deg, rgba(30, 29, 26, 0.98) 0%, rgba(25, 24, 22, 0.98) 100%),
        repeating-linear-gradient(45deg,
            rgba(255, 255, 255, 0.012) 0,
            rgba(255, 255, 255, 0.012) 3px,
            transparent 3px,
            transparent 9px);
}

:is([data-theme="dark"], body.theme-dark) .mobile-bottom-tabs {
    background: color-mix(in srgb, var(--surface-base) 97%, transparent);
    border-top-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) .mobile-tab-btn {
    color: var(--text-main);
}

:is([data-theme="dark"], body.theme-dark) .mobile-tab-btn.mobile-tab-active {
    background: var(--control-bg-hover);
    color: var(--control-text-strong);
    box-shadow: inset 0 0 0 1px var(--control-border);
}

:is([data-theme="dark"], body.theme-dark) .mobile-tab-indicator {
    background: var(--control-bg-hover);
    box-shadow: inset 0 0 0 1px var(--control-border);
}

:is([data-theme="dark"], body.theme-dark) .mobile-bottom-tabs.has-indicator .mobile-tab-btn.mobile-tab-active {
    background: transparent;
    box-shadow: none;
}

:is([data-theme="dark"], body.theme-dark) .bg-white {
    background-color: var(--surface-elevated) !important;
}

:is([data-theme="dark"], body.theme-dark) .bg-slate-50 {
    background-color: var(--surface-subtle) !important;
}

:is([data-theme="dark"], body.theme-dark) .bg-slate-100 {
    background-color: var(--tw-dark-bg-slate-100);
}

:is([data-theme="dark"], body.theme-dark) .bg-slate-200 {
    background-color: var(--tw-dark-bg-slate-200);
}

:is([data-theme="dark"], body.theme-dark) .bg-white\/85 {
    background-color: var(--tw-dark-bg-white-85);
}

:is([data-theme="dark"], body.theme-dark) .border-slate-100,
:is([data-theme="dark"], body.theme-dark) .border-slate-200,
:is([data-theme="dark"], body.theme-dark) .border-slate-300,
:is([data-theme="dark"], body.theme-dark) .border-gray-100,
:is([data-theme="dark"], body.theme-dark) .border-gray-200,
:is([data-theme="dark"], body.theme-dark) .border-gray-300,
:is([data-theme="dark"], body.theme-dark) .border-r,
:is([data-theme="dark"], body.theme-dark) .border-l,
:is([data-theme="dark"], body.theme-dark) .border-t,
:is([data-theme="dark"], body.theme-dark) .border-b {
    border-color: var(--surface-border) !important;
}

:is([data-theme="dark"], body.theme-dark) .border-slate-400 {
    border-color: var(--tw-dark-border-slate-400);
}

:is([data-theme="dark"], body.theme-dark) .text-slate-900 {
    color: var(--tw-dark-text-slate-900) !important;
}

:is([data-theme="dark"], body.theme-dark) .text-slate-800 {
    color: var(--tw-dark-text-slate-800) !important;
}

:is([data-theme="dark"], body.theme-dark) .text-slate-50,
:is([data-theme="dark"], body.theme-dark) .text-gray-50,
:is([data-theme="dark"], body.theme-dark) .text-slate-100,
:is([data-theme="dark"], body.theme-dark) .text-gray-100,
:is([data-theme="dark"], body.theme-dark) .text-white {
    color: var(--tw-dark-text-white);
}

:is([data-theme="dark"], body.theme-dark) .text-slate-700 {
    color: var(--tw-dark-text-slate-700);
}

:is([data-theme="dark"], body.theme-dark) .text-slate-600 {
    color: var(--tw-dark-text-slate-600);
}

:is([data-theme="dark"], body.theme-dark) .text-slate-500 {
    color: var(--tw-dark-text-slate-500) !important;
}

:is([data-theme="dark"], body.theme-dark) .text-slate-400 {
    color: var(--tw-dark-text-slate-400) !important;
}

/* Light-mode counterpart to the dark remap above (light needs no theme
   selector: it's the implicit default, and the dark rules above/below all
   out-specificity this plain-class rule via their :is([data-theme="dark"],
   body.theme-dark) wrapper, so this only ever applies outside dark mode).
   Tailwind's raw .text-slate-400 (#94a3b8) and .text-slate-500 (#64748b)
   were authored with a plain white background in mind: against this app's
   warm light surfaces they land at 2.4:1 and 4.07-4.55:1 respectively —
   both fail the 4.5:1 AA text threshold (slate-500 fails on 4 of 5
   surfaces, slate-400 fails on all 5). --ink-secondary clears 4.64-5.18:1
   on every light surface. Dark mode already had this remap; light mode
   did not. */
.text-slate-400,
.text-slate-500 {
    color: var(--ink-secondary) !important;
}

/* ── Modal close icon button (phosphor 'x') ───────────────────────────
   Shared style for the small icon-only close buttons in the corner of
   modal dialogs (AI Assistant, Texts Menu, Chapter Grid, Calendar,
   Library Category, Devtools Inspector, ...). These previously rendered
   a raw "&times;" HTML entity colored with Tailwind's .text-slate-400/
   -500 utilities, which -- before the remap above -- measured well under
   the WCAG 3:1 UI-component floor against this app's warm surfaces.
   Now backed by the real phosphor 'x' icon (see templates/components/
   icons.html) and --text-muted/--text-main, which already resolve to
   WCAG-AA-safe, theme-aware values in both light and dark mode (see
   --ink-secondary above and its dark-theme value in tokens.css), so no
   separate :is([data-theme="dark"]) block is needed here. */
.modal-close-icon-btn {
    color: var(--text-muted);
    transition: color var(--motion-dur-fast) var(--motion-ease-out), scale var(--motion-dur-fast) var(--motion-ease-out);
}

.modal-close-icon-btn:hover {
    color: var(--text-main);
}

.modal-close-icon-btn:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
    border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
    .modal-close-icon-btn {
        transition: none;
    }
}

:is([data-theme="dark"], body.theme-dark) .text-slate-200,
:is([data-theme="dark"], body.theme-dark) .text-slate-300,
:is([data-theme="dark"], body.theme-dark) .text-gray-200,
:is([data-theme="dark"], body.theme-dark) .text-gray-300 {
    color: var(--tw-dark-text-slate-300);
}

:is([data-theme="dark"], body.theme-dark) .hover\:bg-white:hover,
:is([data-theme="dark"], body.theme-dark) .hover\:bg-slate-50:hover,
:is([data-theme="dark"], body.theme-dark) .hover\:bg-slate-100:hover,
:is([data-theme="dark"], body.theme-dark) .hover\:bg-slate-200:hover {
    background-color: var(--tw-dark-bg-hover) !important;
}

:is([data-theme="dark"], body.theme-dark) .bg-emerald-50,
:is([data-theme="dark"], body.theme-dark) .bg-emerald-100 {
    background-color: var(--tw-dark-bg-emerald);
}

:is([data-theme="dark"], body.theme-dark) .border-emerald-200 {
    border-color: var(--tw-dark-border-emerald);
}

:is([data-theme="dark"], body.theme-dark) .text-emerald-500,
:is([data-theme="dark"], body.theme-dark) .text-emerald-700,
:is([data-theme="dark"], body.theme-dark) .text-emerald-800 {
    color: var(--tw-dark-text-emerald);
}

:is([data-theme="dark"], body.theme-dark) .bg-amber-50,
:is([data-theme="dark"], body.theme-dark) .bg-amber-100 {
    background-color: var(--tw-dark-bg-amber);
}

:is([data-theme="dark"], body.theme-dark) .border-amber-200 {
    border-color: var(--tw-dark-border-amber);
}

:is([data-theme="dark"], body.theme-dark) .text-amber-700,
:is([data-theme="dark"], body.theme-dark) .text-amber-800 {
    color: var(--tw-dark-text-amber);
}

/* Legal-acceptance modal: the ToS/Privacy links use an arbitrary-value
   Tailwind class (text-[#1f3f63]) that the generic .text-slate-* / .text-blue-*
   remaps above can't match, so they'd stay literal navy on the dark modal
   surface with poor contrast. */
:is([data-theme="dark"], body.theme-dark) #legalModal a[class*="text-[#1f3f63]"] {
    color: var(--accent-primary);
}

:is([data-theme="dark"], body.theme-dark) #legalModal a[class*="text-[#1f3f63]"]:hover {
    color: var(--accent-primary-hover);
}

:is([data-theme="dark"], body.theme-dark) .bg-red-50,
:is([data-theme="dark"], body.theme-dark) .bg-rose-50 {
    background-color: var(--tw-dark-bg-red);
}

:is([data-theme="dark"], body.theme-dark) .border-red-200,
:is([data-theme="dark"], body.theme-dark) .border-rose-200 {
    border-color: var(--tw-dark-border-red);
}

:is([data-theme="dark"], body.theme-dark) .text-red-500,
:is([data-theme="dark"], body.theme-dark) .text-red-700,
:is([data-theme="dark"], body.theme-dark) .text-rose-700 {
    color: var(--tw-dark-text-red);
}

:is([data-theme="dark"], body.theme-dark) .text-navy,
:is([data-theme="dark"], body.theme-dark) .hover\:text-navy:hover,
:is([data-theme="dark"], body.theme-dark) [class*=" text-navy"],
:is([data-theme="dark"], body.theme-dark) [class^="text-navy"] {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .text-blue-500,
:is([data-theme="dark"], body.theme-dark) .text-blue-600,
:is([data-theme="dark"], body.theme-dark) .text-blue-700,
:is([data-theme="dark"], body.theme-dark) .text-blue-800,
:is([data-theme="dark"], body.theme-dark) .text-blue-900,
:is([data-theme="dark"], body.theme-dark) .text-indigo-700,
:is([data-theme="dark"], body.theme-dark) .text-indigo-800,
:is([data-theme="dark"], body.theme-dark) .text-indigo-900 {
    color: var(--tw-dark-text-blue);
}

:is([data-theme="dark"], body.theme-dark) .bg-blue-50,
:is([data-theme="dark"], body.theme-dark) .bg-blue-100,
:is([data-theme="dark"], body.theme-dark) .bg-indigo-50 {
    background-color: var(--tw-dark-bg-blue);
}

:is([data-theme="dark"], body.theme-dark) .border-blue-200,
:is([data-theme="dark"], body.theme-dark) .border-indigo-200 {
    border-color: var(--tw-dark-border-blue);
}

:is([data-theme="dark"], body.theme-dark) .focus\:ring-blue-300:focus,
:is([data-theme="dark"], body.theme-dark) .focus\:ring-blue-400:focus,
:is([data-theme="dark"], body.theme-dark) .focus\:ring-blue-500:focus {
    --tw-ring-color: rgba(176, 154, 116, 0.45);
}

:is([data-theme="dark"], body.theme-dark) .focus\:border-blue-300:focus,
:is([data-theme="dark"], body.theme-dark) .focus\:border-blue-400:focus,
:is([data-theme="dark"], body.theme-dark) .focus\:border-blue-500:focus {
    border-color: var(--tw-dark-focus-border);
}

:is([data-theme="dark"], body.theme-dark) .fc,
:is([data-theme="dark"], body.theme-dark) #calendar {
    color: var(--text-main);
}

:is([data-theme="dark"], body.theme-dark) .fc .fc-col-header-cell,
:is([data-theme="dark"], body.theme-dark) .fc .fc-daygrid-day {
    background: var(--surface-elevated);
}

:is([data-theme="dark"], body.theme-dark) #calendarModal th {
    background: var(--surface-elevated);
}

:is([data-theme="dark"], body.theme-dark) th {
    background: var(--surface-elevated);
}

:is([data-theme="dark"], body.theme-dark) .fc .fc-daygrid-day {
    background: var(--surface-base);
}

:is([data-theme="dark"], body.theme-dark) .fc-day-today {
    background: var(--surface-pill);
}

:is([data-theme="dark"], body.theme-dark) .fc .fc-toolbar-title {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .fc .fc-button {
    background-color: var(--control-bg);
    border-color: var(--control-border);
    color: var(--accent-cream) !important;
}

:is([data-theme="dark"], body.theme-dark) .fc .fc-button:hover {
    background-color: var(--control-bg-hover);
    border-color: var(--control-border);
}

:is([data-theme="dark"], body.theme-dark) .fc .fc-button:disabled {
    background-color: var(--surface-pill);
    border-color: var(--surface-border) !important;
    color: var(--text-muted) !important;
}

:is([data-theme="dark"], body.theme-dark) .lang-btn.lang-btn-active {
    /* Opposite of the light-mode rule above (subtle dark tint + brown text):
       a subtle light tint + warm gold text. Was --control-strong-bg, a
       saturated steel-blue fill that read as a stray "blue icon" against
       the rest of the warm dark palette. --accent-gold (not -light) keeps
       it in the same muted-bronze family as the rest of the dark palette
       instead of the brighter, more saturated gold reading as "yellow".
       Overlay dropped 0.08→0.05: composited over --surface-2, 0.08 put
       --accent-gold text at 4.499:1 (fails 4.5:1 AA by a hair); 0.05
       lightens the tint less, giving the gold text 4.96:1. */
    background-color: rgba(255, 255, 255, 0.05) !important;
    border-color: var(--control-border) !important;
    color: var(--accent-gold) !important;
    font-weight: 700;
}

:is([data-theme="dark"], body.theme-dark) .lang-btn:active,
:is([data-theme="dark"], body.theme-dark) #mobileLangToggle:active {
    background-color: var(--control-bg-hover) !important;
    border-color: var(--control-border) !important;
}

/* Selects: the outline is the field's boundary, so it takes the 3:1
   --conv-edge rather than the --surface-border divider (1.2:1 here). */
:is([data-theme="dark"], body.theme-dark) #settingsPanel select,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel select {
    background-color: var(--surface-pill) !important;
    border-color: var(--conv-edge);
    color: var(--accent-cream);
}

/* Dark overlay backgrounds - neutralize to prevent color bleed */
:is([data-theme="dark"], body.theme-dark) .bg-slate-900\/60 {
    background-color: color-mix(in srgb, var(--surface-base) 84%, transparent);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

:is([data-theme="dark"], body.theme-dark) .bg-slate-900\/45 {
    background-color: color-mix(in srgb, var(--surface-base) 88%, transparent);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

:is([data-theme="dark"], body.theme-dark) #calendarModal,
:is([data-theme="dark"], body.theme-dark) #textsMenuModal {
    background-color: color-mix(in srgb, var(--surface-base) 84%, transparent);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

:is([data-theme="dark"], body.theme-dark) #mobileDrawerBackdrop {
    background-color: color-mix(in srgb, var(--surface-base) 88%, transparent);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

/* Dark mode focus rings - warm gold/brown, matching the rest of the palette */
:is([data-theme="dark"], body.theme-dark) .ring-blue-400,
:is([data-theme="dark"], body.theme-dark) .focus\:ring-blue-400:focus,
:is([data-theme="dark"], body.theme-dark) .focus-ring {
    --tw-ring-color: rgba(176, 154, 116, 0.42);
}

:is([data-theme="dark"], body.theme-dark) .border-blue-400 {
    border-color: #7a6d57;
}

/* Dark calendar button active states */
:is([data-theme="dark"], body.theme-dark) .fc .fc-button-primary:not(:disabled).fc-button-active {
    background-color: var(--control-bg-hover);
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) .fc .fc-button-primary:not(:disabled).fc-button-active:focus {
    background-color: var(--control-bg);
}

/* Per-category event backgrounds now come from calendar.css's .fc-event.cal-cat-*
   rules (same var()s, both themes) — no blanket dark override needed here anymore;
   one used to flatten every event to --surface-pill regardless of category. */

:is([data-theme="dark"], body.theme-dark) #settingsPanel select option,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel select option {
    background: var(--surface-elevated);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel select option:checked,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel select option:checked {
    background: var(--control-bg-hover);
    color: var(--control-text-strong);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel select:focus option:checked,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel select:focus option:checked {
    box-shadow: inset 0 0 0 999px var(--control-bg-hover);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel input[type="range"],
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel input[type="range"] {
    /* Defensive fallback for a range input without .reader-range-slider;
       every range input in these panels currently has that class, which
       sets appearance:none and paints its own track via the
       --range-complete/--range-incomplete gradient below, so accent-color
       has no visible effect on them today. */
    accent-color: var(--gold);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel input[type="checkbox"],
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel input[type="checkbox"] {
    accent-color: var(--tw-dark-checkbox-accent);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel input[type="checkbox"]:focus-visible,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel input[type="checkbox"]:focus-visible {
    outline: 2px solid rgba(176, 154, 116, 0.5);
    outline-offset: 2px;
}

/* Settings panels sit a layer deeper (--surface-subtle) than the buttons and
   controls placed on top of them (--surface-2/--ctrl-bg, via --surface-elevated
   elsewhere), so the panel itself reads as a distinct backdrop instead of
   blending into its own contents. */
:is([data-theme="dark"], body.theme-dark) #aiTrustSection {
    background: var(--surface-pill);
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) #aiConfidenceBadge,
:is([data-theme="dark"], body.theme-dark) #aiModeBadge,
:is([data-theme="dark"], body.theme-dark) #aiCommunityBadge,
:is([data-theme="dark"], body.theme-dark) #aiSourcesBadge {
    background: var(--surface-pill);
    border: 1px solid var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #aiWarningBadge {
    background: var(--ai-warning-bg);
    border-color: var(--ai-warning-border);
    color: var(--ai-warning-text);
}

/* .segment-label/.segment-translit render real text (verse numbers,
   transliteration), not icons, so they need the 4.5:1 text threshold, not
   the 3:1 UI-component threshold --icon-muted is tuned for (--icon-muted
   only reaches 3.30-4.02:1 against the dark surfaces). --ink-secondary
   clears 5.17-6.30:1 across all dark surfaces. */
:is([data-theme="dark"], body.theme-dark) .segment-label,
:is([data-theme="dark"], body.theme-dark) .segment-translit {
    color: var(--ink-secondary);
}

:is([data-theme="dark"], body.theme-dark) #reader .reader-row-mid-label {
    background: var(--surface-base);
}

:is([data-theme="dark"], body.theme-dark) svg {
    color: currentColor;
    fill: currentColor;
}

:is([data-theme="dark"], body.theme-dark) button svg,
:is([data-theme="dark"], body.theme-dark) [role="button"] svg:not(.cal-event-icon),
:is([data-theme="dark"], body.theme-dark) .navigator-pane svg,
:is([data-theme="dark"], body.theme-dark) .pulse-pane svg {
    color: var(--icon-muted) !important;
}

:is([data-theme="dark"], body.theme-dark) #reader .reader-source-lines,
:is([data-theme="dark"], body.theme-dark) #reader .reader-text-row,
:is([data-theme="dark"], body.theme-dark) #reader .source-grid.layout-reverse .source-he:not(.reader-text-he) {
    border-color: var(--reader-row-border) !important;
}

:is([data-theme="dark"], body.theme-dark) #readerTopBar {
    background: rgba(27, 27, 25, 0.95);
    border-top-color: var(--reader-topbar-border);
    border-bottom-color: var(--reader-topbar-border);
}

:is([data-theme="dark"], body.theme-dark) #readerTopBar button {
    background: transparent;
    border: none;
    color: var(--reader-btn-color);
}

:is([data-theme="dark"], body.theme-dark) #readerTopBar button:hover {
    background: transparent;
    border: none;
    color: var(--reader-btn-hover);
}

:is([data-theme="dark"], body.theme-dark) .library-shell .reader-topbar-shell #readerSettingsBtn {
    background: transparent !important;
    border: none !important;
    color: var(--reader-btn-color) !important;
}

:is([data-theme="dark"], body.theme-dark) .library-shell .reader-topbar-shell #readerSettingsBtn:hover,
:is([data-theme="dark"], body.theme-dark) .library-shell .reader-topbar-shell #readerSettingsBtn:focus-visible {
    background: transparent !important;
    border: none !important;
    color: var(--reader-btn-hover) !important;
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-header {
    background: linear-gradient(180deg, var(--surface-elevated) 0%, var(--surface-subtle) 100%);
    color: var(--accent-cream);
    border-bottom-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-subtitle {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-parasha-strip {
    border-bottom-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-parasha-link {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-parasha-link:hover,
:is([data-theme="dark"], body.theme-dark) .chapter-grid-parasha-link:focus-visible {
    background: var(--surface-pill);
    border-color: var(--control-border);
    color: var(--control-text-strong);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-parasha-meta {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-group-label {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-item {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-item:hover,
:is([data-theme="dark"], body.theme-dark) .chapter-grid-item:focus-visible {
    background: var(--surface-pill);
    border-color: var(--control-border);
    color: var(--control-text-strong);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-item-number {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .chapter-grid-item-label {
    color: var(--text-muted);
}

/* Dark mode chapter grid modal scrollable area */
:is([data-theme="dark"], body.theme-dark) #chapterGridModal>div {
    background: var(--surface-base) !important;
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) #chapterGridModal>div .px-5 {
    background: var(--surface-base);
    scrollbar-color: var(--control-border) var(--surface-elevated);
}

/* Dark mode library category modal */
:is([data-theme="dark"], body.theme-dark) #libraryCategoryModal>div {
    background: var(--surface-subtle) !important;
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) #libraryCategoryModal .chapter-grid-header {
    background: var(--surface-elevated);
    border-bottom-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) #libraryCategoryModal h2 {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #libraryCategoryModal #libraryCategorySubtitle {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) #libraryCategoryModal #libraryCategoryBody {
    background: var(--surface-subtle);
}

:is([data-theme="dark"], body.theme-dark) #closeLibraryCategoryBtn {
    color: var(--text-muted);
}

/* Dark mode reader settings + settings panel buttons */
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel .grid button,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel .space-y-2 button,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .grid button,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .space-y-2 button {
    background: var(--surface-pill);
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel .grid button:hover,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel .space-y-2 button:hover,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .grid button:hover,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .space-y-2 button:hover {
    background: var(--control-bg-hover);
    border-color: var(--control-border);
    color: var(--control-text-strong);
}

/* Dark mode – all buttons in settings panels (broad catch-all) */
:is([data-theme="dark"], body.theme-dark) #settingsPanel button,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel button {
    background: var(--surface-pill);
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel button:hover,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel button:hover {
    background: var(--control-bg-hover);
    border-color: var(--control-border);
    color: var(--control-text-strong);
}

/* Dark mode – settings panel label text */
:is([data-theme="dark"], body.theme-dark) #settingsPanel label,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel label,
:is([data-theme="dark"], body.theme-dark) #settingsPanel p,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel p {
    color: var(--text-main) !important;
}

/* Dark mode – settings panel text inputs */
:is([data-theme="dark"], body.theme-dark) #settingsPanel input[type="text"],
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel input[type="text"] {
    background: var(--surface-pill);
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel input[type="text"]::placeholder,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel input[type="text"]::placeholder {
    color: var(--text-muted);
}

/* Dark mode – settings panel internal dividers */
:is([data-theme="dark"], body.theme-dark) #settingsPanel .border-t,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel .border-t {
    border-top-color: var(--surface-border);
}

/* Fix right sidebar scrollbar in dark mode */
:is([data-theme="dark"], body.theme-dark) #rightSidebar {
    scrollbar-color: var(--control-border) var(--surface-subtle);
}

:is([data-theme="dark"], body.theme-dark) #rightSidebar::-webkit-scrollbar-track {
    background: var(--surface-subtle);
}

:is([data-theme="dark"], body.theme-dark) #rightSidebar::-webkit-scrollbar-thumb {
    background: var(--control-border);
}

:is([data-theme="dark"], body.theme-dark) #rightSidebar::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--text-muted) 60%, var(--control-border));
}

:is([data-theme="dark"], body.theme-dark) .home-section-label,
:is([data-theme="dark"], body.theme-dark) .home-daily-label,
:is([data-theme="dark"], body.theme-dark) .text-blue-100 {
    color: var(--home-label-color);
}

:is([data-theme="dark"], body.theme-dark) .home-topic-title,
:is([data-theme="dark"], body.theme-dark) .home-library-title,
:is([data-theme="dark"], body.theme-dark) .home-daily-link,
:is([data-theme="dark"], body.theme-dark) #readerTitle {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .home-link-tanakh .home-library-title {
    color: var(--accent-tanakh);
}

:is([data-theme="dark"], body.theme-dark) .home-link-mishnah .home-library-title {
    color: var(--accent-mishnah);
}

:is([data-theme="dark"], body.theme-dark) .home-link-talmud .home-library-title {
    color: var(--accent-talmud);
}

:is([data-theme="dark"], body.theme-dark) .home-link-halakhah .home-library-title {
    color: var(--accent-halakhah);
}

:is([data-theme="dark"], body.theme-dark) .home-link-customs .home-library-title {
    color: var(--accent-customs);
}

:is([data-theme="dark"], body.theme-dark) .home-link-thought .home-library-title {
    color: var(--accent-thought);
}

:is([data-theme="dark"], body.theme-dark) .home-library-description {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) #popularTextsGrid button {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
    box-shadow: inset 0 0 0 1px rgba(202, 189, 168, 0.08);
}

:is([data-theme="dark"], body.theme-dark) #popularTextsGrid button:hover,
:is([data-theme="dark"], body.theme-dark) #popularTextsGrid button:focus-visible {
    background: var(--surface-pill);
    border-color: var(--control-border);
}

:is([data-theme="dark"], body.theme-dark) #popularTextsGrid button .text-slate-700,
:is([data-theme="dark"], body.theme-dark) #popularTextsGrid button .text-slate-800 {
    color: var(--accent-cream) !important;
}

:is([data-theme="dark"], body.theme-dark) #popularTextsGrid button .text-slate-500 {
    color: var(--text-muted) !important;
}

:is([data-theme="dark"], body.theme-dark) .home-library-link:hover .home-library-title,
:is([data-theme="dark"], body.theme-dark) .home-topic-title:hover,
:is([data-theme="dark"], body.theme-dark) .home-daily-link:hover {
    color: var(--control-text-strong);
}

:is([data-theme="dark"], body.theme-dark) .home-calendar-btn {
    background: linear-gradient(135deg, var(--surface-elevated) 0%, var(--surface-subtle) 100%);
    border-color: color-mix(in srgb, var(--gold) 55%, var(--surface-border));
    color: var(--gold);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}

:is([data-theme="dark"], body.theme-dark) .home-calendar-btn:hover {
    background: linear-gradient(135deg, var(--surface-pill) 0%, var(--surface-elevated) 100%);
    border-color: var(--gold);
    color: var(--gold-light);
}

:is([data-theme="dark"], body.theme-dark) #nextZmanBadge {
    border-color: var(--surface-border);
    background: var(--surface-pill);
    color: var(--text-main);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.28);
}

:is([data-theme="dark"], body.theme-dark) #zmanimWarning {
    background: color-mix(in srgb, var(--zmanim-warn-accent) 12%, var(--surface-subtle));
    border-color: var(--zmanim-warn-accent);
    color: var(--zmanim-warn-text);
}

:is([data-theme="dark"], body.theme-dark) .today-zmanim-list [data-zman-row] {
    background: transparent;
    border-color: var(--surface-border);
    border-radius: 0;
    padding-inline-start: 0;
    padding-inline-end: 0;
    margin-bottom: 0;
}

:is([data-theme="dark"], body.theme-dark) .today-zmanim-list [data-zman-row] span {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) .today-zmanim-list [data-zman-row] b {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .today-zmanim-list [data-zman-row].zman-next-highlight {
    background: rgba(63, 57, 47, 0.46);
    border-color: var(--control-border) !important;
    border-radius: 0.45rem;
    padding-inline-start: 0.45rem;
    padding-inline-end: 0.45rem;
    box-shadow: inset 0 0 0 1px rgba(195, 175, 138, 0.18);
}

:is([data-theme="dark"], body.theme-dark) .today-zmanim-list [data-zman-row].zman-next-highlight b {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar summary,
:is([data-theme="dark"], body.theme-dark) #leftSidebar button,
:is([data-theme="dark"], body.theme-dark) #libraryIndexSidebar button,
:is([data-theme="dark"], body.theme-dark) #prayerBooksNavList button {
    color: var(--text-main) !important;
}

:is([data-theme="dark"], body.theme-dark) .library-node-open.library-node-active {
    background: transparent;
    border: 0;
    border-inline-start: 3px solid var(--gold);
    color: var(--accent-cream);
    box-shadow: none;
}

:is([data-theme="dark"], body.theme-dark) .library-node-open.library-node-active:hover {
    background: rgba(68, 60, 48, 0.35);
    color: var(--control-text-strong);
}

:is([data-theme="dark"], body.theme-dark) .shelf-open.shelf-open-active {
    background: var(--surface-pill);
    border-color: var(--control-border);
    box-shadow: inset 0 0 0 1px rgba(165, 142, 101, 0.24);
}

:is([data-theme="dark"], body.theme-dark) .shelf-open.shelf-open-active span:first-child {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .shelf-open.shelf-open-active span:last-child {
    color: var(--gold);
}

:is([data-theme="dark"], body.theme-dark) .shelf-open:focus-visible,
:is([data-theme="dark"], body.theme-dark) .library-node-open:focus-visible {
    outline: 2px solid var(--control-accent);
    outline-offset: 2px;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar summary:hover,
:is([data-theme="dark"], body.theme-dark) #leftSidebar button:hover,
:is([data-theme="dark"], body.theme-dark) #libraryIndexSidebar button:hover,
:is([data-theme="dark"], body.theme-dark) #prayerBooksNavList button:hover {
    color: var(--accent-cream) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar .border-b,
:is([data-theme="dark"], body.theme-dark) #leftSidebar .border-l-2,
:is([data-theme="dark"], body.theme-dark) #leftSidebar .border-slate-100,
:is([data-theme="dark"], body.theme-dark) #leftSidebar .border-slate-200 {
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) .mobile-drawer-left {
    border-inline-end-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) .mobile-drawer-right {
    border-inline-start-color: var(--surface-border);
}

/* Dark mode: ensure buttons and links inside mobile drawer / hamburger and settings
   panels use the elevated surface styles so they are readable and consistent. */
:is([data-theme="dark"], body.theme-dark) .mobile-drawer.mobile-open button,
:is([data-theme="dark"], body.theme-dark) .mobile-drawer.mobile-open a,
:is([data-theme="dark"], body.theme-dark) .mobile-drawer.mobile-open .topbar-flat-btn,
:is([data-theme="dark"], body.theme-dark) .mobile-drawer.mobile-open .mobile-tab-btn,
:is([data-theme="dark"], body.theme-dark) #settingsPanel button,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel button,
:is([data-theme="dark"], body.theme-dark) #settingsPanel a,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel a {
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .mobile-drawer.mobile-open button:hover,
:is([data-theme="dark"], body.theme-dark) .mobile-drawer.mobile-open a:hover,
:is([data-theme="dark"], body.theme-dark) #settingsPanel button:hover,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel button:hover {
    background: var(--control-bg-hover);
    border-color: var(--control-border);
    color: var(--control-text-strong);
}

:is([data-theme="dark"], body.theme-dark) .reader-range-slider {
    /* The base rule sets these as LOCAL custom properties (light values) on
       this same element, which shadows the global dark tokens through normal
       inheritance, so they are redeclared here for dark. The unfilled track
       uses --surface-pill (the panel's own <select> background); the fill is
       --control-accent, the gold a checked switch beside it uses, and the
       thumb is cream (--accent-cream), ringed in the same gold. */
    --range-complete: var(--control-accent);
    --range-incomplete: var(--control-border);
    --range-thumb-bg: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .reader-switch {
    background: var(--surface-pill);
    border-color: var(--control-border);
}

:is([data-theme="dark"], body.theme-dark) .reader-switch::after {
    background: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) .reader-switch:checked {
    background: var(--control-accent);
    border-color: var(--control-accent);
}

:is([data-theme="dark"], body.theme-dark) .mobile-drawer-left {
    border-inline-end-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) .mobile-drawer-right {
    border-inline-start-color: var(--surface-border) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar h3,
:is([data-theme="dark"], body.theme-dark) #sourcesDynamicContent .italic {
    color: var(--accent-menu) !important;
}

/* Scope arbitrary Tailwind value overrides to sidebars to avoid breaking buttons/cards elsewhere */
:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="bg-[#"] {
    background-color: var(--surface-elevated) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#"] {
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="text-[#"] {
    color: var(--text-main) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:bg-[#"]:hover {
    background-color: var(--control-bg-hover);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#"]:hover,
:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="group-hover:text-[#"]:hover {
    color: var(--control-text-strong) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#004e5f]"]:hover {
    color: var(--accent-tanakh) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#8b5e34]"]:hover {
    color: var(--accent-talmud-hover) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#5a99b7]"]:hover {
    color: var(--accent-mishnah) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#a08a4a]"]:hover {
    color: var(--accent-talmud);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#802f3e]"]:hover {
    color: var(--accent-halakhah) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#594176]"]:hover {
    color: var(--accent-customs) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#00827f]"]:hover {
    color: var(--accent-thought) !important;
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="hover:text-[#002147]"]:hover {
    color: var(--accent-menu) !important;
}

:is([data-theme="dark"], body.theme-dark) [id^="zRow"] span,
:is([data-theme="dark"], body.theme-dark) #nextZmanBadge span {
    color: var(--accent-zmanim);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#004e5f"] {
    border-color: rgba(138, 194, 205, 0.38);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#8b5e34"] {
    border-color: rgba(204, 179, 137, 0.34);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#5a99b7"] {
    border-color: rgba(153, 185, 221, 0.39);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#ccb479"] {
    border-color: rgba(207, 184, 137, 0.43);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#802f3e"] {
    border-color: rgba(207, 151, 162, 0.41);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#594176"] {
    border-color: rgba(188, 168, 216, 0.4);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#00827f"] {
    border-color: rgba(151, 199, 184, 0.39);
}

:is([data-theme="dark"], body.theme-dark) #leftSidebar [class*="border-[#002147"] {
    border-color: rgba(169, 189, 210, 0.39);
}

:is([data-theme="dark"], body.theme-dark) .prose p,
:is([data-theme="dark"], body.theme-dark) .prose em,
:is([data-theme="dark"], body.theme-dark) .prose h3,
:is([data-theme="dark"], body.theme-dark) .prose strong,
:is([data-theme="dark"], body.theme-dark) .prose h2 {
    color: var(--prose-text-dark) !important;
}

:is([data-theme="dark"], body.theme-dark) .prose code {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
    color: var(--text-main);
}

/* .ai-source-card / .ai-wiki-card / .ai-custom-card dark overrides — owned by static/css/ai.css */
:is([data-theme="dark"], body.theme-dark) .ai-synthesis {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
    color: var(--text-main);
}

:is([data-theme="dark"], body.theme-dark) #textsMenuModal .bg-linear-to-r.from-navy.to-blue-900,
:is([data-theme="dark"], body.theme-dark) #devtoolsInspectorModal .bg-linear-to-r.from-navy.to-blue-900 {
    background-image: linear-gradient(to right, var(--surface-elevated), var(--surface-pill));
}

:is([data-theme="dark"], body.theme-dark) .source-ref {
    background: var(--surface-pill);
    color: var(--text-main);
}

:is([data-theme="dark"], body.theme-dark) .source-ref:hover {
    background: var(--control-bg-hover);
}

/* Use semantic variables for text and borders to reduce !important usage */
.text-dynamic-main {
    color: var(--text-main);
}

.text-dynamic-muted {
    color: var(--text-muted);
}

.border-dynamic {
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) ::-webkit-scrollbar-track,
:is([data-theme="dark"], body.theme-dark) .custom-scrollbar::-webkit-scrollbar-track {
    background: var(--surface-subtle);
}

:is([data-theme="dark"], body.theme-dark) ::-webkit-scrollbar-thumb,
:is([data-theme="dark"], body.theme-dark) .custom-scrollbar::-webkit-scrollbar-thumb {
    background: var(--control-border);
}

:is([data-theme="dark"], body.theme-dark) ::-webkit-scrollbar-thumb:hover,
:is([data-theme="dark"], body.theme-dark) .custom-scrollbar::-webkit-scrollbar-thumb:hover {
    background: var(--control-bg-hover);
}

:is([data-theme="dark"], body.theme-dark) .custom-scrollbar::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

:is([data-theme="dark"], body.theme-dark) .custom-scrollbar::-webkit-scrollbar-track {
    background: var(--surface-subtle);
    border-radius: 10px;
}

:is([data-theme="dark"], body.theme-dark) .custom-scrollbar::-webkit-scrollbar-thumb {
    background: var(--control-border);
    border-radius: 10px;
}

:is([data-theme="dark"], body.theme-dark) .custom-scrollbar::-webkit-scrollbar-thumb:hover {
    background: var(--control-bg-hover);
}

/* RTL Overrides for Mobile Drawers */
html[dir="rtl"] .mobile-drawer-left {
    transform: translateX(105%);
    /* Move off-screen to the right */
}

html[dir="rtl"] .mobile-drawer-left.mobile-open {
    transform: translateX(0);
}

html[dir="rtl"] .mobile-drawer-right {
    transform: translateX(-105%);
    /* Move off-screen to the left */
}

html[dir="rtl"] .mobile-drawer-right.mobile-open {
    transform: translateX(0);
}

/* ═══════════════════════════════════════════════════════════════════ */
/* DARK MODE ADDITIONS — city search, commentary UI */
/* ═══════════════════════════════════════════════════════════════════ */

/* City search popover dark mode */
:is([data-theme="dark"], body.theme-dark) #citySearchPopover {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
    color: var(--text-main);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45);
}

:is([data-theme="dark"], body.theme-dark) #citySearchPopover p {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) #citySearchInput {
    background: var(--surface-pill) !important;
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #citySearchInput::placeholder {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) #citySearchInput:focus {
    border-color: var(--control-border);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--gold) 25%, transparent);
}

/* Gold accent (not the light-mode navy) to match this popover's warm dark
   palette — its border, focus ring, and label already use --gold. Styled as
   a subtle dark-surface + gold-outline button (same language as
   .home-calendar-btn's dark-mode treatment) rather than a solid gold fill,
   which read as an out-of-place bright block against the rest of dark
   mode's muted button palette. */
:is([data-theme="dark"], body.theme-dark) #citySearchSubmit {
    background: var(--surface-elevated);
    color: var(--gold);
    border: 1px solid var(--gold);
}

:is([data-theme="dark"], body.theme-dark) #citySearchSubmit:hover {
    background: var(--surface-pill);
    color: var(--gold-light);
    border-color: var(--gold-light);
}

:is([data-theme="dark"], body.theme-dark) #citySearchBtn {
    background: var(--surface-pill);
    border-color: var(--surface-border);
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) #citySearchBtn:hover {
    background: var(--control-bg-hover);
    color: var(--accent-cream);
}

/* Commentary sidebar: the comments of one commentary read as a single block,
   spaced by the scale rather than ruled off one by one. */
.commentary-part + .commentary-part {
    margin-top: var(--sp-4);
}

/* Commentary sidebar: back-to-list button dark mode */
:is([data-theme="dark"], body.theme-dark) #rightSidebar [class*="text-[#004e5f]"],
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody [class*="text-[#004e5f]"] {
    color: var(--accent-teal);
}

/* selectionInsights body dark mode — word meaning and commentary chooser */
:is([data-theme="dark"], body.theme-dark) #selectionInsights {
    background: var(--surface-elevated);
    border-color: var(--surface-border);
    color: var(--text-main);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsHint {
    color: var(--text-muted) !important;
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody .rounded-lg {
    background: var(--surface-pill);
    border-color: var(--surface-border);
    color: var(--text-main);
}

/* Word meaning box */
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody [class*="bg-[#f2eadc]"],
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody [class*="bg-[#"] {
    background: var(--surface-pill);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody [class*="border-[#d7c8ad]"],
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody [class*="border-[#"] {
    border-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody [class*="text-[#5d4c36]"],
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody [class*="text-[#4f4130]"],
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody [class*="text-[#6a5842]"] {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody .text-slate-700,
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody .text-slate-800 {
    color: var(--text-main);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody .text-slate-500 {
    color: var(--text-muted);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody .border-slate-100,
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody .border-slate-200 {
    border-color: var(--surface-border);
}

/* Commentary text in dark mode */
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody article {
    border-bottom-color: var(--surface-border);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody .font-hebrew {
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody .font-serif {
    color: var(--text-main);
}

/* Reader topbar library button: right in RTL mode */
html.rtl #readerTopBar #readerLibraryTopBarBtn {
    order: 10;
    margin-inline-start: auto;
}

/* dark mode - menu parasha quick link fix */
:is([data-theme="dark"], body.theme-dark) .menu-parasha-quick-link {
    background: linear-gradient(180deg, var(--surface-elevated) 0%, var(--surface-pill) 100%);
    border-color: var(--control-border);
    color: var(--accent-cream);
    box-shadow: inset 0 0 0 1px rgba(201, 168, 78, 0.18);
}

/* Selection insights - text area for commentary content */
:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody button {
    color: var(--accent-teal);
}

:is([data-theme="dark"], body.theme-dark) #selectionInsightsBody button:hover {
    color: var(--control-text-strong);
}

/* Loading shimmer dark mode */
:is([data-theme="dark"], body.theme-dark) .reader-loading-shimmer {
    background: linear-gradient(90deg,
            var(--surface-subtle) 25%,
            var(--surface-pill) 50%,
            var(--surface-subtle) 75%);
    background-size: 200% 100%;
}

/* ── Settings panel dark overrides (Tailwind utility → token mapping) ── */
:is([data-theme="dark"], body.theme-dark) #settingsPanel,
:is([data-theme="dark"], body.theme-dark) #readerSettingsPanel {
    background: var(--surface-elevated) !important;
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #searchInput {
    background: var(--surface-pill);
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #searchInput:hover {
    background: var(--surface-elevated) !important;
    border-color: var(--search-hover-border) !important;
}

/* Was --accent-blue (#6888a8) -- a stray cool steel-blue focus ring, out
   of place against the rest of the warm dark palette (same family of fix
   as the settings-button/lang-toggle slate tint above). Gold ties the
   focus state to the search bar's AI-entry-point identity (see
   .search-ai-sparkle) instead of reading as a generic form-field focus
   color. */
:is([data-theme="dark"], body.theme-dark) #searchInput:focus {
    background: var(--surface-elevated) !important;
    border-color: var(--accent-gold) !important;
    box-shadow: 0 0 0 3px rgba(201, 172, 94, 0.22);
}

:is([data-theme="dark"], body.theme-dark) #searchIcon { color: var(--text-muted) !important; }

:is([data-theme="dark"], body.theme-dark) .fc .fc-col-header-cell-cushion,
:is([data-theme="dark"], body.theme-dark) .fc .fc-daygrid-day-number { color: var(--accent-cream); }

:is([data-theme="dark"], body.theme-dark) .today-zmanim-list span { color: var(--accent-cream); }
:is([data-theme="dark"], body.theme-dark) .today-zmanim-list b { color: var(--text-main); }

:is([data-theme="dark"], body.theme-dark) #holidayName,
:is([data-theme="dark"], body.theme-dark) #shabbatWeekName,
:is([data-theme="dark"], body.theme-dark) #omerCount { color: var(--accent-cream); }

:is([data-theme="dark"], body.theme-dark) #settingsPanel .text-slate-400,
:is([data-theme="dark"], body.theme-dark) #settingsPanel p.text-\[11px\],
:is([data-theme="dark"], body.theme-dark) #settingsPanel .uppercase { color: var(--text-muted) !important; }

:is([data-theme="dark"], body.theme-dark) #settingsPanel .bg-slate-50,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .bg-slate-100,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .bg-white {
    background: var(--surface-pill) !important;
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel .text-slate-700,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .text-slate-600,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .text-slate-500 { color: var(--accent-cream); }

:is([data-theme="dark"], body.theme-dark) #settingsPanel .border-slate-100,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .border-slate-200 { border-color: var(--surface-border); }

:is([data-theme="dark"], body.theme-dark) #settingsPanel input,
:is([data-theme="dark"], body.theme-dark) #settingsPanel textarea,
:is([data-theme="dark"], body.theme-dark) #settingsPanel button {
    background: var(--surface-pill);
    border-color: var(--surface-border);
    color: var(--accent-cream);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel input::placeholder,
:is([data-theme="dark"], body.theme-dark) #settingsPanel textarea::placeholder { color: var(--text-muted); }

:is([data-theme="dark"], body.theme-dark) #themeToggleBtn {
    background: rgba(148, 163, 184, 0.16);
    color: var(--accent-cream);
    border-color: rgba(148, 163, 184, 0.6);
}

:is([data-theme="dark"], body.theme-dark) #themeToggleBtn:hover {
    background: rgba(148, 163, 184, 0.26);
    border-color: rgba(148, 163, 184, 0.75);
    color: var(--accent-cream);
}

/* The dark-mode Quick Settings button rules live only here (an identical
   earlier copy near the light-theme #settingsPanel rules was removed: this
   one always won the cascade, and duplicate selectors trip SonarCloud
   css:S4666). Warm stone-chip treatment matches #settingsMenuBtn /
   #mobileLangToggle so all Quick Settings controls read consistently in
   dark mode instead of the near-invisible flat --surface-pill fill (and
   without the cool blue-gray tint slate-400 carried). */
:is([data-theme="dark"], body.theme-dark) #settingsPanel button:not(#bookmarkCurrentBtn) {
    background: rgba(168, 162, 158, 0.16) !important;
    border-color: rgba(168, 162, 158, 0.6) !important;
    color: var(--accent-cream) !important;
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel button:not(#bookmarkCurrentBtn):hover {
    background: rgba(168, 162, 158, 0.26) !important;
    border-color: rgba(168, 162, 158, 0.75) !important;
    color: var(--accent-cream) !important;
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel .text-xs,
:is([data-theme="dark"], body.theme-dark) #settingsPanel .text-sm { color: var(--text-muted) !important; }

/* #settingsPanel prefix boosts specificity past the button/select/input
   catch-all just above, which was flattening this to plain --control-bg
   and hiding the "Save Current" primary-action emphasis that light mode
   keeps (--ctrl-filled-bg, #46688d bg, white text). Went through gold here
   for a stretch (matching --accent-gold) but that read as an odd, out-of-
   place accent next to the rest of the panel -- Save Current is the one
   control the user actually wants to keep reading as light mode's blue
   "primary action" identity, just re-tuned so it still clears contrast
   against a dark panel (the light-mode fill itself would be a bit flat
   here). #3d70ab is a warmer, softer blue than the earlier #4f7599 steel-
   blue attempt (which was the original "harsh blue" complaint) -- fill
   measures 3.29:1 against --surface-elevated (#1e1d1a) and white text
   measures 5.12:1 against the fill, clearing the 3:1 / 4.5:1 AA floors.
   Hover keeps the same fill and signals state via a brighter border. */
:is([data-theme="dark"], body.theme-dark) #settingsPanel button#bookmarkCurrentBtn {
    background: #3d70ab !important;
    border-color: #234a70 !important;
    color: #ffffff !important;
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel button#bookmarkCurrentBtn:hover {
    background: #3d70ab !important;
    border-color: #7fb0e0 !important;
    color: #ffffff !important;
    box-shadow: 0 0 0 2px rgba(127, 176, 224, 0.3);
}

:is([data-theme="dark"], body.theme-dark) #settingsPanel .hover\:bg-slate-200:hover {
    background-color: var(--control-bg-hover);
}

/* ── Analytics consent banner ─────────────────────────────────────────── */

#analyticsConsentBanner {
    position: fixed;
    left: var(--sp-4);
    right: var(--sp-4);
    bottom: var(--sp-4);
    z-index: 200;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    max-width: 40rem;
    margin: 0 auto;
    padding: var(--sp-4);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-lg);
    background: var(--surface-2);
    color: var(--ink-primary);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}

/* Phones and tablets: above the bottom tab bar (in flow at the bottom of
   the screen; its height is measured into --mobile-tabs-height by shell.js),
   never over it. */
@media (max-width: 1023px) {
    #analyticsConsentBanner {
        bottom: calc(var(--mobile-tabs-height, 64px) + var(--sp-4));
    }
}

#analyticsConsentBanner.hidden,
html[data-consent-set] #analyticsConsentBanner {
    display: none;
}

#analyticsConsentBanner p {
    margin: 0;
    font-size: var(--text-sm);
    flex: 1 1 16rem;
}

.analytics-consent-actions {
    display: flex;
    gap: var(--sp-2);
    flex-shrink: 0;
}

.analytics-consent-actions button {
    min-height: 44px;
    padding: var(--sp-2) var(--sp-4);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
    background: var(--surface-1);
    color: var(--ink-primary);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--motion-dur-fast) var(--motion-ease-out), scale var(--motion-dur-fast) var(--motion-ease-out);
}

#analyticsConsentAccept {
    background: var(--accent-primary);
    border-color: var(--accent-primary);
    color: var(--ink-on-accent);
}

/* Dark theme's --accent-primary (#6888a8) against --ink-on-accent (#f0ebe3) is
   only 3.12:1 -- below WCAG AA's 4.5:1, caught by the pa11y-ci dark-theme scan
   (npm run test:a11y:dark). Darkened for this one button rather than the shared
   token, since --accent-primary is used broadly and a global dark-theme retune
   needs its own reviewed pass. #4e667e clears 4.5:1 with margin (~5.0:1). */
[data-theme="dark"] #analyticsConsentAccept,
html.theme-dark #analyticsConsentAccept,
body.theme-dark #analyticsConsentAccept {
    background: #4e667e;
    border-color: #4e667e;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) #analyticsConsentAccept {
        background: #4e667e;
        border-color: #4e667e;
    }
}

.analytics-consent-actions button:hover {
    background: var(--ctrl-bg-hover);
}

.analytics-consent-actions button:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .analytics-consent-actions button {
        transition: none;
    }
}


/* ═══════════════════════════════════════════════════════════════════
   MOTION POLISH — screen entrances, press feedback, hover gaps
   Keyframes live in tokens.css; transform/opacity only; all of it is
   switched off under prefers-reduced-motion. The AI surfaces
   (conversation.css, ai.css) own their motion and are excluded.
═══════════════════════════════════════════════════════════════════ */

/* Screens (home, reader, the reader's panels, the consent banner) rise
   into place when shown. The class is added by watchViewEntrance()
   (index.html) and removed on animationend, so no transform lingers to
   become a containing block for anything positioned inside. */
.view-enter {
    animation: shelah-fade-up var(--motion-dur-base) var(--motion-ease-decel);
}

/* Press feedback: controls dip a little while held. The standalone
   `scale` property composes with any `transform` a control already has
   (centring translates, hover lifts), so pressing never knocks one out.
   Controls that tune their own :active (top-bar buttons, bottom tabs,
   the reader's deliberately static icon row) keep theirs. */
.library-shell :is(button, [role="button"], summary):where(:not(:disabled, [aria-disabled="true"], .reader-topbar-icon-btn, .topbar-flat-btn, .topbar-brand, .mobile-tab-btn, #topbarAskBtn, #legalAcceptBtn, .answer-feedback-btn)):where(:not(:is(#convPanel, #convPip, #mobileSearchTray, #aiDiscoveryTip) *)):active {
    scale: var(--press-scale, 0.97);
}

/* Wide cards and rows shrink by more pixels for the same ratio; ease
   them off so a press reads as a dip, not a jump. */
.library-shell :is(.home-library-link, #popularTextsGrid button, #leftSidebar button, #leftSidebar summary, .shelf-open, .library-node-open) {
    --press-scale: 0.985;
}

/* Tailwind's transition utilities load after this sheet and replace the
   property list above, so `scale` is added back for the controls that
   use them -- otherwise the press would snap in and out. */
.library-shell :is(button, [role="button"], summary).transition {
    /* Not box-shadow, filter or backdrop-filter: each repaints every
       frame it tweens (audit M-9). */
    transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, transform, scale;
}

.library-shell :is(button, [role="button"], summary).transition-colors {
    transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, scale;
}

/* Hover gaps ---------------------------------------------------------- */

/* The AA remap of .text-slate-400/500 (above) is !important, which also
   beat every hover:text-* utility on those controls -- the sidebar's
   section summaries and small text buttons showed no hover at all.
   Hovering now moves them to the primary ink: darker in light, lighter
   in dark (both AA on every surface, see tokens.css). The AI-surface
   exclusion sits in :where() so its ids add no specificity -- the
   dark sidebar's own #leftSidebar hover colours must still win. */
.library-shell :is(button, a[href], summary, [role="button"]):is(.text-slate-400, .text-slate-500):not(:disabled):where(:not(:is(#convPanel, #convPip, #mobileSearchTray, #aiDiscoveryTip) *)):hover {
    color: var(--ink-primary) !important;
}

/* The open text's row in the library sidebar had no hover of its own. */
.library-shell .shelf-open.shelf-open-active:hover {
    background: #ede2d0;
}

:is([data-theme="dark"], body.theme-dark) .shelf-open.shelf-open-active:hover {
    background: var(--ctrl-bg-hover);
}

/* The consent banner's Accept fill is set by an #id rule, so the shared
   .analytics-consent-actions hover never showed on it. Light: the
   accent's hover shade. Dark: deepen the AA-tuned fill (its text is
   light, so darker only widens the 5.0:1 margin). */
#analyticsConsentAccept:hover {
    background: var(--accent-primary-hover);
    border-color: var(--accent-primary-hover);
}

:is([data-theme="dark"], html.theme-dark, body.theme-dark) #analyticsConsentAccept:hover {
    background: color-mix(in srgb, #4e667e 82%, black);
    border-color: color-mix(in srgb, #4e667e 82%, black);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) #analyticsConsentAccept:hover {
        background: color-mix(in srgb, #4e667e 82%, black);
        border-color: color-mix(in srgb, #4e667e 82%, black);
    }
}

/* Texts-menu "Clear": its hover:bg-slate-200 is remapped paler than the
   remapped bg-slate-100 fill. The control hover token is darker in
   light and lighter in dark. */
.library-shell #libraryIndexFilterClear:hover {
    background: var(--ctrl-bg-hover) !important;
}

@media (prefers-reduced-motion: reduce) {
    .view-enter {
        animation: none;
    }

    .library-shell :is(button, [role="button"], summary):active {
        scale: none;
    }
}

/* ── A region that failed to load (static/js/load-region.js) ──────── */
.region-error {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-3);
    padding-block: var(--sp-4);
    grid-column: 1 / -1; /* the full row of a grid region (popular texts) */
}

.region-error__message {
    margin: 0;
    color: var(--accent-red);
}

.region-error__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
}

.region-error__retry,
.region-error__action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: 2.75rem;
    min-inline-size: 2.75rem;
    padding: var(--sp-2) var(--sp-4);
    border: 1px solid var(--ctrl-border);
    border-radius: var(--radius-md);
    background: var(--ctrl-bg);
    color: var(--ctrl-text-strong);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--motion-dur-fast) var(--motion-ease-out),
        transform var(--motion-dur-fast) var(--motion-ease-out);
}

:is(.region-error__retry, .region-error__action):hover { background: var(--ctrl-bg-hover); }
:is(.region-error__retry, .region-error__action):active { transform: scale(0.97); }
:is(.region-error__retry, .region-error__action):focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}

/* A control whose view is on its way (index.html markTriggerPending). */
[data-pending="true"] {
    cursor: progress;
    opacity: 0.7;
}

@media (prefers-reduced-motion: reduce) {
    :is(.region-error__retry, .region-error__action) { transition: none; }
    :is(.region-error__retry, .region-error__action):active { transform: none; }
}
