/* ============================================================
   READING ROOM — books design system
   ------------------------------------------------------------
   A serif-only interface that reads like the interior of a
   well-printed book. Single typeface throughout (Newsreader),
   ink on aged paper, no rectangular chrome.
   ============================================================ */

/* ------------------------------------------------------------
   FONTS — Newsreader (Production Type, OFL), self-hosted.
   Six woff2 subsets total: vietnamese, latin-ext, latin × normal
   and italic. The variable font covers all weights (200–800)
   and optical sizes (6–72) so the same family stretches from
   marginalia at 0.75rem to display headings at 5.5rem. The
   browser picks the right subset by unicode-range; books does
   not contact any external font server.
   ------------------------------------------------------------ */

/* italic — vietnamese */
@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/newsreader-italic-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* italic — latin-ext */
@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/newsreader-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* italic — latin */
@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/newsreader-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* normal — vietnamese */
@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/newsreader-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* normal — latin-ext */
@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/newsreader-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* normal — latin */
@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/newsreader-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================
   TOKENS
   ============================================================ */
:root {
  /* color — light: paper and ink */
  --paper: #f4efe3;
  --paper-soft: #e9e1cd;
  --ink: #1a1612;
  --ink-soft: #5a4e3e;
  --margin: #a89880;
  --stamp: #7a1e1e;
  --leaf: #3d6b4a;

  /* type — single Newsreader family for both text and display.
     The variable font's `opsz` axis is selected automatically by the
     browser via font-optical-sizing: auto (the default). The two
     named tokens are kept for clarity at call sites only. */
  --font-text: "Newsreader", "Iowan Old Style", "Palatino Linotype",
               "Book Antiqua", Palatino, Georgia, serif;
  --font-display: "Newsreader", "Iowan Old Style", "Palatino Linotype",
                  "Book Antiqua", Palatino, Georgia, serif;
  --font-mono: "JetBrains Mono", "IBM Plex Mono", ui-monospace,
               "SFMono-Regular", Menlo, monospace;

  /* type scale — minor third (1.2) above body, minor second below */
  --t-marginalia: 0.75rem;
  --t-small: 0.875rem;
  --t-body: 1.0625rem;
  --t-h6: 1.0625rem;
  --t-h5: 1.2rem;
  --t-h4: 1.44rem;
  --t-h3: 1.728rem;
  --t-h2: 2.074rem;
  --t-h1: 2.488rem;
  --t-folio: 2.986rem;
  --t-dropcap: 5.5rem;

  /* leading and tracking */
  --lh-text: 1.55;
  --lh-tight: 1.15;
  --tracking-smcp: 0.06em;
  --tracking-folio: 0.02em;

  /* space scale — fibonacci-ish, in rem */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 5rem;

  /* layout */
  --col-reading: 36rem;
  --col-list: 52rem;
  --rule: 1px solid var(--margin);
  --rule-soft: 1px solid var(--paper-soft);

  /* motion */
  --ease: cubic-bezier(.2, .7, .3, 1);
  --dur: 120ms;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #1a1612;
    --paper-soft: #221d18;
    --ink: #f0e8d6;
    --ink-soft: #b8a989;
    --margin: #6d5e48;
    --stamp: #b04545;
    --leaf: #7fa889;
  }
}

/* manual override (theme.js): wins over the prefers-color-scheme rule. */
[data-theme="light"] {
  --paper: #f4efe3;
  --paper-soft: #e9e1cd;
  --ink: #1a1612;
  --ink-soft: #5a4e3e;
  --margin: #a89880;
  --stamp: #7a1e1e;
  --leaf: #3d6b4a;
}
[data-theme="dark"] {
  --paper: #1a1612;
  --paper-soft: #221d18;
  --ink: #f0e8d6;
  --ink-soft: #b8a989;
  --margin: #6d5e48;
  --stamp: #b04545;
  --leaf: #7fa889;
}

