/* Book Radar — light only. Warm paper, ink, one green accent.
   Borders are uniform 1px hairlines; nothing gets a thick edge on one side. */

/* Simonetta, self-hosted. Latin and latin-ext, 400 + 400 italic + 900 — the
   extended subset matters because book titles and author names arrive from the
   catalogues and routinely carry ł, ś, ž and friends.
   SIL Open Font License 1.1 — see fonts/Simonetta-OFL.txt. */
@font-face {
  font-family: 'Simonetta';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/simonetta-400-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;
}
@font-face {
  font-family: 'Simonetta';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/simonetta-400-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;
}
@font-face {
  font-family: 'Simonetta';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/simonetta-400i-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;
}
@font-face {
  font-family: 'Simonetta';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/simonetta-400i-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;
}
@font-face {
  font-family: 'Simonetta';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url('../fonts/simonetta-900-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;
}
@font-face {
  font-family: 'Simonetta';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url('../fonts/simonetta-900-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;
}

:root {
  /* These are the "Paper & ink" scheme, written out. js/theme.js derives the
     same values from six seed colours and can swap the lot at runtime; the
     block below is what the page looks like before any of that runs, and with
     JavaScript off. Do not hand-edit one line of it — change the seeds and
     paste in what the Colours panel copies out. */
  --paper:        #faf9f6;
  --surface:      #ffffff;
  --surface-sunk: #f4f2ec;

  --ink:          #17171a;
  --ink-2:        #484540;
  --muted:        #7b776f;
  --muted-2:      #9a958b;

  --line:         #e4e1d9;
  --line-strong:  #cfcbbf;

  --accent:       #1d5c4f;
  --accent-deep:  #14453b;
  --accent-line:  #d5e3df;
  --accent-wash:  #eef4f2;
  /* The seed at full strength, for the two places colour is decoration rather
     than information: the brand mark and the progress bar. */
  --accent-vivid: #1d5c4f;

  /* The one blue: a review the model is looking at right now. Nothing else in
     the palette is blue, which is the point — it reads as machine activity
     rather than part of the page. */
  --working:      #1f5fa8;
  --working-wash: #f5f8fb;

  --amber:        #8a6524;
  --amber-wash:   #f9f2e7;

  --on-ink:       #ffffff;   /* text on the ink itself: the skip link, the toast */
  --shadow-rgb:   23, 23, 26;

  --radius:   6px;
  --radius-s: 4px;

  --serif: 'Simonetta', Georgia, 'Iowan Old Style', 'Times New Roman', Times, serif;
  --sans:  -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  --wrap: 1180px;
  --sticky-h: 0px;   /* measured at runtime; see syncStickyOffset() */
}

*, *::before, *::after { box-sizing: border-box; }

/* The browser hides [hidden] with a user-agent rule, which any author rule that
   sets `display` silently beats. .results, .clerk and .clerk-recall all set one,
   so they stayed on screen with the attribute applied — the recall button most
   visibly, since it has no opacity of its own to mask it. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding-inline: 24px;
}


.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--on-ink); padding: 10px 16px;
}
.skip:focus { left: 8px; top: 8px; }

a { color: var(--accent); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ------------------------------------------------------------------ *
 * Masthead
 * ------------------------------------------------------------------ */

.masthead {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.masthead-inner {
  display: flex;
  align-items: baseline;
  gap: 20px;
  flex-wrap: wrap;
  padding-block: 20px 18px;
}

.brand { display: flex; align-items: center; gap: 10px; }

.brand-mark {
  width: 18px; height: 18px;
  border: 1px solid var(--accent);
  border-radius: 50%;
  position: relative;
  flex: none;
}
.brand-mark::after {
  content: '';
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: var(--accent-vivid);
}

.brand-name {
  font-family: var(--serif);
  font-size: 21px;
  letter-spacing: -0.01em;
  font-weight: 900;
}

.brand-tagline {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
}

/* ------------------------------------------------------------------ *
 * Search bar
 * ------------------------------------------------------------------ */

.searchbar {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding-block: 26px 24px;
  position: sticky;
  top: 0;
  z-index: 40;
}

.field-label {
  display: block;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}

.combo { position: relative; }

.field {
  width: 100%;
  font-family: var(--serif);
  font-size: 21px;
  line-height: 1.3;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 14px 92px 14px 16px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field::placeholder { color: var(--muted-2); }
.field:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-wash);
}


.clear-btn {
  position: absolute;
  top: 50%; right: 10px;
  transform: translateY(-50%);
  font: inherit;
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 6px 10px;
  cursor: pointer;
}
.clear-btn:hover { color: var(--ink); border-color: var(--line-strong); }


/* Suggestions ------------------------------------------------------- */

.suggestions {
  position: absolute;
  top: calc(100% + 6px);
  left: 0; right: 0;
  z-index: 50;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: 0 10px 28px rgba(var(--shadow-rgb), 0.10);
  max-height: 60vh;
  overflow-y: auto;
}

.sg-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 10px;
  border-radius: var(--radius-s);
  cursor: pointer;
}
.sg-item:hover, .sg-item.is-active { background: var(--accent-wash); }

.sg-cover {
  width: 34px; height: 50px;
  object-fit: cover;
  flex: none;
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: 2px;
}
.sg-cover-blank { display: block; }

.sg-text { min-width: 0; display: flex; flex-direction: column; }

.sg-title {
  font-family: var(--serif);
  font-size: 16px;
  color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.sg-meta {
  font-size: 13px;
  color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The last row: what you typed, whether or not a catalogue agrees it exists.
   Set apart by a rule above it rather than a different ground, so it reads as
   a way out of the list rather than another book in it.

   Sticky, because the list scrolls at 60vh and eight suggestions push this
   below the fold — an escape hatch you have to scroll to find is not one. */
.sg-free {
  position: sticky;
  bottom: -4px;                    /* cancel the list's own 4px padding */
  background: var(--surface);
  border-top: 1px solid var(--line);
}
.sg-free .sg-title { font-style: italic; color: var(--ink-2); }
.sg-free .sg-cover-blank { opacity: .5; }

.sg-empty {
  padding: 14px 12px;
  color: var(--muted);
  font-size: 14px;
}

/* Recents ----------------------------------------------------------- */


/* Chips ------------------------------------------------------------- */


/* ------------------------------------------------------------------ *
 * Intro
 * ------------------------------------------------------------------ */

.intro { padding-block: 56px 72px; }

.intro-lead { max-width: 660px; }

.intro h1 {
  font-family: var(--serif);
  font-size: clamp(28px, 4vw, 40px);
  line-height: 1.18;
  letter-spacing: -0.02em;
  margin: 0 0 18px;
  font-weight: 900;
}

.intro p {
  margin: 0;
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink-2);
}


/* ------------------------------------------------------------------ *
 * Results layout
 * ------------------------------------------------------------------ */

.results {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 48px;
  padding-block: 40px 80px;
  align-items: start;
  scroll-margin-top: calc(var(--sticky-h) + 16px);
}

.book-pane {
  position: sticky;
  top: calc(var(--sticky-h) + 24px);
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Book card --------------------------------------------------------- */

.book-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
}

.bc-top { display: flex; gap: 16px; }

.bc-cover {
  width: 84px;
  height: 124px;
  object-fit: cover;
  flex: none;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--surface-sunk);
}

.bc-cover-blank {
  display: grid;
  place-items: center;
  font-family: var(--serif);
  font-size: 34px;
  color: var(--muted-2);
}

.bc-head { min-width: 0; }

.bc-title {
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.25;
  margin: 0 0 4px;
  letter-spacing: -0.01em;
  font-weight: 900;
}

.bc-subtitle {
  margin: 0 0 6px;
  font-size: 14px;
  color: var(--muted);
  font-style: italic;
}

.bc-author {
  margin: 0;
  font-size: 16px;
  color: var(--ink-2);
}

.facts {
  margin: 18px 0 0;
  padding: 16px 0 0;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 7px;
}

.fact {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  font-size: 14.5px;
}
.fact dt { color: var(--muted); }
.fact dd {
  margin: 0;
  color: var(--ink);
  text-align: right;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.ratings {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
}

.rating { display: flex; flex-direction: column; }

.rating-score {
  font-family: var(--serif);
  font-size: 21px;
  line-height: 1.1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.rating-of { font-size: 13px; color: var(--muted-2); }

.rating-src { font-size: 12px; color: var(--muted); margin-top: 2px; }

/* Panels ------------------------------------------------------------ *
 *
 * The shape the Prices and Podcasts blocks are built from. It was the Swedish
 * edition card's own styling until that card went — the book card answers the
 * Swedish question in a single row now — and the shell is what was worth
 * keeping.
 * ------------------------------------------------------------------ */

.ident {
  background: var(--accent-wash);
  border: 1px solid var(--accent-line);
  border-radius: var(--radius);
  padding: 16px 18px;
}

.ident-head {
  margin: 0 0 8px;
  font-size: 11.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-deep);
  font-weight: 600;
}



.ident-note { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--muted); }

.ident-none { margin: 0 0 8px; font-size: 15px; color: var(--ink-2); }


.ident-link {
  display: inline-block;
  margin-top: 10px;
  font-size: 13px;
  color: var(--accent-deep);
}

/* Prices ------------------------------------------------------------ *
 *
 * Sits under the edition panels and borrows their shape, because it answers
 * the next question in the same breath: this is the book, here is what it
 * costs. One line per format, cheapest first.
 * ------------------------------------------------------------------ */

/* It arrives late — after the sweep — into a column the reader has already
   settled on, so it announces itself rather than appearing between blinks:
   the panel rises and fades, then the rows follow it one at a time. */
.prices {
  margin-bottom: 16px;
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .32s ease, transform .32s ease;
}
.prices.is-in { opacity: 1; transform: none; }

.prices.is-in .price-row {
  animation: priceIn .34s cubic-bezier(.22, .8, .3, 1) backwards;
  animation-delay: calc(var(--i) * 65ms + 120ms);
}

@keyframes priceIn {
  from { opacity: 0; transform: translateY(-7px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .prices { transition: none; }
  .prices.is-in .price-row { animation: none; }
}

.price-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.price-row + .price-row { border-top: 1px solid var(--accent-line); }

/* Only the cheapest shows until asked. The rest are in the list already, so
   unfolding costs nothing but the class. */
.price-row:not(:first-child) { display: none; }
.prices.is-expanded .price-row:not(:first-child) { display: block; }

.price-more {
  margin-top: 9px;
  font: inherit;
  font-size: 12.5px;
  color: var(--accent);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--accent-line);
  padding: 0 0 1px;
  cursor: pointer;
}
.price-more:hover { color: var(--accent-deep); border-bottom-color: var(--accent); }
.price-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.price-link {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  text-decoration: none;
  color: inherit;
}
.price-link:hover .price-what { color: var(--accent-deep); text-decoration: underline; text-underline-offset: 2px; }
.price-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

.price-what {
  font-size: 14px;
  color: var(--ink-2);
  min-width: 0;
}

.price-amount {
  flex: none;
  font-size: 16px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.price-kr { font-size: 11.5px; color: var(--muted); margin-left: 2px; }

/* A reduction, shown as the ordinary price struck through beside the real
   one — the only place in the app where anything is struck out. */
.price-was {
  margin-right: 6px;
  font-size: 12.5px;
  color: var(--muted-2);
  text-decoration-thickness: 1px;
}
.price-row.is-reduced .price-amount { color: var(--amber); }

/* The list is the answer; the notes under it are the caveats, so they get a
   rule and some air rather than running straight on from the last price. */
.prices .price-list + .ident-note,
.prices .ident-none + .ident-note { margin-top: 10px; }
.prices .ident-note + .ident-note {
  margin-top: 9px;
  padding-top: 9px;
  border-top: 1px solid var(--accent-line);
}

.price-elsewhere { margin: 6px 0 0; display: flex; gap: 14px; }
.price-elsewhere .ident-link { margin-top: 0; font-size: 12.5px; }

/* Podcasts ---------------------------------------------------------- *
 *
 * Last in the left column, after the editions: by the time you are wondering
 * what an hour of argument about it sounds like, you have already read what it
 * is and what it costs.
 * ------------------------------------------------------------------ */

.podcasts { margin-top: 16px; }

.pod-list { list-style: none; margin: 0; padding: 0; }
.pod-row + .pod-row { margin-top: 2px; padding-top: 10px; border-top: 1px solid var(--accent-line); }

.pod-link {
  display: block;
  padding: 2px 0 8px;
  text-decoration: none;
  color: inherit;
}
.pod-link:hover .pod-title { color: var(--accent-deep); text-decoration: underline; text-underline-offset: 2px; }
.pod-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

.pod-title {
  display: block;
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 1.35;
  color: var(--ink);
}

.pod-meta {
  display: block;
  margin-top: 3px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--muted);
}

.podcasts .ident-note { margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--accent-line); }

/* Reading list ------------------------------------------------------- *
 *
 * The books you chose to keep, as a page of its own at #list. The cache
 * behind it holds every book you have opened; this is the curated subset,
 * and the only part that exports.
 * ------------------------------------------------------------------ */

.masthead-slot { display: flex; align-items: center; gap: 14px; }

.list-link {
  font-size: 13.5px;
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: 1px;
  white-space: nowrap;
}
.list-link:hover { color: var(--accent-deep); border-bottom-color: var(--accent); }
.list-count {
  margin-left: 6px;
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  color: var(--accent-deep);
  background: var(--accent-wash);
  border: 1px solid var(--accent-line);
  border-radius: 10px;
  padding: 1px 7px;
  vertical-align: 1px;
}

.list-view { padding-block: 28px 48px; }
.lv-tools { display: flex; gap: 8px; }

.lv-row {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  gap: 14px;
  align-items: center;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.lv-cover {
  width: 44px; height: 62px;
  object-fit: cover;
  border-radius: 3px;
  background: var(--surface-sunk);
  border: 1px solid var(--line);
}
.lv-cover-blank {
  display: grid; place-items: center;
  font-family: var(--serif); font-size: 22px; color: var(--muted-2);
}
.lv-open {
  display: block;
  text-decoration: none;
  color: inherit;
  min-width: 0;
}
.lv-open:hover .lv-title { color: var(--accent-deep); text-decoration: underline; text-underline-offset: 2px; }
.lv-title {
  display: block;
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.25;
  color: var(--ink);
}
.lv-meta { display: block; margin-top: 3px; font-size: 13px; color: var(--muted); }
.lv-remove {
  font: inherit; font-size: 12.5px;
  color: var(--muted);
  background: none; border: 0; padding: 4px 6px; cursor: pointer;
  border-bottom: 1px solid transparent;
}
.lv-remove:hover { color: var(--amber); border-bottom-color: var(--amber); }
.lv-empty { margin: 24px 0; font-size: 15px; color: var(--muted); max-width: 52ch; line-height: 1.5; }

/* The save button on the book card. */
.bc-save {
  margin-top: 14px;
  width: 100%;
  font-size: 13px;
  padding: 8px 12px;
}
.bc-save.is-saved { color: var(--accent-deep); background: var(--accent-wash); border-color: var(--accent-line); }

/* Provenance on the status line: this came from the store, and how old it is. */
.status-cached { color: var(--muted-2); }

/* ------------------------------------------------------------------ *
 * Reviews pane
 * ------------------------------------------------------------------ */


.reviews-pane { min-width: 0; }

/* "1 outlet unreachable" is a button, because the useful question is always
   which one. */
.status-more {
  font: inherit;
  font-size: inherit;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}
.status-more:hover { color: var(--accent-deep); text-decoration-style: solid; }
.status-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

.unreachable {
  margin-top: 12px;
  padding: 11px 14px;
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.55;
}
.unreachable h4 {
  margin: 0 0 6px;
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted-2);
  font-weight: 600;
}
.unreachable ul { list-style: none; margin: 0; padding: 0; }
.unreachable li { display: flex; gap: 10px; flex-wrap: wrap; padding: 2px 0; }
.unreachable .u-name { color: var(--ink-2); }
.unreachable .u-why { font-family: var(--mono); font-size: 11px; color: var(--muted-2); }
.unreachable p { margin: 7px 0 0; font-size: 12px; color: var(--muted-2); }

.progress { margin-top: 16px; }

.progress-track {
  height: 3px;
  background: var(--surface-sunk);
  border-radius: 2px;
  overflow: hidden;
}

.progress-bar {
  height: 100%;
  width: 0;
  background: var(--accent-vivid);
  transition: width .25s ease;
}

.progress-text {
  margin: 7px 0 0;
  font-size: 12.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* The clerk reads the closing paragraphs back to you. He is drawn on his own
   cream ground and faces left, so the bubble sits to his left and he keeps his
   own background rather than being cut out onto the page. */
/* A footnote marker: [1], [2]. Points at the one review that statement rests
   on; clicking it raises a copy of that review above the bubble. */
.clerk-ref {
  display: inline;
  font-family: var(--sans);
  font-size: 0.72em;
  font-weight: 600;
  line-height: 1;
  vertical-align: 0.35em;          /* sits like a superscript without shifting the line */
  color: var(--accent);
  cursor: pointer;
  padding: 0 1px;
  border-radius: 2px;
  white-space: nowrap;
}
.clerk-ref:hover,
.clerk-ref.is-open {
  color: var(--surface);
  background: var(--accent-deep);
}
.clerk-ref:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* The raised copy of the cited review. Fixed, and positioned from the bubble
   each time it opens, so it sits directly above whatever height it happens to be. */
.clerk-card {
  position: fixed;
  z-index: 70;
  max-height: 46vh;
  overflow-y: auto;
  filter: drop-shadow(0 10px 28px rgba(var(--shadow-rgb), 0.22));
  animation: cardIn .18s ease;
}
.clerk-card .review { margin-bottom: 0; }

@keyframes cardIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

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

/* The clerk floats over the page rather than sitting in the flow: fixed to the
   bottom right, fading in once he has something to say, and dismissed by
   clicking him. The artwork is transparent, so only he and the bubble cover
   what is behind them. */
.clerk {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 60;
  display: flex;
  align-items: flex-end;
  max-width: min(620px, calc(100vw - 40px));
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .3s ease, transform .3s ease;
  /* the gap between bubble and clerk should not swallow clicks on the page */
  pointer-events: none;
}
.clerk > * { pointer-events: auto; }
.clerk.is-in { opacity: 1; transform: none; }

.clerk-bubble {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 152px;                 /* room for the tail to reach his mouth */
  position: relative;
  margin-right: 14px;
  padding: 16px 18px;
  background: var(--accent-wash);
  border: 1px solid var(--accent-line);
  border-radius: 14px;
  box-shadow: 0 6px 28px rgba(var(--shadow-rgb), 0.14);
}

/* The tail, in two layers so it keeps the bubble's border. His mouth is 51% of
   the way down the artwork, so at 257px tall it sits 126px above the bottom
   edge — and both he and the bubble are bottom-aligned. */
.clerk-bubble::before,
.clerk-bubble::after {
  content: '';
  position: absolute;
  bottom: 126px;
  width: 0; height: 0;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}
.clerk-bubble::before {
  right: -11px;
  border-left: 11px solid var(--accent-line);
}
.clerk-bubble::after {
  right: -9px;
  border-left: 10px solid var(--accent-wash);
}

.clerk-tag {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent-deep);
  font-weight: 600;
}

.clerk-verdict {
  margin-bottom: 8px;
  font-size: 10.5px;
  letter-spacing: 0.06em;
  color: var(--surface);
  background: var(--accent-deep);
  border-radius: 3px;
  padding: 2px 7px;
}
.clerk-verdict:empty { display: none; }

.clerk-text {
  margin: 0;
  font-family: var(--serif);
  font-size: 17.5px;
  line-height: 1.55;
  color: var(--ink);
}

.clerk-source {
  margin: 8px 0 0;
  font-size: 11.5px;
  color: var(--muted);
}
.clerk-source:empty { display: none; }

/* He is the dismiss control, so he is a button — keyboard reachable, and with
   a cursor that says he can be clicked. */
.clerk-dismiss {
  flex: none;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: var(--radius);
  transition: transform .15s ease, filter .15s ease;
}
.clerk-dismiss:hover { transform: translateY(2px); filter: brightness(1.04); }
.clerk-dismiss:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.clerk-art {
  width: 190px;
  height: 257px;
  display: block;
  filter: drop-shadow(0 4px 10px rgba(var(--shadow-rgb), 0.18));
}

@media (max-width: 760px) {
  .clerk { right: 12px; bottom: 12px; max-width: calc(100vw - 24px); }
  .clerk-bubble { min-height: 108px; padding: 13px 14px; margin-right: 10px; }
  .clerk-bubble::before, .clerk-bubble::after { bottom: 88px; }
  .clerk-text { font-size: 16px; }
  .clerk-art { width: 132px; height: 179px; }
}

/* The podcast tip ---------------------------------------------------- *
 *
 * The clerk's opposite number. He arrives bottom right with the critics'
 * verdict; she arrives bottom left when one of the two trusted shows has done
 * an episode. Same artwork height as him — 257px — so the two read as the same
 * pair of hands, even though her source image is a different crop.
 * ------------------------------------------------------------------ */

.podrec {
  position: fixed;
  left: 20px;
  bottom: 20px;
  z-index: 60;
  display: flex;
  /* Centred, not bottom-aligned as he is. His bubble holds a paragraph and is
     tall enough that a tail measured up from its foot lands mid-panel; hers
     holds one sentence, and the same sum put the tail out through the top
     corner. Centring the bubble means the tail sits in its middle whatever the
     line length, and the 17px lifts that middle the last few pixels onto her
     mouth. */
  align-items: center;
  max-width: min(560px, calc(100vw - 40px));
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .3s ease, transform .3s ease;
  pointer-events: none;
}
.podrec > * { pointer-events: auto; }
.podrec.is-in { opacity: 1; transform: none; }

/* She is the dismiss control, the way he is. */
.podrec-dismiss {
  flex: none;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.podrec-dismiss:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.podrec-art {
  width: 206px;                      /* 257px tall at the artwork's 600:750 */
  height: 257px;
  display: block;
  filter: drop-shadow(0 4px 10px rgba(var(--shadow-rgb), 0.18));
}

.podrec-bubble {
  flex: 0 1 auto;
  min-width: 0;
  position: relative;
  margin: 0 0 17px 14px;
  padding: 16px 18px;
  background: var(--amber-wash);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  box-shadow: 0 6px 28px rgba(var(--shadow-rgb), 0.14);
}

/* The tail points the other way to his, because she stands on the other side,
   and sits at the bubble's own middle rather than a fixed height off its foot. */
.podrec-bubble::before,
.podrec-bubble::after {
  content: '';
  position: absolute;
  top: 50%;
  margin-top: -9px;
  width: 0; height: 0;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}
.podrec-bubble::before {
  left: -11px;
  border-right: 11px solid var(--line-strong);
}
.podrec-bubble::after {
  left: -9px;
  border-right: 10px solid var(--amber-wash);
}

.podrec-tag {
  margin: 0 0 8px;
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--amber);
  font-weight: 600;
}

.podrec-text {
  margin: 0;
  font-family: var(--serif);
  font-size: 17.5px;
  line-height: 1.55;
  color: var(--ink);
}

/* On a phone the two of them cannot stand side by side, so she goes above him
   rather than shrinking — the point of matching his height is lost if she only
   matches it on a desktop. Her artwork stays 257px; only the bubble tightens. */
@media (max-width: 760px) {
  .podrec { left: 12px; bottom: 290px; max-width: calc(100vw - 24px); }
  .podrec-bubble { padding: 13px 14px; margin: 0 0 17px 10px; }
  .podrec-text { font-size: 16px; }
}

/* Once he has been sent away, a small page icon takes his place in the corner
   so the summary can be called back. Same corner, same z-index, so one replaces
   the other rather than the two ever sitting side by side. */
.clerk-recall {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 60;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  box-shadow: 0 4px 16px rgba(var(--shadow-rgb), 0.14);
  cursor: pointer;
  transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
}
.clerk-recall:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: 0 7px 20px rgba(var(--shadow-rgb), 0.18);
}
.clerk-recall:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.clerk-recall svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: var(--accent-deep);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 760px) {
  .clerk-recall { right: 12px; bottom: 12px; }
}

