/* ===== MOBILE OVERRIDES =====
   One shared file so we don't have to touch every page's inline CSS.
   !important is used because every page's inline <style> block sets
   these same properties, and later-loaded inline styles would win
   without it. */

/* ============================================================
   LITERARY POLISH LAYER
   Global typography, cover, and surface refinements applied
   across every page without touching each file's inline styles.
   Ordered so later declarations can override earlier ones.
   ============================================================ */

:root {
  --cover-shadow: 6px 4px 0 -2px rgba(47, 42, 53, 0.06),
                  0 10px 24px -4px rgba(47, 42, 53, 0.18),
                  0 2px 4px rgba(47, 42, 53, 0.10);
  --cover-shadow-sm: 3px 2px 0 -1px rgba(47, 42, 53, 0.06),
                     0 6px 14px -2px rgba(47, 42, 53, 0.15);
}

/* ---------- Kill legacy nav notification elements ----------
   The bell icon + popover is now the single source of truth for
   notifications. These older elements linger in some pages' HTML but
   should never render. Force them hidden globally. */
#avatar-notification-dot,
.notif-count,
#friend-request-badge {
  display: none !important;
}

/* ---------- Pre-auth pages: hide every notification artifact ----------
   Defensive belt against stale JS (cached service worker, older PWA
   install). Splash / login / create-account / about have a <body
   class="rp-pre-auth"> set by the pre-auth gate; CSS here guarantees no
   bell, no count badge, no red notification dot can ever appear on
   those surfaces, regardless of what supabase-client.js is doing. */
body.rp-pre-auth #rp-notif-bell,
body.rp-pre-auth #rp-notif-panel,
body.rp-pre-auth #rp-notif-count,
body.rp-pre-auth .rp-notif-wrapper,
body.rp-pre-auth #avatar-notification-dot,
body.rp-pre-auth #friend-request-badge,
body.rp-pre-auth .notif-count {
  display: none !important;
}

/* ---------- Per-shelf search inputs: phone-friendly sizing ----------
   The inline styles on these inputs set font-size:12px with tiny
   padding — cramped on a phone, and the row's dead space reads as a
   layout bug above an empty shelf. Bump font to 14px and give the
   input real padding + full-width behaviour so the row doesn't
   feel adrift in yellow space. */
@media (max-width: 768px) {
  #my-collection-search,
  #now-reading-search,
  #next-to-explore-search,
  #dnf-search,
  .shelf-search-input {
    font-size: 14px !important;
    padding: 11px 13px !important;
    border-radius: 2px !important;
    width: 100% !important;
    flex: 1 1 100% !important;
    min-width: 0 !important;
  }
}

/* ---------- Nav avatar consistency ----------
   Every page injects the avatar via `innerHTML = <img src=...>` without any
   local CSS, so the image renders at its intrinsic size — a vertical photo
   gets cropped differently than a square one, and the zoom varies page to
   page. Lock it to fill-the-circle with center-cover. */
.nav-avatar img {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  object-position: center center !important;
  display: block !important;
  border-radius: 0 !important; /* parent disc already clips */
}

/* ---------- Cover shadow on every book cover ----------
   Target common cover wrappers + direct book <img> children
   that reliably hold book covers across the app. */
.book-cover img,
.book-cover,
.result-cover img,
.shelf-book-cover img,
.cover img,
img.cover,
.nightstand-book img,
.nightstand-cover img,
.nightstand-cover,
.book-cover-slot img,
.book-cover-slot,
.path-book-cover img,
.rec-book-cover img,
.book-card img.cover,
img[alt*="cover" i] {
  box-shadow: var(--cover-shadow) !important;
  border-radius: 1.5px !important;
  transition: transform 180ms ease, box-shadow 180ms ease !important;
}

/* Gentle lift on hover (desktop only). */
@media (hover: hover) {
  .book-cover img:hover,
  .result-cover img:hover,
  .shelf-book-cover img:hover,
  a:hover > .book-cover img,
  a:hover > .result-cover img {
    transform: translateY(-2px) !important;
    box-shadow: 6px 4px 0 -2px rgba(47, 42, 53, 0.08),
                0 14px 30px -4px rgba(47, 42, 53, 0.24),
                0 4px 8px rgba(47, 42, 53, 0.14) !important;
  }
}

/* ---------- Editorial row utility ----------
   Replaces the flat card pattern for content lists (paths, letters,
   recommendations). Usage: add class="rp-editorial-row" to a row
   that currently sits in an rgba fill card. */
.rp-editorial-row {
  background: transparent !important;
  border: none !important;
  border-bottom: 1px solid rgba(47, 42, 53, 0.10) !important;
  border-radius: 0 !important;
  padding: 1.5rem 0 !important;
  box-shadow: none !important;
}
.rp-editorial-row:last-child { border-bottom: none !important; }

/* ---------- Reader-identity as literary line ----------
   The one-line "who this reader is" in each card is the most human
   signal on the page. Raise it to a real editorial italic. */
.reader-identity,
.reader-identity-title,
.letter-identity {
  font-family: var(--font-secondary) !important;
  font-style: italic !important;
  font-weight: 400 !important;
  font-size: 14px !important;
  color: var(--almost-plum) !important;
  opacity: 0.92 !important;
  line-height: 1.5 !important;
}

/* Reader cards: warmer container with a plum accent. Turns the wall of
   near-identical tiles into something that reads as people-with-books. */
.reader-card {
  background: var(--antique-white) !important;
  border: 1px solid rgba(47, 42, 53, 0.10) !important;
  border-left: 3px solid rgba(145, 78, 86, 0.45) !important;
  transition: border-color 200ms ease, transform 200ms ease, box-shadow 200ms ease !important;
}
.reader-card:hover {
  border-left-color: var(--almost-plum) !important;
  transform: translateY(-2px) !important;
  box-shadow: 0 6px 18px rgba(47, 42, 53, 0.10) !important;
}

/* ---------- Reader-avatar warmth ----------
   Soften the powder-blue disc wall by letting the antique-white
   peek through and giving initials real display weight. */
.reader-avatar {
  background: linear-gradient(145deg, rgba(195, 219, 231, 0.85), rgba(240, 234, 216, 0.6)) !important;
  box-shadow: inset 0 0 0 1px rgba(47, 42, 53, 0.08),
              0 1px 2px rgba(47, 42, 53, 0.08);
}
.reader-avatar span,
.reader-avatar-initials {
  font-family: var(--font-secondary) !important;
  font-weight: 700 !important;
  font-size: 17px !important;
  color: rgba(47, 42, 53, 0.78) !important;
}