/* ============================================================
   RESET
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  font-size: 17px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body {
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: var(--lh-text);
  font-feature-settings: "kern", "liga", "onum";
  background: var(--paper);
  color: var(--ink);
}

/* a faint paper texture: subtle vertical grain via repeating gradient.
   It's almost imperceptible — its job is to keep the background from
   feeling like a flat color block on a high-DPI screen. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: -1;
  background-image:
    repeating-linear-gradient(
      0deg,
      transparent 0,
      transparent 3px,
      rgba(0, 0, 0, 0.012) 3px,
      rgba(0, 0, 0, 0.012) 4px
    );
}

/* ============================================================
   ELEMENTS
   ============================================================ */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--lh-tight);
  color: var(--ink);
  margin-block: var(--s-5) var(--s-3);
}
h1 { font-size: var(--t-h1); font-weight: 300; letter-spacing: -0.01em; }
h2 { font-size: var(--t-h2); font-weight: 300; letter-spacing: -0.005em; }
h3 { font-size: var(--t-h3); font-weight: 400; }
h4 { font-size: var(--t-h4); font-weight: 500; }
h5 { font-size: var(--t-h5); font-weight: 500; }
h6 {
  font-size: var(--t-marginalia);
  font-family: var(--font-text);
  font-weight: 500;
  font-style: italic;
  font-variant: small-caps;
  letter-spacing: var(--tracking-smcp);
  color: var(--ink-soft);
}

p { margin-block-end: var(--s-4); max-width: var(--col-reading); }
p:last-child { margin-block-end: 0; }

small { font-size: var(--t-small); color: var(--ink-soft); }

a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: var(--margin);
  transition: color var(--dur) var(--ease),
              text-decoration-color var(--dur) var(--ease),
              text-decoration-thickness var(--dur) var(--ease);
}
a:hover {
  color: var(--stamp);
  text-decoration-color: var(--stamp);
  text-decoration-thickness: 2px;
}

em, i { font-style: italic; }
strong { font-weight: 600; }

ul, ol { padding-left: var(--s-5); margin-block-end: var(--s-4); }
li { margin-block-end: var(--s-1); }

hr {
  border: 0;
  border-top: var(--rule);
  margin-block: var(--s-5);
  max-width: var(--col-list);
}

blockquote {
  font-style: italic;
  color: var(--ink-soft);
  border-left: 2px solid var(--margin);
  padding-left: var(--s-4);
  margin-block-end: var(--s-4);
  max-width: var(--col-reading);
}

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  padding: 0 0.2em;
  background: var(--paper-soft);
}

pre {
  font-family: var(--font-mono);
  font-size: var(--t-small);
  background: var(--paper-soft);
  padding: var(--s-4);
  margin-block-end: var(--s-4);
  overflow-x: auto;
  border-left: 2px solid var(--margin);
}
pre code { background: transparent; padding: 0; }

table {
  width: 100%;
  max-width: var(--col-list);
  border-collapse: collapse;
  margin-block-end: var(--s-5);
}
th, td {
  text-align: left;
  padding: var(--s-3) var(--s-4) var(--s-3) 0;
  border-bottom: var(--rule-soft);
}
th {
  font-weight: 500;
  font-style: italic;
  font-variant: small-caps;
  font-size: var(--t-marginalia);
  letter-spacing: var(--tracking-smcp);
  color: var(--ink-soft);
  border-bottom: var(--rule);
}

/* ============================================================
   FORMS — bottom-bordered, no boxes
   ============================================================ */
input, textarea, select, button {
  font: inherit;
  color: inherit;
  background: transparent;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="url"],
input[type="number"],
textarea,
select {
  display: block;
  width: 100%;
  max-width: var(--col-reading);
  /* Small inline-start padding prevents italic letters (f, j, etc.)
     from being clipped by the input content box — glyphs like the
     italic f have left-side overhang that overflows zero-padded
     inputs, cutting the top of the ascender. */
  padding: var(--s-2) 0 var(--s-2) 0.12em;
  border: 0;
  border-bottom: var(--rule);
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: var(--lh-text);
  color: var(--ink);
  transition: border-color var(--dur) var(--ease);
}
input::placeholder, textarea::placeholder {
  color: var(--ink-soft);
  font-style: italic;
}
input:focus, textarea:focus, select:focus {
  outline: 0;
  border-bottom-color: var(--stamp);
  border-bottom-width: 2px;
}

textarea {
  min-height: 8rem;
  resize: vertical;
}

