/* Shared reading system: loaded after each surface stylesheet, including shelf shadows. */
:root, :root[data-theme='light'] {
  /* Deep harbour: sea-mist ground, foam-white reading sheets, harbour-teal actions. Every
     pair below is measured at WCAG 2.1 AAA (7:1 text, 3:1 non-text) against every surface it
     can land on. See docs/oceanic-light-palette.md. */
  --bg: #eef4f6; --surface: #ffffff; --surface-2: #dde9ed;
  --want-bg: #e3e9e5; --want-fg: #2c4038; --reading-bg: #cfe6ec; --reading-fg: #123c47;
  --read-bg: #d8e8da; --read-fg: #1d4229; --dnf-bg: #e8e1ea; --dnf-fg: #43334d;
  --text: #0d2a33; --muted: #28454e; --accent: #0b3d4d; --on-accent: #ffffff;
  --accent-hover: #06272f; --accent-soft: #dbeaee; --accent-line: #4f7783;
  --border: #9fbcc5; --border-strong: #5d7c86; --danger: #8a1c2e; --danger-soft: #f7e2e4;
  --sidebar: #eef4f6; --star: #7a5512; --star-empty: #6d8891; --ring: #0b3d4d;
  --ground: #eef4f6; --halo-fg: var(--text); --halo-muted: var(--muted); --halo-accent: var(--accent);
  --halo-shadow: none; --shadow: none; --shadow-lift: none;

  --r: 12px; --r-sm: 6px;

  --ease-out: cubic-bezier(.16,1,.3,1); --ease-spring: var(--ease-out);
  --t-fast: 180ms; --t: 280ms;
  --nav-text: #0d2a33; --nav-label: #28454e; --nav-hover: #e2edf0;
  --nav-selected: #cbe0e6; --nav-selected-text: #0f313b; --nav-focus: #0b3d4d;
  --tidepool: #e2eef1; --sand: #f0e7d7;
}
:root[data-theme='dark'] {
  --want-bg: #2b3545; --want-fg: #e0e7f3; --reading-bg: #322f43; --reading-fg: #e5d9fa;
  --read-bg: #243b48; --read-fg: #ceecf8; --dnf-bg: #3b2e41; --dnf-fg: #eed9f0;
  --bg: #151e2b; --surface: #1d2838; --surface-2: #29364a;
  --text: #edf2fa; --muted: #c4d0e1; --accent: #c6d8f2; --on-accent: #1c2b42;
  --accent-hover: #e0eafa; --accent-soft: #28364b; --accent-line: #869bb9;
  --border: #46556b; --border-strong: #8495ae; --danger: #fac6d5; --danger-soft: #432e40;
  --sidebar: #151e2b; --star: #e1d5b9; --star-empty: #9babbe; --ring: #c6d8f2;
  --ground: #151e2b; --halo-fg: var(--text); --halo-muted: var(--muted); --halo-accent: var(--accent);
  --halo-shadow: none; --shadow: none; --shadow-lift: none;
  --nav-text: #edf2fa; --nav-label: #c4d0e1; --nav-hover: #243247;
  --nav-selected: #2c3d56; --nav-selected-text: #edf2fa; --nav-focus: #c6d8f2;
  --tidepool: #293449; --sand: #303549;
}
html { scroll-padding-block: 6rem 3rem; scrollbar-color: var(--border-strong) var(--bg); }
body { font-family: var(--font-ui); font-size: var(--type-body); line-height: 1.6; color: var(--text); background: var(--bg); }
body::before, .aurora, .stage-note, .reading-note, .status-dot { display: none; }
*, *::before, *::after { box-sizing: border-box; }
::selection { background: var(--accent); color: var(--on-accent); }
input, textarea { caret-color: var(--accent); }
a { text-underline-offset: .22em; text-decoration-thickness: .09em; }
p { max-width: 75ch; }
h1, h2, h3, .display, .page-head h1, .feature-heading h1, .settings-heading h1 {
  font-family: var(--font-ui); font-weight: 700; letter-spacing: normal; text-wrap: balance; line-height: 1.2;
}
h1, .page-head h1, .feature-heading h1 { font-size: var(--type-page); }
h2 { margin-block: 2rem .75rem; }
button, input, select, textarea { font-family: inherit; }
button, .btn, button.btn, .btn.small, .icon-btn, .seg, .segmented button, select,
input:not([type='checkbox']):not([type='radio']), summary, .settings-tab, .menu-item {
  min-height: 44px; font-size: var(--type-body);
}
button, .icon-btn { min-width: 44px; }
/* WebKit ignores min-height on a native <select> (it rendered 23-25px), so the 44px floor
   was missing on iOS, where fingers are the pointer. `height` is honoured, and 2.2em matches
   what Chromium and Firefox compute at each reading size (44 / 44 / ~52px).
   WebKit-only (`-apple-pay-button-style` is WebKit-exclusive) so the other engines are not
   grown. `appearance: none` would also work but drops the native chevron. */
@supports (-apple-pay-button-style: white) {
  select { height: max(44px, 2.2em); }
  .discover-page .discover-search select { height: max(48px, 2.2em); }
}
.btn, button.btn { border-radius: 6px; padding: .6rem 1rem; box-shadow: none; }
.btn.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.btn.primary:hover { background: var(--accent-hover); color: var(--on-accent); border-color: var(--accent-hover); }
.btn.ghost { color: var(--accent); background: transparent; }
input:not([type='checkbox']):not([type='radio']), select, textarea { border-color: var(--border-strong); background-color: var(--surface); color: var(--text); border-radius: 6px; max-width: 100%; }
input::placeholder, textarea::placeholder { color: var(--muted); opacity: 1; }
label, .muted, .small, small { color: var(--muted); }
label:has(input[type='checkbox']), label:has(input[type='radio']) { min-height: 44px; align-content: center; cursor: pointer; }
input[type='checkbox'], input[type='radio'] { accent-color: var(--accent); width: 22px; height: 22px; flex: 0 0 22px; }
:focus-visible { outline: 3px solid var(--ring); outline-offset: 4px; scroll-margin-block: 6rem; }
button:disabled, input:disabled, select:disabled { cursor: not-allowed; }
.skip-link { position: fixed; top: .5rem; left: 1rem; z-index: 1000; padding: .8rem 1rem; background: var(--surface); color: var(--text); transform: translateY(-200%); }
.skip-link:focus { transform: none; }
.eyebrow { display: none; }
.card, .panel, .notice, .filter-panel, .interest-editor, .sharing-settings, .settings-card { background: var(--surface); border-radius: 12px; box-shadow: none; }
.card .card, .panel .panel { border: 0; background: transparent; }
.notice.error { color: var(--danger); background: var(--danger-soft); border-color: var(--danger); }
.page-head, .feature-heading, .feature-page, .settings-workspace, .crumb, .book-main .titles { color: var(--text); text-shadow: none; }
.page-head, .feature-heading { padding-bottom: 1.5rem; margin-bottom: 1.5rem; animation: none; }
.page-head::after, .feature-heading::after, .nav-item.active::before { display: none; }
.page-head p, .feature-heading p { margin-top: .75rem; }
.toolbar { padding: 1rem; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; gap: .75rem; }
.toolbar .search { min-width: min(100%, 16rem); }
.toolbar label { margin: 0; }
.app { gap: 0; }
.app > main { flex: 1; min-width: 0; padding: 2.5rem clamp(1rem,3vw,3rem) 4rem; }
.sidebar { width: 250px; flex: 0 0 250px; padding: 1.5rem 1rem; background: var(--sidebar); color: var(--nav-text); border: 0; }
.sidebar .brand { display: flex; align-items: center; gap: .65rem; padding: .25rem .5rem 1.5rem; margin: 0; color: var(--nav-text); }
.brand-name { font-size: var(--type-card); font-weight: 700; letter-spacing: normal; }
.sidebar .brand-mark { width: 34px; height: 34px; --bg: var(--sidebar); flex: none; }
.sidebar .nav { gap: 1.5rem; }
.sidebar .nav-label { display: block; font: 700 var(--type-body)/1.6 var(--font-ui); letter-spacing: normal; color: var(--nav-label); margin: .5rem .75rem; }
.sidebar .nav-box { background: transparent; border: 0; padding: 0; }
.sidebar .nav-list { margin: 0; }
.sidebar .nav-item { color: var(--nav-text); border-radius: 6px; min-height: 48px; padding: .65rem .75rem; gap: .7rem; font-size: var(--type-body); }
.sidebar .nav-item:hover { background: var(--nav-hover); color: var(--nav-text); }
.sidebar .nav-item.active { background: var(--nav-selected); color: var(--nav-selected-text); font-weight: 700; }
.sidebar .nav-item .count { color: inherit; background: transparent; font: inherit; }
.sidebar :focus-visible { outline-color: var(--nav-focus); }
.sidebar .account { color: var(--nav-text); }
.sidebar .who { color: var(--nav-text); }
.sidebar .new-library { margin-top: .6rem; }
.sidebar-foot { border-color: var(--border); }
.sidebar .menu { background: var(--surface); color: var(--text); }
.sidebar .menu :focus-visible { outline-color: var(--ring); }
.nav-mobile-head, .mobile-app-header { display: none; }
.library-appearance-tools { justify-content: flex-start; margin: .75rem 0 1.5rem; }
/* Zero: the ✕ overhang strip belongs to the grid, not the canvas. Canvas padding narrowed
   the header and Reading-now band too, and put the strip above the header rather than above
   the first shelf row, leaving delete buttons over the now-row and group headings. The strip
   is on .shelf / .shelf-grid below, as .discover-grid does. */