/* ---------- Button register ----------
   Soften every primary CTA's letter-spacing so buttons feel
   considered rather than shouting. Keep the palette. */
button,
.btn,
.btn-primary,
.setup-button,
.search-btn,
.nav-cta {
  letter-spacing: 0.18em !important;
}

/* ---------- Literary select affordance ----------
   Restyle any inline-styled action <select> used in the library and
   elsewhere. Strips native chrome, adds a serif ⋯ chevron, matches the
   antique-white register. Targets selects whose handler is the library
   action dispatcher so we don't touch unrelated selects. */
select[onchange*="handleLibraryAction"],
select.rp-literary-select {
  appearance: none !important;
  -webkit-appearance: none !important;
  -moz-appearance: none !important;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5 L6 7.5 L9 4.5' stroke='%232F2A35' stroke-width='1' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: right 0.65rem center !important;
  background-size: 11px 11px !important;
  padding: 0.5rem 2rem 0.5rem 0.85rem !important;
  border: 1px solid rgba(47, 42, 53, 0.18) !important;
  border-radius: 2px !important;
  background-color: rgba(240, 234, 216, 0.55) !important;
  font-family: var(--font-primary) !important;
  font-size: 10px !important;
  letter-spacing: 0.14em !important;
  text-transform: uppercase !important;
  color: var(--blueberry) !important;
  cursor: pointer !important;
  transition: border-color 180ms ease, background-color 180ms ease !important;
  min-width: 140px;
}
select[onchange*="handleLibraryAction"]:hover,
select.rp-literary-select:hover {
  border-color: var(--blueberry) !important;
  background-color: rgba(240, 234, 216, 0.85) !important;
}
select[onchange*="handleLibraryAction"]:focus,
select.rp-literary-select:focus {
  outline: none !important;
  border-color: var(--almost-plum) !important;
  background-color: rgba(240, 234, 216, 0.95) !important;
}

/* Narrower action dropdown on mobile — the 140px baseline is fine on
   desktop cards but fills ~40% of a narrow PWA card (390px viewport).
   iOS Safari opens a native picker on tap, so the BUTTON width can be
   tight without hiding options. */
@media (max-width: 600px) {
  select[onchange*="handleLibraryAction"],
  select.rp-literary-select {
    min-width: 0 !important;
    width: auto !important;
    max-width: 100% !important;
    padding: 0.45rem 1.75rem 0.45rem 0.7rem !important;
    font-size: 9.5px !important;
    letter-spacing: 0.1em !important;
  }
}

/* ---------- Shelves: lighter bottom hairline ----------
   Earlier iteration used a saturated plum wood-tone strip which read
   too heavy against lemon-tart. A single restrained hairline is enough
   to imply the shelf edge without dominating the card. */
.shelf,
.shelf-container {
  position: relative;
}

/* ---------- Empty states ----------
   Unify italic tone across any explicit empty-state class,
   so the warm bookish voice on book-detail spreads site-wide.
   Color raised from 0.58 → 0.82 for AAA contrast (was ~3.5:1, now ~7:1). */
.empty-state,
.state,
.empty,
.no-books,
.empty-shelf {
  font-family: var(--font-secondary) !important;
  font-style: italic !important;
  font-size: 14px !important;
  color: rgba(47, 42, 53, 0.82) !important;
  text-align: center !important;
  padding: 2.5rem 1rem !important;
}

/* ---------- Paper texture on antique-white surfaces ----------
   Very subtle fiber texture layered inside antique-white cards.
   Stacks UNDER content; 4% opacity only. */
.antique-paper,
.portrait-section,
.identity-block,
.letter-card {
  position: relative;
}
.antique-paper::before,
.portrait-section::before,
.identity-block::before,
.letter-card::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.29 0 0 0 0 0.25 0 0 0 0 0.21 0 0 0 0.45 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23p)'/%3E%3C/svg%3E");
  background-size: 220px;
  opacity: 0.05;
  mix-blend-mode: multiply;
  border-radius: inherit;
}
/* Children must sit above the texture layer. */
.antique-paper > *,
.portrait-section > *,
.identity-block > *,
.letter-card > * {
  position: relative;
  z-index: 1;
}


@media (max-width: 768px) {
  /* Compact nav so it stays roughly one line. */
  nav {
    padding: 0.75rem 1rem !important;
    align-items: center !important;
  }
  .nav-logo {
    font-size: 10px !important;
    letter-spacing: 0.15em !important;
  }
  .nav-links {
    gap: 0.6rem !important;
    flex-wrap: wrap !important;
    justify-content: flex-end !important;
  }
  .nav-links a {
    font-size: 11px !important;
    letter-spacing: 0.08em !important;
    padding: 0.35rem 0 !important;
    white-space: nowrap;
  }
  .nav-links a.nav-cta,
  .nav-cta {
    padding: 0.6rem 1.1rem !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    letter-spacing: 0.14em !important;
    color: var(--blueberry) !important;
  }
  .nav-avatar {
    width: 36px !important;
    height: 36px !important;
    position: relative !important;
  }
  /* Expand the tap area beyond the visual disc so mis-taps on adjacent
     nav links stop happening. */
  .nav-avatar::before {
    content: '';
    position: absolute;
    inset: -6px;
  }

  /* Welcome section + nav grid: tighter mobile rhythm. The 5rem margin-
     bottom on desktop eats 80px of a 812px viewport; bring it down. */
  .welcome-section {
    margin-bottom: 2.5rem !important;
  }
  .nav-grid {
    gap: 1rem !important;
  }
  .nav-card {
    padding: 1.5rem !important;
  }

  /* Ensure every top-level container clears the (possibly two-line) nav. */
  .portrait-container,
  .dashboard-container,
  .library-container,
  .feedback-container,
  .fellow-container,
  .expanded-container,
  .account-container,
  .about-container,
  .login-container,
  .reading-room-container,
  .profile-header,
  .setup-header,
  .shelves-section,
  .questions-container,
  .features-container,
  .tracks-container,
  .outputs-container,
  .pillars-container,
  .tabs-container,
  .shelf-container,
  .tags-container {
    padding-top: 120px !important;
  }

  /* Splash page hero uses .page-header for a full-bleed treatment that
     shouldn't reserve nav space. Other pages with .page-header keep
     their own mobile padding. */
  body.page-splash .page-header {
    padding-top: 0 !important;
    margin-top: 1rem !important;
  }

  /* Library shelves (BP §21c redesign): shelves are transparent BANDS now
     — no box padding; the page's own CSS handles mobile layout. */
  .shelf {
    max-height: none !important;
    padding: 0 !important;
  }

  /* Fixed progress bar on portrait page: it has margin-top:5rem for desktop,
     but on mobile the nav wraps so we need more clearance */
  .portrait-progress-section {
    margin-top: 6.5rem !important;
    padding: 0.75rem 1rem !important;
  }

  /* Beta feedback block on dashboard — keep text readable when cramped */
  h1, h2 { word-break: break-word; }

  /* Tab nav inside portrait view — make horizontally scrollable instead of wrapping */
  .tabs-nav {
    flex-wrap: nowrap !important;
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .tabs-nav::-webkit-scrollbar { display: none; }
  .tab-button {
    white-space: nowrap !important;
    flex-shrink: 0 !important;
  }

  /* Portrait view: hero takes ~250px before content on desktop. Tighten on mobile. */
  .portrait-header {
    padding-top: 1rem !important;
    padding-bottom: 1rem !important;
  }
  .portrait-headline {
    font-size: 22px !important;
    line-height: 1.2 !important;
  }
  .portrait-tagline {
    font-size: 13px !important;
    line-height: 1.5 !important;
  }

  /* Portrait sections that use auto-fit grids with 220-250px min columns —
     collapse to 1 column on narrow screens so cards don't squeeze. */
  #identity-content > div[style*="grid-template-columns"],
  #curriculum-content > div[style*="grid-template-columns"],
  #by-country-content > div[style*="grid-template-columns"],
  #consider-removing-content > div[style*="grid-template-columns"],
  #extra-credit-content > div[style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
  }

  /* Library page: tighten quick-add block + shrink shelf previews so all 3
     shelves + DNF link fit on one screen without deep scroll. */
  .quick-add-section {
    padding: 1rem 1.25rem !important;
    margin-bottom: 1.25rem !important;
  }
  .shelf-preview,
  .shelf-preview-scroll,
  .shelf-books-list {
    max-height: 220px !important;
  }
}