input[type="checkbox"], input[type="radio"] {
  appearance: none;
  width: 0.9rem;
  height: 0.9rem;
  border: 1px solid var(--margin);
  margin-right: var(--s-2);
  vertical-align: -0.1em;
  background: transparent;
}
input[type="checkbox"]:checked {
  background: var(--stamp);
  border-color: var(--stamp);
}
input[type="radio"] {
  border-radius: 50%;
}
input[type="radio"]:checked {
  background: radial-gradient(circle, var(--stamp) 40%, transparent 41%);
}

label {
  display: block;
  font-size: var(--t-marginalia);
  font-style: italic;
  font-variant: small-caps;
  letter-spacing: var(--tracking-smcp);
  color: var(--ink-soft);
  margin-block-end: var(--s-1);
}
label.inline {
  display: inline-flex;
  align-items: center;
  margin-right: var(--s-4);
  font-style: normal;
  font-variant: normal;
  letter-spacing: 0;
  font-size: var(--t-body);
  color: var(--ink);
}

button {
  font-family: var(--font-text);
  font-size: var(--t-body);
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: var(--margin);
  transition: color var(--dur) var(--ease),
              text-decoration-color var(--dur) var(--ease);
}
button:hover:not(:disabled) {
  color: var(--stamp);
  text-decoration-color: var(--stamp);
  text-decoration-thickness: 2px;
}
button:disabled {
  color: var(--ink-soft);
  cursor: not-allowed;
}

/* The single exception: a "Save" submit button gets a larger, bolder
   treatment because it confirms work. Still no rectangle. */
button[type="submit"], .save {
  font-family: var(--font-display);
  font-size: var(--t-h5);
  font-style: italic;
  font-weight: 400;
}

/* ============================================================
   FLASH — one-shot message rendered at the top of the main
   content area. Set via ?flash=<msg> query parameter on the
   redirect target; auto-clears on the next navigation because
   the URL no longer carries the parameter.
   ============================================================ */
.flash {
  max-width: var(--col-list);
  margin: 0 auto var(--s-5);
  padding: var(--s-3) var(--s-5);
  border-inline-start: 2px solid var(--stamp);
  background: var(--paper-soft);
  font-style: italic;
  font-size: var(--t-small);
  color: var(--ink);
}

/* ============================================================
   SITE HEADER — thin top strip with three italic nav items on
   the left (shelf · library · errata) and an upload action on
   the right. No wordmark, no chrome, no background. Just the
   words, a paper-soft rule underneath, and breathing room
   before the page content starts.
   ------------------------------------------------------------
   Active nav link: ink (vs. ink-soft) plus a thin stamp rule
   directly under the word. Hover: stamp color, no rule.
   Upload matches the nav-link voice but carries no is-current
   state — it's an action, not a destination.
   ============================================================ */
.site-header {
  max-width: var(--col-list);
  margin: 0 auto;
  padding: var(--s-5) var(--s-5) var(--s-4);
  border-block-end: var(--rule-soft);
  margin-block-end: var(--s-6);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-5);
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--t-body);
}
.site-header nav {
  display: flex;
  gap: var(--s-6);
}
.site-header a,
.site-header button.site-header-action {
  color: var(--ink-soft);
  text-decoration: none;
  padding-block-end: 2px;
  border-block-end: 1px solid transparent;
  transition: color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
  font: inherit;
  cursor: pointer;
}
.site-header a:hover,
.site-header button.site-header-action:hover {
  color: var(--stamp);
}
.site-header nav a.is-current {
  color: var(--ink);
  border-block-end-color: var(--stamp);
}

/* ============================================================
   PAGE NAV — legacy dropdown chrome, now only used by the
   design-system prototype pages for their own navigation
   between style guide and preview pages. The real site uses
   .site-header (above).
   ------------------------------------------------------------
   Behavior is in design/nav.js (vanilla, ~40 lines, accessible).
   ============================================================ */
.page-nav {
  position: fixed;
  top: var(--s-5);
  right: var(--s-5);
  z-index: 10;
  font-family: var(--font-text);
}