.library-canvas { padding: 0; }
/* The overhang's reserved strip, on whatever owns the first row (each .shelf-grid in
   grouped mode, not .shelf.list, whose ✕ sits inside the row). The right half keeps the last
   column's box inside the appearance host's `contain: layout paint` clip, or part of the
   button goes dead to hit-testing. It must be real width: a negative margin shrinks the host
   and the clip with it. */
.shelf:not(.list):not(.grouped), .shelf-grid { padding: var(--tile-out, 22px) var(--tile-out, 22px) 0 0; }
/* The skeleton reserves the same strip, or the first row jumps --tile-out on load. */
.sk-shelf { padding: var(--tile-out, 22px) var(--tile-out, 22px) 0 0; }
/* The overhang can never exceed the gutter. Inside the appearance host the gutter is
   `--library-gap`, which reader custom CSS may set (shared/feature-policy.json) down to 4px,
   so clamp: a narrow gutter slides the ✕ onto its own cover, never the next book. Clamped
   here, not in the allowlist, which is a security boundary, not a layout fix. */
:host { --tile-out: min(22px, var(--library-gap, 22px)); }
.library-canvas > .reading-scene { display: none; }
.book:not(.add-tile), .book-row, .now-row, .add-tile, .add-row {
  background: var(--surface); backdrop-filter: none; -webkit-backdrop-filter: none;
  box-shadow: none; border: 1px solid var(--border); border-radius: 12px; color: var(--text);
}
.book:not(.add-tile) { padding: .65rem; }
.book .body { padding: .85rem .15rem .25rem; }
.book .title, .book .author, .library-canvas .book .title, .library-canvas .book .author { opacity: 1; color: var(--text); }
.book .author, .library-canvas .book .author { color: var(--muted); }
.book .title { font-size: var(--type-body); line-height: 1.35; }
.book .cover, .book-jacket .cover-lg { border-radius: 5px; box-shadow: none; border-left-width: 1px; }
.cover .placeholder, .cover-lg .placeholder { font-family: var(--font-ui); font-weight: 700; color: var(--text); padding: 1rem; }
.now-row { padding: 1.25rem; gap: 1rem; }
.now-row .now-actions { gap: .6rem; }
.now-row .now-actions .btn:last-child { margin-left: .6rem; }
.now-head h2 { font-family: var(--font-ui); font-size: var(--type-section); text-shadow: none; }
.status, .pill { background: var(--accent-soft); color: var(--text); font: 700 var(--type-body)/1.6 var(--font-ui); letter-spacing: normal; }
.stars, .stars-fill { color: var(--star); }
.stars-base { color: var(--star-empty); }
.star-track { min-height: 44px; }
.book-section-head { flex-wrap: wrap; gap: .5rem; }
.book-main .input-title { font-family: var(--font-ui); letter-spacing: normal; color: var(--text); }
.book-main .input-author { color: var(--muted); }
.book-page-title { font-size: var(--type-section); margin: 0 0 1rem; }
.crumb a { display: inline-flex; align-items: center; min-height: 44px; }
.book-main .card, .book-main .panel { padding: 1.5rem; }
.book-jacket { transform: none; }
.save-bar, .book-savebar { position: static; margin-top: 1.5rem; background: var(--surface); border: 1px solid var(--border-strong); box-shadow: none; padding: 1rem; border-radius: 12px; }
.stats-grid { gap: 0; background: var(--surface); border-radius: 12px; padding: .75rem; }
.stats-grid .card { border: 0; margin: 0; background: transparent; }
.stats-grid .stat { text-shadow: none; padding: 1rem; }
.discover-grid { grid-template-columns: repeat(auto-fill,minmax(180px,1fr)); gap: 2rem 1.25rem; }
.discover-card { border: 0; border-radius: 0; background: transparent; box-shadow: none; padding: 0; }
.discover-card h3 { font-size: var(--type-card); }
.discover-card h3 a { display: flex; min-height: 44px; align-items: center; text-decoration: underline; }
.discover-cover { border: 0; border-radius: 6px; box-shadow: none; }
.discover-author, .recommendation-reason, .feature-tags span { font-size: var(--type-body); color: var(--muted); }
.discover-card .feature-actions { align-items: stretch; }
.discover-card .feature-actions .btn { flex: 1; }
.feature-tags span { color: var(--text); }
/* This file owns the 44px box (the target). The surface belongs to the ornament inside
   (features.css .dismiss-book .x-mark), or the whole box would paint as a circle. */