@media (max-width: 480px) {
  nav { padding: 0.65rem 0.75rem !important; }
  .nav-logo { font-size: 9.5px !important; }
  .nav-links { gap: 0.55rem !important; }
  .nav-links a { font-size: 10.5px !important; letter-spacing: 0.06em !important; }
  .nav-links a.nav-cta,
  .nav-cta { font-size: 10.5px !important; padding: 0.5rem 0.95rem !important; font-weight: 700 !important; letter-spacing: 0.12em !important; color: var(--blueberry) !important; }

  /* Dashboard search — drop the redundant button (Enter submits). */
  .quick-add-section .search-btn { display: none !important; }
  .quick-add-section .search-box .search-input { width: 100% !important; }

  /* Smaller containers on small phones */
  .portrait-container,
  .dashboard-container,
  .library-container,
  .feedback-container,
  .fellow-container,
  .expanded-container,
  .account-container,
  .about-container,
  .login-container {
    padding-left: 1rem !important;
    padding-right: 1rem !important;
    padding-top: 130px !important;
  }

  .portrait-progress-section {
    margin-top: 7rem !important;
  }
}

/* Narrow-nav collapse (≤1023px): hide the primary inline links and let
   the avatar dropdown carry them instead. Desktop ≥1024px keeps all 4
   items inline. Critical qualifier: only collapse if the nav HAS an
   avatar menu — otherwise (splash / login / create-account, when the
   reader is signed out) there's nothing to fold the links into, and
   hiding them makes Sign In + Begin invisible. */
@media (max-width: 1023px) {
  nav:has(.nav-avatar-menu) .nav-links > li:not(.nav-avatar-menu):not(.rp-notif-wrapper) {
    display: none !important;
  }
  /* Inside the dropdown, reveal the primary links that were prepended. */
  nav:has(.nav-avatar-menu) .nav-dropdown a.nav-dropdown-primary {
    display: flex !important;
  }
  /* On no-avatar pages (splash/login/create-account), let the nav wrap or
     tighten gracefully instead of hiding. The splash has 3 short items
     (About, Sign In, Begin) — they fit. */
  nav:not(:has(.nav-avatar-menu)) .nav-links {
    gap: 0.9rem !important;
  }
  nav:not(:has(.nav-avatar-menu)) .nav-links a {
    font-size: 10px !important;
    letter-spacing: 0.12em !important;
  }
  nav:not(:has(.nav-avatar-menu)) .nav-links a.nav-cta {
    padding: 0.5rem 0.9rem !important;
  }
}
/* At desktop ≥1024px, the primary links are already inline in the top
   nav — hide them inside the dropdown so they don't duplicate. */
@media (min-width: 1024px) {
  .nav-dropdown a.nav-dropdown-primary {
    display: none !important;
  }
}

/* Portrait tabs — 6 labels (Reading Identity · Reading Year Ahead ·
   The Monthly Letter · By Country · Year in Review · The Unread Shelf)
   wrap to 2 ugly rows at laptop widths. Fall back to a single horizontal
   scroll strip (swipe/drag on touch, scroll-on-hover on desktop) anywhere
   below full desktop. The ≤768px rule above already does this; this
   extends the same behavior up to 1279px and tightens tab padding. */