.page-nav__trigger {
  background: transparent;
  border: 0;
  padding: var(--s-1) 0;
  font: inherit;
  font-style: italic;
  font-size: var(--t-small);
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: none;
  transition: color var(--dur) var(--ease);
}
.page-nav__trigger:hover,
.page-nav__trigger:focus,
.page-nav.is-open .page-nav__trigger {
  color: var(--stamp);
  outline: 0;
}
.page-nav__trigger .chev {
  display: inline-block;
  font-size: 0.75em;
  margin-left: 0.2em;
  transition: transform var(--dur) var(--ease);
}
.page-nav.is-open .page-nav__trigger .chev {
  transform: translateY(0.05em) rotate(180deg);
}

.page-nav__panel {
  position: absolute;
  top: 100%;
  right: 0;
  margin: 0;
  margin-top: var(--s-2);
  padding: var(--s-3) var(--s-5);
  list-style: none;
  background: var(--paper);
  border: var(--rule);
  min-width: 11rem;
  text-align: right;
  /* a paper-aged drop hint — barely there */
  box-shadow: 0 2px 0 0 var(--paper-soft);
}
.page-nav__panel li { margin: 0; }
.page-nav__panel a {
  display: block;
  padding: var(--s-1) 0;
  font-style: italic;
  font-size: var(--t-small);
  color: var(--ink-soft);
  text-decoration: none;
  text-underline-offset: 0.2em;
  transition: color var(--dur) var(--ease);
}
.page-nav__panel a:hover {
  color: var(--stamp);
}
.page-nav__panel a.is-current {
  color: var(--ink);
}
.page-nav__panel a.is-current::before {
  content: "→\00a0";
  color: var(--ink-soft);
  font-style: normal;
}

/* ============================================================
   PAGE LAYOUT — book-width column, generous margins
   ============================================================ */
.page {
  max-width: var(--col-list);
  margin: var(--s-7) auto var(--s-8);
  padding-inline: var(--s-5);
}
.page--reading {
  max-width: calc(var(--col-reading) + 8rem);
}

/* ============================================================
   BOOK ENTRY — used in the library list
   ============================================================ */
.book-entry {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--s-2) var(--s-5);
  padding: var(--s-4) 0;
  border-bottom: var(--rule-soft);
}
.book-entry:last-child { border-bottom: 0; }

.book-entry-title {
  font-family: var(--font-display);
  font-size: var(--t-h4);
  font-weight: 400;
  line-height: 1.2;
  margin: 0;
}
.book-entry-title a {
  color: inherit;
  text-decoration: none;
}
.book-entry-title a:hover {
  color: var(--stamp);
}

.book-entry-author {
  grid-column: 1;
  font-style: italic;
  color: var(--ink-soft);
  font-size: var(--t-body);
}
.book-entry-author a, .book-author a, .tag a, .book-marginalia a {
  text-decoration: none;
  color: inherit;
}
.book-entry-author a:hover, .book-author a:hover, .tag a:hover, .book-marginalia a:hover {
  text-decoration: underline;
  text-decoration-color: var(--stamp);
}

.book-entry-meta {
  grid-column: 2;
  grid-row: 1 / span 2;
  text-align: right;
  font-size: var(--t-marginalia);
  font-style: italic;
  font-variant: small-caps;
  letter-spacing: var(--tracking-smcp);
  color: var(--ink-soft);
  align-self: end;
  white-space: nowrap;
}

@media (max-width: 32rem) {
  .book-entry { grid-template-columns: 1fr; }
  .book-entry-meta {
    grid-column: 1;
    grid-row: auto;
    text-align: left;
  }
}

/* ------------------------------------------------------------
   SHELF variant — tighter, progress rule doubles as divider.
   Title drops from h4 to h5, row gap collapses, and the remove
   action hides until hover/focus so the typographic block
   (title / byline / progress) reads as one object.
   ------------------------------------------------------------ */