.dismiss-book { width: 44px; height: 44px; background: none; color: var(--text); }
/* --border-strong: the control-boundary token. --border is a decorative 2.01:1 hairline. */
.dismiss-book .x-mark { background: var(--surface); border-color: var(--border-strong); }
.settings-layout { grid-template-columns: 220px minmax(0,1fr); gap: 2rem; }
.settings-tabs { position: static; background: var(--surface); border-radius: 12px; padding: .5rem; }
.settings-tab { color: var(--text); padding: .8rem; }
.settings-tab[aria-pressed='true'] { background: var(--accent); color: var(--on-accent); }
.settings-card { border: 0; padding: 1.5rem; }
.setting-row { gap: 1rem; padding: 1.25rem 0; }
.setting-row p { font-size: var(--type-body); }
.setting-switch { min-height: 44px; }
.reading-dialog { width: min(540px,calc(100% - 2rem)); max-height: calc(100dvh - 2rem); overflow: auto; background: var(--surface); color: var(--text); border: 1px solid var(--border-strong); border-radius: 12px; padding: 1.5rem; }
.reading-dialog::backdrop { background: #061b21a8; }
.reading-dialog header { display: flex; justify-content: space-between; align-items: center; gap: 1rem; }
.reading-dialog h2 { margin: 0; }
.reading-dialog label { margin: 1.25rem 0 .35rem; }
.reading-dialog select { width: 100%; }
.reading-dialog .reading-check { display: flex; gap: .75rem; align-items: center; }
.reading-dialog p { line-height: 1.6; }
.reading-options { white-space: nowrap; }
html[data-reading-size='large'] { font-size: 125% !important; }
html[data-reading-size='larger'] { font-size: 150% !important; }
html[data-reading-spacing='wide'] p { line-height: 2; margin-block: 1em 2em; letter-spacing: normal; word-spacing: .08em; }
html[data-reading-spacing='wide'] textarea { line-height: 2; }
/* The book record arrives only after its data. Its text is visible in the base state. */
@keyframes guide-arrive { from { transform: translateY(5px); } to { transform: none; } }
#view.guide-arrival { animation: guide-arrive 320ms var(--ease-out); }
.btn, .nav-item, .shelf-btn, .settings-tab { transition: transform var(--t-fast) var(--ease-out); }
.landing .wrap { max-width: 1260px; }
/* The bar is part of the hero's accent room, not a lid on it, so it carries the room's
   ground and no hairline. welcome.css sets the ink and the inverted mark. This sheet has
   to carry the ground itself because it loads last at the same specificity. */
.landing .topbar { position: static; background: var(--accent); border-bottom: 0; backdrop-filter: none; }
.landing .topbar .wrap { flex-wrap: wrap; gap: 1.5rem; padding-block: .4rem; }
.landing .nav-links { flex-wrap: wrap; gap: .75rem; }
.landing .nav-links a { display: inline-flex; align-items: center; min-height: 44px; color: var(--text); }
.landing .nav-links .primary { color: var(--on-accent); }
.landing .hero { background: var(--bg); padding: 4rem 0; overflow: visible; }
.landing .two-col { grid-template-columns: minmax(0,.85fr) minmax(0,1.15fr); gap: 3rem; align-items: center; }
.landing .display { font-family: var(--font-ui); font-size: var(--type-page); font-weight: 700; letter-spacing: normal; line-height: 1.08; }
.landing .display em { font-style: normal; color: var(--accent); }
.landing .lede { font-size: var(--type-card); color: var(--muted); max-width: 48ch; }
.landing .credit { color: var(--muted); font-size: var(--type-body); }
/* Open figures, not boxes. The landing's containers are gone and type carries structure.
   These sit here rather than in welcome.css because this sheet loads last. */
.landing .shelf-stage { background: transparent; border: 0; padding: 0; border-radius: 0; }
.landing .shelf-stage::before, .landing .shelf-stage::after { display: none; }
.landing .mock { transform: none; border: 0; border-radius: 0; box-shadow: none; background: transparent; padding: .25rem; }
/* Shelf name and its line of explanation share one row: under a section heading that
   already names the instrument, two stacked labels above three books is all label. */
.landing .shelf-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem .5rem; margin: 0 0 1rem; }
.landing .shelf-name { margin: 0; font-size: var(--type-body); font-weight: 600; }
.landing .shelf-sub { margin: 0; color: var(--muted); font: var(--type-body)/1.6 var(--font-ui); }
.landing .mock .demo-caption { margin: 1rem 0 0; color: var(--muted); font-size: var(--type-body); }
.landing .mock-body { grid-template-columns: 1fr; gap: 1rem; }
.landing .mock-body > div:first-child { display: flex; flex-wrap: wrap; gap: .5rem; }
.landing .rail-label { display: none; }
.landing .rail-box, .landing .rail-list { display: contents; }
.landing .shelf-btn { width: auto; min-height: 44px; border-radius: 6px; padding: .5rem .75rem; font-size: var(--type-body); }
.landing .shelf-btn[aria-pressed='true'] { color: var(--on-accent); background: var(--accent); }
/* Translucent white over the accent measured 6.07:1 against the white label, under 7:1, so a
   solid deeper well clears it and reads as recessed. */
.landing .shelf-btn[aria-pressed='true'] .ct { background: var(--accent-hover); color: var(--on-accent); }
.landing .mock .grid { max-width: 34rem; }
.landing .tile { background: transparent; border: 0; box-shadow: none; padding: 0; }
/* The two-line lock is derived from the line-height set here, not styles.css's 1.22, or a
   one-line title reserves less than two lines and the authors below it stop aligning. */
.landing .tile .t { font-size: var(--type-body); line-height: 1.4; min-height: calc(var(--type-body) * 1.4 * 2); }
.landing .tile .a { font-size: var(--type-body); color: var(--muted); }
.landing .tile .cover { border-radius: 4px; box-shadow: none; }
/* Air instead of edges. The sections that are not instruments take the same 6rem the
   instrument sections take, so one rhythm runs the whole document. Owned here because
   this sheet loads after welcome.css at the same specificity. */
.landing .sect { padding-block: 6rem; }
.landing .h-sect { font-size: var(--type-page); }
.landing .feature-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 3rem; }
.landing .feature-card { padding: 0; border: 0; border-radius: 0; box-shadow: none; background: transparent; }
.landing .feature-card h3 { font: 700 var(--type-section)/1.6 var(--font-ui); }
.landing .feature-card p { color: var(--muted); }
.landing .rating-demo { background: transparent; border: 0; border-radius: 0; padding: 0; }
.landing .theme-art { display: none; }
.landing .plan { box-shadow: none; background: var(--surface); border-radius: 12px; }
.landing .plan.pro { border-color: var(--accent); }
.landing .tier { background: var(--surface); color: var(--text); box-shadow: none; border-radius: 12px; }
/* Overridden further down, where the reasoning lives, and kept in step. */
.landing .tier.featured { background: var(--surface); border-color: var(--accent); }
.landing .tier .badge { background: var(--accent); color: var(--on-accent); }
.landing .faq-q { color: var(--text); }
.landing .mock, .landing .feature-card.entered { animation: none; }
/* The deal: covers land one after another, so choosing a shelf reads as books being placed
   rather than a panel swapping. welcome.js sets --i, and three tiles put the last one at 120ms. */
.landing .grid:not([hidden]) .tile { animation: guide-arrive 320ms var(--ease-out) calc(var(--i, 0) * 60ms) backwards; }
.landing .plan li, .landing .plan p, .landing .fineprint { color: var(--muted); }
/* The rule divides controls, not sections. It sits between adjacent questions rather than
   running under the last one, and recedes against the open ground. */