@media (min-width: 769px) and (max-width: 1279px) {
  .tabs-nav {
    flex-wrap: nowrap !important;
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .tabs-nav::-webkit-scrollbar { display: none; }
  .tab-button {
    white-space: nowrap !important;
    flex-shrink: 0 !important;
    padding: 1rem 1.4rem !important;
    font-size: 11.5px !important;
  }
}

/* ===== AVATAR DROPDOWN =====
   Every page renders the dropdown with inline styles on each <a>:
   11px font, 0.75rem padding, 0.7 opacity — below WCAG tap-target
   and readability minimums. Apply at all widths (the problem isn't
   mobile-only) and bump further on touch. */
.nav-dropdown {
  min-width: 200px !important;
  padding: 0.35rem 0 !important;
  box-shadow: 0 8px 24px rgba(47, 42, 53, 0.25) !important;
}
.nav-dropdown a {
  font-size: 13px !important;
  letter-spacing: 0.14em !important;
  padding: 0.95rem 1.35rem !important;
  opacity: 0.95 !important;
  min-height: 48px !important;
  display: flex !important;
  align-items: center !important;
  transition: background 0.15s, opacity 0.15s !important;
}
.nav-dropdown a:hover,
.nav-dropdown a:focus-visible {
  background: rgba(255, 255, 255, 0.08) !important;
  opacity: 1 !important;
}

@media (max-width: 768px) {
  .nav-dropdown {
    min-width: 220px !important;
  }
  .nav-dropdown a {
    font-size: 14px !important;
    padding: 1rem 1.35rem !important;
    min-height: 52px !important;
  }
}

/* ===== SPLASH PAGE ===== */
/* Stack the two hero CTAs on narrow screens — at 375px the side-by-side
   layout squeezes them below usable tap sizes. */
@media (max-width: 600px) {
  body.page-splash .hero-actions {
    flex-direction: column !important;
    align-items: stretch !important;
    gap: 0.75rem !important;
    width: 100% !important;
  }
  body.page-splash .hero-actions .button {
    width: 100% !important;
    text-align: center !important;
    box-sizing: border-box !important;
    padding: 1rem 1.5rem !important;
  }
  body.page-splash .features-grid {
    grid-template-columns: 1fr !important;
  }
  body.page-splash .feature-item {
    padding: 2rem 1.25rem !important;
    border-right: none !important;
    border-bottom: 0.5px solid rgba(240, 234, 216, 0.1) !important;
  }
}

/* Footers across the site are position:fixed on desktop — they sit
   over the last ~84px of page content on mobile, hiding CTAs and
   copy. Unpin on touch viewports so content breathes. */
@media (max-width: 1024px) {
  footer {
    position: static !important;
    padding: 1.5rem 1.5rem !important;
    flex-direction: column !important;
    gap: 0.5rem !important;
    text-align: center !important;
  }
}

/* ============================================================
   PWA BACK BUTTON SUPPORT
   When the back button (injected by supabase-client.js) is present
   on non-splash pages in standalone mode, the body gets the class
   `rp-has-back-btn`. The nav shifts its left padding right so the
   back chevron and the "Reading Portrait" logo don't stack on top
   of each other.
   ============================================================ */
body.rp-has-back-btn nav {
  padding-left: 4rem !important;
}
@media (max-width: 768px) {
  body.rp-has-back-btn nav {
    padding-left: 3rem !important;
  }
}

/* Home-indicator clearance for the bottom-pinned footer on devices that
   have one (iPhone X+). Only applies when footer is position:fixed, not
   after the mobile @media above unstacks it. */
@media (min-width: 1025px) {
  footer {
    padding-bottom: max(2.5rem, calc(env(safe-area-inset-bottom) + 1rem)) !important;
  }
}

/* ============================================================
   MOBILE TOUCH-TARGET + SPACING FIXES  (Apr 2026)
   User feedback: buttons too close together at ~390px on PWA;
   two-column layout on My Library doesn't work on mobile.
   HIG/Material baseline: ≥44px tall, ≥8px gap between adjacent
   tappables. These rules only fire at ≤768px — desktop unchanged.
   ============================================================ */
@media (max-width: 768px) {

  /* (Removed Apr-2026 single-column override — the shelves redesign,
     BP §21c, made each shelf a horizontally scrolling band of cover
     tiles on mobile; the library page now owns its mobile layout.) */

  /* --- LIBRARY: in-card action buttons (Move / Remove) ---
     Desktop uses a 2fr/1fr grid at 0.6rem padding. On mobile we stack
     with explicit 44px min-height and 10px gap. */
  .book-actions {
    display: flex !important;
    flex-direction: column !important;
    gap: 0.6rem !important;
    margin-top: 0.75rem !important;
  }
  .book-action-btn {
    min-height: 44px !important;
    padding: 0.75rem 1rem !important;
    font-size: 11px !important;
  }

  /* --- LIBRARY / SHELF-EXPANDED: action <select> dropdowns ---
     The handleLibraryAction selects and reaction selects render at
     11px font, 3-4px padding — well below 44px tall. Also the inline
     `width:100%` on these selects stretches them across the whole card
     on mobile, which looks heavy. Clamp to ~160px and keep the touch
     target tall enough (44px min-height for HIG). */
  select[onchange*="handleLibraryAction"],
  select[onchange*="handleReactionChange"],
  select.rp-literary-select {
    min-width: 0 !important;
    width: auto !important;
    max-width: 160px !important;
    min-height: 44px !important;
    padding: 0.7rem 2rem 0.7rem 0.85rem !important;
    font-size: 11.5px !important;
    letter-spacing: 0.1em !important;
    box-sizing: border-box !important;
  }

  /* --- SHELF-EXPANDED: filter chips + sort button ---
     Inline styles set padding: 0.45rem 0.8rem (≈28px tall) with
     gap: 0.4rem (≈6px) — both below HIG minimum. */
  #shelf-filter-chips {
    gap: 0.5rem !important;
    row-gap: 0.6rem !important;
  }
  #shelf-filter-chips button,
  #shelf-sort-btn {
    min-height: 40px !important;
    padding: 0.65rem 0.9rem !important;
    font-size: 11px !important;
  }
  #shelf-toolbar {
    gap: 0.75rem !important;
  }

  /* --- SHELF-EXPANDED: in-card action + finish buttons ---
     Bring them up to the same register as library. */
  .book-finish-actions { gap: 0.55rem !important; }
  .book-finish-btn {
    min-height: 44px !important;
    padding: 0.7rem 0.95rem !important;
  }

  /* --- READING ROOM: tab strip ---
     4 tabs (Activity · Readers · Shelves & Paths · Field Trip) with
     gap:0 means adjacent active-underlines touch. Pad each tab and
     add rhythm between them. */
  .rr-tabs {
    gap: 0.15rem !important;
  }
  .rr-tab {
    padding: 1rem 0.9rem !important;
    font-size: 11.5px !important;
    min-height: 48px !important;
  }

  /* --- READING ROOM: Accept / Decline on pending requests ---
     Inline buttons at padding 0.5rem 0.8rem with gap 0.4rem put the
     two CTAs ~6px apart — the #1 mis-tap surface in the app. */
  #rr-pending-grid > div > div:last-child {
    gap: 0.65rem !important;
  }
  #rr-pending-grid button {
    min-height: 44px !important;
    padding: 0.7rem 1rem !important;
    font-size: 11px !important;
  }
  /* Stack pending-request cards single-column (was minmax 240px). */
  #rr-pending-grid {
    grid-template-columns: 1fr !important;
  }

  /* --- PORTRAIT VIEW: tab strip ---
     6 tabs in a scrolling strip. Keep them scrolling but add a touch
     of gap so adjacent active-underlines don't visually collide, and
     enforce a 48px min-height for the scroll track. */
  .tabs-nav {
    gap: 0.15rem !important;
  }
  .tab-button {
    padding: 1rem 1.1rem !important;
    font-size: 11.5px !important;
    min-height: 48px !important;
  }

  /* --- PORTRAIT VIEW: Share buttons ---
     The .btn-primary Share CTAs on Identity / Reading Year / Year in
     Review are close to bottom CTAs in each tab's content. Give them
     breathing room. */
  .tab-content .btn-primary[id*="share-"] {
    min-height: 48px !important;
    padding: 0.9rem 1.25rem !important;
    margin-top: 1.25rem !important;
  }

  /* --- GLOBAL: favorite-star buttons (library + shelf-expanded) ---
     The ☆/★ toggle sits at 18px font with 0.2rem padding — tappable
     area ≈22px. Grow the hit-zone without changing visual size. */
  button[onclick*="handleToggleFavorite"] {
    min-width: 44px !important;
    min-height: 44px !important;
    padding: 0.5rem !important;
  }
  /* …except the library's cover-overlay star, where a 44px chip would
     blanket a third of a 118px cover. 32px keeps it tappable enough. */
  button.tile-fav {
    min-width: 32px !important;
    min-height: 32px !important;
    width: 32px !important;
    height: 32px !important;
    padding: 0 !important;
  }

  /* ============================================================
     ROUND 2 — DEFERRED SPACING ITEMS (P1)
     ============================================================ */

  /* --- QUESTIONNAIRE (setup_profile_questionnaire): radio/checkbox rows ---
     Q2 and Q4 use <div class="option"> rows with a 20px checkbox/radio and
     a sibling <label>. At 15px font with 0.35rem vertical padding, each row
     is ~42px tall and the entire row isn't tappable — only the 20px circle
     and the text are. On a 375px viewport adjacent rows sit <8px apart and
     readers regularly mis-tap the one below.
     Fix: make the whole row a 48px tap target (the label already has
     flex-grow:1 and covers the text, but we force the row min-height and
     give the label its own min-height so label clicks work anywhere on
     the row's full height). gap moves from 1rem → 0.6rem+min-height to
     keep the list compact while guaranteeing ≥8px between adjacent taps. */
  .options-group {
    gap: 0.6rem !important;
  }
  .options-group .option {
    min-height: 52px !important;
    padding: 0.5rem 0 !important;
    cursor: pointer !important;
  }
  .options-group .option label {
    min-height: 44px !important;
    display: flex !important;
    align-items: center !important;
    padding: 0.25rem 0 !important;
    flex: 1 1 auto !important;
  }
  .options-group .option input[type="radio"],
  .options-group .option input[type="checkbox"] {
    width: 22px !important;
    height: 22px !important;
    margin-right: 0.85rem !important;
  }
  /* Q1, Q3, Q4-style button-options: auto-fit minmax(160px,1fr) renders
     2 columns at 375px, squeezing long labels onto 3 wrapped lines.
     Stack single-column at mobile and lock each button to a 48px tap
     target with comfortable vertical gap. */
  .button-options {
    grid-template-columns: 1fr !important;
    gap: 0.65rem !important;
  }
  .option-button {
    min-height: 52px !important;
    padding: 0.95rem 1.25rem !important;
  }

  /* --- READING ROOM: Field-trip & friend-selector cards ---
     .friend-card renders from an inline template (string concat in JS) at
     padding 1rem 1.25rem — fine on desktop, but the 2-col grid on mobile
     leaves cards ~150px wide with covers + identity quote squeezed. Stack
     single column ≤480px with a proper vertical gap. */
  #friends-list,
  #follows-list,
  #shared-shelves-container,
  .friends-grid {
    display: grid !important;
    grid-template-columns: 1fr !important;
    gap: 0.75rem !important;
  }
  .friend-card {
    min-height: 88px !important;
    padding: 1rem 1.25rem !important;
  }
  /* The small "View →" link floated top-right of each selectable card
     sits at 9px font with 4px padding — a ~14px tap target inside
     another tappable surface. Grow hit-zone without growing the visible
     label. */
  .friend-card a[href*="reader_page"] {
    min-width: 44px !important;
    min-height: 32px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 8px 10px !important;
  }
  /* Field-trip "Pack my shelf" submit button — inline style at 0.85rem
     1.6rem leaves a tap target barely over 40px. */
  #ft-submit {
    min-height: 48px !important;
    padding: 0.95rem 1.6rem !important;
    width: 100% !important;
  }

  /* --- DASHBOARD: dismissible banners × hit zone ---
     The fresh-picks card has a "Not now" dismiss control rendered as a
     plain text button with padding:0 — hit zone ≈18px tall. The card
     footer action row packs "Begin →" and "Not now" inline. Grow the
     hit area on both controls to ≥44px without resizing the visible
     label. Same treatment for the Reading Paths nudge "Continue the
     path →" link. */
  #fresh-picks-card a,
  #fresh-picks-card button,
  #reading-paths-nudge a,
  #reading-paths-nudge button {
    min-height: 44px !important;
    display: inline-flex !important;
    align-items: center !important;
    padding: 0.6rem 0.25rem !important;
    margin-right: 0.5rem !important;
  }
  /* Generic dismiss/close buttons on banners — covers any ×/close
     control across dashboard banners. Keeps the visible ×/label size
     untouched by applying to the button wrapper; transparent padding
     extends hit zone to ≥44×44. */
  #notifications-block button[aria-label*="ismiss" i],
  #notifications-block button[aria-label*="lose" i],
  .banner-close,
  .notification-dismiss {
    min-width: 44px !important;
    min-height: 44px !important;
    padding: 12px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
  }
}