.book-entry--shelf {
  padding: var(--s-5) 0 0 0;
  grid-template-columns: 1fr auto;
  gap: 0 var(--s-5);
  border-bottom: 0;
  align-items: baseline;
}
.book-entry--shelf .book-entry-title {
  grid-column: 1 / -1;
  font-size: var(--t-h5);
  line-height: 1.15;
}
.book-entry--shelf .book-entry-author {
  grid-column: 1;
  font-size: var(--t-small);
}
.book-entry--shelf .book-entry-meta {
  grid-column: 2;
  grid-row: auto;
  align-self: baseline;
}
.book-entry--shelf .book-entry-meta button[type="submit"] {
  font-family: var(--font-text);
  font-size: var(--t-marginalia);
  font-style: italic;
  font-variant: small-caps;
  font-weight: 400;
  letter-spacing: var(--tracking-smcp);
  color: color-mix(in srgb, var(--ink-soft) 40%, transparent);
  transition: color var(--dur) var(--ease);
}
.book-entry--shelf:hover .book-entry-meta button[type="submit"],
.book-entry--shelf .book-entry-meta button[type="submit"]:focus {
  color: var(--ink);
}
.book-entry--shelf .book-entry-meta button[type="submit"]:hover {
  color: var(--stamp);
}
.book-entry--shelf .progress {
  grid-column: 1 / -1;
  margin-block-start: 0;
}

/* ============================================================
   DELETE CONFIRM — inline two-step destructive action. First
   click shows "delete book"; a second click within 5 seconds
   confirms. No modal, no dialog. The confirm state is stamp
   color and italic; the resting state is ink-soft underline
   matching the rest of the book-action links.
   ============================================================ */
.delete-confirm {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--t-body);
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--margin);
  text-underline-offset: 0.2em;
}
.delete-confirm:hover {
  color: var(--stamp);
  text-decoration-color: var(--stamp);
}
.delete-confirm.is-armed {
  color: var(--stamp);
  text-decoration-color: var(--stamp);
  text-decoration-thickness: 2px;
}
.delete-confirm.is-armed::before {
  content: "really? ";
  font-style: italic;
  color: var(--ink-soft);
}

/* ============================================================
   BOOK DETAIL — cover floats left, metadata flows right
   ============================================================ */
.book {
  display: grid;
  grid-template-columns: 14rem 1fr;
  gap: var(--s-6);
  align-items: start;
}
.book-cover {
  width: 14rem;
  border: var(--rule);
  background: var(--paper-soft);
}
.book-title {
  font-family: var(--font-display);
  font-size: var(--t-h1);
  font-weight: 300;
  line-height: var(--lh-tight);
  margin: 0;
}
.book-author {
  font-family: var(--font-display);
  font-size: var(--t-h4);
  font-style: italic;
  font-weight: 300;
  color: var(--ink-soft);
  margin-block: var(--s-2) var(--s-5);
}
.book-marginalia {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-2) var(--s-4);
  margin-block: 0 var(--s-5);
  padding-block: var(--s-4);
  border-block-end: var(--rule-soft);
  font-size: var(--t-small);
  max-width: var(--col-reading);
}
.book-marginalia dt {
  font-style: italic;
  font-variant: small-caps;
  letter-spacing: var(--tracking-smcp);
  color: var(--ink-soft);
}
.book-marginalia dd { margin: 0; color: var(--ink); }

.book-description {
  font-size: var(--t-body);
  line-height: var(--lh-text);
  max-width: var(--col-reading);
}
.book-description::first-letter {
  font-family: var(--font-display);
  font-size: 5rem;
  font-weight: 200;
  float: left;
  line-height: 0.95;
  padding-right: 0.14em;
  padding-top: 0;
  color: var(--ink);
}

/* ------------------------------------------------------------
   DESCRIPTION REVEAL — for descriptions over 1000 chars, show a
   clamped preview with a one-way "view all" affordance. The
   hidden checkbox expands clamp and hides the label via sibling
   selectors; no JS.
   ------------------------------------------------------------ */