.reviews-list { margin-top: 20px; }

.review-items {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The blurb ---------------------------------------------------------- *
 *
 * What the book is about, above the list, while the sweep is still running.
 * Deliberately not a card: it is context, not a result, and a bordered block
 * here would read as the first review.
 * ------------------------------------------------------------------ */

.blurb {
  margin: 14px 0 18px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}

.blurb-label {
  margin: 0 0 6px;
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.blurb-body { display: block; }
.blurb.is-hidden .blurb-body { display: none; }

.blurb-body p {
  margin: 0 0 9px;
  font-family: var(--serif);
  /* It sits a card’s padding wider than the quotes below it, so at the same
     size it reads a touch longer — 83 characters. */
  font-size: 22px;
  line-height: 1.5;
  color: var(--ink-2);
}
.blurb-body p:last-child { margin-bottom: 0; }

.blurb-more {
  margin-top: 8px;
  font: inherit;
  font-size: 12.5px;
  color: var(--accent);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--accent-line);
  padding: 0 0 1px;
  cursor: pointer;
}
.blurb-more:hover { color: var(--accent-deep); border-bottom-color: var(--accent); }
.blurb-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Separate cards rather than one bordered list. The 10px is a margin, not a
   flex gap, so that a card being discarded can collapse its own spacing too —
   a zero-height flex item still takes its gap, which would leave a hole. */
.review {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: 10px;
}
.review:last-child { margin-bottom: 0; }



/* Being looked at by the model: a 2px dashed ring that crawls slowly clockwise.

   It is painted on a pseudo-element rather than as a border or outline, so the
   card does not resize and nothing below it shifts. The two masks cut the fill
   down to a 2px ring that follows the card's own corner radius — a plain
   `border: dashed` cannot be animated, and straight gradient edges would leave
   gaps at the corners. */
.review.is-verifying { position: relative; background: var(--working-wash); }

.review.is-verifying::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  padding: 2px;                       /* the thickness of the ring */
  border-radius: inherit;
  pointer-events: none;
  background: repeating-linear-gradient(
    45deg,
    var(--working) 0 7px,
    transparent 7px 15px
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: ants 700ms linear infinite;
}

@keyframes ants {
  to { background-position: 21.21px 0; }   /* one full stripe cycle at 45 degrees */
}

@media (prefers-reduced-motion: reduce) {
  .review.is-verifying::after { animation: none; }
}

/* Thrown out as a different book: fade, then collapse so the rows below slide
   up into the gap. The height is set in JS because it has to be measured first
   — you cannot transition from auto. */
.review.is-leaving {
  overflow: hidden;
  opacity: 0;
  transform: translateX(-12px);
  margin-bottom: 0;
  /* border-width too, or border-box leaves a 2px sliver at height: 0 */
  border-width: 0;
  transition: height .34s cubic-bezier(.4, 0, .2, 1),
              margin-bottom .34s cubic-bezier(.4, 0, .2, 1),
              border-width .34s cubic-bezier(.4, 0, .2, 1),
              opacity .2s ease,
              transform .24s ease;
}

.review-link {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 15px 18px;
  text-decoration: none;
  color: inherit;
}
.review-link:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Set in the serif, italic and uppercased. Capitals set solid look cramped, so
   they get a little tracking back, and the size drops since uppercase reads
   larger than the same point size in mixed case. */
.review-outlet {
  font-family: var(--serif);
  font-style: italic;
  /* 900 is the heaviest Simonetta ships; asking for more only gets a synthetic
     smear. At 10px the capitals need the extra tracking to stay readable. */
  font-weight: 900;
  font-size: 10px;
  line-height: 1.3;
  letter-spacing: 0.085em;
  text-transform: uppercase;
  color: var(--accent-deep);
}

.review-headline {
  font-family: var(--serif);
  font-size: 25px;
  line-height: 1.28;
  color: var(--ink);
}
.review-link:hover .review-headline { text-decoration: underline; text-underline-offset: 2px; }

.review-top {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

/* The date rides with the outlet rather than sitting in a footer of its own.
   Quieter than the outlet and not set in caps, so the pair reads as one line
   with an emphasis rather than as two competing labels. */
.review-date {
  font-size: 11.5px;
  color: var(--muted-2);
  white-space: nowrap;
}

.rating-badge {
  flex: none;
  margin-left: auto;
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--accent-deep);
  background: var(--accent-wash);
  border: 1px solid var(--accent-line);
  border-radius: 3px;
  padding: 2px 7px;
}

/* No box, and no label. The quote sits straight on the card under the
   headline, which is enough to say what it is. */
.review-closing {
  display: block;
  margin-top: 7px;
}

.closing-text {
  display: block;
  font-family: var(--serif);
  /* Simonetta has a smaller x-height than Georgia, so the quote needed a point
     back to read as comfortably at the same measure. Out of its box it carries
     the card on its own, and took another. */
  /* At 16px this ran to 104 characters a line in a 726px column, half as long
     again as anything you would set a book in. Raising the size rather than
     narrowing the column brings it to 79. */
  font-size: 21px;
  line-height: 1.55;
  color: var(--ink-2);
  quotes: '\201C' '\201D';
}
.closing-text::before { content: open-quote; }
.closing-text::after  { content: close-quote; }


.review-snippet {
  font-size: 16px;
  line-height: 1.55;
  color: var(--muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.reviews-list-quiet .review-headline { font-size: 19px; }
.reviews-list-quiet .review { background: var(--surface-sunk); }

.mentions-wrap { margin-top: 18px; }

.disclosure {
  font: inherit;
  font-size: 13.5px;
  color: var(--ink-2);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line-strong);
  padding: 4px 0;
  cursor: pointer;
}
.disclosure::before {
  content: '+';
  display: inline-block;
  width: 14px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.disclosure[aria-expanded="true"]::before { content: '\2212'; }
.disclosure:hover { color: var(--accent-deep); border-bottom-color: var(--accent); }

.reviews-pane .empty {
  margin: 20px 0 0;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  line-height: 1.6;
  max-width: 68ch;
}

/* ------------------------------------------------------------------ *
 * Sources pane
 * ------------------------------------------------------------------ */

.pane-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line-strong);
}

.pane-head h2 {
  font-family: var(--serif);
  font-size: 29px;
  margin: 0;
  letter-spacing: -0.01em;
  font-weight: 900;
}


.pane-count { margin: 0; font-size: 13.5px; color: var(--muted); }

.pane-side {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}



.btn {
  font: inherit;
  font-size: 13.5px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  padding: 8px 15px;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .12s ease, background .12s ease;
}
.btn:hover { border-color: var(--accent); color: var(--accent-deep); background: var(--accent-wash); }


/* Groups & rows ----------------------------------------------------- */



.empty { color: var(--muted); font-size: 14px; }

/* ------------------------------------------------------------------ *
 * Footer & toast
 * ------------------------------------------------------------------ */

.footer {
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding-block: 28px 40px;
}

.footer-inner { max-width: 760px; }

.footer p { margin: 0 0 9px; font-size: 16px; line-height: 1.55; color: var(--muted); }

.footer-meta { font-size: 13.5px; line-height: 1.5; color: var(--muted-2); }

.footer code {
  font-family: var(--mono);
  font-size: 12px;
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 1px 5px;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translate(-50%, 12px);
  z-index: 90;
  background: var(--ink);
  color: var(--on-ink);
  font-size: 14px;
  padding: 11px 20px;
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(var(--shadow-rgb), 0.22);
  opacity: 0;
  transition: opacity .18s ease, transform .18s ease;
}
.toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* ------------------------------------------------------------------ *
 * Responsive
 * ------------------------------------------------------------------ */

@media (max-width: 1000px) {
  .results { grid-template-columns: 1fr; gap: 32px; }
  .book-pane { position: static; }
  .book-card { display: grid; }
}

@media (max-width: 640px) {
  .wrap { padding-inline: 16px; }
  .searchbar { position: static; padding-block: 20px; }
  .field { font-size: 17px; padding: 12px 84px 12px 13px; }
  .intro { padding-block: 36px 48px; }
  .pane-head { flex-direction: column; align-items: flex-start; gap: 8px; }
  .pane-head h2 { font-size: 25px; }
  .review-link { padding: 14px 15px; }

  /* The sizes above are set for a 726px column. Carried onto a phone they cut
     the quote to 36 characters a line — as unreadable at the short end as 104
     was at the long. These bring it back to the mid-forties. */
  .review-headline { font-size: 21px; }
  .closing-text { font-size: 17px; }
  .blurb-body p { font-size: 17.5px; }
  .review-snippet { font-size: 15px; }
  .reviews-list-quiet .review-headline { font-size: 17px; }
  .footer p { font-size: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}

@media print {
  .searchbar, .footer, .toast, .skip, .btn { display: none; }
  .results { grid-template-columns: 1fr; }
  .review-link { color: #000; }
}
/* ------------------------------------------------------------------ *
 * Colours panel
 *
 * Built by js/theme.js, so any page that loads the script gets it — the
 * styleguide needs it as much as the app does, since that is where colour
 * decisions actually get made.
 * ------------------------------------------------------------------ */

.masthead-slot { margin-left: auto; align-self: center; }
.rg-slot { float: right; }

.theme-launch {
  font: inherit;
  font-size: 12.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 5px 11px;
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.theme-launch:hover { color: var(--accent-deep); border-color: var(--accent-line); }
.theme-launch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.theme-launch.is-floating { position: fixed; top: 16px; right: 16px; z-index: 60; background: var(--surface); }

.theme-lab {
  position: fixed;
  top: 64px;
  right: 20px;
  z-index: 70;
  width: 332px;
  max-height: calc(100vh - 88px);
  overflow-y: auto;
  padding: 18px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: 0 14px 40px rgba(var(--shadow-rgb), 0.16);
}

.tl-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.tl-head h2 {
  margin: 0;
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 900;
  color: var(--ink);
}
.tl-close {
  font: inherit;
  font-size: 12.5px;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 2px;
  cursor: pointer;
}
.tl-close:hover { color: var(--accent-deep); }
.tl-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.tl-presets { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.tl-chip {
  font: inherit;
  font-size: 13px;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 5px 10px;
  cursor: pointer;
}
.tl-chip:hover { border-color: var(--accent-line); color: var(--accent-deep); }
.tl-chip[aria-pressed="true"] {
  color: var(--accent-deep);
  background: var(--accent-wash);
  border-color: var(--accent-line);
  font-weight: 600;
}
.tl-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.tl-custom { margin: 8px 0 0; font-size: 12.5px; color: var(--muted); }

.tl-intro {
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}

.tl-row {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  margin-top: 16px;
}

.tl-swatch {
  flex: none;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  background: none;
  cursor: pointer;
}
.tl-swatch::-webkit-color-swatch-wrapper { padding: 2px; }
.tl-swatch::-webkit-color-swatch { border: 0; border-radius: 2px; }
.tl-swatch::-moz-color-swatch { border: 0; border-radius: 2px; }
.tl-swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.tl-body { min-width: 0; flex: 1; }

.tl-label {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}

.tl-hex {
  width: 100%;
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--ink-2);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 4px 7px;
}
.tl-hex:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent-line); }

.tl-note { margin: 5px 0 0; font-size: 12px; line-height: 1.45; color: var(--muted); }

.tl-strip { display: flex; gap: 3px; margin-top: 7px; }
.tl-token {
  flex: 1;
  height: 15px;
  border: 1px solid var(--line);
  border-radius: 2px;
}

.tl-readout { margin: 6px 0 0; font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.tl-readout.is-thin { color: var(--amber); }

.tl-foot {
  display: flex;
  gap: 8px;
  margin-top: 20px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.tl-btn { font-size: 13px; padding: 6px 12px; }

@media (max-width: 640px) {
  .theme-lab { right: 12px; left: 12px; width: auto; top: 56px; }
}