/* ============================================================
   ACCESSIBILITY — CONTRAST FLOOR (WCAG AA / AAA)
   ============================================================
   Audit finding (Apr 2026): secondary copy across the site uses
   opacity 0.3–0.55 on blueberry (#2F2A35). On lemon-tart + white
   backgrounds that pushes contrast to ~3:1 — below AA (4.5:1 for
   normal text) and far below AAA (7:1). These rules lift the
   floor everywhere we can reach without editing every inline
   style. Target opacity:
     · 0.82 for body / helper copy   → ~7:1 on white (AAA pass)
     · 0.75 for nav links / metadata → ~6:1 (AA pass, close to AAA)
     · 0.88 on dark-backgrounded white → ~9:1
   Fixing inline styles: rules use `!important` because the
   offending declarations are overwhelmingly inline style="".
   ============================================================ */

/* Section / card labels — short uppercase eyebrows like
   "LAST UPDATED", "YOUR READING IDENTITY", "FRESH PICKS FOR YOU".
   Almost always opacity:0.5–0.6 inline, and sit on light bg. */
p[style*="text-transform:uppercase"][style*="letter-spacing:0.2"],
p[style*="text-transform:uppercase"][style*="letter-spacing:0.22"],
p[style*="text-transform:uppercase"][style*="letter-spacing:0.24"],
p[style*="text-transform:uppercase"][style*="letter-spacing:0.18"],
p[style*="text-transform:uppercase"][style*="letter-spacing:0.16"],
p[style*="text-transform:uppercase"][style*="letter-spacing:0.14"] {
  opacity: 0.88 !important;
}

