
/* One page column everywhere: width:100% defeats flex-column shrink-to-fit on
   pages whose body is a flex column (sticky footers) — without it the header
   collapses to content width and the appbar drifts off the shared grid. */
.wrap{ width:100%; max-width:1160px; margin-left:auto; margin-right:auto; box-sizing:border-box; }
/* Shared page rhythm — the vertical spacing between sections on every page.
   Link this AFTER the kit stylesheet so its tokens are already defined and
   these rules can win on source order without needing !important.

   Owner feedback (walkthrough #2, 2026-08-31): home's section spacing read
   "too far apart" — this file's --sect-gap is deliberately tighter than the
   ad hoc clamp(32px,4vw,48px)/clamp(48px,6vw,80px) values pages had been
   hand-rolling per section. Apply the `.sect` class to any top-level page
   section (or `.sect-tight` for a smaller in-page break, e.g. between a hero
   and the strip directly under it) instead of writing a new margin-top.

   This is the foundation piece of a cross-page pass: W1 wires home.html;
   later batches wire find/clubs/profile/shelves onto the same classes so
   rhythm stays consistent app-wide. Keep this file small — layout/columns
   stay in each page's own <style>, only vertical rhythm lives here. */

:root{
  --sect-gap: clamp(22px, 2.6vw, 32px);      /* section-to-section, tightened from the old 32–48px range */
  --sect-gap-tight: clamp(14px, 1.6vw, 20px); /* a closer in-page break, e.g. hero → shelf strip directly under it */
  --sect-gap-loose: clamp(40px, 5vw, 64px);   /* rare: a deliberately larger break (e.g. above the footer) */
}

.sect{ margin-top: var(--sect-gap); }
.sect-tight{ margin-top: var(--sect-gap-tight); }
.sect-loose{ margin-top: var(--sect-gap-loose); }

/* ── Shared appbar + footer (D0, 2026-08-31) ───────────────────────────────
   Every page (book/clubs/find/home/import/profile/shelves) hand-rolled its
   own copy of these rules and they'd started to drift — book.html's wordmark
   was 17px against everyone else's 18px, find.html's nav gap was a flat 24px
   instead of the clamp() the rest used, some pages had the nav a:hover rule
   and some didn't. nav.js renders the markup (.appbar > .wordmark + .nav +
   .who); this is now the ONE place its geometry is defined, so every tab's
   top bar is pixel-identical. wrapped.html hand-codes its own appbar markup
   (it needs an extra year-switcher control nav.js doesn't support) but reuses
   these same class names deliberately, for the same reason.
   Sub-component sizing inside .who (the 44px theme toggle + avatar hit
   target, the notifications panel) is injected by nav.js itself at runtime
   (see ensureStyles() in nav.js) — that half of the appbar was already single-
   sourced; this file closes the other half. */
.appbar{ display:flex; align-items:center; justify-content:space-between; gap:var(--s5); padding:var(--s5) 0; flex-wrap:wrap; }
.wordmark{ font-size:18px; font-weight:800; letter-spacing:-.02em; color:var(--ink); text-decoration:none; flex:0 0 auto; }
.wordmark b{ color:var(--link); }
.nav{ display:flex; gap:clamp(16px,2vw,28px); align-items:center; }
.nav a{ font-size:14.5px; font-weight:650; color:var(--ink-3); text-decoration:none; padding-bottom:3px; border-bottom:2px solid transparent; }
.nav a:hover{ color:var(--ink); }
.nav a[aria-current]{ color:var(--ink); border-color:var(--butter); }
.who{ display:flex; align-items:center; gap:var(--s3); flex:0 0 auto; position:relative; }
/* The 44px theme-toggle + avatar hit-target, shared by every appbar (nav.js's
   rendered markup on 7 pages, and wrapped.html's hand-coded twin). Kit's base
   .iconbtn is 48px with a shadow pill; the appbar variant is smaller, flat,
   and outlined instead — .nav-theme carries that override. */
.nav-theme{ width:44px; height:44px; background:transparent; border:1px solid var(--hair); box-shadow:none; }
.nav-avatar-hit{ width:44px; height:44px; display:grid; place-items:center; border-radius:var(--r-pill); flex:0 0 auto; background:transparent; border:0; cursor:pointer; position:relative; }
.nav-avatar-circle{ width:36px; height:36px; }
/* D5: a signed-in reader's uploaded photo (avatarUrl) can now show anywhere
   a plain .avatar chip renders — kit's base .avatar has no overflow clip, so
   an <img> child would spill past the circle without this. Additive only;
   the initial+color fallback (kit.css's own .avatar rules) is untouched. */
