/* main.css — shared design tokens, layers, utilities, and component
   styles for both index.html and stats.html. */

/* ========================================
   @font-face & Design Tokens (outside layers)
   ======================================== */
/* font-display: SpaceMono is short, ornamental masthead/eyebrow copy — `swap`
   is fine. The other three render across many rows; on a PWA with SW
   precache, `optional` skips the font-swap reflow that drives CLS. */
@font-face {
  font-family: 'SpaceMono';
  src: url('space-mono-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'DMSerif';
  src: url('dm-serif-display-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: optional;
}
@font-face {
  font-family: 'WorkSans';
  src: url('work-sans-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: optional;
}
@font-face {
  font-family: 'WorkSans';
  src: url('work-sans-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: optional;
}
@font-face {
  font-family: 'JetBrainsMono';
  src: url('jetbrains-mono-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: optional;
}

:root {
  --c-deep: #1E104E;
  --c-purple: #452E5A;
  --c-orange: #FF653F;
  --c-yellow: #FFC85C;
  --c-white: #FFFFFF;
  --surface: #F4F1F7;
  --surface-alt: #EAE5F0;

  --f-brand: 'SpaceMono', monospace;
  --f-title: 'DMSerif', serif;
  --f-body: 'WorkSans', sans-serif;
  --f-mono: 'JetBrainsMono', monospace;

  --text-xs: 0.7rem;
  --text-sm: 0.8125rem;
  --text-base: 0.9375rem;
  --text-lg: 1.125rem;
  --text-xl: 1.5rem;
  --text-2xl: 2rem;
  --text-3xl: 2.75rem;
  --text-hero: 3.5rem;

  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.25rem;
  --sp-6: 1.5rem;
  --sp-8: 2rem;
}

@layer reset, utility, component;

/* ========================================
   @layer reset
   ======================================== */
@layer reset {
  *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
  /* Native `hidden` must beat layout utilities like `.flex`/`.grid`. */
  [hidden] { display: none !important; }
  body {
    font-family: var(--f-body);
    font-size: var(--text-base);
    color: var(--c-deep);
    background: var(--surface);
    -webkit-font-smoothing: antialiased;
    /* Extend the document into the iOS bottom safe-area strip so
       backgrounds and the footer reach the physical screen edge on
       installed PWAs. Inset is 0 in browser mode, harmless. */
    min-height: calc(100dvh + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
  }
  a { color: inherit; text-decoration: none; }
  button { cursor: pointer; border: none; font: inherit; }
  input { border: none; font: inherit; outline: none; }
  img { display: block; max-width: 100%; }
  ul, ol { list-style: none; }
  dl, dt, dd { margin: 0; }
  sup { font-size: 0.7em; vertical-align: top; }
}

/* ========================================
   @layer utility
   ======================================== */
@layer utility {
  .bg-deep { background: var(--c-deep); }
  .bg-purple { background: var(--c-purple); }
  .bg-orange { background: var(--c-orange); }
  .bg-yellow { background: var(--c-yellow); }
  .bg-white { background: var(--c-white); }
  .bg-surface { background: var(--surface); }
  .bg-surface-alt { background: var(--surface-alt); }

  .color-deep { color: var(--c-deep); }
  .color-purple { color: var(--c-purple); }
  .color-orange { color: var(--c-orange); }
  .color-yellow { color: var(--c-yellow); }
  .color-white { color: var(--c-white); }
  .color-mid { color: var(--c-purple); }
  .color-white-50 { color: rgba(255,255,255,0.5); }
  .color-white-65 { color: rgba(255,255,255,0.65); }

  .font-brand { font-family: var(--f-brand); }
  .font-title { font-family: var(--f-title); }
  .font-body { font-family: var(--f-body); }
  .font-mono { font-family: var(--f-mono); }

  .text-xs { font-size: var(--text-xs); }
  .text-sm { font-size: var(--text-sm); }
  .text-base { font-size: var(--text-base); }
  .text-lg { font-size: var(--text-lg); }
  .text-xl { font-size: var(--text-xl); }
  .text-2xl { font-size: var(--text-2xl); }
  .text-3xl { font-size: var(--text-3xl); }
  .text-hero { font-size: var(--text-hero); }

  .fw-400 { font-weight: 400; }
  .fw-600 { font-weight: 600; }
  .fw-700 { font-weight: 700; }

  .uppercase { text-transform: uppercase; }
  .italic { font-style: italic; }
  .leading-tight { line-height: 1.05; }
  .leading-relaxed { line-height: 1.55; }
  .tracking-sm { letter-spacing: 0.04em; }
  .tracking-wide { letter-spacing: 0.1em; }
  .tracking-wider { letter-spacing: 0.12em; }
  .text-center { text-align: center; }

  .p-1 { padding: var(--sp-1); }
  .p-2 { padding: var(--sp-2); }
  .p-3 { padding: var(--sp-3); }
  .p-4 { padding: var(--sp-4); }
  .p-5 { padding: var(--sp-5); }
  .p-6 { padding: var(--sp-6); }
  .px-2 { padding-inline: var(--sp-2); }
  .px-3 { padding-inline: var(--sp-3); }
  .px-4 { padding-inline: var(--sp-4); }
  .px-5 { padding-inline: var(--sp-5); }
  .py-1 { padding-block: var(--sp-1); }
  .py-2 { padding-block: var(--sp-2); }
  .py-3 { padding-block: var(--sp-3); }
  .py-4 { padding-block: var(--sp-4); }
  .py-5 { padding-block: var(--sp-5); }
  .py-6 { padding-block: var(--sp-6); }
  .pb-2 { padding-bottom: var(--sp-2); }
  .pb-5 { padding-bottom: var(--sp-5); }
  .mt-1 { margin-top: var(--sp-1); }
  .mt-2 { margin-top: var(--sp-2); }
  .mb-3 { margin-bottom: var(--sp-3); }
  .ml-auto { margin-left: auto; }
  .mx-auto { margin-inline: auto; }
  .gap-2 { gap: var(--sp-2); }
  .gap-3 { gap: var(--sp-3); }
  .gap-4 { gap: var(--sp-4); }

  .flex { display: flex; }
  .flex-col { flex-direction: column; }
  .flex-1 { flex: 1; }
  .flex-wrap { flex-wrap: wrap; }
  .items-center { align-items: center; }
  .items-start { align-items: flex-start; }
  .items-stretch { align-items: stretch; }
  .items-baseline { align-items: baseline; }
  .justify-center { justify-content: center; }
  .justify-between { justify-content: space-between; }
  .shrink-0 { flex-shrink: 0; }
  .grid { display: grid; }
  .block { display: block; }
  .hidden { display: none; }

  .w-full { width: 100%; }
  .w-6 { width: 1.5rem; }
  .h-6 { height: 1.5rem; }
  .max-w-app { max-width: 640px; }

  /* List cover: every cover occupies the entire 88×132 column, stretching
     to fill (object-fit: fill) so all covers render at identical size
     regardless of source aspect ratio. The 2:3 aspect-ratio is a fallback
     for placeholders and pre-load sizing. */
  .cover-sm {
    width: 100%;
    height: 100%;
    aspect-ratio: 2 / 3;
    display: block;
    object-fit: fill;
  }
  .cover-lg { width: 132px; height: 198px; aspect-ratio: 2 / 3; object-fit: contain; }
  .score-col-w { width: 64px; }
  .cover-col-w { width: 88px; }
  .meta-label-w { width: 90px; }

  .object-cover { object-fit: cover; }
  .object-contain { object-fit: contain; }
  .object-fill { object-fit: fill; }
  .min-w-0 { min-width: 0; }
  .relative { position: relative; }
}

/* ========================================
   @layer component
   ======================================== */
@layer component {
  /* Top safe-area: with status-bar-style: black-translucent, content
     renders under the status bar / Dynamic Island. Pad the toolbar by the
     reported inset so the brand row never sits behind the camera band.
     Inset is 0 in browser mode, so the rule is safe to apply unconditionally. */
  .toolbar-sticky {
    position: sticky;
    top: 0;
    z-index: 10;
    padding-top: env(safe-area-inset-top, 0px);
  }
  .accent-strip { height: 4px; }

  /* Bottom safe-area: keep the footer content above the iPhone home
     indicator on installed PWAs. The inset is 0 in browser mode. */
  footer { padding-bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px)); }

  .sort-toggle {
    display: inline-flex;
    gap: 2px;
  }

  .sort-btn {
    background: transparent;
    color: var(--c-purple);
    border: none;
    padding: var(--sp-1) var(--sp-2);
    cursor: pointer;
    transition: background 0.1s, color 0.1s;
  }
  .sort-btn:not([aria-pressed="true"]):hover,
  .sort-btn:not([aria-pressed="true"]):focus-visible {
    background: var(--c-yellow);
    color: var(--c-deep);
    outline: none;
  }
  .sort-btn[aria-pressed="true"] {
    background: var(--c-orange);
    color: var(--c-white);
  }

  .nav-link {
    transition: color 0.1s, background 0.1s;
    padding: var(--sp-1) var(--sp-2);
  }
  .nav-link:hover { color: var(--c-yellow); }

  /* Secondary nav strip — sits below the brand/search row on the sticky
     toolbar. Four equal-width section tabs reusing the brutalist palette:
     muted yellow-tinted labels on deep purple, with the active tab
     inverting to white-on-orange. The orange accent strip below ties the
     whole header together visually. */
  .subnav { gap: 0; }
  .subnav-link {
    flex: 1;
    padding: var(--sp-3) var(--sp-2);
    text-align: center;
    text-decoration: none;
    color: rgba(255, 255, 255, 0.55);
    transition: color 0.1s, background 0.1s;
  }
  .subnav-link + .subnav-link {
    box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.05);
  }
  .subnav-link:hover {
    color: var(--c-yellow);
    background: rgba(255, 200, 92, 0.08);
  }
  .subnav-link[aria-current="page"] {
    color: var(--c-white);
    background: var(--c-orange);
  }
  .subnav-link[aria-current="page"]:hover {
    color: var(--c-white);
    background: var(--c-orange);
  }

  .search-input {
    transition: background 0.15s;
    &::placeholder {
      color: var(--c-purple);
      font-family: var(--f-mono);
      font-size: var(--text-xs);
      text-transform: uppercase;
      letter-spacing: 0.08em;
    }
    &:focus {
      background: var(--c-yellow);
    }
  }

  /* ----- Book list (index.html) ----- */
  .book-row {
    display: flex;
    align-items: stretch;
    cursor: pointer;
    min-height: 132px;
    transition: background 0.1s;
    background: var(--c-white);
    /* Off-screen rows skip layout + paint. The intrinsic-size hint keeps
       the scrollbar honest so the page height matches the rendered count.
       Single biggest scroll-perf win on a 100+ row list. */
    content-visibility: auto;
    contain-intrinsic-size: auto 132px;
    &:nth-child(even) { background: var(--surface); }
    &:nth-child(even) .book-cover-col { background: rgba(30,16,78,0.06); }
    &:hover { background: var(--c-yellow); }
    &:hover .book-score { background: var(--c-deep); color: var(--c-yellow); }
    &:hover .book-cover-col { background: rgba(30,16,78,0.08); }
    &.selected { background: var(--surface-alt); }
    &.selected .book-cover-col { background: rgba(30,16,78,0.08); }
  }

  .book-cover-col {
    width: 88px;
    flex-shrink: 0;
    display: flex;
    align-items: stretch;
    justify-content: stretch;
    background: rgba(30,16,78,0.04);
  }

  .book-score {
    font-family: var(--f-mono);
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--c-deep);
    transition: background 0.1s, color 0.1s;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* Score color scale — used by both book-score-N (book list) and
     score-N (stats score chart). */
  .book-score-1, .score-1   { background: hsl(40, 15%, 88%); color: var(--c-deep); }
  .book-score-2, .score-2   { background: hsl(40, 25%, 85%); color: var(--c-deep); }
  .book-score-3, .score-3   { background: hsl(40, 35%, 82%); color: var(--c-deep); }
  .book-score-4, .score-4   { background: hsl(40, 45%, 78%); color: var(--c-deep); }
  .book-score-5, .score-5   { background: hsl(40, 55%, 75%); color: var(--c-deep); }
  .book-score-6, .score-6   { background: hsl(40, 65%, 72%); color: var(--c-deep); }
  .book-score-7, .score-7   { background: hsl(40, 75%, 68%); color: var(--c-deep); }
  .book-score-8, .score-8   { background: hsl(40, 85%, 64%); color: var(--c-deep); }
  .book-score-9, .score-9   { background: hsl(40, 92%, 60%); color: var(--c-deep); }
  .book-score-10, .score-10 { background: hsl(40, 100%, 58%); color: var(--c-deep); }

  .cover-ph { display: flex; align-items: center; justify-content: center; }
  .cover-initials { font-family: var(--f-brand); font-weight: 700; color: rgba(255,255,255,0.85); font-size: 16px; letter-spacing: 0.05em; }
  .cover-initials-lg { font-size: 32px; }
  .ph-0 { background: linear-gradient(160deg, var(--c-orange), var(--c-yellow)); }
  .ph-1 { background: linear-gradient(160deg, var(--c-purple), var(--c-deep)); }
  .ph-2 { background: linear-gradient(160deg, var(--c-deep), var(--c-orange)); }
  .ph-3 { background: linear-gradient(160deg, var(--c-yellow), var(--c-orange)); }
  .ph-4 { background: linear-gradient(160deg, var(--c-purple), var(--c-orange)); }

  /* Text overflow — fixed row height */
  .row-title-text {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .row-subtitle {
    opacity: 0.7;
    margin-top: 1px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .row-original {
    opacity: 0.5;
    margin-top: 1px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .row-author {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .saga-end {
    height: 3px;
    background: var(--c-orange);
  }

  .saga-group .book-row .book-cover-col {
    background: rgba(69,46,90,0.1);
  }
  .saga-group .book-row:nth-child(even) .book-cover-col {
    background: rgba(69,46,90,0.14);
  }

  .row-title {
    display: flex;
    align-items: baseline;
    gap: 6px;
    min-width: 0;
  }
  .row-title-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
  }
  .saga-order {
    margin-left: auto;
    flex-shrink: 0;
  }

  .detail-saga-badge:not([hidden]) {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    margin-top: 0.5rem;
  }

  .detail-grid { display: grid; grid-template-columns: 120px 1fr; }
  .detail-score-number { width: 120px; flex-shrink: 0; padding: var(--sp-3) 0; }

  .meta-row {
    display: flex;
    background: var(--c-white);
    &:nth-child(odd) { background: var(--surface); }
  }

  .close-btn {
    transition: background 0.1s;
    &:hover { background: var(--c-orange); }
  }

  .footer-link {
    text-decoration: none;
    transition: color 0.1s;
    &:hover { color: var(--c-orange); }
  }

  dialog {
    border: none;
    padding: 0;
    position: fixed;
    inset: 0;
    margin: auto;
    max-width: 640px;
    width: 100%;
    height: max-content;
    max-height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--c-white);
    &::backdrop { background: rgba(30,16,78,0.6); }
    opacity: 1;
    transform: scale(1);
    transition: opacity 0.2s ease, transform 0.2s ease,
                overlay 0.2s ease allow-discrete,
                display 0.2s ease allow-discrete;
    @starting-style { opacity: 0; transform: scale(0.95); }
    &:not([open]) { opacity: 0; transform: scale(0.95); }
  }

  .help-list div {
    &:nth-child(even) { background: var(--surface); }
  }

  .detail-nav {
    display: none;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    border: none;
    background: rgba(30, 16, 78, 0.55);
    color: var(--c-white);
    font-size: 18px;
    cursor: pointer;
    z-index: 1;
    &:active { background: rgba(30, 16, 78, 0.8); }
  }
  .detail-nav-prev { left: 4px; }
  .detail-nav-next { right: 4px; }
  .detail-nav[disabled] { opacity: 0.25; pointer-events: none; }

  /* ----- Stats page (stats.html) — dashboard treatment ----- */
  /* All major surfaces stack at max-app width. Centering and width are
     handled here so the markup stays terse. */
  .stats-main > section,
  .stats-main > header {
    max-width: 640px;
    margin-inline: auto;
    width: 100%;
  }

  /* Page-load stagger — each surface rises into place once, staggered by
     index. backwards fill so the initial state is the rise-from state. */
  @keyframes lev-rise {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
  }
  .stats-main > * {
    animation: lev-rise 0.45s cubic-bezier(0.25, 1, 0.5, 1) backwards;
  }
  .stats-main > *:nth-child(1)  { animation-delay: 0.00s; }
  .stats-main > *:nth-child(2)  { animation-delay: 0.06s; }
  .stats-main > *:nth-child(3)  { animation-delay: 0.10s; }
  .stats-main > *:nth-child(4)  { animation-delay: 0.14s; }
  .stats-main > *:nth-child(5)  { animation-delay: 0.18s; }
  .stats-main > *:nth-child(6)  { animation-delay: 0.22s; }
  .stats-main > *:nth-child(7)  { animation-delay: 0.26s; }
  .stats-main > *:nth-child(8)  { animation-delay: 0.30s; }
  .stats-main > *:nth-child(9)  { animation-delay: 0.32s; }
  .stats-main > *:nth-child(10) { animation-delay: 0.34s; }
  .stats-main > *:nth-child(n+11) { animation-delay: 0.36s; }
  @media (prefers-reduced-motion: reduce) {
    .stats-main > * { animation: none; }
  }

  /* ----- Hero ----- */
  /* A single mega numeral leads the page. An orange eyebrow above sets
     section context; below the number a thin orange divider separates
     the primary KPI from a row of three smaller substats. */
  .hero-section {
    padding: var(--sp-6) var(--sp-5) var(--sp-5);
    position: relative;
    overflow: hidden;
  }
  .hero-section::after {
    /* Decorative oversize "L" sitting in the bottom-right at very low
       opacity — adds atmosphere without any new asset or color. Stays
       inside the deep-purple panel via overflow: hidden above. */
    content: 'L';
    position: absolute;
    right: -0.18em;
    bottom: -0.32em;
    font-family: var(--f-title);
    font-size: clamp(16rem, 60vw, 24rem);
    line-height: 1;
    color: var(--c-purple);
    opacity: 0.55;
    pointer-events: none;
    user-select: none;
  }
  .hero-section > * { position: relative; z-index: 1; }

  .hero-eyebrow {
    display: block;
    font-family: var(--f-brand);
    font-weight: 700;
    font-size: var(--text-xs);
    color: var(--c-orange);
    text-transform: uppercase;
    letter-spacing: 0.22em;
  }
  .hero-mega {
    font-family: var(--f-brand);
    font-weight: 700;
    /* Mobile-first: clamp grows the numeral up to ~7rem on wider screens. */
    font-size: clamp(4.5rem, 24vw, 7rem);
    color: var(--c-yellow);
    line-height: 0.88;
    letter-spacing: -0.04em;
    margin-top: var(--sp-2);
  }
  .hero-mega-label {
    font-family: var(--f-brand);
    font-weight: 700;
    font-size: var(--text-sm);
    color: rgba(255, 255, 255, 0.7);
    text-transform: uppercase;
    letter-spacing: 0.22em;
    margin-top: var(--sp-2);
  }
  .hero-divider {
    height: 2px;
    background: var(--c-orange);
    margin-block: var(--sp-5);
    width: 56px;
  }
  .hero-substats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-3);
  }
  .hero-substat { min-width: 0; }
  .hero-sub-num {
    font-family: var(--f-brand);
    font-weight: 700;
    font-size: clamp(1.6rem, 8vw, 2.4rem);
    color: var(--c-white);
    line-height: 1;
    letter-spacing: -0.02em;
  }
  .hero-sub-label {
    font-family: var(--f-mono);
    font-weight: 700;
    font-size: 0.62rem;
    color: rgba(255, 255, 255, 0.5);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    margin-top: var(--sp-2);
  }

  /* ----- Section dividers (Taste / Eras / Lists) ----- */
  /* Three-column row: orange section number on the left, big yellow name
     in the middle, italic muted subtitle on the right. Replaces the old
     centered yellow label. */
  .section-divider {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: baseline;
    gap: var(--sp-3);
    padding: var(--sp-5) var(--sp-5);
  }
  .section-divider-number {
    font-family: var(--f-mono);
    font-weight: 700;
    font-size: var(--text-xs);
    color: var(--c-orange);
    letter-spacing: 0.1em;
  }
  .section-divider-name {
    font-family: var(--f-brand);
    font-weight: 700;
    font-size: var(--text-xl);
    color: var(--c-yellow);
    text-transform: uppercase;
    letter-spacing: 0.18em;
    line-height: 1;
  }
  .section-divider-sub {
    font-family: var(--f-body);
    font-style: italic;
    font-size: var(--text-xs);
    color: rgba(255, 255, 255, 0.55);
    text-align: right;
  }
  @media (max-width: 480px) {
    .section-divider {
      grid-template-columns: auto 1fr;
      row-gap: var(--sp-1);
    }
    .section-divider-sub {
      grid-column: 1 / -1;
      text-align: left;
    }
  }

  /* ----- Panel header (per-section title + optional callout) ----- */
  .panel-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5) var(--sp-2);
  }
  .panel-label {
    font-family: var(--f-brand);
    font-weight: 700;
    font-size: var(--text-xs);
    color: var(--c-orange);
    text-transform: uppercase;
    letter-spacing: 0.18em;
    border-bottom: 0;
  }
  .panel-callout {
    font-family: var(--f-mono);
    font-weight: 700;
    font-size: var(--text-xs);
    color: var(--c-deep);
    white-space: nowrap;
  }
  .panel-callout-muted {
    color: var(--c-purple);
    font-style: italic;
    font-weight: 400;
  }
  .panel-callout-formula {
    font-family: var(--f-mono);
    font-size: var(--text-xs);
    color: var(--c-purple);
    opacity: 0.7;
    white-space: nowrap;
  }

  /* Kept for legacy callers (other pages) — stats.html now uses
     .panel-label. */
  .section-label {
    border-bottom: 0;
  }

  /* Book titles in stats lists are links back to the matching book on the
     index page (deep-linked via #<id>). The hash is what triggers the
     modal to open on the books page. */
  .book-link {
    color: inherit;
    text-decoration: none;
    transition: color 0.1s, background 0.1s;
  }
  .book-link:hover { color: var(--c-orange); }
  .book-link:focus-visible {
    outline: none;
    background: var(--c-yellow);
    color: var(--c-deep);
  }

  /* Trophy row — filled orange badge with white "10" anchors the row.
     Title (DM Serif) on its own line, author muted below. Badge spans
     both rows so the two text rows stack to its right. */
  .trophy-list li {
    display: grid;
    grid-template-columns: 48px minmax(0, 1fr);
    grid-template-areas:
      "mark title"
      "mark author";
    column-gap: var(--sp-4);
    row-gap: 2px;
    align-items: start;
    padding: var(--sp-3) var(--sp-5);
    transition: background 0.1s;
  }
  .trophy-list li:hover { background: var(--c-yellow); }
  .trophy-list li:hover .trophy-author { color: var(--c-deep); }
  .trophy-list .trophy-mark {
    grid-area: mark;
    align-self: center;
    font-family: var(--f-mono);
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--c-white);
    background: var(--c-orange);
    height: 48px;
    width: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    letter-spacing: -0.02em;
  }
  .trophy-list .trophy-title {
    grid-area: title;
    font-family: var(--f-title);
    font-size: var(--text-lg);
    color: var(--c-deep);
    line-height: 1.1;
    overflow: hidden;
    text-overflow: ellipsis;
    align-self: end;
  }
  .trophy-list .trophy-author {
    grid-area: author;
    font-family: var(--f-body);
    font-size: var(--text-xs);
    color: var(--c-purple);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    align-self: start;
  }
  .trophy-list .empty {
    padding: var(--sp-4) var(--sp-5);
    color: var(--c-purple);
    font-style: italic;
    font-size: var(--text-sm);
    grid-column: 1 / -1;
  }

  .score-chart-row {
    display: grid;
    grid-template-columns: 32px 1fr 36px;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-1) 0;
  }
  .score-chart-row .badge {
    font-family: var(--f-mono);
    font-weight: 700;
    text-align: center;
    padding: 2px 0;
  }
  .score-chart-row .bar {
    height: 18px;
    min-width: 2px;
    transition: width 0.3s;
  }
  .score-chart-row .count {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-purple);
    text-align: right;
    font-size: var(--text-xs);
  }

  .decade-chart-row {
    display: grid;
    grid-template-columns: 48px 1fr 36px;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-1) 0;
  }
  .decade-chart-row .label {
    font-family: var(--f-mono);
    font-weight: 700;
    font-size: var(--text-xs);
    color: var(--c-purple);
  }
  .decade-chart-row .bar {
    height: 18px;
    min-width: 2px;
    background: var(--c-purple);
    transition: width 0.3s;
  }
  .decade-chart-row .count {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-purple);
    text-align: right;
    font-size: var(--text-xs);
  }

  .ranked-list li {
    display: grid;
    grid-template-columns: 28px 1fr auto;
    align-items: baseline;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-5);
  }
  .ranked-list li:nth-child(even) { background: var(--surface); }
  .ranked-list .rank {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-orange);
  }
  .ranked-list .name {
    font-family: var(--f-body);
    font-weight: 600;
  }
  .ranked-list .meta {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-purple);
    font-size: var(--text-xs);
    text-align: right;
  }
  .ranked-list .empty {
    padding: var(--sp-4) var(--sp-5);
    color: var(--c-purple);
    font-style: italic;
    font-size: var(--text-sm);
    grid-template-columns: 1fr;
  }

  /* ----- Lists stats (stats.html → Lists section) ----- */
  /* Five-tile metrics row. Each tile is a left-aligned KPI: number on top
     in brand-font yellow, a thin orange underline, and a mono label
     beneath. Tiles are separated by transparent 1px lines via gap +
     subtle deep-purple-derived dividers to feel dashboard-grade. */
  .lists-stats-section {
    padding: var(--sp-5) var(--sp-4);
  }
  .lists-stats-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--sp-3);
  }
  .lists-stat {
    min-width: 0;
    padding: var(--sp-1) var(--sp-2);
    text-align: left;
  }
  .lists-stat + .lists-stat {
    border-left: 1px solid rgba(255, 255, 255, 0.08);
  }
  .lists-stat-num {
    font-family: var(--f-brand);
    font-weight: 700;
    font-size: clamp(1.4rem, 7vw, 2.4rem);
    color: var(--c-yellow);
    line-height: 1;
    letter-spacing: -0.02em;
  }
  .lists-stat-num::after {
    content: '';
    display: block;
    width: 18px;
    height: 2px;
    background: var(--c-orange);
    margin-top: var(--sp-2);
  }
  .lists-stat-label {
    font-family: var(--f-mono);
    font-weight: 700;
    font-size: 0.6rem;
    color: rgba(255, 255, 255, 0.55);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin-top: var(--sp-2);
    line-height: 1.25;
  }

  /* Most-listed row: rank | check | title-block | count.
     Title-block stacks Spanish title (serif), original (small body), and
     author (body). Count is right-aligned mono accent. */
  .most-listed li {
    display: grid;
    grid-template-columns: 28px 16px minmax(0, 1fr) auto;
    column-gap: var(--sp-3);
    align-items: baseline;
    padding: var(--sp-3) var(--sp-5);
    background: var(--c-white);
  }
  .most-listed li:nth-child(even) { background: var(--surface); }
  .most-listed .rank {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-orange);
  }
  .most-listed-titles { min-width: 0; }
  .most-listed-title {
    font-family: var(--f-title);
    font-size: var(--text-base);
    color: var(--c-deep);
    line-height: 1.1;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
  }
  .most-listed-original {
    font-family: var(--f-body);
    font-size: var(--text-xs);
    color: var(--c-purple);
    opacity: 0.7;
    margin-top: 1px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
  }
  .most-listed-author {
    font-family: var(--f-body);
    font-size: var(--text-sm);
    color: var(--c-purple);
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .most-listed-count {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-orange);
    font-size: var(--text-lg);
    white-space: nowrap;
    align-self: center;
  }
  .most-listed .empty {
    padding: var(--sp-4) var(--sp-5);
    color: var(--c-purple);
    font-style: italic;
    font-size: var(--text-sm);
  }

  /* Most-listed authors: single-line row, rank + check + name + count. */
  .most-listed-authors li {
    display: grid;
    grid-template-columns: 28px 16px minmax(0, 1fr) auto;
    column-gap: var(--sp-3);
    align-items: center;
    padding: var(--sp-3) var(--sp-5);
    background: var(--surface);
  }
  .most-listed-authors li:nth-child(even) { background: var(--surface-alt); }
  .most-listed-authors .rank {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-orange);
  }
  .most-listed-authors .name {
    font-family: var(--f-body);
    font-weight: 600;
    color: var(--c-deep);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .most-listed-authors .count {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-orange);
    font-size: var(--text-lg);
    white-space: nowrap;
  }
  .most-listed-authors .empty {
    padding: var(--sp-4) var(--sp-5);
    color: var(--c-purple);
    font-style: italic;
    font-size: var(--text-sm);
  }

  /* ----- Decade timeline ----- */
  /* Three columns per decade: marker (dot + decade label) on the left,
     books in the middle, single score badge on the right (all books in
     a decade group share the same score by construction).
     The vertical line is drawn as a ::before on each .decade-group; the
     pseudo-elements stack contiguously between siblings so the segments
     read as one continuous line. First/last groups trim the line so it
     starts/ends at the dot rather than overshooting. */
  #decade-list { position: relative; }

  .decade-group {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-5);
    position: relative;
    background: transparent;
  }

  .decade-group::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    /* Dot center: left padding (var(--sp-5)) + half dot width (6px) */
    left: calc(var(--sp-5) + 6px);
    width: 2px;
    background: var(--c-orange);
    z-index: 0;
  }
  .decade-group:first-child::before { top: 50%; }
  .decade-group:last-child::before { bottom: 50%; }

  .decade-books {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    min-width: 0;
  }

  .decade-row {
    display: flex;
    align-items: baseline;
    gap: var(--sp-2);
    flex-wrap: wrap;
  }

  .decade-title {
    font-family: var(--f-body);
    font-weight: 600;
  }
  .decade-author {
    color: var(--c-purple);
    font-size: var(--text-sm);
  }
  .decade-score {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-orange);
    font-size: var(--text-sm);
    white-space: nowrap;
  }

  .decade-marker {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    position: relative;
    z-index: 1;
  }
  .decade-dot {
    width: 14px;
    height: 14px;
    background: var(--c-orange);
    flex-shrink: 0;
    border-radius: 10px;
  }
  .decade-label {
    font-family: var(--f-title);
    font-weight: 400;
    color: var(--c-orange);
    font-size: var(--text-lg);
    line-height: 1;
    white-space: nowrap;
  }

  /* ----- Book-detail modal: sticky header + Appears-in section ----- */
  /* The dialog itself is the scroll container (overflow-y: auto), so a
     position: sticky on the header keeps the title and CLOSE button
     reachable no matter how long the review or the appears-in list grows. */
  .detail-header-sticky {
    position: sticky;
    top: 0;
    z-index: 2;
  }
  .detail-accent-strip {
    position: sticky;
    top: var(--detail-header-h, 0);
    z-index: 2;
  }

  .detail-lists li {
    background: var(--c-white);
  }
  .detail-lists li:nth-child(even) { background: var(--surface); }
  .detail-lists a {
    display: grid;
    grid-template-columns: 48px 1fr;
    column-gap: var(--sp-3);
    align-items: baseline;
    padding: var(--sp-3) var(--sp-5);
    color: inherit;
    transition: background 0.1s, color 0.1s;
  }
  .detail-lists a:hover,
  .detail-lists a:focus-visible {
    background: var(--c-yellow);
    color: var(--c-deep);
    outline: none;
  }
  .detail-lists .detail-list-pos {
    font-family: var(--f-mono);
    font-weight: 700;
    color: var(--c-orange);
    text-align: right;
    white-space: nowrap;
  }
  .detail-lists .detail-list-name {
    font-family: var(--f-body);
    font-weight: 600;
    color: var(--c-deep);
    overflow-wrap: anywhere;
  }

  /* ----- Lists page (lists.html) ----- */
  /* List header strip mirrors the saga-header look but with stronger
     hierarchy: brand-font name on the left, count on the right. The 2px
     accent strip below ties back to the toolbar accent. */
  .list-section + .list-section { margin-top: var(--sp-3); }
  .accent-strip-2 { height: 2px; }

  /* Sticky list header: tucks under the sticky toolbar so the user always
     knows which list they are scrolling through. --toolbar-h is set by
     lists.js from the actual measured toolbar height (toolbar + accent +
     meta + TOC), so the header lands flush regardless of viewport. */
  .list-section { scroll-margin-top: var(--toolbar-h, 0px); }
  .list-header {
    position: sticky;
    top: var(--toolbar-h, 0px);
    z-index: 3;
  }

  .list-count { letter-spacing: 0.04em; }

  /* ----- TOC ----- */
  /* Vertical table of contents at the top of the lists page. One row per
     list, two columns: name on the left, read count on the right. Scrolls
     with the page (not sticky) so the user reaches it by scrolling up. */
  .lists-toc { background: var(--c-white); }
  .lists-toc-label { border-bottom: 0; }
  .lists-toc-row {
    display: flex;
    flex-direction: column;
  }
  .lists-toc-row li:nth-child(even) { background: var(--surface); }
  .lists-toc-link {
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: var(--sp-3);
    align-items: baseline;
    padding: var(--sp-3) var(--sp-4);
    color: var(--c-deep);
    font-family: var(--f-body);
    font-weight: 600;
    text-decoration: none;
    transition: background 0.1s, color 0.1s;
  }
  .lists-toc-link > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }
  .lists-toc-link:hover,
  .lists-toc-link:focus-visible {
    background: var(--c-yellow);
    color: var(--c-deep);
    outline: none;
  }
  .lists-toc-count {
    font-family: var(--f-mono);
    color: var(--c-orange);
    font-weight: 700;
    white-space: nowrap;
  }
  .lists-toc-link:hover .lists-toc-count,
  .lists-toc-link:focus-visible .lists-toc-count {
    color: var(--c-deep);
  }

  /* Row grid:
     pos | check | year | title-block (title + original) | author
     Title-block and author share the remaining space at a 1.4 : 1 ratio so
     authors form a visible right column you can scan top-down. */
  .list-row {
    display: grid;
    grid-template-columns: 24px 16px 44px minmax(0, 1.4fr) minmax(0, 1fr);
    column-gap: var(--sp-3);
    align-items: baseline;
    padding: var(--sp-2) var(--sp-4);
    background: var(--c-white);
    transition: background 0.1s;
    content-visibility: auto;
    contain-intrinsic-size: auto 56px;
  }
  .list-rows .list-row:nth-child(even) { background: var(--surface); }
  .list-row:hover { background: var(--c-yellow); }
  .list-row.read .list-title { color: var(--c-deep); }
  .list-row.unread .list-title { color: rgba(30, 16, 78, 0.55); }
  .list-row.unread .list-author { color: rgba(69, 46, 90, 0.65); }

  /* Checkbox cell — filled orange square with white tick for read books,
     low-contrast surface block for unread. Zero borders, zero radius. */
  .list-check {
    width: 14px;
    height: 14px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--f-mono);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
  }
  .list-check.check-read { background: var(--c-orange); color: var(--c-white); }
  .list-check.check-empty { background: var(--surface-alt); }

  .list-pos { text-align: right; }
  .list-year { white-space: nowrap; }
  .list-year-missing { color: rgba(69, 46, 90, 0.4); }

  .list-title-block { min-width: 0; }
  .list-title {
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    word-break: break-word;
  }
  .list-original {
    opacity: 0.7;
    margin-top: 1px;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    word-break: break-word;
  }
  .list-author {
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    word-break: break-word;
  }

  /* Focus pulse — when lists.html?book=<id> opens, every matching row
     briefly inverts to yellow so the user spots all occurrences. The
     animation duration is mirrored by the JS timeout that removes the
     class. */
  @keyframes lev-focus-pulse {
    0%   { background: var(--c-yellow); }
    60%  { background: var(--c-yellow); }
    100% { background: transparent; }
  }
  .list-row.focus-pulse {
    animation: lev-focus-pulse 2.2s ease-out 1;
  }

  /* ----- Responsive ----- */
  @media (max-width: 640px) {
    .detail-nav { display: block; }
    dialog {
      max-width: 100%;
      max-height: 100%;
      width: 100vw;
      height: 100dvh;
      margin: 0;
      overflow-y: auto;
      overscroll-behavior: contain;
      padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    .detail-grid { grid-template-columns: 1fr; }
    .detail-score-strip { flex-direction: column; }
    .detail-score-number { width: 100%; }
    footer { flex-direction: column; align-items: flex-start; }
  }

  @media (min-width: 641px) {
    nav { max-width: 640px; margin-inline: auto; }
    .accent-strip { max-width: 640px; margin-inline: auto; }
  }

  /* ======================================================================
     graph.html — similarity graph view
     ====================================================================== */

  /* Mode strip toggle (Books / Authors) */
  .graph-mode-toggle {
    display: inline-flex;
    background: var(--c-deep);
  }
  .mode-btn {
    background: var(--c-deep);
    color: rgba(255,255,255,0.55);
    padding: var(--sp-2) var(--sp-3);
    border: none;
  }
  .mode-btn[aria-pressed="true"] {
    background: var(--c-yellow);
    color: var(--c-deep);
  }
  .mode-btn:hover { color: var(--c-yellow); }
  .mode-btn[aria-pressed="true"]:hover { color: var(--c-deep); }

  /* ---- Stage (SVG focused graph) ---- */
  #stage-section {
    /* Bleed background to viewport edges within max-w-app — keeps the dark
       stage feeling cinematic against the toolbar above and list below. */
    padding: var(--sp-3) 0 0;
  }
  .stage-empty {
    color: var(--c-white);
    min-height: 180px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }
  .stage-svg {
    display: block;
    background: var(--c-deep);
    user-select: none;
    -webkit-user-select: none;
    width: 100%;
    height: 100%;
  }
  #stage-section {
    /* Fixed height + overflow hidden so the SVG scales to fit the visible
       box. preserveAspectRatio="xMidYMid meet" keeps everything inside
       and centered — no panning required. */
    height: 70dvh;
    max-height: 70dvh;
    overflow: hidden;
  }
  .stage-controls {
    background: var(--c-deep);
    border-top: 1px solid rgba(255,255,255,0.06);
  }
  .stage-ctrl {
    background: transparent;
    color: var(--c-yellow);
    padding: var(--sp-1) var(--sp-3);
    border: 1px solid var(--c-yellow);
  }
  .stage-ctrl[aria-pressed="true"] {
    background: var(--c-yellow);
    color: var(--c-deep);
  }
  .stage-ctrl:hover { background: var(--c-yellow); color: var(--c-deep); }

  /* ----------------------------------------------------------------
     Constellation map — refined typography on a luminous orbital chart.
     This is the one place in the app where we depart from the brutalist
     sharp-edged language: the focused graph reads as an editorial mind
     map, so cards are pill-shaped, edges glow softly, and a measured
     stagger eases everything into place.
     ---------------------------------------------------------------- */

  .orbit-ring {
    fill: none;
    stroke: rgba(255,255,255,0.06);
    stroke-width: 1;
    stroke-dasharray: 2 6;
  }

  .edge {
    fill: none;
    opacity: 0;
    animation: lev-graph-edge-in 320ms ease-out forwards;
    animation-delay: calc(60ms + var(--i, 0) * 25ms);
  }
  @keyframes lev-graph-edge-in {
    from { opacity: 0; stroke-dasharray: 600; stroke-dashoffset: 600; }
    to   { opacity: 0.9; stroke-dasharray: 600; stroke-dashoffset: 0; }
  }

  /* Edge weight is encoded purely by line thickness + color tier now —
     no numeric pill. Keeps the graph quieter and lets typography breathe. */

  .node-card {
    cursor: pointer;
    opacity: 0;
    transform-box: fill-box;
    transform-origin: center;
    animation: lev-graph-card-in 380ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
    animation-delay: calc(var(--i, 0) * 35ms);
    transition: filter 200ms ease;
  }
  @keyframes lev-graph-card-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }

  .node-bg {
    transition: fill 180ms ease, stroke 180ms ease;
  }

  /* Center node — solid yellow block, no gradient. The center-glow filter
     applied inline from JS supplies the halo. */
  .node-center .node-bg {
    fill: var(--c-yellow);
    stroke: var(--c-yellow);
    stroke-width: 1.5;
  }
  /* Font sizes balance readability against viewBox bloat — bigger cards
     force a larger viewBox which makes everything shrink on small screens
     (the SVG scales to fit). These values keep titles legible without
     blowing the orbit out past comfortable on-screen scale. */
  .node-center .node-title {
    font-family: var(--f-title);
    font-size: 26px;
    fill: var(--c-deep);
    letter-spacing: 0.005em;
  }
  .node-center .node-sub {
    font-family: var(--f-body);
    font-weight: 600;
    font-size: 16px;
    fill: rgba(30, 16, 78, 0.75);
  }

  /* Orbit (neighbor) nodes — solid deep-purple block with an orange rim. */
  .node-orbit .node-bg {
    fill: var(--c-deep);
    stroke: var(--c-orange);
    stroke-width: 1.5;
  }
  .node-orbit .node-title {
    font-family: var(--f-title);
    font-size: 18px;
    fill: var(--c-white);
  }
  .node-orbit .node-sub {
    font-family: var(--f-body);
    font-size: 14px;
    fill: rgba(255, 255, 255, 0.78);
  }

  /* Read book — solid orange with deep-purple text for high contrast. */
  .node-orbit.node-read .node-bg {
    fill: var(--c-orange);
    stroke: var(--c-yellow);
  }
  .node-orbit.node-read .node-title { fill: var(--c-deep); }
  .node-orbit.node-read .node-sub   { fill: var(--c-deep); }

  /* Hover/focus: lift toward yellow + intensify glow via filter. */
  .node-orbit:hover .node-bg,
  .node-orbit:focus .node-bg {
    fill: var(--c-yellow);
    stroke: var(--c-yellow);
  }
  .node-orbit:hover .node-title,
  .node-orbit:focus .node-title { fill: var(--c-deep); }
  .node-orbit:hover .node-sub,
  .node-orbit:focus .node-sub   { fill: rgba(30, 16, 78, 0.78); }
  .node-orbit:hover,
  .node-orbit:focus { filter: drop-shadow(0 0 6px rgba(255, 200, 92, 0.55)); }
  .node-orbit:focus { outline: none; }

  .node-center:hover .node-bg,
  .node-center:focus .node-bg {
    stroke: var(--c-white);
    stroke-width: 2;
  }
  .node-center:focus { outline: none; }

  .stage-bg-rect { pointer-events: none; }

  /* ---- List view ---- */
  .list-section-header {
    position: sticky;
    top: var(--toolbar-h, 0);
    z-index: 1;
  }
  .accent-strip-2 { height: 3px; }

  .node-list { background: var(--c-white); }
  .node-row { background: var(--c-white); }
  .node-row + .node-row { box-shadow: inset 0 1px 0 var(--surface-alt); }
  .node-row-btn {
    display: grid;
    grid-template-columns: 36px 18px 50px 1fr 72px;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    width: 100%;
    background: transparent;
    text-align: left;
  }
  .node-row-btn:hover {
    background: var(--c-yellow);
  }
  .node-row-btn.focused {
    background: var(--c-deep);
    color: var(--c-white);
  }
  .node-row-btn.focused .node-row-title { color: var(--c-yellow); }
  .node-row-btn.focused .node-row-sub,
  .node-row-btn.focused .node-row-rank,
  .node-row-btn.focused .node-row-year { color: rgba(255,255,255,0.65); }
  .node-row-text { min-width: 0; }
  .node-row-title {
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
  }
  .node-row-sub {
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .node-row-count {
    justify-self: stretch;
    padding: 4px 6px;
    text-align: center;
    min-width: 24px;
    line-height: 1.05;
    letter-spacing: 0.04em;
    font-size: 0.62rem;
    white-space: normal;
    word-break: keep-all;
  }
  /* Author rows use the original 3 tiers (count-weak/mid/strong) keyed on
     neighbor count. Book rows use the 5-tier match-* palette below — a
     warming gradient from empty surface through pale yellow up to a hot
     orange chip that earns its weight by sitting alone at the top. */
  .count-weak   { color: var(--c-purple); background: var(--surface-alt); }
  .count-mid    { color: var(--c-deep);   background: var(--c-yellow); }
  .count-strong { color: var(--c-white);  background: var(--c-orange); }

  .match-faint  { color: rgba(69, 46, 90, 0.5);  background: transparent; }
  .match-low    { color: var(--c-purple);        background: var(--surface-alt); }
  .match-mid    { color: var(--c-deep);          background: rgba(255, 200, 92, 0.35); }
  .match-high   { color: var(--c-deep);          background: var(--c-yellow); }
  .match-love   { color: var(--c-white);         background: var(--c-orange); }

  .node-row-check {
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--f-mono);
    font-weight: 700;
    font-size: 12px;
  }
  .check-read  { background: var(--c-orange); color: var(--c-white); }
  .check-empty { background: var(--surface-alt); }

  /* ---- Detail panel ---- */
  .detail-card { display: block; }
  .detail-head { /* dark masthead for the focused node */ }
  .detail-stats {
    grid-template-columns: repeat(4, 1fr);
    background: var(--c-white);
  }
  .detail-stat {
    padding: var(--sp-3) var(--sp-4);
    border-right: 1px solid var(--surface-alt);
    display: flex;
    flex-direction: column;
    gap: 2px;
  }
  .detail-stat:last-child { border-right: none; }
  .detail-stat dd { margin: 0; }
  .score-faint { color: rgba(69, 46, 90, 0.55); }
  .score-low   { color: var(--c-purple); }
  .score-mid   { color: var(--c-deep); }
  .score-high  { color: var(--c-orange); }
  /* score-love wears an orange chip so it visually outranks score-high,
     which is plain orange text. The Match figure inside <dd> shrinks to
     fit so "GONNA LOVE IT" doesn't overflow the 1fr column. */
  .score-love {
    color: var(--c-white);
    background: var(--c-orange);
    padding: 2px 6px;
    align-self: flex-start;
  }
  .detail-stat dd[data-slot="likeness"],
  .detail-stat dd[data-slot="match"] {
    font-size: var(--text-base);
    line-height: 1.1;
    letter-spacing: 0.02em;
    white-space: normal;
    word-break: keep-all;
  }
  .status-read   { color: var(--c-orange); }
  .status-unread { color: var(--c-purple); }

  .detail-section { background: var(--surface-alt); }
  .detail-section-thin { background: var(--c-white); }
  .detail-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    margin: 0;
    padding: 0;
  }
  .detail-list li { padding: 2px 0; }
  .detail-row { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-2) 0; border-top: 1px solid rgba(69,46,90,0.12); }
  .detail-row:first-child { border-top: none; }
  .detail-db-row { display: flex; align-items: baseline; gap: var(--sp-2); padding: 2px 0; }
  .detail-link {
    color: var(--c-orange);
    background: transparent;
  }
  .detail-link:hover { color: var(--c-deep); background: var(--c-yellow); }
  .detail-link-inline {
    color: var(--c-deep);
    text-decoration: underline;
    text-decoration-color: var(--c-orange);
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
  }
  .detail-link-inline:hover { color: var(--c-orange); }

  /* Responsive: collapse detail stats on small screens, shrink stage */
  @media (max-width: 480px) {
    .detail-stats { grid-template-columns: repeat(2, 1fr); }
    .detail-stat:nth-child(2n) { border-right: none; }
    .detail-stat:nth-child(-n+2) { border-bottom: 1px solid var(--surface-alt); }
    #stage-section { height: 60dvh; max-height: 60dvh; }
    .node-row-btn { grid-template-columns: 30px 16px 42px 1fr 68px; gap: var(--sp-2); padding: var(--sp-3); }
  }
}