/* Generic secondary body copy set directly on blueberry with low
   opacity. Nav-card descriptions, renewal info, helper notes. */
.nav-card-description,
.renewal-info,
.setting-description,
.section-description,
.shared-shelves-description {
  opacity: 1 !important;
  color: rgba(47, 42, 53, 0.85) !important;
}

/* Metadata / timestamps / "@username" (≤12px italic, opacity 0.4–0.55) */
p[style*="font-style:italic"][style*="opacity:0.4"],
p[style*="font-style:italic"][style*="opacity:0.45"],
p[style*="font-style:italic"][style*="opacity:0.5"],
p[style*="font-style:italic"][style*="opacity:0.55"],
p[style*="font-style:italic"][style*="opacity:0.6"] {
  opacity: 0.82 !important;
}

/* Footer copy — sits on blueberry; white at opacity 0.3 is ~5:1
   (AA for large text only). Bump to 0.7 for AAA on 11px body. */
.footer-copy {
  opacity: 0.82 !important;
}
.footer-logo {
  opacity: 0.9 !important;
}

/* Nav links — white on blueberry at opacity 0.7 is ~10:1 which is
   already AAA, but hover state reveals pattern; keep .95 baseline
   so the "quiet" state still reads clearly. */
nav .nav-links a,
.nav-dropdown a {
  opacity: 0.9 !important;
}
nav .nav-links a:hover,
.nav-dropdown a:hover,
.nav-dropdown a:focus-visible {
  opacity: 1 !important;
}

/* Form placeholders — Safari / iOS default to about 42% dim.
   Some pages explicitly set opacity:0.4/0.5 which fails WCAG. */
.form-input::placeholder,
.search-input::placeholder,
input::placeholder,
textarea::placeholder {
  color: rgba(47, 42, 53, 0.72) !important;
  opacity: 1 !important;
}

/* Muted brand-blueberry text where the inline style used opacity
   specifically to look "ghosted." Catch the common 0.3–0.55 range. */
*[style*="color:var(--blueberry)"][style*="opacity:0.3"],
*[style*="color:var(--blueberry)"][style*="opacity:0.35"],
*[style*="color:var(--blueberry)"][style*="opacity:0.4"],
*[style*="color:var(--blueberry)"][style*="opacity:0.45"],
*[style*="color:var(--blueberry)"][style*="opacity:0.5"],
*[style*="color:var(--blueberry)"][style*="opacity:0.55"],
*[style*="color:var(--blueberry)"][style*="opacity:0.6"] {
  opacity: 0.82 !important;
}

/* Same for white text on dark backgrounds that went too ghostly */
*[style*="color:#FFFFFF"][style*="opacity:0.3"],
*[style*="color:#FFFFFF"][style*="opacity:0.4"],
*[style*="color:#FFFFFF"][style*="opacity:0.5"],
*[style*="color:#FFFFFF"][style*="opacity:0.55"],
*[style*="color:#FFFFFF"][style*="opacity:0.6"] {
  opacity: 0.88 !important;
}

/* Any element declared with --dark-gray (#94AAB2) as text color
   fails AAA on every background we ship. Promote to darker olive. */
[style*="color:var(--dark-gray)"],
[style*="color: var(--dark-gray)"],
[style*="color:#94AAB2"] {
  color: var(--dark-olive-green) !important;
}

/* Accessible focus rings — currently many buttons strip outline
   on :focus without offering a :focus-visible alternative, which
   blocks keyboard users from seeing their position. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--almost-plum) !important;
  outline-offset: 2px !important;
}

/* ============================================================
   ACCESSIBILITY — BEYOND CONTRAST (WCAG 2.1 AAA)
   ============================================================
   · 1.4.8 Visual Presentation — AAA: paragraphs need line-height
     ≥ 1.5× and paragraph spacing ≥ 2× font size.
   · 1.4.12 Text Spacing — AA: users must be able to override
     spacing; our base CSS must not break layout when they do.
   · 2.4.1 Bypass Blocks — A: skip-to-content link (injected by
     supabase-client.js; styles below).
   · 2.4.7 Focus Visible — AA (done above).
   · 2.5.5 Target Size — AAA: interactive targets ≥ 44×44px
     (mobile overrides above handle most).
   ============================================================ */

/* Line-height floor on body copy. Applies only where the author
   hasn't explicitly set a tighter value they want preserved
   (e.g. headlines set clamp() + 1.1 line-height on purpose). */
p {
  line-height: 1.6;
}
p + p {
  margin-top: 0.85em;
}

/* Skip-to-content link. Rendered by supabase-client.js on every
   page; visually hidden until focused. Jumps keyboard + screen-
   reader users past the nav into the main content block. */
#rp-skip-link {
  position: absolute;
  top: -100px;
  left: 0;
  z-index: 9999;
  background: var(--blueberry);
  color: #FFFFFF;
  padding: 0.85rem 1.25rem;
  font-family: var(--font-primary);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: 2px;
  transition: top 0.15s ease;
}
#rp-skip-link:focus {
  top: 0.5rem;
  left: 0.5rem;
  outline: 2px solid var(--almost-plum);
  outline-offset: 2px;
}

/* No-justify rule — AAA 1.4.8: text must not be justified. Some
   long-form prose blocks (monthly letter, identity description)
   were hand-set to "justify" for a literary feel. That creates
   rivers of whitespace that hurt readers with cognitive /
   dyslexic-spectrum difficulties. Always left-align. */
p, div {
  text-align: start;
}
p[style*="text-align:center"],
p[style*="text-align: center"],
div[style*="text-align:center"],
div[style*="text-align: center"] {
  text-align: center !important;
}
/* Explicitly kill justified blocks even if the author set it. */
p[style*="text-align:justify"],
p[style*="text-align: justify"],
*[style*="text-align:justify"],
*[style*="text-align: justify"] {
  text-align: left !important;
}

/* Screen-reader only utility, since we reference it in multiple
   HTMLs without always defining it. Harmless duplicate. */