.avatar{ overflow:hidden; }
.avatar img{ width:100%; height:100%; object-fit:cover; display:block; }
.nav-avatar-hit:focus-visible{ outline:2px solid var(--link); outline-offset:2px; }
/* R7 nits (a): a consistent, visible keyboard-focus ring app-wide. Before this, most
   interactive elements had no explicit :focus-visible styling at all (relying on
   whatever the browser default happened to be, which several of this app's own rules —
   e.g. buttons with `outline:none` elsewhere — silently strip). Reuses the same accent
   token (--link) and 2px/2px shape .nav-avatar-hit already established above, so the
   ring reads as one system rather than a patchwork; :focus-visible (not :focus) so a
   mouse click never shows the ring, only real keyboard/AT navigation does. */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible{
  outline:2px solid var(--link); outline-offset:2px;
}
@media (max-width:640px){
  .appbar{ row-gap:var(--s3); }
  .nav{ order:3; width:100%; justify-content:center; gap:clamp(12px,4vw,20px); flex-wrap:wrap; }
}

/* ── D6 · cover-tilt (CSS 3D, shared component treatment) ──────────────────
   A tiny hover/focus perspective tilt on a book cover — reads as a physical
   object you could pick up, not a UI effect. Shared between the home deck
   strip and the shelves grids (both scroll a row of covers a reader taps
   through), so it lives here rather than duplicated per page. Settles back
   flat the instant hover/focus ends (transition, not a hold state); no
   entrance loop, no bounce, transform-only (no layout shift). Gated on
   prefers-reduced-motion: no-preference — with reduced motion the cover
   never leaves its flat resting transform. Not applied to shelves.html's
   .trow (want-to-read list): those rows are drag-reorder targets and already
   carry their own drag transform/transition, and a hover tilt there would
   read as fighting the drag affordance rather than aiding it.
   The transition is !important: every page this class is used on also sets
   its own `transition: opacity …` on the same image (the existing hover
   fade), and a shorthand `transition` from a same- or higher-specificity
   page rule would otherwise silently drop the transform half — this keeps
   the shared effect working regardless of what a page's own rule declares,
   without requiring every page to remember to append `, transform …` to it. */
@media (prefers-reduced-motion: no-preference){
  .cover-tilt{ transition: opacity .16s ease-out, transform .16s ease-out !important; transform: perspective(640px) rotateX(0deg) rotateY(0deg); will-change: transform; }
  .cover-tilt:hover, a:focus-visible > .cover-tilt, button:focus-visible > .cover-tilt{
    transform: perspective(640px) rotateX(2deg) rotateY(-4deg);
  }
}

/* ── Continue-reading strip (goodnight R1 B, prototype-tonight #5) ─────────
   Rendered by nav.js into the [data-continue-strip] div it appends after
   .appbar inside every data-nav mount (reader.html never mounts nav.js at
   all, so the strip never appears there — no extra exclusion rule needed).
   One insertion point for all seven pages that carry the appbar, same as
   D0's own appbar/footer pass above. */
.continue-strip{ display:flex; align-items:center; gap:var(--s3); padding:10px var(--s4); margin-bottom:var(--s3); background:var(--surf-2); border-radius:var(--r-card); }
.continue-strip[hidden]{ display:none; }
.continue-link{ flex:1; min-width:0; display:flex; align-items:center; gap:var(--s3); text-decoration:none; color:inherit; }
.continue-cover{ width:34px; height:50px; border-radius:4px; object-fit:cover; box-shadow:var(--sh-cover); flex:0 0 auto; }
.continue-meta{ min-width:0; display:flex; flex-direction:column; gap:1px; }
.continue-title{ font-size:13.5px; font-weight:700; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.continue-pos{ font-size:12px; color:var(--ink-3); }
.continue-dismiss{ flex:0 0 auto; width:28px; height:28px; display:grid; place-items:center; border-radius:50%; font-size:15px; line-height:1; color:var(--ink-3); }
.continue-dismiss:hover{ background:var(--surf-3); color:var(--ink); }

/* Quiet one-line footer used across the app shell (class="wrap" on the
   <footer>, matching each page's content-width wrapper). Scoped to
   footer.wrap deliberately — it must not touch reader.html's immersive
   .pagefoot, import.html's .closing completion panel, or index.html's
   pre-auth micro-footer, all of which are intentionally different. */
footer.wrap{ margin-top: var(--sect-gap-loose); padding: var(--s6) 0 var(--s8); border-top: 1px solid var(--hair-soft); font-size: 12.5px; color: var(--ink-3); }