.landing .faq-item { box-shadow: none; border-radius: 0; border: 0; }
.landing .faq-item + .faq-item { border-top: 1px solid color-mix(in srgb, var(--border) 55%, var(--bg)); }
.landing .faq-item summary { padding-block: 1rem; }
.landing .bottom-cta { background: var(--accent-soft); }
.landing footer { background: var(--bg); }
@media (max-width: 1050px) {
  .sidebar { width: 220px; flex-basis: 220px; }
  .landing .two-col { grid-template-columns: 1fr; }
  .landing .hero .display { max-width: 18ch; }
  .landing .shelf-stage { max-width: 760px; }
  .settings-layout { grid-template-columns: 1fr; }
  .settings-tabs { flex-direction: row; flex-wrap: wrap; }
}
@media (max-width: 820px) {
  .app { display: block; padding: 0; }
  .app > main { padding: 1.5rem 1rem 3rem; }
  .mobile-app-header { display: flex; align-items: center; justify-content: space-between; gap: .75rem; background: var(--sidebar); color: var(--nav-text); padding: .75rem 1rem; }
  .mobile-app-header a { color: inherit; font-size: var(--type-card); font-weight: 700; }
  .mobile-app-header .btn { background: var(--nav-selected); color: var(--nav-selected-text); }
  .mobile-app-header[hidden] { display: none; }
  .sidebar { display: flex; position: fixed; inset: 0 auto 0 0; z-index: 100; width: min(320px,calc(100% - 56px)); height: 100dvh; overflow: auto; padding: 1rem; box-shadow: none; visibility: hidden; transform: translateX(-100%); transition: transform 280ms cubic-bezier(.16,1,.3,1), visibility 280ms; }
  .sidebar[data-open='true'] { visibility: visible; transform: translateX(0); transition: transform 280ms cubic-bezier(.16,1,.3,1); }
  .sidebar[hidden] { display: none; }
  .nav-backdrop { position: fixed; inset: 0; z-index: 99; background: #061b21a8; visibility: hidden; opacity: 0; transition: opacity 280ms, visibility 280ms; }
  .nav-backdrop[data-open='true'] { visibility: visible; opacity: 1; }
  .nav-mobile-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
  .sidebar .brand, .sidebar .sidebar-foot { position: static; background: transparent; border: 0; padding: .5rem; }
  .sidebar .nav { position: static; inset: auto; flex-direction: column; overflow: auto; padding: .5rem 0; border: 0; background: transparent; flex: 1; gap: 1rem; }
  .sidebar .nav-group, .sidebar .nav-group.shelves { display: flex; flex-direction: column; align-items: stretch; flex: none; overflow: visible; }
  .sidebar .nav-box, .sidebar .nav-list { display: flex; flex-direction: column; gap: .25rem; }
  .sidebar .nav-item { flex-direction: row; flex: none; text-align: left; width: 100%; }
  .sidebar .nav-item .nav-text { display: block; white-space: normal; overflow: visible; }
  .sidebar .nav-item .count { position: static; margin: 0; font-size: var(--type-body); }
  .sidebar .sidebar-foot { flex-direction: column; align-items: stretch; }
  .sidebar-foot #theme .nav-text, .sidebar-foot #ambient-control .nav-text { display: block; }
  .sidebar .sidebar-foot .account-wrap { flex: none; }
  .sidebar .menu { top: auto; bottom: 100%; left: 0; right: 0; }
  .sidebar .shelf-scroll-next { display: none; }
  .toolbar { padding: .75rem; }
  .toolbar select { min-width: 0; flex: 1; }
  .now-row { flex-wrap: wrap; }
  .now-row .now-actions { width: 100%; justify-content: flex-end; }
  .setting-row { grid-template-columns: 1fr; gap: .5rem; }
  .setting-row select, .setting-row input[type='number'], .setting-switch { justify-self: start; width: auto; max-width: 100%; }
  .landing .hero { padding: 2rem 0; }
  .landing .feature-grid { grid-template-columns: 1fr; }
  .landing .shelf-stage { padding: 0; }
  .landing .mock { padding: 1rem; }
  .landing .mock .grid { gap: .75rem; }
  .landing .sect { padding-block: 2.5rem; }
  /* The bar wraps to two rows at this width, so its 1.5rem gap is paid twice. */
  .landing .topbar .wrap { gap: .6rem; }
  .landing .nav-links .btn { display: inline-flex; }
}
@media (max-width: 440px) {
  .discover-grid { grid-template-columns: repeat(2,minmax(0,1fr)); gap: 1.5rem .75rem; }
  .discover-card .feature-actions { flex-direction: column; }
  .landing .cta-row { align-items: stretch; flex-direction: column; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}
/* `:root[data-motion='reduced'] *` never matches <html>, the page scroller (and
   `scroll-behavior` does not inherit), so the in-app Reduce motion switch left smooth
   scrolling on. These two :root selectors fix that. The rail (.nav) was already covered. */
:root[data-motion='reduced'], :root[data-reading-motion='reduced'],
:root[data-motion='reduced'] *, :root[data-motion='reduced'] *::before, :root[data-motion='reduced'] *::after,
:root[data-reading-motion='reduced'] *, :root[data-reading-motion='reduced'] *::before, :root[data-reading-motion='reduced'] *::after,
:host([data-motion='reduced']), :host([data-motion='reduced']) *, :host([data-motion='reduced']) *::before, :host([data-motion='reduced']) *::after {
  animation: none !important; transition: none !important; scroll-behavior: auto !important;
}
@media (forced-colors: active) {
  .btn, .nav-item, .shelf-btn, .settings-tab, .bar { border: 1px solid ButtonText; }
  :focus-visible { outline: 3px solid Highlight; }
  /* A selected tab is a fill in every other mode, and forced colours takes fills away, so
     the journey's lens tabs need the system ring to say which one is open. */
  .nav-item.active, [aria-pressed='true'], [role='radio'][aria-checked='true'],
  [role='tab'][aria-selected='true'] { outline: 2px solid Highlight; }
  /* The two cover ✕ buttons draw their ring on .x-mark and set `outline: none` on the button
     at higher specificity, so forced colours must put the system ring back on .x-mark or
     lose focus indication entirely. */
  .card-remove:focus-visible .x-mark,
  .dismiss-book:focus-visible .x-mark { outline: 3px solid Highlight; }
  .card-remove .x-mark, .dismiss-book .x-mark { border: 1px solid ButtonText; }
  /* The ✕ is drawn with `background: currentColor`, and forced colours forces backgrounds to
     Canvas, which made the ✕ vanish (white on white). A system colour declared here is
     honoured, so no forced-color-adjust opt-out is needed. */
  .card-remove .x-mark::before, .card-remove .x-mark::after,
  .dismiss-book .x-mark::before, .dismiss-book .x-mark::after { background: ButtonText; }
}

/* Settled theme colours also stay readable while navigation moves. */
body, .btn, .nav-item, .shelf-btn, .settings-tab, .seg, .rating-row {
  transition-property: transform;
}
.topbar { background: var(--surface); color: var(--text); }
.topbar a:not(.primary) { color: var(--text); }
.landing .band.rail { background: var(--accent-soft); color: var(--text); }
.landing .band.rail .lede { color: var(--muted); }
.seg.active { background: var(--accent); color: var(--on-accent); }
/* The arriving button keeps the fill, and waits for it. Painting it at the press covered the
   thumb's destination, so the slide read as a second pill rather than as one moving. The
   leaving label waits too, until the thumb has cleared the words rather than the button, since
   switching it under the thumb put muted ink on accent. Both switch rather than fade, as the
   book page's status block does. */
.segmented .seg { transition: transform var(--t-fast) var(--ease-out),
                              color 0s linear calc(var(--t) * .14), background-color 0s; }
.segmented .seg.active {
  transition: transform var(--t-fast) var(--ease-out),
              color 0s linear calc(var(--t) * .35), background-color 0s linear calc(var(--t) * .35);
}
.book-ratings .rating-row.overall { background: var(--accent-soft); }
.sidebar .nav-item { background: transparent; }
.sidebar .nav-item:hover { background: var(--nav-hover); }
.sidebar .nav-item.active { background: var(--nav-selected); color: var(--nav-selected-text); }
.sidebar .account.active .who { color: var(--nav-text); }
.mobile-app-header a, .topbar .brand, footer .brand, footer nav a {
  display: inline-flex; align-items: center; min-height: 44px;
}
.stepper .finish, .rating-clear, .discover-card .feature-actions .btn { min-height: 44px; }
.now-row .cover { flex-shrink: 0; }

/* Review corrections: open reading sheets, durable navigation and text reflow. */
.sidebar { overflow-y: auto; }
.sidebar .nav { flex: none; overflow: visible; gap: .75rem; }
.sidebar .sidebar-foot { flex: none; position: static; margin-top: auto; }
.sidebar .brand { padding-bottom: .75rem; }
.book-page > .book-page-title { grid-column: 1 / -1; margin: 0; }
.now-cover:not(:has(img)) { display: none; }
.book-ratings .stars-base, .book-ratings .stars-track:hover .stars-base { color: var(--muted); }
.book-ratings .aspects .rating-row { border: 0; border-top: 1px solid var(--border); border-radius: 0; padding: 1rem 0; }
.book-ratings .aspects .rating-row:focus-within { background: var(--surface); }
.book-jacket { background: transparent; border: 0; padding: 0; }
.book-jacket .cover-lg, .book-jacket:hover .cover-lg { background: var(--accent-soft); transform: none; }
.book-jacket .cover-lg:not(:has(img)) { border: 1px solid var(--border); padding: 1rem; }
.jacket-spark, .book-sticker { display: none; }
.discover-page .discover-card, .discover-page .discover-card:hover { background: transparent; border: 0; padding: 0; box-shadow: none; transform: none; backdrop-filter: none; }
.discover-page .discover-card h3 { display: block; overflow: visible; }
.topbar .wrap, .topbar .nav-links { flex-wrap: wrap; gap: .75rem; }
.topbar .wrap { padding-block: 1rem; }
.topbar .nav-links a { display: inline-flex; min-height: 44px; align-items: center; }
.mobile-app-header { flex-wrap: wrap; }
.toolbar .search-wrap, .toolbar .search { min-width: 0; max-width: 100%; }
/* The add page's columns must WRAP, not collapse: a flat `min-width: 0` let the hint
   shrink while its sentence kept its width, overflowing 401-440px viewports. `min()` still
   forces the wrap and never exceeds the container. */
.add-target .field { min-width: min(12rem, 100%); max-width: 100%; }
.add-target .small { min-width: min(14rem, 100%); max-width: 100%; }
.toolbar .sort-group { flex-wrap: wrap; }
input, select, textarea { min-width: 0; max-width: 100%; }
.book-page .rating-row { min-width: 0; }
.book-page .stars-track { max-width: 100%; font-size: var(--type-card); }
.book-ratings .rating-row.overall .stars-track { font-size: var(--type-section); }
.book-page .rating-row.overall { grid-template-columns: minmax(0,1fr); }
.book-page .rating-row.overall .rating-side { grid-column: 1; grid-row: 3; flex-direction: row; justify-content: space-between; }
.book-jacket .cover-lg .placeholder { overflow-wrap: anywhere; padding: 0; }
@media (max-width: 820px) {
  .book-page > .book-page-title { grid-row: 1; }
  .book-main > .titles { grid-row: 2; }
  .book-side { grid-row: 3; grid-template-columns: minmax(0,1fr); }
  .book-side .book-jacket { display: none; }
  .book-side .panel { height: auto; }
  .book-ratings .aspects { grid-template-columns: minmax(0,1fr); }
}
@media (max-width: 440px) {
  .landing .rating-demo .rating-line { row-gap: 0; }
  .discover-grid { grid-template-columns: repeat(auto-fit,minmax(min(100%,9rem),1fr)); }
  /* 9rem needs ~412px of viewport before two tracks fit beside a 12px gap, so a 390px phone
     fell to one column and showed three full-width covers. */
  /* The shelf keeps all three covers on one row instead of wrapping 2+1. A shelf is a row,
     and the wrap cost 420px of height for a ragged result. Fixed tracks, not auto-fit, so
     the count cannot change with the viewport. */
  .landing .mock .grid { grid-template-columns: repeat(3,minmax(0,1fr)); gap: .5rem; }
  /* A 101px column wraps title and author, so the caption under each cover is set tight
     enough that the words do not out-measure the book. */
  .landing .mock .tile .t { line-height: 1.25; min-height: calc(var(--type-body) * 1.25 * 2); }
  .landing .mock .tile .a { line-height: 1.3; }
  .landing .mock .grid .tile { min-width: 0; }
  .reading-options { white-space: normal; }
}
@media (max-width: 440px) {
  .topbar .brand { flex-wrap: wrap; max-width: 100%; }
  .topbar .brand-name { overflow-wrap: anywhere; }
  .search-wrap, .search-wrap.big, .sort-group { min-width: 0; max-width: 100%; }
  .sort-group { display: flex; flex-wrap: wrap; }
  .toolbar .sort-group select { width: 100%; flex-basis: 100%; }
  .book-page .stars-track, .book-ratings .rating-row.overall .stars-track { font-size: var(--type-card); letter-spacing: normal; }
  .book-ratings .aspects .rating-row { grid-template-columns: minmax(0,1fr); }
  .landing .rating-demo { padding: 0; }
  .landing .rating-demo .stars-track { font-size: var(--type-card); }
  .legal { overflow-wrap: anywhere; }
}
@media (max-width: 820px) {
  .toolbar .search-wrap { flex: 1 0 100%; width: 100%; }
  .toolbar .search-wrap .search { width: 100%; }
  .toolbar .sort-group { flex: 1 1 auto; }
}

/* Pastel reading surfaces: colour and rules provide structure without elevation. */
.toolbar { background: transparent; border: 0; border-block: 1px solid var(--border); border-radius: 0; padding: 1rem 0; }
.book:not(.add-tile), .book:not(.add-tile):hover {
  background: transparent; border: 0; border-bottom: 1px solid var(--border);
  border-radius: 0; padding: 0 0 1rem; box-shadow: none; transform: none;
}
.landing .tile:hover, .landing .tile:hover .cover,
.landing .feature-card:hover {
  box-shadow: none; transform: none;
}
/* The shelf cover keeps its hover scale and loses only the lift. This direction removes
   elevation, and growing within its own footprint is not that. */
.book:hover .cover { box-shadow: none; }
.now-row { background: var(--tidepool); border: 0; border-radius: 12px; }
.book-row { border: 0; border-bottom: 1px solid var(--border); border-radius: 0; }
/* The progress track (--accent-soft) is 1.04-1.23:1 against the surfaces it sits on, so it
   gets a border (G183/G195) rather than trying to make one pastel out-contrast another. */
.bar { box-shadow: inset 0 0 0 1px var(--border-strong); }
.landing .tier { border: 1px solid var(--border-strong); }
/* The featured tier is a sheet with a ring, not a tinted panel: --accent-soft rendered
   1.01:1 against the --surface-2 band (1.00:1 in dark), so the featured tier read as the
   weaker one. Pro is marked by a 2px --accent border instead (9.48:1). Do not restore a
   tinted fill without measuring it against --surface-2: every soft token in this palette is
   within a percent of the others. */
.landing .tier.featured { background: var(--surface); border: 2px solid var(--accent); }
.menu, .confirm, .toast, .reading-dialog { box-shadow: none; border: 1px solid var(--border-strong); }
.stars-track { min-height: 44px; display: inline-flex; align-items: center; }
.stars-track .stars-fill { display: flex; align-items: center; }
/* Keep content fully opaque during movement, including its text contrast. */
.fold-body, .filter-panel, .sk { animation-name: guide-arrive; animation-duration: 280ms; }
.landing .grid .tile { animation-delay: 0ms; }
.btn:active:not(:disabled) { transform: translateY(1px); }
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--ring); outline-offset: 4px;
}
:root[data-reading-motion='reduced']::view-transition-old(root),
:root[data-reading-motion='reduced']::view-transition-new(root),
:root[data-motion='reduced']::view-transition-old(root),
:root[data-motion='reduced']::view-transition-new(root) { animation: none !important; }
/* Final reflow and control corrections from the desktop / phone review. */
/* The hero heading's size, leading and tracking are typography.css's. It loads after this file
   and names this exact selector, so a rule here would be dead. (One was, until 2026-09-20.) */