.sr-only:not(:focus) {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0,0,0,0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* Respect reduced-motion preference — AAA 2.3.3. Kills all the
   fade-up / translateY intros for readers who opt out. Our page
   CSS also has some @media prefers-reduced-motion blocks; this
   is belt-and-braces. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
   §9 GLOBAL ACCESSIBILITY + PWA POLISH (shipped in audit batch)
   Applies sitewide. See audit notes for reasoning on each.
   ============================================================ */

/* Global: prevent rogue-width elements from triggering horizontal scroll. */
html, body { overflow-x: hidden !important; }

/* Global: kill the 300ms tap delay on older WebKit. */
button, a, input[type="submit"], input[type="button"], [role="button"] {
  touch-action: manipulation !important;
}

/* Global: restore a visible focus ring for keyboard users. The blueberry
   outline stands on every background we ship. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[role="button"]:focus-visible {
  outline: 2px solid var(--blueberry) !important;
  outline-offset: 2px !important;
}

/* Global: 44px tap-target floor on the nav dropdown + filter chips +
   reaction pills (iOS HIG + WCAG 2.5.5). */
.nav-dropdown a,
.nav-links a,
.rr-tab,
.shelf-tab,
.rp-path-filter,
.filter-chip,
.rp-path-book-add,
[data-path-pin],
[data-filter],
.rp-reaction-btn,
button.button,
.button--primary,
.button--secondary {
  min-height: 44px !important;
}

/* iOS safe-area (Capacitor full-screen webview, viewport-fit=cover).
   Push the whole page below the status bar / Dynamic Island, and drop
   the fixed nav to sit just under it (it keeps its own design padding).
   env() is 0 on non-notch devices, so this is a no-op in the browser
   and on desktop — no media query needed. */
body {
  padding-top: env(safe-area-inset-top) !important;
}
nav {
  top: env(safe-area-inset-top) !important;
}
@supports (padding: max(0px, env(safe-area-inset-bottom))) {
  footer {
    padding-bottom: max(2.5rem, env(safe-area-inset-bottom)) !important;
  }
}

/* Messages composer: resize content when iOS keyboard opens. */
@supports (interactive-widget: resizes-content) {
  @viewport { interactive-widget: resizes-content; }
}

/* ============================================================
   DYNAMIC SIZING — scale type / buttons / inputs with viewport
   so laptop + desktop users don't get mobile-sized UI.
   Base ramp:   mobile (<=768)  →  laptop (1024-1439)  →  desktop (1440+)
   ============================================================ */

/* Laptop bump — 1024-1439px. */
@media (min-width: 1024px) {
  body {
    font-size: 16px !important;
  }
  /* Base paragraph / body copy used site-wide. */
  p, li, .nav-card-description, .shelf-book-author, .book-author,
  .setting-description, .hero-sub, .pillar-desc, .feature-card-desc,
  .empty-state, .quote-text {
    font-size: 16px !important;
  }
  /* Input + select + textarea — dynamic sizing. */
  input[type="text"], input[type="email"], input[type="password"],
  input[type="url"], input[type="search"], textarea, select {
    font-size: 16px !important;
    padding: 0.85rem 1rem !important;
  }
  /* Buttons — larger tap area on laptop without looking oversized. */
  button, .btn-primary, .btn-secondary, .button, input[type="submit"] {
    font-size: 12px !important;
    padding-top: 0.75rem !important;
    padding-bottom: 0.75rem !important;
  }
  /* Search bars explicitly (library, book picker, reader search). */
  [id$="-search"], [placeholder*="Search"] {
    font-size: 16px !important;
    padding: 0.85rem 1.1rem !important;
  }
}

/* Desktop bump — 1440px+. */
@media (min-width: 1440px) {
  body {
    font-size: 17px !important;
  }
  p, li, .nav-card-description, .shelf-book-author, .book-author,
  .setting-description, .hero-sub, .pillar-desc, .feature-card-desc,
  .empty-state, .quote-text {
    font-size: 17px !important;
  }
  input[type="text"], input[type="email"], input[type="password"],
  input[type="url"], input[type="search"], textarea, select {
    font-size: 17px !important;
    padding: 0.95rem 1.15rem !important;
  }
  button, .btn-primary, .btn-secondary, .button, input[type="submit"] {
    font-size: 13px !important;
  }
  [id$="-search"], [placeholder*="Search"] {
    font-size: 17px !important;
    padding: 0.95rem 1.25rem !important;
  }
  /* Shelf titles + section titles scale up. */
  .shelf-title, .section-title, .friends-title, .pillars-title {
    font-size: clamp(26px, 2vw, 32px) !important;
  }
}

/* ============================================================
   PALETTE DIRECTION — April 24 2026
   Owner preferences: butter-yellow is canonical body, plum minimized,
   more blueberry + powder-blue + new --soft-blue surfaces, retire
   muddy pale-golden-rod panels. These rules land in mobile-overrides
   so they cascade across every page without touching each per-page
   inline <style> block.
   ============================================================ */

/* Retire pale-golden-rod panels. Anywhere a card or banner was using
   the muddy gold background it gets promoted to the softer blue. Keep
   the token defined (harmless) — just stop rendering it as a surface. */
[style*="background:var(--soft-blue)"],
[style*="background: var(--soft-blue)"] {
  background: var(--soft-blue) !important;
}

/* The dashboard monthly-letter card explicitly wants the cozier butter
   tone (it's the hero "a new letter" moment). Scope narrower so the
   general retirement above doesn't flatten everything. */
#monthly-letter-card {
  background: var(--lemon-tart) !important;
}

/* Thread-palette color arrays in the portrait view that include
   `var(--dark-gray)` — retired value is still a slate now, AAA-safe.
   Same for the book-badge borders. No rule needed; sed already darkened
   the hex. */

/* Plum → blue family for eyebrow captions + identity chip.
   Applied narrowly so error / destructive plum uses stay untouched. */
.friends-title + p[style*="color:var(--almost-plum)"],
[class*="eyebrow"][style*="color:var(--almost-plum)"] {
  color: var(--deep-blue) !important;
  opacity: 1 !important;
}

/* Identity-chip italic next to names in the Reading Room feed —
   swap plum → deep-blue so it reads as "reader identity" without the
   purple vibe. Matches inline `color:var(--almost-plum)` with italic. */
span[style*="font-style:italic"][style*="color:var(--almost-plum)"] {
  color: var(--deep-blue) !important;
  opacity: 0.95 !important;
}

/* Track-number labels ("Track 1/2/3") were plum@0.7 — visibly fail AAA.
   Promote to blueberry with a safe opacity. */