.book-description-reveal {
  max-width: var(--col-reading);
}
.book-description-toggle {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.book-description--clamped {
  max-height: calc(8 * var(--lh-text) * var(--t-body));
  overflow: hidden;
  mask-image: linear-gradient(to bottom, black 80%, transparent);
  -webkit-mask-image: linear-gradient(to bottom, black 80%, transparent);
}
.book-description-label {
  display: block;
  cursor: pointer;
  font-style: normal;
  font-variant: normal;
  letter-spacing: 0;
  color: inherit;
  font-size: inherit;
}
.book-description-toggle:checked ~ .book-description-label {
  cursor: default;
  pointer-events: none;
}
.book-description-toggle:checked ~ .book-description-label .book-description--clamped {
  max-height: none;
  overflow: visible;
  mask-image: none;
  -webkit-mask-image: none;
}

@media (max-width: 40rem) {
  .book { grid-template-columns: 1fr; }
  .book-cover { width: 10rem; margin: 0 auto; }
}

/* ============================================================
   EDIT FORM — bookish two-column form for the metadata editor.
   Labels hang in the right-aligned left column like marginalia,
   inputs flow in the right column. The cursor enters the page as
   body text; the bottom rule turns stamp on focus.
   ============================================================ */
.edit-form {
  display: grid;
  grid-template-columns: 9rem 1fr;
  column-gap: var(--s-5);
  row-gap: var(--s-5);
  align-items: baseline;
  max-width: var(--col-list);
}
.edit-form > label {
  text-align: right;
  margin: 0;
  padding-block-start: var(--s-2);
}
.edit-form > input,
.edit-form > textarea,
.edit-form > select {
  max-width: none;
  font-size: var(--t-h5);
  font-family: var(--font-display);
  font-weight: 300;
}
.edit-form > textarea {
  font-size: var(--t-body);
  font-family: var(--font-text);
  font-weight: 400;
}
.edit-form__cover {
  display: flex;
  gap: var(--s-4);
  align-items: flex-start;
}
.edit-form__cover-thumb {
  width: 5rem;
  aspect-ratio: 2/3;
  border: var(--rule);
  background: var(--paper-soft);
  flex-shrink: 0;
}
.edit-form__cover input[type="file"] {
  font-family: var(--font-text);
  font-size: var(--t-small);
  font-style: italic;
  color: var(--ink-soft);
  border: 0;
  padding: 0;
}
.edit-form__changes {
  grid-column: 2;
  margin: 0;
  font-size: var(--t-small);
}
.edit-form__actions {
  grid-column: 2;
  margin: 0;
  font-style: italic;
  color: var(--ink-soft);
}
.edit-form__actions a {
  font-style: italic;
}

@media (max-width: 36rem) {
  .edit-form {
    grid-template-columns: 1fr;
    row-gap: var(--s-4);
  }
  .edit-form > label {
    text-align: left;
    padding-block-start: 0;
    margin-block-end: calc(-1 * var(--s-3));
  }
  .edit-form__changes,
  .edit-form__actions {
    grid-column: 1;
  }
}

/* ============================================================
   DEVICE ENTRY — token URL is the only place mono is allowed
   ============================================================ */
.device-entry {
  padding: var(--s-4) 0;
  border-bottom: var(--rule-soft);
}
.device-name {
  font-family: var(--font-display);
  font-size: var(--t-h4);
  font-weight: 400;
  font-style: italic;
}
.device-url {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-small);
  color: var(--ink-soft);
  padding: var(--s-2) 0;
  word-break: break-all;
}
.device-meta {
  font-size: var(--t-marginalia);
  font-style: italic;
  font-variant: small-caps;
  letter-spacing: var(--tracking-smcp);
  color: var(--ink-soft);
  margin-right: var(--s-4);
}

/* ============================================================
   TAGS / LABELS — italic small caps, inline
   ============================================================ */
.tag {
  font-style: italic;
  font-variant: small-caps;
  letter-spacing: var(--tracking-smcp);
  font-size: var(--t-marginalia);
  color: var(--ink-soft);
  margin-right: var(--s-3);
}
.tag::before { content: "·\00a0"; opacity: 0.5; }
.tag:first-child::before { content: ""; }

/* a single subtle marker for "currently selected" or "edited" state. */
.stamp {
  color: var(--stamp);
  font-style: italic;
}

/* ============================================================
   PROTOTYPE CHROME — only used by design/index.html and
   design/components/. Stripped from real pages.
   ============================================================ */