.book-page .stepper .finish, .book-ratings .rating-clear { min-height: 44px; }
.book-page .card, .book-page .panel { border-radius: 12px; box-shadow: none; }
.book-page .book-journal { background: var(--surface); }
.book-ratings .stars-fill { top: 0; transform: none; }
.book-main details[open] > .fold-body { animation: guide-arrive 280ms var(--ease-out); }
.book-page .btn:hover, .book-page .btn:active { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .btn:active:not(:disabled) { transform: none; }
}
:root[data-reading-motion='reduced'] .btn:active:not(:disabled),
:root[data-motion='reduced'] .btn:active:not(:disabled),
:host([data-motion='reduced']) .btn:active:not(:disabled) { transform: none; }

/* The sign-in page is full bleed. styles.css says so, but `.app > main` above ties with it
   on specificity and wins on load order, so scope restates it here. */
.app > main:has(.auth-wrap) { padding: 0; }

/* Pricing tiers: the padding nobody declares. No rule gave `.card .tier` padding, so text
sat flush against the border and the 3px/4px-offset focus ring on a stretched button was
sheared off (2.4.7, 2.4.13). The padding buys the ring its room, and the `overflow` reset
keeps a clipping ancestor from re-clipping it. */
.landing .tier { padding: 1.5rem; overflow: visible; }
@media (max-width: 440px) { .landing .tier { padding: 1.15rem; } }