span[style*="letter-spacing:0.12em"][style*="color:var(--almost-plum)"],
span[style*="letter-spacing:0.14em"][style*="color:var(--almost-plum)"],
span[style*="letter-spacing:0.16em"][style*="color:var(--almost-plum)"] {
  color: var(--blueberry) !important;
  opacity: 0.75 !important;
}

/* Feed-card inner surfaces (Reading Room): alternate antique-white
   and soft-blue for visual rhythm. Using nth-of-type against the
   common feed row container. Scoped to #feed-grid so it doesn't
   bleed into other surfaces. */
#feed-grid > div:nth-of-type(even) {
  background: var(--soft-blue) !important;
}

/* Form inputs + textareas — global 16px floor so iOS doesn't focus-zoom.
   Covers every inline-styled input the audit flagged. */
input[type="text"], input[type="email"], input[type="password"],
input[type="url"], input[type="search"], input[type="tel"],
input[type="number"], textarea, select {
  font-size: 16px !important;
}

/* Legend dot in portrait-view using the retired grey — now reads as
   a slate dot with safe text contrast. */
div[style*="background:var(--dark-gray)"] + span[style*="color:var(--blueberry)"][style*="opacity:0.6"] {
  opacity: 0.82 !important;
}

/* ============================================================
   EYEBROW SIZE FLOOR — 9-10px caps too small on laptop+
   Bumps any Josefin-Sans caps-letter-spaced caption to 11.5px
   minimum via attribute-selector targeting the inline styles
   the app leans on.
   ============================================================ */
@media (min-width: 1024px) {
  [style*="font-family:var(--font-primary)"][style*="font-size:9px"],
  [style*="font-family:var(--font-primary)"][style*="font-size:9.5px"],
  [style*="font-family:var(--font-primary)"][style*="font-size:10px"],
  [style*="font-family: var(--font-primary)"][style*="font-size: 9px"],
  [style*="font-family: var(--font-primary)"][style*="font-size: 9.5px"],
  [style*="font-family: var(--font-primary)"][style*="font-size: 10px"] {
    font-size: 11.5px !important;
  }
  /* Track-number / identity-chip italic captions at 12-12.5px → 13.5px */
  [style*="font-size:12px"][style*="font-style:italic"],
  [style*="font-size:12.5px"][style*="font-style:italic"] {
    font-size: 13.5px !important;
  }
}

/* ============================================================
   IDENTITY HERO — the one ink surface
   (Survivor of the retired Apr-2026 "Variant 5" color regime: every
   other colored card surface — plum book blocks, soft-blue nightstand,
   butter monthly letter, alternating plum shared shelves — was removed
   Jun 2026 when the warm-paper + white-card dialect landed in
   rp-ui.css. Ink remains reserved for the reader's identity alone.)
   ============================================================ */
#identity-hero {
  background: var(--blueberry) !important;
  border-color: rgba(255,255,255,0.08) !important;
}
#identity-hero > p:first-child {
  color: var(--lemon-tart) !important;
  opacity: 0.95 !important;
}
#identity-hero #identity-hero-title {
  color: var(--antique-white) !important;
}
#identity-hero #identity-hero-description {
  color: var(--antique-white) !important;
  opacity: 0.85 !important;
}
#identity-hero a[href*="portrait_view"] {
  background: var(--lemon-tart) !important;
  color: var(--blueberry) !important;
}
#identity-hero [style*="color:var(--blueberry)"],
#identity-hero [style*="color: var(--blueberry)"],
#identity-hero [style*="color:#2F2A35"] {
  color: var(--antique-white) !important;
}

/* ============================================================
   ACCESSIBILITY KEEPERS (from the Apr-2026 audit)
   ============================================================ */

/* Empty states: 0.5 opacity reads as "disabled"; this is the moment a
   user decides whether to engage. */
.empty-state,
p.empty-state,
[class*="empty-state"] {
  opacity: 0.82 !important;
  font-size: 15px !important;
  line-height: 1.65 !important;
}

/* Placeholders: floor at 0.65 opacity (WCAG-driven). */
input::placeholder,
textarea::placeholder {
  opacity: 0.65 !important;
}

/* Body copy floor on laptop+: bump 11-12px body (not eyebrows). */
@media (min-width: 1024px) {
  p[style*="font-size:11px"]:not([style*="letter-spacing"]),
  p[style*="font-size:12px"]:not([style*="letter-spacing"]),
  span[style*="font-size:11px"]:not([style*="letter-spacing"]),
  span[style*="font-size:12px"]:not([style*="letter-spacing"]) {
    font-size: 14px !important;
  }
}

/* Retired --dark-gray text references — safety net. */
[style*="color:var(--dark-gray)"],
[style*="color: var(--dark-gray)"] {
  color: var(--deep-blue) !important;
}

/* Text guard: anything rendered on an inline soft-blue or butter panel
   keeps blueberry text, however deeply nested. */
[style*="background:var(--soft-blue)"],
[style*="background: var(--soft-blue)"],
[style*="background:var(--lemon-tart)"],
[style*="background: var(--lemon-tart)"] {
  color: var(--blueberry) !important;
}
[style*="background:var(--soft-blue)"] *,
[style*="background: var(--soft-blue)"] *,
[style*="background:var(--lemon-tart)"] *:not(a):not(button),
[style*="background: var(--lemon-tart)"] *:not(a):not(button) {
  color: var(--blueberry) !important;
}

/* ============================================================
   MOBILE AUDIT FIXES — Jun 2026
   Targeted items from the 375-414px usability audit.
   ============================================================ */
@media (max-width: 480px) {
  /* Library + expanded shelves: slimmer covers so ~3 fit per band
     before the horizontal scroll begins. */
  .shelf-book { width: 96px; }
  .tile-cover { width: 96px; height: 144px; }
  .shelf-books { gap: 1rem 0.7rem; }

  /* Fellow Readers: two faces per row, gallery-style. */
  .card-grid { grid-template-columns: repeat(2, 1fr) !important; gap: 0.75rem !important; }
  .reader-avatar { width: 76px !important; height: 76px !important; border-radius: 18px !important; }
}

@media (max-width: 768px) {
  /* Text-entry tap targets: 44px floor (iOS HIG). */
  input[type="search"],
  input[type="text"],
  input[type="url"],
  input[type="email"],
  input[type="password"] {
    min-height: 44px;
  }

  /* Book-detail shelf modal: breathe on narrow phones. */
  .shelf-modal { max-width: calc(100vw - 1.5rem) !important; }

  /* The Reading Room feed well: slightly taller on phones — the page
     chrome above it is shorter there, and the feed is the main event. */
  #feed-grid { max-height: 70vh !important; }
}