.prototype-page {
  max-width: var(--col-list);
  margin: var(--s-6) auto var(--s-8);
  padding-inline: var(--s-5);
}
.prototype-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-5);
  margin-block-end: var(--s-5);
}
.prototype-title h1 {
  font-family: var(--font-display);
  font-size: var(--t-folio);
  font-weight: 200;
  letter-spacing: var(--tracking-folio);
  margin: 0;
}
.prototype-subtitle {
  font-style: italic;
  font-size: var(--t-marginalia);
  font-variant: small-caps;
  letter-spacing: var(--tracking-smcp);
  color: var(--ink-soft);
  margin: var(--s-1) 0 0;
}
.prototype-title-actions {
  display: flex;
  align-items: baseline;
  gap: var(--s-4);
  font-style: italic;
  font-size: var(--t-small);
  color: var(--ink-soft);
}
.prototype-title-actions a {
  color: inherit;
  text-decoration-color: transparent;
}
.prototype-title-actions a:hover {
  color: var(--stamp);
  text-decoration-color: var(--stamp);
}
.prototype-title-actions button {
  font-family: var(--font-text);
  font-style: italic;
  font-size: var(--t-small);
  color: var(--ink-soft);
  background: transparent;
  border: 0;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: transparent;
}
.prototype-title-actions button:hover {
  color: var(--stamp);
  text-decoration-color: var(--stamp);
}

.prototype-toc {
  list-style: none;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  margin-block-end: var(--s-7);
  padding-block-end: var(--s-3);
  border-bottom: var(--rule);
  font-style: italic;
  font-size: var(--t-small);
}
.prototype-toc li { margin: 0; }
.prototype-toc a {
  color: var(--ink-soft);
  text-decoration-color: transparent;
}
.prototype-toc a:hover {
  color: var(--stamp);
  text-decoration-color: var(--stamp);
}

.prototype-section {
  margin-block-end: var(--s-8);
  padding-block-start: var(--s-5);
}
.prototype-section > h2 {
  font-family: var(--font-text);
  font-size: var(--t-marginalia);
  font-style: italic;
  font-variant: small-caps;
  font-weight: 500;
  letter-spacing: var(--tracking-smcp);
  color: var(--ink-soft);
  margin: 0 0 var(--s-4) 0;
  padding-block-end: var(--s-2);
  border-bottom: var(--rule);
}

.prototype-swatches {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: var(--s-4);
}
.prototype-swatch {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}
.prototype-swatch-box {
  aspect-ratio: 3 / 2;
  border: var(--rule);
}
.prototype-swatch-label {
  font-style: italic;
  font-size: var(--t-marginalia);
  color: var(--ink-soft);
}

.prototype-space-scale {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.prototype-space-row {
  display: flex;
  align-items: center;
  gap: var(--s-4);
}
.prototype-space-bar {
  height: 0.6rem;
  background: var(--margin);
}
.prototype-space-label {
  font-style: italic;
  font-size: var(--t-marginalia);
  color: var(--ink-soft);
  min-width: 5rem;
}

/* dev-chrome bar above page previews. Intentionally looks like a
   prototyping environment, not part of the page being previewed. */
.prototype-header {
  display: flex;
  align-items: baseline;
  gap: var(--s-4);
  padding: var(--s-2) var(--s-4);
  background: var(--paper-soft);
  border-bottom: 1px dashed var(--margin);
  font-family: var(--font-mono);
  font-size: var(--t-marginalia);
  color: var(--ink-soft);
}
.prototype-header a { color: inherit; }
.prototype-header a:hover { color: var(--stamp); }
.prototype-header-spacer { flex: 1; }
.prototype-breadcrumb {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
}
.prototype-breadcrumb span { opacity: 0.5; }
.prototype-header button {
  font-family: var(--font-mono);
  font-size: var(--t-marginalia);
  color: inherit;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-decoration: underline;
}

/* ============================================================
   PROGRESS — hair-thin fore-edge rule.
   Used on the shelf under the byline, and on the book page
   between byline and marginalia. All three reading states
   share this element; only the fill width varies.
   ============================================================ */
.progress {
  display: block;
  width: 100%;
  height: 1px;
  background: color-mix(in srgb, var(--margin) 50%, var(--paper-soft));
  margin-block-start: var(--s-2);
}
.progress__fill {
  display: block;
  height: 100%;
  background: var(--leaf);
}