/* Phone composition: spend less space on chrome, retain readable controls and zoom. */
@media (max-width: 540px) {
  .app > main { padding: 1rem 1rem 2rem; }
  .mobile-app-header { padding-block: .5rem; }
  .app .page-head, .app .feature-heading { padding-bottom: 1rem; margin-bottom: 1rem; gap: .75rem; }
  .app h1, .app .page-head h1, .app .feature-heading h1 { font-size: var(--type-section); }
  .app .btn { padding: .4rem .75rem; }
  .app .toolbar .sort-group { gap: .5rem; }
  .app .toolbar .sort-group select { width: auto; flex: 1 1 11rem; }
  .app .now-row, .app .settings-card, .app .book-main .card, .app .book-main .panel { padding: 1rem; }
}

/* ------------------------------------------------------------ book page (Plan 26) */
/* An open page: no card boxes and no divider lines. Spacing and type carry the structure,
   and only form controls keep a boundary. Scoped under .bk-page, which still matches the
   older .book-page rules above, so the ones that would leak in are overridden here. */
.bk-page { display: block; max-width: 1120px; margin-inline: auto; }
.bk-page .bk-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.bk-head { display: grid; grid-template-columns: 180px minmax(0, 1fr); grid-template-rows: auto 1fr; gap: 20px 40px; align-items: start; padding: 8px 0 16px; }
.bk-cover-col { display: flex; flex-direction: column; gap: 20px; min-width: 0; grid-column: 1; grid-row: 1; }
.bk-page .bk-cover-col .cover-lg { width: 180px; border-radius: 5px; box-shadow: none; }
.bk-page .cover-lg .placeholder { aspect-ratio: 2 / 3; display: flex; align-items: center; justify-content: center; padding: .5rem; text-align: center;
  background: var(--accent-soft); border-radius: 5px; overflow-wrap: break-word; hyphens: auto; }
/* After the reading controls in source (focus order), under the cover on screen. The main
   column spans both rows. */
.bk-edition { display: flex; flex-direction: column; gap: 12px; grid-column: 1; grid-row: 2; }
.bk-page h2 { margin: 0; font-size: var(--type-card); font-weight: 600; line-height: 1.25; letter-spacing: normal; }
.bk-edition dl { margin: 0; display: flex; flex-direction: column; gap: 10px; }
.bk-edition dt { color: var(--muted); }
.bk-edition dd { margin: 0; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
.bk-source { margin: 0; color: var(--muted); }
/* A link-styled button. Inline in a sentence it is exempt from the target size (2.5.5). */
.bk-link { border: 0; background: none; padding: 0 2px; font: inherit; font-weight: 600; color: var(--accent); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.bk-link:hover { color: var(--accent-hover); }

.bk-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; grid-column: 2; grid-row: 1 / span 2; }
.bk-titles { display: flex; flex-direction: column; gap: 4px; }
.bk-page .bk-title { margin: 0; font-size: var(--type-page); font-weight: 700; line-height: 1.25; }
.bk-by { margin: 0; font-size: var(--type-card); color: var(--muted); }
.bk-meta { margin: 4px 0 0; color: var(--muted); font-variant-numeric: tabular-nums; }
.bk-genres { list-style: none; margin: -4px 0 -10px; padding: 0; display: flex; flex-wrap: wrap; column-gap: 8px; }
/* The link is the 44px target. The chip is drawn inside it. */
.bk-genre { display: inline-flex; align-items: center; min-height: 44px; text-decoration: none; }
.bk-genre span { display: inline-block; padding: 3px 12px; border-radius: 8px; background: var(--surface); color: var(--accent); font-weight: 600;
  transition: transform 300ms cubic-bezier(.34, 1.3, .64, 1); }
.bk-genre:hover span { transform: translateY(-2px); }

.bk-synopsis { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.bk-synopsis p { margin: 0; max-width: 65ch; max-height: 4.8em; overflow: hidden; transition: max-height 560ms cubic-bezier(.16, 1, .3, 1); }
.bk-synopsis-text { display: block; }
.bk-more { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; margin-left: -12px; padding: 0 12px; border: 0; border-radius: 6px;
  background: transparent; color: var(--accent); font: inherit; font-weight: 600; cursor: pointer; }
.bk-more span { text-decoration: underline; text-underline-offset: 3px; }
.bk-chevron { transition: transform 280ms cubic-bezier(.16, 1, .3, 1); }
.bk-synopsis.open .bk-chevron { transform: rotate(180deg); }

/* Status: equal cells, each a 44px target drawing a 36px block. The droplet runs between. */
.bk-status { position: relative; align-self: flex-start; display: grid; grid-template-columns: repeat(4, 110px); column-gap: 6px; row-gap: 4px; }
/* Labels may wrap: at 150% text or under a text-spacing override "Did not finish" outgrows
   its cell, and the block grows with the button (statusDroplet) rather than the label
   spilling off it. 2px sides keep the bold label on one line at the default size. */
.bk-status-btn { position: relative; z-index: 1; min-height: 44px; padding: 8px 2px; border: 0; border-radius: 10px; background: transparent; color: var(--text);
  font: inherit; line-height: 1.25; text-wrap: balance; cursor: pointer; transition: transform 180ms cubic-bezier(.16, 1, .3, 1); }
.bk-status-btn:active { transform: scale(.94); }
.bk-status-btn.active { color: var(--on-accent); font-weight: 600; }
.bk-status-word { display: inline-block; transition: transform 300ms cubic-bezier(.34, 1.3, .64, 1); }
.bk-status-btn:hover .bk-status-word { transform: translateY(-2px) scale(1.05); }
.bk-status-block, .bk-status-ghost, .bk-drop-block { position: absolute; height: 36px; border-radius: 10px; }
.bk-status-block, .bk-drop-block, .bk-bead { background: var(--accent); }
.bk-status-ghost { background: var(--surface); opacity: 0;
  transition: opacity 180ms ease-out, left 340ms cubic-bezier(.34, 1.3, .64, 1), top 340ms cubic-bezier(.34, 1.3, .64, 1), width 340ms ease-out; }
.bk-status-ghost.on { opacity: 1; }
.bk-status-goo { position: absolute; inset: 0; pointer-events: none; filter: url(#bk-goo); }
.bk-bead { position: absolute; border-radius: 50%; }
.bk-wishlist { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.bk-wishlist:has(> [hidden]:first-child) { display: none; }
.bk-page .bk-wishlist .toggle { width: auto; margin: 0; min-height: 44px; padding: 0 16px; }

/* Progress: a slim bar the handle rides inside. The invisible range input over it keeps the
   44px hit area, the keyboard and the screen-reader value. */
.bk-progress { display: flex; flex-direction: column; gap: 10px; }
.bk-progress-read { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.bk-page-of { font-weight: 600; font-variant-numeric: tabular-nums; }
.bk-progress-read .muted { font-variant-numeric: tabular-nums; }
.bk-progress.no-pages .bk-track, .bk-progress.no-pages .bk-stepper { display: none; }
.bk-progress.no-pages .bk-page-of { font-weight: 400; color: var(--muted); }
.bk-track { --frac: 0; position: relative; height: 24px; margin: 10px 0; border-radius: 999px; background: var(--surface); box-shadow: inset 0 0 0 1px var(--border-strong); }
.bk-fill { position: absolute; left: 0; top: 0; bottom: 0; width: calc(24px + (100% - 24px) * var(--frac)); border-radius: 999px; background: var(--accent);
  transition: width 200ms cubic-bezier(.16, 1, .3, 1); }
.bk-notch { position: absolute; top: 10px; width: 4px; height: 4px; border-radius: 999px; background: var(--border-strong); }
.bk-notch:nth-of-type(1) { left: calc(10px + (100% - 24px) * .25); }
.bk-notch:nth-of-type(2) { left: calc(10px + (100% - 24px) * .5); }
.bk-notch:nth-of-type(3) { left: calc(10px + (100% - 24px) * .75); }
.bk-notch.reached { background: var(--on-accent); }
.bk-burst { position: absolute; left: calc(100% - 12px); top: 12px; width: 0; height: 0; }
.bk-bit { position: absolute; left: 0; top: 0; }
.bk-page .bk-track input[type='range'] { position: absolute; left: 0; top: -10px; width: 100%; height: 44px; margin: 0; padding: 0; opacity: 0; cursor: pointer; }
.bk-knob { position: absolute; top: 4px; left: calc((100% - 24px) * var(--frac) + 4px); width: 16px; height: 16px; border-radius: 999px; background: var(--surface);
  pointer-events: none; transition: left 200ms cubic-bezier(.16, 1, .3, 1), transform 180ms cubic-bezier(.16, 1, .3, 1); }
/* Two-tone (C40): --ring is --accent, so over the fill the ring alone measured 1:1. The
   surface band inside it carries the contrast there, the ring everywhere else. */
.bk-track input:focus-visible ~ .bk-knob { outline: 3px solid var(--ring); outline-offset: 3px; box-shadow: 0 0 0 3px var(--surface); }
.bk-track:active .bk-knob { transform: scale(.88); }
.bk-stepper { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.bk-steps { display: flex; align-items: center; gap: 6px; }
.bk-step { width: 44px; height: 44px; border: 0; border-radius: 999px; background: var(--surface); color: var(--text); font: inherit; font-size: var(--type-card);
  cursor: pointer; transition: transform 180ms cubic-bezier(.16, 1, .3, 1); }
.bk-step:active { transform: scale(.93); }
.bk-page .bk-page-box { width: 64px; min-width: 0; height: 44px; box-sizing: border-box; padding: 0 4px; border: 0; border-bottom: 2px solid var(--border-strong);
  border-radius: 0; background: transparent; box-shadow: none; text-align: center; font: inherit; color: var(--text); font-variant-numeric: tabular-nums; }
.bk-finish { min-height: 44px; padding: 0 12px; }

.bk-dates { display: flex; gap: 16px; flex-wrap: wrap; }
.bk-dates .field { display: flex; flex-direction: column; gap: 4px; margin: 0; }
.bk-dates label { font-weight: 600; }
.bk-page .bk-dates input { width: 180px; min-height: 44px; font-variant-numeric: tabular-nums; }
/* WebKit never matches :focus-visible on a date field (focus sits in its segments), so it drew
   no ring, since a date field is typed into, so :focus is the keyboard case anyway.
   The journey composer's date field is the same quirk, so it shares the rule. */
.bk-page .bk-dates input:focus,
.jr-compose input[type='date']:focus { outline: 3px solid var(--ring); outline-offset: 4px; }
.bk-page .book-live-note { min-height: 1.6em; margin: 0; }

/* Below the header: the journal gets the wide column, the rating and shelf the narrow one. */
.bk-body { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: 64px; padding-top: 24px; align-items: start; }
.bk-page .book-journal { background: transparent; border: 0; border-radius: 0; padding: 0; box-shadow: none; }
.bk-page .book-journal > summary { min-height: 44px; font-size: var(--type-card); }
.bk-page .book-journal .fold-body { display: flex; flex-direction: column; gap: 12px; margin-top: 8px; padding-left: 22px; }
.bk-page .book-journal .field { margin: 0; display: flex; flex-direction: column; gap: 6px; }
.bk-page .journal-note, .bk-page .journal-count { margin: 0; color: var(--muted); }
.bk-page .book-savebar { margin-top: 32px; padding: 0; background: transparent; border: 0; border-radius: 0; box-shadow: none; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.bk-page .book-save-state { flex-grow: 1; color: var(--muted); }
.bk-side { display: flex; flex-direction: column; gap: 24px; min-width: 0; }
.bk-side .field { margin: 0; display: flex; flex-direction: column; gap: 4px; }
.bk-side .field label { font-weight: 600; }

/* Ratings: open rows, no boxes and no dividers. The landing page's demonstration is the
   same control, so it is named beside .bk-page on each rule rather than given a second
   set — a change to how a star looks cannot reach one page and miss the other. The app's
   own selectors are untouched, so no specificity in the book page moves. */
.bk-page .book-ratings { display: flex; flex-direction: column; gap: 16px; }
.bk-page .book-ratings > p { margin: 0; }
.bk-page .book-ratings .rating-row, .bk-page .book-ratings .rating-row.overall, .bk-page .book-ratings .aspects .rating-row, .landing .rating-demo .rating-row {
  display: flex; flex-direction: column; gap: 2px; padding: 0; margin: 0; border: 0; border-radius: 0; background: transparent; }
.bk-page .book-ratings .aspects, .landing .rating-demo .aspects { display: flex; flex-direction: column; gap: 8px; }
.bk-page .book-ratings .rating-row, .landing .rating-demo .rating-row { align-items: flex-start; text-align: left; }
.bk-page .book-ratings [data-el="aspectSummary"] { margin: 0; padding: 0; border: 0; text-align: left; }
.bk-page .rating-row .rating-label, .landing .rating-demo .rating-label { color: var(--text); font-weight: 600; margin: 0; }
.bk-page .rating-line, .landing .rating-demo .rating-line { display: flex; align-items: center; column-gap: 12px; flex-wrap: wrap; }
.bk-page .book-ratings .stars-track, .landing .rating-demo .stars-track { display: inline-flex; width: auto; min-height: 44px; font-size: var(--type-section); line-height: 44px; }
.bk-page .book-ratings .rating-row.overall .stars-track { font-size: var(--type-page); }
.bk-page .rating-value, .landing .rating-demo .rating-value { min-width: 3.6em; color: var(--text); font-variant-numeric: tabular-nums; }
.bk-page .rating-value.muted, .landing .rating-demo .rating-value.muted { color: var(--muted); }
.bk-page .rating-clear, .landing .rating-demo .rating-clear { min-height: 44px; padding: 0 12px; color: var(--accent); font-weight: 600; }
.bk-page .star, .landing .rating-demo .star { position: relative; display: inline-block; width: 1.1em; text-align: center; }
.bk-page .star-lift, .landing .rating-demo .star-lift { position: relative; display: inline-block; transition: transform 300ms cubic-bezier(.34, 1.3, .64, 1); }
.bk-page .star-lift.lit, .landing .rating-demo .star-lift.lit { transform: translateY(-2px) scale(1.06); }
.bk-page .star-lift.under, .landing .rating-demo .star-lift.under { transform: translateY(-4px) scale(1.22); }
.bk-page .star-base, .landing .rating-demo .star-base { color: var(--star-empty); }
.bk-page .star-fill, .landing .rating-demo .star-fill { position: absolute; left: 0; top: 0; width: 100%; color: var(--star); transition: clip-path 220ms cubic-bezier(.16, 1, .3, 1); }
.bk-page .sparks { position: absolute; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none; }
.bk-page .sparks i { position: absolute; left: -.09em; top: -.09em; width: .18em; height: .18em; border-radius: 999px; background: var(--star); opacity: 0; }
/* Springier where linear() exists. The cubic-beziers above are the fallback. */
@supports (transition-timing-function: linear(0, 1)) {
  .bk-page .star-lift, .landing .rating-demo .star-lift, .bk-status-word {
    transition-timing-function: linear(0, 0.065, 0.218, 0.406, 0.593, 0.758, 0.888, 0.981, 1.041, 1.073, 1.083, 1.08, 1.068, 1.053, 1.037, 1.023, 1.011, 1.003, 0.997, 0.994, 0.993, 0.993, 0.994, 0.995, 0.997, 0.998, 0.999, 1, 1);
    transition-duration: 420ms;
  }
}

/* The Edit details dialog. */
.bk-dialog { width: min(640px, calc(100% - 2rem)); max-height: calc(100dvh - 2rem); padding: 1.5rem; border-radius: 12px; background: var(--surface); color: var(--text); }
.bk-dialog::backdrop { background: #061b21a8; } /* the reading dialog's scrim */
.bk-edit-form { display: flex; flex-direction: column; gap: 16px; }
.bk-edit-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; }
.bk-edit-grid .field { margin: 0; display: flex; flex-direction: column; gap: 4px; }
.bk-edit-grid .field.wide { grid-column: 1 / -1; }
.bk-edit-grid label { font-weight: 600; }
.bk-edit-form .form-actions { display: flex; justify-content: flex-end; gap: 12px; }

@media (max-width: 820px) {
  /* The phone order: cover beside the title, then everything else full width, with the
     edition facts after the reading controls. display: contents lets both columns' children
     share one grid. */
  .bk-head { grid-template-columns: 96px minmax(0, 1fr); grid-template-rows: none; column-gap: 16px; row-gap: 16px; }
  .bk-cover-col, .bk-main { display: contents; }
  .bk-page .bk-cover-col .cover-lg { grid-column: 1; grid-row: 1; width: 96px; }
  .bk-page .cover-lg .placeholder { font-size: var(--type-body); }
  .bk-titles { grid-column: 2; grid-row: 1; align-self: end; }
  .bk-page .bk-title { font-size: var(--type-section); }
  .bk-by { font-size: var(--type-body); }
  .bk-main > :not(.bk-titles) { grid-column: 1 / -1; }
  .bk-edition { grid-column: 1 / -1; grid-row: auto; }
  .bk-body { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .bk-side { order: -1; }
  .bk-page .book-journal .fold-body { padding-left: 0; }
  .bk-synopsis p { max-height: 6.4em; }
}
@media (max-width: 540px) {
  .bk-status { grid-template-columns: repeat(2, minmax(0, 142px)); }
  .bk-dates { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .bk-page .bk-dates input { width: 100%; }
  .bk-edit-grid { grid-template-columns: minmax(0, 1fr); }
}
/* Forced colours flatten every fill to Canvas, which erased the progress bar and the status
   block. Here, not in the block above: these must follow the rules they override. The track
   takes the focus ring, as a Highlight ring round the knob would sit on a Highlight fill. */
@media (forced-colors: active) {
  .bk-track { border: 1px solid CanvasText; }
  .bk-step { border: 1px solid ButtonText; } /* as .btn gets above, where the fill was its edge */
  .bk-fill, .bk-status-block, .bk-drop-block, .bk-bead { background: Highlight; }
  .bk-knob { background: Canvas; border: 2px solid CanvasText; }
  .bk-notch { background: CanvasText; }
  .bk-notch.reached { background: HighlightText; }
  .bk-track:has(input:focus-visible) { outline: 3px solid Highlight; outline-offset: 4px; }
  .bk-track input:focus-visible ~ .bk-knob { outline: none; }
  /* Opted out, or the text backplate (Canvas) hides a HighlightText label on its block. */
  .bk-status-btn.active { forced-color-adjust: none; color: HighlightText; }
  .bk-page .star-base, .landing .rating-demo .star-base { color: GrayText; }
  .bk-page .star-fill, .landing .rating-demo .star-fill { color: CanvasText; }
}
