/* ── Rhyme Finder · v2 Xuan Paper ─────────────────────────────────
   Warm xuan-paper canvas, ink-black calligraphy, vermilion seal accent.
   Minimal, but with the quiet weight of an old folio.
*/

:root {
  /* Warm xuan paper palette — keyed to the Wang Shimin reference */
  --paper: #dcc28e;
  --paper-warm: #d4b67a;
  --paper-deep: #c8a567;

  --ink: #1a140e;            /* sumi black, slightly warm */
  --ink-soft: #3a2e1f;
  --ink-faded: #6e5a3c;      /* aged ink */
  --ink-ghost: rgba(26, 20, 14, 0.14);
  --hair: rgba(26, 20, 14, 0.22);
  --hair-soft: rgba(26, 20, 14, 0.10);

  --vermilion: #b13b2c;      /* hanko / 朱印 red */
  --vermilion-deep: #8a2a1e;
  --jade: #4a5a3a;           /* deep painting green */
  --indigo: #2a3a4a;         /* deep painting blue */

  --serif: "Cormorant Garamond", "Songti SC", "STSong", "SimSun", "Times New Roman", serif;
  --display: "Cormorant Garamond", "Songti SC", "STSong", serif;
  --hand: "Ma Shan Zheng", "Cormorant Garamond", serif;
  --sans: "Inter", "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "DM Mono", ui-monospace, "SF Mono", Menlo, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

body {
  min-height: 100vh;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  background-color: var(--paper);
  background-image: url("./xuan-bg.png");
  background-size: 600px 600px;
  background-repeat: repeat;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Vignette + paper-edge shadow framing the viewport */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 95% 75% at 50% 35%, rgba(255, 230, 180, 0.18), transparent 70%);
  box-shadow:
    inset 0 0 120px rgba(80, 50, 20, 0.18),
    inset 0 0 280px rgba(100, 70, 30, 0.10);
  z-index: 0;
}

/* ── Layout ──────────────────────────────────────────────────── */

.rf-app {
  position: relative;
  min-height: 100vh;
  width: min(880px, calc(100vw - 40px));
  margin: 0 auto;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  z-index: 2;
}

/* Empty start state — fix the hero (title + input) dead-center of the
   viewport, like Google's homepage. Its position never moves when the
   active epigraph below changes height. */
.rf-app:not(:has(#results:not(:empty))):not(:has(#source-summary:not(:empty))) .rf-hero {
  position: fixed;
  top: 42%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(880px, calc(100vw - 40px));
  z-index: 3;
}
.rf-app:not(:has(#results:not(:empty))):not(:has(#source-summary:not(:empty))) .rf-results-shell {
  display: none;
}
/* Footer pinned to viewport bottom on the empty start state. */
.rf-app:not(:has(#results:not(:empty))):not(:has(#source-summary:not(:empty))) .rf-epigraphs {
  position: fixed;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  border-top: none;
  padding-top: 0;
  z-index: 2;
}

/* ── Hero ────────────────────────────────────────────────────── */

.rf-hero {
  text-align: center;
  padding-top: 0;
  margin-bottom: 0;
  position: relative;
  transition: padding-top 0.3s ease, margin-bottom 0.3s ease;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* ── Merged sticky bar (slim banner + old #stickybar) ──────────
   Once results land, the hero collapses into a single sticky bar:
   韵 seal (home link), pill input, tab toggle, jump + filter icons.
   The bar absorbs the role of the old #stickybar (now removed) —
   it's the only sticky chrome on the page. Paper-warm tint with
   xuan-bg multiply blend mirrors the old stickybar's "stamped
   paper" feel. */
.rf-app:has(#results:not(:empty)) .rf-hero,
.rf-app:has(#source-summary:not(:empty)) .rf-hero {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 14px;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  /* Extra right padding reserves room for the colophon, which is
     position: fixed at the bar's right edge (see .rf-colophon below).
     ~56px = colophon icon (26) + hairline gap (16) + breathing (14). */
  padding: 10px calc(clamp(20px, 4vw, 56px) + 56px) 10px clamp(20px, 4vw, 56px);
  margin-bottom: 18px;
  border-top: 0;
  border-bottom: 1px solid var(--ink);
  text-align: left;
  position: sticky;
  top: 0;
  z-index: 40;
  background-color: var(--paper);
  background-image: url("/rhyme-finder/xuan-bg.png");
  background-size: 600px 600px;
  background-blend-mode: multiply;
  /* Soft drop only — the vermilion 1 px hard shadow that used to
     sit right under the bar created a visible extra line in the
     bar/drawer seam at scroll-top. The ink border-bottom is enough. */
  box-shadow: 0 6px 16px -10px rgba(26, 20, 14, 0.22);
}

/* Title row collapses to inline-flex; shanshui hides. */
.rf-app:has(#results:not(:empty)) .rf-title-row,
.rf-app:has(#source-summary:not(:empty)) .rf-title-row {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
.rf-app:has(#results:not(:empty)) .rf-title-row .rf-mg-shanshui,
.rf-app:has(#source-summary:not(:empty)) .rf-title-row .rf-mg-shanshui {
  display: none;
}

/* The wordmark — clickable link back to the empty/home state.
   In the merged sticky bar the seal is always visible; the
   "Rhyme · Finder" text only appears at ≥1100 px viewport (see the
   media-query block below) — under that, the bar is too tight to
   carry it without crowding the pill. */
.rf-app:has(#results:not(:empty)) .rf-title,
.rf-app:has(#source-summary:not(:empty)) .rf-title {
  font-size: 0;
  line-height: 1;
  margin: 0;
  cursor: pointer;
}
.rf-app:has(#results:not(:empty)) .rf-title-rhyme,
.rf-app:has(#source-summary:not(:empty)) .rf-title-rhyme,
.rf-app:has(#results:not(:empty)) .rf-title-amp,
.rf-app:has(#source-summary:not(:empty)) .rf-title-amp,
.rf-app:has(#results:not(:empty)) .rf-title-finder,
.rf-app:has(#source-summary:not(:empty)) .rf-title-finder {
  display: none;
}

/* ≥1100 px — the bar has enough room to carry the full wordmark
   inline beside the seal. Title text reads as the brand cue +
   click target back home; the seal stays as a stamped accent. */
@media (min-width: 1100px) {
  .rf-app:has(#results:not(:empty)) .rf-title,
  .rf-app:has(#source-summary:not(:empty)) .rf-title {
    font-size: 22px;
    display: inline-flex;
    align-items: baseline;
    gap: 0;
  }
  .rf-app:has(#results:not(:empty)) .rf-title-rhyme,
  .rf-app:has(#source-summary:not(:empty)) .rf-title-rhyme {
    display: inline;
    font-style: italic;
    font-weight: 500;
    color: var(--ink);
    transition: color 160ms ease;
  }
  .rf-app:has(#results:not(:empty)) .rf-title-amp,
  .rf-app:has(#source-summary:not(:empty)) .rf-title-amp {
    display: inline-block;
    font-style: normal;
    font-size: 11px;
    font-weight: 400;
    color: var(--ink-faded);
    margin: 0 4px;
    transform: translateY(-3px);
  }
  .rf-app:has(#results:not(:empty)) .rf-title-finder,
  .rf-app:has(#source-summary:not(:empty)) .rf-title-finder {
    display: inline;
    font-style: normal;
    font-weight: 400;
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
    align-self: center;
  }
  .rf-app:has(#results:not(:empty)) .rf-title:hover .rf-title-rhyme,
  .rf-app:has(#source-summary:not(:empty)) .rf-title:hover .rf-title-rhyme,
  .rf-app:has(#results:not(:empty)) .rf-title:hover .rf-title-finder,
  .rf-app:has(#source-summary:not(:empty)) .rf-title:hover .rf-title-finder {
    color: var(--vermilion);
  }
  /* Mirror the bar's left padding as right margin on the wordmark
     so the breathing room either side of "Rhyme · Finder 韵" is
     visually symmetric on wide viewports. Subtract the 14 px flex
     gap that already sits between the wordmark and the pill. */
  .rf-app:has(#results:not(:empty)) .rf-title,
  .rf-app:has(#source-summary:not(:empty)) .rf-title {
    margin-right: calc(clamp(20px, 4vw, 56px) - 14px);
  }
}

/* Seal shrinks to ~22px and sits standalone as the home link. */
.rf-app:has(#results:not(:empty)) .rf-seal,
.rf-app:has(#source-summary:not(:empty)) .rf-seal {
  position: static;
  width: 22px;
  height: 22px;
  font-size: 12px;
  margin-left: 0;
  transform: rotate(-6deg);
  box-shadow:
    inset 0 0 0 1.5px rgba(255, 240, 220, 0.18),
    inset 0 0 8px rgba(80, 10, 0, 0.4);
  transition: transform 160ms ease;
}
.rf-app:has(#results:not(:empty)) .rf-title:hover .rf-seal,
.rf-app:has(#source-summary:not(:empty)) .rf-title:hover .rf-seal {
  transform: rotate(-6deg) scale(1.08);
}

/* Panel becomes the pill container: centered in the remaining
   horizontal space, no top margin. The pill itself is the existing
   .rf-input-row, only its border/padding/internal layout changes. */
.rf-app:has(#results:not(:empty)) .rf-panel,
.rf-app:has(#source-summary:not(:empty)) .rf-panel {
  /* Left-anchored next to the seal — the bar is a 3-group composition
     (logo+pill · tools · colophon) so the pill sits as part of the
     left group, not centered. Grows to 460 px max. */
  margin: 0;
  max-width: 460px;
  flex: 1 1 auto;
  width: auto;
}
.rf-app:has(#results:not(:empty)) .rf-input-row,
.rf-app:has(#source-summary:not(:empty)) .rf-input-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 6px 5px 12px;
  border: 1px solid var(--ink);
  background: rgba(255, 250, 235, 0.45);
}
/* Vermilion brush-stroke under the pill — overrides the empty-state
   ink-ghost shadow to keep the brand accent visible after collapse. */
.rf-app:has(#results:not(:empty)) .rf-input-row::after,
.rf-app:has(#source-summary:not(:empty)) .rf-input-row::after {
  left: 0;
  right: 0;
  bottom: -3px;
  height: 1px;
  background: var(--vermilion);
  opacity: 0.5;
}
.rf-app:has(#results:not(:empty)) .rf-input-row:focus-within,
.rf-app:has(#source-summary:not(:empty)) .rf-input-row:focus-within {
  border-color: var(--vermilion);
}

.rf-app:has(#results:not(:empty)) input[type="text"],
.rf-app:has(#source-summary:not(:empty)) input[type="text"] {
  font-size: 18px;
  text-align: left;
  padding: 2px 0;
  letter-spacing: -0.005em;
}

/* Surface the glyph + clear button only in the collapsed state. */
.rf-app:has(#results:not(:empty)) .rf-input-glyph,
.rf-app:has(#source-summary:not(:empty)) .rf-input-glyph {
  display: inline-block;
}
.rf-app:has(#results:not(:empty)) .rf-input-clear,
.rf-app:has(#source-summary:not(:empty)) .rf-input-clear {
  display: inline-flex;
}
/* In collapsed mode the go-btn cedes its slot to "clear ×"; Enter
   still submits via the form, so submission stays available. */
.rf-app:has(#results:not(:empty)) .rf-go-btn,
.rf-app:has(#source-summary:not(:empty)) .rf-go-btn {
  display: none;
}

/* The status node (loading text / errors) drops below the pill at
   small scale so it stays visible without busting the banner row. */
.rf-app:has(#results:not(:empty)) .rf-status,
.rf-app:has(#source-summary:not(:empty)) .rf-status {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  margin-top: 4px;
  font-size: 9px;
}

/* Empty-state defaults for the new pill chrome — both hidden until
   the slim-banner selector flips them on. */
.rf-input-glyph {
  display: none;
  font-family: var(--display);
  font-style: italic;
  font-size: 16px;
  color: var(--ink-faded);
  line-height: 1;
  align-items: center;
}
/* Glyph-only × — no box, no label. The pill stops competing with the
   wordmark; the action is implied. Italic Cormorant matches the pill
   word's voice; hover grows it slightly + turns vermilion. */
.rf-input-clear {
  display: none;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  appearance: none;
  border: 0;
  background: transparent;
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 20px;
  line-height: 1;
  color: var(--ink-faded);
  cursor: pointer;
  transition: color 160ms ease, transform 160ms ease;
}
.rf-input-clear:hover {
  color: var(--vermilion);
  transform: scale(1.08);
}

/* ── Bar tools · tab toggle + jump/filter iconbtns ────────────
   Surface only when results are present. The toggle sits at 30px
   tall; the iconbtns are 26×26 so they read as secondary controls
   under the toggle's primary "what am I looking at" affordance. */
.rf-bar-tools {
  display: none;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  position: relative;
}
.rf-app:has(#results:not(:empty)) .rf-bar-tools,
.rf-app:has(#source-summary:not(:empty)) .rf-bar-tools {
  display: inline-flex;
  /* Hairline separator between the logo+pill group on the left and
     the tools group — group 1 / group 2 of the 3-group bar. */
  padding-left: 14px;
  margin-left: 4px;
}
.rf-app:has(#results:not(:empty)) .rf-bar-tools::before,
.rf-app:has(#source-summary:not(:empty)) .rf-bar-tools::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 26px;
  background: var(--hair);
}

/* Tab toggle · knob-in-track. Track sits deeper (paper-deep tint
   + inset shadow); the vermilion knob is raised (inset highlight
   + drop shadow). Slide curve over-shoots slightly so the knob
   movement reads as the primary event. */
.rf-tab-toggle {
  position: relative;
  display: inline-flex;
  /* 78 (not 76) so the inner content is 76 px with border-box — two
     38 px cells fit exactly, and the 34-wide vermilion marker keeps
     a symmetric 2 px gap on every side (left, right, top, bottom)
     in either state. Smaller widths made the corpus-state marker
     touch the inner right border. */
  width: 78px;
  height: 30px;
  border: 1px solid var(--ink);
  background: var(--paper-deep);
  padding: 0;
  flex: 0 0 auto;
  box-shadow:
    inset 0 1px 2px rgba(26, 20, 14, 0.22),
    inset 0 0 0 1px rgba(0, 0, 0, 0.04);
}
.rf-toggle-marker {
  position: absolute;
  top: 2px;
  bottom: 2px;
  width: 34px;
  left: 2px;
  background: var(--vermilion);
  transition: left 280ms cubic-bezier(0.5, 0, 0.25, 1.1);
  box-shadow:
    inset 0 0 0 1px rgba(255, 240, 220, 0.22),
    inset 0 0 6px rgba(80, 10, 0, 0.4),
    0 1px 2px rgba(26, 20, 14, 0.3);
  pointer-events: none;
}
.rf-tab-toggle[data-state="corpus"] .rf-toggle-marker {
  left: 40px;
}
.rf-toggle-cell {
  appearance: none;
  border: 0;
  background: transparent;
  cursor: pointer;
  position: relative;
  z-index: 1;
  width: 38px;
  height: 100%;
  color: var(--ink-soft);
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 200ms ease;
  padding: 0;
}
.rf-toggle-cell[aria-selected="true"] {
  color: var(--paper);
}

/* Jump + filter icon buttons · 26 × 26, smaller than the toggle so
   the toggle reads as the dominant control. Hover fills with ink;
   open state ("pressed") stays ink-filled. On the corpus tab both
   are disabled (dashed border, dimmed); the tooltip explains why. */
.rf-iconbtn {
  appearance: none;
  cursor: pointer;
  width: 26px;
  height: 26px;
  border: 1px solid var(--ink);
  background: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  flex: 0 0 auto;
  padding: 0;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.rf-iconbtn:hover {
  background: var(--ink);
  color: var(--paper);
}
.rf-iconbtn[aria-expanded="true"] {
  background: var(--ink);
  color: var(--paper);
}
.rf-iconbtn[aria-disabled="true"] {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
  border-style: dashed;
  border-color: var(--hair);
  background: transparent;
  color: var(--ink-faded);
}
.rf-svg { display: block; }

/* Tab-aware dim — when the corpus tab is active, the jump + filter
   tools don't apply, so the icons go dashed-dim. Mirrors the
   aria-disabled rule above but driven by app-level state instead
   of per-button attributes (so we don't have to flip them in JS). */
.rf-app[data-active-tab="corpus"] #btn-jump,
.rf-app[data-active-tab="corpus"] #btn-filter {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
  border-style: dashed;
  border-color: var(--hair);
  background: transparent;
  color: var(--ink-faded);
}

/* Drawer · slides open below the merged bar to host the jump
   shortcuts or the lex filter chips. The body holds the controls
   and grows left-to-right; the close × sits at the right edge. The
   drawer reads visibly lighter than the sticky bar — soft warm-
   white wash so it feels like a peeled-back layer of paper, not a
   continuation of the bar's stamped surface. */
.rf-drawer {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  /* Symmetric vertical padding so the close × lines up exactly with
     the drawer's true centre, not 1 px off. */
  padding: 10px clamp(20px, 4vw, 56px);
  /* Vermilion wash — the drawer picks up the same accent the seal
     and the active-tab underline use. Reads as a deliberate "tool
     layer" rather than a pale interruption of the paper. */
  background:
    linear-gradient(rgba(177, 59, 44, 0.07), rgba(177, 59, 44, 0.07)),
    var(--paper);
  border-bottom: 1px solid var(--hair);
  position: sticky;
  /* Sticks just below the 58.5px-tall bar (was 51px — a stale
     estimate that let the drawer slide ~8px under the bar when
     scrolled). */
  top: 58px;
  z-index: 39;
  box-shadow: 0 4px 10px -10px rgba(26, 20, 14, 0.2);
  /* Pull up flush against the bar — cancels the bar's 18px
     margin-bottom so there's no empty gap between bar and drawer.
     The bar keeps its 18px when no drawer is open (this element is
     display:none then, so the margin doesn't apply). */
  margin-top: -18px;
}
.rf-drawer[hidden] {
  display: none;
}
.rf-drawer-body {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 14px;
  flex: 1 1 auto;
  min-width: 0;
}
/* Close × — a frameless italic Cormorant glyph (no box). Larger and
   lighter than a labelled control, with a generous invisible hit area;
   on hover it warms to vermilion and rotates a quarter-turn. */
.rf-drawer-close {
  appearance: none;
  cursor: pointer;
  width: 30px;
  height: 30px;
  padding: 0;
  flex: 0 0 auto;
  border: 0;
  background: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: 23px;
  line-height: 1;
  color: var(--ink-faded);
  transition: color 180ms ease, transform 240ms cubic-bezier(0.4, 0, 0.2, 1);
}
.rf-drawer-close:hover {
  color: var(--vermilion);
  transform: rotate(90deg);
}

/* Jump-drawer body — tier shortcuts as mono-caps buttons. */
.rf-drawer-tiers {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  align-items: baseline;
}
.rf-drawer-tier {
  appearance: none;
  border: 0;
  background: transparent;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 3px 8px;
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  transition: color 160ms ease;
}
/* Hover draws a vermilion underline sliding in left → right. */
.rf-drawer-tier::after {
  content: "";
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 0;
  height: 1px;
  background: var(--vermilion);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 220ms cubic-bezier(0.5, 0, 0.25, 1.1);
}
.rf-drawer-tier:hover { color: var(--vermilion); }
.rf-drawer-tier:hover::after { transform: scaleX(1); }
.rf-drawer-tier .n {
  color: var(--vermilion);
  font-weight: 500;
}

.rf-eyebrow {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 13px;
  color: var(--ink-faded);
  margin-bottom: 22px;
  letter-spacing: 0.04em;
}

.rf-title {
  font-family: var(--display);
  font-style: normal;
  font-weight: 500;
  font-size: clamp(44px, 6vw, 68px);
  line-height: 0.95;
  letter-spacing: 0.005em;
  color: var(--ink);
  margin: 0 0 8px;
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0;
  white-space: nowrap;
}

/* "Rhyme" — italic, the leading voice */
.rf-title-rhyme {
  font-style: italic;
  font-weight: 500;
}

/* Middot between the two words — ink dot, smaller, mid-baseline */
.rf-title-amp {
  display: inline-block;
  font-style: normal;
  font-size: 0.42em;
  font-weight: 400;
  color: var(--ink-faded);
  margin: 0 0.32em;
  transform: translateY(-0.32em);
}

/* "Finder" — upright, smaller, letter-spaced —
   the quiet utility word beside the poetic one */
.rf-title-finder {
  font-style: normal;
  font-weight: 400;
  font-size: 0.62em;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  align-self: center;
  padding-top: 0.18em;
}

/* Vermilion seal — a small hanko-style stamp tucked beside the title */
.rf-seal {
  position: absolute;
  top: 2px;
  right: -54px;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--vermilion);
  color: var(--paper);
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  line-height: 1;
  letter-spacing: 0;
  /* the stamp ink is uneven — irregular borders + grainy mask */
  border-radius: 2px;
  box-shadow:
    inset 0 0 0 2px rgba(255, 240, 220, 0.18),
    inset 0 0 12px rgba(80, 10, 0, 0.45);
  transform: rotate(-6deg);
  mask-image: radial-gradient(ellipse at 30% 40%, black 60%, rgba(0,0,0,0.85) 80%, rgba(0,0,0,0.6) 95%);
  -webkit-mask-image: radial-gradient(ellipse at 30% 40%, black 60%, rgba(0,0,0,0.85) 80%, rgba(0,0,0,0.6) 95%);
}

.rf-seal-glyph {
  text-shadow: 0 0 1px rgba(255,255,255,0.10);
}

.rf-divider {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin: 22px auto 0;
  max-width: 240px;
  color: var(--ink-faded);
}

.rf-divider-line {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--hair), transparent);
}

.rf-divider-mark {
  font-family: var(--display);
  font-size: 13px;
  color: var(--ink-faded);
  line-height: 1;
}

/* ── Epigraphs (footer rotator) ──────────────────────────────── */

/* One epigraph at a time — they cross-fade on a slow rotation.
   Berman speaks of the room a rhyme builds; Oliver of the discipline
   of answering the call. The footer holds both, only one visible. */
.rf-epigraphs {
  position: relative;
  width: 100%;
  max-width: 600px;
  margin: 56px auto 0;
  padding: 24px 8px 0;
  border-top: 1px solid var(--hair-soft);
  /* Reserve enough space for the taller of the two so the page
     doesn't reflow as they swap. Mary Oliver's three-paragraph
     epigraph is the taller one. */
  min-height: 230px;
}

.rf-epigraph {
  position: absolute;
  inset: 36px 8px auto 8px;
  margin: 0;
  padding: 0;
  text-align: center;
  color: var(--ink);
  opacity: 0;
  pointer-events: none;
  transition: opacity 600ms ease;
}

.rf-epigraph.is-active {
  opacity: 0.55 !important;
  pointer-events: auto;
  position: relative !important;
  inset: auto !important;
}

/* Berman: short verse, italic centered */
.rf-epigraph-berman {
  font-family: "Spectral", "Songti SC", serif;
  font-style: italic;
  font-weight: 400;
  font-size: 13px;
  line-height: 1.65;
}

.rf-epigraph-line {
  margin: 0;
  text-wrap: balance;
}

/* Mary Oliver: prose, three paragraphs — must fit fully without truncation */
.rf-epigraph-oliver {
  font-family: "Spectral", "Songti SC", serif;
  font-style: normal;
  font-weight: 400;
  font-size: 12.5px;
  line-height: 1.6;
  text-align: left;
  max-width: 600px;
  margin-left: auto;
  margin-right: auto;
}

.rf-epigraph-prose {
  margin: 0 0 8px;
  text-wrap: pretty;
  hyphens: auto;
}
.rf-epigraph-prose:last-of-type { margin-bottom: 0; }

/* Decorative vermilion mark — sits centered above each epigraph */
.rf-epigraph-mark {
  display: block;
  width: 28px;
  height: 28px;
  margin: 0 auto 18px;
}

/* Hide footer once results appear — workspace mode. */
.rf-app:has(#results:not(:empty)) .rf-epigraphs,
.rf-app:has(#source-summary:not(:empty)) .rf-epigraphs {
  display: none;
}

.rf-epigraph-attr {
  display: flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: nowrap;
  gap: 10px;
  margin-top: 18px;
  font-family: var(--mono);
  font-style: normal;
  font-size: 9.5px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
  white-space: nowrap;
}

/* Oliver's attribution sits flush left under the prose */
.rf-epigraph-oliver .rf-epigraph-attr {
  justify-content: flex-start;
}

.rf-epigraph-dash {
  font-family: var(--display);
  font-size: 13px;
  letter-spacing: 0;
  color: var(--ink-faded);
}

.rf-epigraph-dates,
.rf-epigraph-source {
  opacity: 0.7;
  font-feature-settings: "tnum";
}

.rf-epigraph-source {
  font-style: italic;
  text-transform: none;
  letter-spacing: 0.04em;
  font-size: 10px;
}

/* Two dots beneath the epigraphs — manual switcher.
   Vermilion ink-stamp dots, the active one filled. */
.rf-epigraph-dots {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 28px;
  position: relative;
  z-index: 1;
}

.rf-epigraph-dot {
  appearance: none;
  border: 1px solid var(--vermilion);
  background: transparent;
  width: 8px;
  height: 8px;
  padding: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: background 200ms ease, transform 160ms ease, opacity 200ms ease;
  opacity: 0.55;
}

.rf-epigraph-dot:hover { opacity: 0.9; transform: scale(1.15); }

.rf-epigraph-dot[aria-pressed="true"] {
  background: var(--vermilion);
  opacity: 1;
}

@media (max-width: 720px) {
  .rf-epigraphs {
    margin: 40px auto 32px;
    min-height: auto;
  }
  .rf-epigraph-berman { font-size: 13px; }
  .rf-epigraph-oliver { font-size: 12px; }

  /* On mobile the viewport is too short to fix the hero in the center
     and pin the footer to the bottom without overlap — fall back to
     normal document flow: hero near the top, then the epigraph below. */
  .rf-app:not(:has(#results:not(:empty))):not(:has(#source-summary:not(:empty))) .rf-hero {
    position: relative;
    top: auto;
    left: auto;
    transform: none;
    width: 100%;
    margin-top: 6vh;
  }
  .rf-app:not(:has(#results:not(:empty))):not(:has(#source-summary:not(:empty))) .rf-epigraphs {
    position: relative;
    bottom: auto;
    left: auto;
    transform: none;
    border-top: 1px solid var(--hair-soft);
    padding-top: 24px;
  }
  /* Shrink the shanshui painting so the hero takes less vertical space
     on small screens. */
  .rf-title-row .rf-mg-shanshui {
    width: 200px;
    height: 120px;
  }
}

/* ── Marginalia: literary motifs in the corners ───────────────── */

.rf-marginalia {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
}

.rf-mg {
  position: absolute;
}

/* Shanshui sits directly above the title, snug — its water-line and pine-dotted
   ridge form a banner overhead, the red sail and 韵 seal each providing one
   vermilion accent that mirrors across the wordmark. */
.rf-title-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

/* Override .rf-mg's absolute positioning since the painting now lives in
   normal flow as part of the title row. */
.rf-title-row .rf-mg-shanshui {
  position: static;
  width: 240px;
  height: 145px;
  opacity: 0.92;
}

@media (max-width: 980px) {
  .rf-mg-shanshui {
    width: 260px;
    height: 160px;
    opacity: 0.8;
  }
}

.rf-mg-seal-only {
  position: absolute;
  top: calc(8vh + 165px);
  left: max(60px, calc(50vw - 448px));
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--vermilion);
  color: var(--paper);
  font-family: var(--display);
  font-size: 18px;
  font-weight: 600;
  line-height: 1;
  border-radius: 1.5px;
  box-shadow: inset 0 0 0 1.5px rgba(255, 240, 220, 0.18),
              inset 0 0 8px rgba(80, 10, 0, 0.4);
  transform: rotate(-3deg);
  opacity: 0.92;
}

@media (max-width: 980px) {
  .rf-mg-seal-only { display: none; }
}

/* ── Search ──────────────────────────────────────────────────── */

.rf-panel {
  width: 100%;
  max-width: 460px;
  margin: 28px auto 0;
  position: relative;
}

.rf-form { margin: 0; }

.rf-input-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: stretch;
  border-bottom: 1px solid var(--ink);
  background: transparent;
  transition: border-color 160ms ease;
  position: relative;
}

/* A small ink-brush-stroke shadow under the line */
.rf-input-row::after {
  content: "";
  position: absolute;
  left: 6%;
  right: 6%;
  bottom: -3px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--ink-ghost) 30%, var(--ink-ghost) 70%, transparent);
  opacity: 0.7;
}

.rf-input-row:focus-within {
  border-bottom-color: var(--vermilion);
}

input[type="text"] {
  font-family: var(--display);
  font-style: italic;
  font-size: clamp(18px, 2.2vw, 24px);
  font-weight: 400;
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  padding: 10px 4px;
  color: var(--ink);
  text-align: center;
  letter-spacing: 0.005em;
}

/* While the user is actively typing, slide text to the left so the
   cursor sits at the natural reading start. The empty/placeholder
   state stays centered. */
/* (Input text stays centered at all times.) */

input[type="text"]::placeholder {
  color: rgba(107, 94, 74, 0.55);
  font-style: italic;
}

.rf-go-btn {
  font-family: var(--display);
  font-size: 22px;
  border: none;
  background: transparent;
  color: var(--ink);
  padding: 0 12px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 160ms ease, transform 160ms ease;
}

.rf-go-btn:hover { color: var(--vermilion); }
.rf-go-btn:hover .rf-go-btn-arrow { transform: translateX(4px); }
.rf-go-btn-arrow { display: inline-block; transition: transform 160ms ease; }

.rf-go-btn:disabled { opacity: 0.5; cursor: wait; }
.rf-go-btn[data-busy="true"] .rf-go-btn-arrow {
  animation: rf-spin 700ms linear infinite;
}

@keyframes rf-spin { to { transform: rotate(360deg); } }

.rf-status {
  margin-top: 14px;
  text-align: center;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--ink-faded);
  min-height: 1.2em;
  text-transform: uppercase;
}

.rf-status[data-state="error"] { color: var(--vermilion-deep); }

/* ── Results ─────────────────────────────────────────────────── */

.rf-results-shell {
  width: 100%;
  max-width: 760px;
  margin: 56px auto 0;
  padding-bottom: 96px;
}

.rf-results-shell:has(#source-summary:empty):has(#results:empty) {
  display: none;
}

.rf-source-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 18px;
  /* The source-summary block reads as the page's title section — it
     needs visible breathing room below the metadata so the eye knows
     it's a coherent header, not a one-line label. Bottom hair-border
     gives it a soft floor; the tabs sit immediately under (no margin
     gap) so we still don't waste paper. End result: source-summary
     ~90px tall, clearly heavier than each tab cell. */
  padding: 18px 0 24px;
  margin-bottom: 0;
  border-top: 2px solid var(--ink);
  border-bottom: 1px solid var(--hair);
  position: relative;
}

.rf-source-summary:empty { display: none; }

.rf-source-word {
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: clamp(34px, 4.5vw, 48px);
  line-height: 1;
  color: var(--ink);
  letter-spacing: -0.005em;
}

.rf-source-tag {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
}

.rf-source-tag::before { content: "·  "; color: var(--vermilion); opacity: 0.7; }
.rf-source-tag:first-of-type::before { content: ""; }
.rf-source-tag:first-of-type {
  color: var(--paper);
  background: var(--ink);
  padding: 4px 9px;
  letter-spacing: 0.2em;
}
/* Stress tag carries an info popover that appears on hover (desktop)
   or tap-to-focus (touch — tabindex="0" makes it focusable, and
   :focus-within shows the popover; tapping elsewhere blurs it). */
.rf-source-tag-stress {
  position: relative;
  cursor: pointer;
}
/* The popover resets the parent's mono caps + 0.2em letter-spacing so
   the prose inside reads as body text. */
.rf-source-tag-stress > .rf-tier-pop {
  letter-spacing: 0;
  text-transform: none;
  font-weight: 400;
  color: var(--ink);
  pointer-events: none;
}
.rf-source-tag-stress:hover > .rf-tier-pop,
.rf-source-tag-stress:focus-visible > .rf-tier-pop,
.rf-source-tag-stress:focus-within > .rf-tier-pop {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
  pointer-events: auto;
}

/* Stress popover: a wider 2-column comparison so the reader can
   contrast masculine vs feminine in one glance instead of toggling
   between two single-column popovers. */
.rf-stress-pop { width: 520px; }
.rf-stress-pop-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 18px;
}
.rf-stress-pop-col {
  padding: 0 4px;
}
.rf-stress-pop-col + .rf-stress-pop-col {
  border-left: 1px dashed var(--ink-ghost);
  padding-left: 14px;
}
/* The column matching the searched word's stress class is marked so
   the reader can see where they stand in the comparison. */
.rf-stress-pop-col.is-current .rf-tier-pop-eyebrow {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.rf-stress-pop-current-tag {
  font-family: var(--mono);
  font-size: 8px;
  letter-spacing: 0.14em;
  color: var(--paper);
  background: var(--vermilion);
  padding: 2px 6px;
  border-radius: 1px;
}
.rf-stress-pop-examples-label {
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
}
@media (max-width: 720px) {
  .rf-stress-pop { width: 92vw; }
  .rf-stress-pop-cols { grid-template-columns: 1fr; gap: 14px; }
  .rf-stress-pop-col + .rf-stress-pop-col {
    border-left: none;
    border-top: 1px dashed var(--ink-ghost);
    padding-left: 4px;
    padding-top: 12px;
  }
}

/* Highlight the phonetic kernel — the vowel & coda values */
.rf-source-tag .rf-tag-val {
  color: var(--vermilion);
  font-weight: 600;
}

.rf-results { display: grid; gap: 44px; }

.rf-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 40px 24px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  color: var(--ink-faded);
  text-transform: uppercase;
}

.rf-spinner {
  display: inline-block;
  width: 11px;
  height: 11px;
  border: 1.5px solid var(--hair);
  border-top-color: var(--vermilion);
  border-radius: 50%;
  animation: rf-spin 700ms linear infinite;
}

/* Tier — each tier card sits behind a vertical bar whose colour fades
   with the stability score: full vermilion at stability 5 (Perfect),
   ink-ghost at 1 (Consonance). The eye reads the gradient down the
   page as a stable→loose axis without needing a label on each tier. */
.rf-tier {
  position: relative;
  padding: 4px 0 8px 22px;
  border-left: 3px solid var(--vermilion);
}
.rf-tier[data-stability="5"] { border-left-color: var(--vermilion); }
.rf-tier[data-stability="4"] { border-left-color: rgba(177, 59, 44, 0.75); }
.rf-tier[data-stability="3"] { border-left-color: rgba(177, 59, 44, 0.50); }
.rf-tier[data-stability="2"] { border-left-color: rgba(177, 59, 44, 0.30); }
.rf-tier[data-stability="1"] { border-left-color: rgba(177, 59, 44, 0.15); }
/* Identity is off the rhyme scale — neutral grey rather than vermilion. */
.rf-tier[data-stability="0"] { border-left-color: rgba(60, 50, 40, 0.25); border-left-style: dashed; }
.rf-tier[data-stability="0"] .rf-tier-title { color: rgba(26, 20, 14, 0.65); }

.rf-tier-head {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  column-gap: 18px;
  row-gap: 6px;
  margin-bottom: 22px;
  position: relative; /* anchor for .rf-tier-pop */
}

/* Title strip is a button so users discover the click affordance via
   the cursor; visually, default button chrome is reset. */
.rf-tier-titlebox {
  appearance: none;
  border: none;
  background: transparent;
  padding: 4px 8px 4px 0;
  margin-left: -8px;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-width: 0;
  border-radius: 2px;
  transition: background 100ms ease;
}
.rf-tier-titlebox:hover { background: rgba(177, 59, 44, 0.06); }
.rf-tier-titlebox:hover .rf-tier-info { color: var(--vermilion); border-color: var(--vermilion); }
.rf-tier-titlebox:hover .rf-tier-title { color: var(--vermilion); }
.rf-tier-titlebox:hover .rf-tier-subtitle { color: var(--vermilion); opacity: 0.85; }

/* Title row sits on top — italic display, default ink, vermilion on
   hover/open. The "?" info glyph rides next to the label, not below. */
.rf-tier-title-row {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.rf-tier-title {
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 30px;
  line-height: 1.1;
  color: var(--ink);
  letter-spacing: -0.005em;
  transition: color 120ms ease;
}
.rf-tier-head-open .rf-tier-title { color: var(--vermilion); }

/* Subtitle drops to its own line beneath the title in mono caps —
   reads as an editorial dateline rather than an inline aside. */
.rf-tier-subtitle {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  font-style: normal;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faded);
  line-height: 1;
  transition: color 120ms ease, opacity 120ms ease;
}
.rf-tier-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-left: 2px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  font-style: normal;
  border: 1px solid var(--ink-faded);
  border-radius: 50%;
  color: var(--ink-faded);
  line-height: 1;
  vertical-align: 2px;
  transition: color 100ms ease, border-color 100ms ease;
}
.rf-tier-head-open .rf-tier-info {
  color: var(--paper);
  background: var(--vermilion);
  border-color: var(--vermilion);
}

.rf-spectrum {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
}

.rf-spectrum-end { display: none; }

.rf-cells { display: inline-flex; gap: 3px; align-items: flex-end; }

.rf-cell {
  display: inline-block;
  width: 5px;
  height: 12px;
  background: var(--hair-soft);
}

.rf-cells .rf-cell:nth-child(1) { height: 5px; }
.rf-cells .rf-cell:nth-child(2) { height: 7px; }
.rf-cells .rf-cell:nth-child(3) { height: 9px; }
.rf-cells .rf-cell:nth-child(4) { height: 11px; }
.rf-cells .rf-cell:nth-child(5) { height: 13px; }

/* ── Tier-info popover ─────────────────────────────────────────────
   Reuses the lyric-popover paper / ink / sumi-shadow language. Click
   the title strip to open; click outside / press Esc / re-click to
   close. */
.rf-tier-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 70;
  width: 460px;
  max-width: 92vw;
  padding: 14px 18px 16px;
  background: var(--paper);
  border: 1px solid var(--ink);
  box-shadow: 4px 4px 0 var(--ink-ghost);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-2px);
  transition: opacity 140ms ease, transform 140ms ease, visibility 0s linear 140ms;
  text-align: left;
}
.rf-tier-head-open .rf-tier-pop {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}

.rf-tier-pop-section + .rf-tier-pop-section {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed var(--ink-ghost);
}
.rf-tier-pop-eyebrow {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--vermilion);
  margin-bottom: 6px;
}
.rf-tier-pop-body {
  margin: 0;
  font-family: var(--display);
  font-size: 15px;
  line-height: 1.45;
  color: var(--ink);
  text-wrap: pretty;
}
.rf-tier-pop-example {
  font-style: italic;
  color: var(--ink-soft);
}
.rf-tier-pop-note {
  margin-top: 8px;
  font-size: 13px;
  font-style: italic;
  color: var(--ink-faded);
}
/* Pattison's 3-condition definition: numbered list rendered tight
   inside the popover. Markers sit in their own column so the bullet
   text aligns cleanly across all three rows. */
.rf-tier-pop-rule-list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: rf-rule;
  font-family: var(--display);
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--ink);
  text-wrap: pretty;
}
.rf-tier-pop-rule-list li {
  counter-increment: rf-rule;
  position: relative;
  padding-left: 22px;
}
.rf-tier-pop-rule-list li::before {
  content: counter(rf-rule) ".";
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--vermilion);
}

/* 6-stop spectrum inside the popover. Dots laid out left→right at
   the same height; current tier dot is large + vermilion + with a
   label underneath. Other dots are small ink-ghost markers. */
.rf-tier-spectrum-stops {
  list-style: none;
  margin: 6px 0 4px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  align-items: start;
  position: relative;
}
/* Gradient track behind the dots — vermilion → faint vermilion mirrors
   the per-tier left-bar fade. Positioned to pass through the dot row. */
.rf-tier-spectrum-track {
  position: absolute;
  left: 10%;
  right: 10%;
  top: 6px;
  height: 1px;
  background: linear-gradient(to right, var(--vermilion), rgba(177, 59, 44, 0.2));
  z-index: 0;
}
.rf-tier-spectrum-stop {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: var(--mono);
  font-size: 8.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faded);
  text-align: center;
  line-height: 1.3;
  position: relative;
  z-index: 1;
}
/* Fixed-height slot keeps every dot vertically centered on the same
   horizontal axis regardless of the current dot's larger size. */
.rf-tier-spectrum-dot-slot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  margin-bottom: 6px;
  background: var(--paper); /* mask the track behind the dot */
}
.rf-tier-spectrum-stop .rf-tier-spectrum-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--ink-ghost);
}
.rf-tier-spectrum-stop.is-current .rf-tier-spectrum-dot {
  width: 10px; height: 10px;
  background: var(--vermilion);
}
/* Labels share a min-height (= 2 lines) so single-word labels and the
   wrapping "Additive / Subtractive" align on the same baseline. */
.rf-tier-spectrum-label {
  min-height: 2.4em;
  display: block;
  opacity: 0.7;
}
.rf-tier-spectrum-stop.is-current .rf-tier-spectrum-label {
  color: var(--ink);
  opacity: 1;
  font-weight: 500;
}
.rf-tier-pop-axis {
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 8px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faded);
  margin-top: 6px;
}

/* Consonant family chart (family tier only). */
.rf-tier-family-chart {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 11px;
  margin-top: 4px;
}
.rf-tier-family-chart th,
.rf-tier-family-chart td {
  border: 1px solid var(--ink-ghost);
  padding: 4px 0;
  text-align: center;
  color: var(--ink);
  font-weight: 500;
}
.rf-tier-family-chart thead th {
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--vermilion);
  border: none;
  border-bottom: 1px solid var(--ink-ghost);
  padding: 4px 4px 6px;
}
.rf-tier-family-chart .rf-tier-family-row-label {
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
  text-align: right;
  border: none;
  padding-right: 8px;
  font-weight: 500;
}
.rf-tier-family-chart .rf-tier-family-empty {
  background: rgba(26, 20, 14, 0.04);
}

.rf-tier-head .rf-cell-on { background: var(--vermilion); }

.rf-tier-count {
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 26px;
  line-height: 1;
  color: var(--vermilion);
  white-space: nowrap;
  justify-self: end;
}

.rf-tier-count::before {
  content: "n. ";
  font-family: var(--mono);
  font-style: normal;
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faded);
  margin-right: 4px;
  vertical-align: 0.18em;
}

.rf-subgroup { margin-top: 20px; }
.rf-subgroup:first-of-type { margin-top: 0; }

/* Per-subgroup "show N more" affordance. The button appears beneath the
   default words within each syllable group when the lower-tier overflow
   is large enough to warrant hiding (more than LOWER_INLINE_THRESHOLD).
   Click reveals the lower-tier words inline within the same subgroup,
   with subtle dimming to mark them as less common. */
.rf-subgroup-show-more {
  display: inline-block;
  margin-top: 8px;
  padding: 3px 8px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink);
  background: transparent;
  border: 1px solid currentColor;
  cursor: pointer;
  opacity: 0.4;
  transition: opacity 0.15s ease;
}
.rf-subgroup-show-more:hover { opacity: 0.85; }

/* Lower-tier candidates flow inline with the default row, dimmed in
   colour. Avoid `opacity` here because it would cascade to nested
   popovers and let surrounding words show through. */
.rf-word--lower.rf-c-very-common,
.rf-word--lower.rf-c-common {
  color: rgba(26, 20, 14, 0.6);
}
.rf-word--lower.rf-c-uncommon {
  color: rgba(58, 46, 31, 0.6);
}
/* Lower words live in the DOM so the lex filter can see them. Hide
   them visually until the subgroup is opened (button click or
   filter-driven auto-reveal). The lex-filter rules carry higher
   specificity, so common-lower words still vanish when the COMMON
   chip is off. */
.rf-subgroup:not(.rf-subgroup--lower-shown) .rf-word--lower {
  display: none;
}

.rf-subgroup-label {
  display: inline-block;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  padding: 3px 8px;
  margin-bottom: 14px;
}

.rf-words {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 22px;
  align-items: baseline;
}

.rf-word {
  display: inline-block;
  font-family: "Spectral", "Songti SC", "STSong", serif;
  font-size: 21px;
  font-weight: 500;
  line-height: 1.5;
  color: var(--ink);
  cursor: default;
  transition: color 120ms ease;
}

/* Hover: just turn the word vermilion. No underline — underlines read
   as 'clickable' on the web, and right now there's nothing to click. */
.rf-word:hover {
  color: var(--vermilion);
}

/* Very-common words: bold + ink color, no underline. Weight contrast
   alone is enough to make them pop against the italic non-bold rest. */
.rf-word.rf-c-very-common {
  font-weight: 700;
  font-style: normal;
  color: var(--ink);
}
.rf-word.rf-c-common { font-weight: 500; font-style: normal; color: var(--ink); }
.rf-word.rf-c-uncommon { font-weight: 400; font-style: italic; color: var(--ink-faded); }

/* Pinned candidate — the word stays vermilion (same hue as hover) so
   the reader can spot which word the popover belongs to from the
   surrounding tier. Higher specificity than every commonness tier and
   the cliché override so the colour wins. Cliché's strikethrough +
   opacity dim still apply, just in vermilion. */
.rf-word.rf-pinned,
.rf-word.rf-pinned.rf-c-very-common,
.rf-word.rf-pinned.rf-c-common,
.rf-word.rf-pinned.rf-c-uncommon,
.rf-word.rf-pinned.rf-cliche,
.rf-word.rf-pinned.rf-mismatch {
  color: var(--vermilion);
  opacity: 1;
}

.rf-word.rf-mismatch {
  color: var(--ink-faded);
  text-decoration: underline dotted;
  text-decoration-color: var(--hair);
  text-underline-offset: 4px;
}

.rf-word.rf-cliche {
  /* Translucent ink instead of opacity — opacity creates a stacking
     context that bled through to the popover, making it look ~45%
     transparent. Colour-alpha keeps the dim text + strikethrough but
     leaves descendants (badge, popover) at full opacity. */
  color: rgba(26, 20, 14, 0.45);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

.rf-word-flag {
  font-family: var(--mono);
  font-size: 8px;
  letter-spacing: 0.08em;
  color: var(--vermilion);
  margin-left: 2px;
  vertical-align: super;
  text-transform: uppercase;
  font-style: normal;
}

.rf-empty {
  padding: 40px 24px;
  text-align: center;
  font-family: var(--display);
  font-style: italic;
  font-size: 18px;
  color: var(--ink-faded);
}

@media (max-width: 640px) {
  .rf-hero { padding-top: 12vh; }
  .rf-tier-head { gap: 8px; }
  .rf-tier-count { margin-left: 0; }
  .rf-seal { right: -42px; width: 36px; height: 36px; font-size: 18px; }

  /* Collapsed bar stays ONE row on phones — seal · pill · toggle ·
     jump · filter all inline (no column stack). Gaps, paddings, and
     the tools cluster are tightened vs. desktop so everything fits
     beside a usable pill at 375px. The 8px left pad and the 56px right
     pad keep the bar edge-symmetric: the seal sits 8px from the left
     and the colophon ✉ (pulled to right:8 below) sits 8px from the
     right, with the reserve just clearing the ✉. */
  .rf-app:has(#results:not(:empty)) .rf-hero,
  .rf-app:has(#source-summary:not(:empty)) .rf-hero {
    gap: 10px;
    padding: 9px 56px 9px 8px;
  }
  /* The search bar is the priority control — let it grow to fill the
     free space, and give it a generous floor so it never reads as a
     stubby little box. The point isn't a literal letter count; it's
     visual balance — a search bar shorter than this looks cramped next
     to the toggle. The stepped breakpoints below shed the secondary
     tools early so the bar stays roomy rather than getting squeezed. */
  .rf-app:has(#results:not(:empty)) .rf-panel,
  .rf-app:has(#source-summary:not(:empty)) .rf-panel {
    max-width: none;
    min-width: 0;
  }
  .rf-app:has(#results:not(:empty)) .rf-input-row,
  .rf-app:has(#source-summary:not(:empty)) .rf-input-row {
    width: 100%;
    min-width: 150px;
  }
  /* min-width:0 lets the input itself scroll for words longer than the
     pill rather than widening (and overflowing) the bar. */
  .rf-app:has(#results:not(:empty)) input[type="text"],
  .rf-app:has(#source-summary:not(:empty)) input[type="text"] {
    min-width: 0;
  }
  /* Tighten the tools cluster so the toggle + 2 icon buttons claim
     less of the row. */
  .rf-app:has(#results:not(:empty)) .rf-bar-tools,
  .rf-app:has(#source-summary:not(:empty)) .rf-bar-tools {
    gap: 6px;
    padding-left: 10px;
    margin-left: 0;
  }
  /* The mobile .rf-seal rule above is for the empty-state hero; in the
     collapsed bar keep the 22px shrunk home stamp. */
  .rf-app:has(#results:not(:empty)) .rf-seal,
  .rf-app:has(#source-summary:not(:empty)) .rf-seal {
    right: auto;
    width: 22px;
    height: 22px;
    font-size: 12px;
  }
  /* (Colophon ✉ position + divider for this collapsed mobile bar are
     overridden in a media query AFTER the base .rf-colophon rules — see
     "Colophon · collapsed mobile" near the colophon section — because
     equal-specificity rules need to win on source order.) */
}

/* ── Collapsed-bar priority: shed tools to protect the search bar ────
   Priority: search bar > filter > toggle > jump. Filter is the ONLY way
   to reach lexicon filtering on a phone, so it (and the colophon ✉) are
   kept at every width; jump and then the toggle yield as the bar
   narrows. The toggle is mirrored by the tab strip below the results,
   so dropping it loses no reach.
     · ≤445px (all phones): drop jump → bar is search · toggle · filter.
       The search bar takes the freed space (e.g. ~168px at 402).
     · ≤383px: drop the toggle too, so the search bar keeps a roomy
       width beside the filter (e.g. ~225px at 375).
   Above 445px (tablets, foldables) all three tools fit beside a roomy
   search bar, so they stay. */
@media (max-width: 445px) {
  .rf-app:has(#results:not(:empty)) #btn-jump,
  .rf-app:has(#source-summary:not(:empty)) #btn-jump {
    display: none;
  }
}
@media (max-width: 383px) {
  .rf-app:has(#results:not(:empty)) .rf-tab-toggle,
  .rf-app:has(#source-summary:not(:empty)) .rf-tab-toggle {
    display: none;
  }
}

/* ── Source-word panel (Phase 1.7) ─────────────────────────────────
   Always-visible strip just under the source-summary header. Anchors
   the searched word's two best end-position quotes so they live
   above the candidate fold rather than buried in popovers. */
.rf-source-panel {
  margin: 0 0 36px;
  padding: 18px 0 22px;
  border-bottom: 1px solid var(--hair);
}
.rf-source-panel:empty { display: none; }

/* Editorial heading + tiny meta line. The display H2 leads, mono caps
   meta sits beneath. */
.rf-source-panel-head {
  padding-bottom: 12px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--hair-soft);
}
.rf-source-panel-title {
  margin: 0;
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 24px;
  line-height: 1.15;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.rf-source-panel-title em {
  font-style: italic;
  color: var(--vermilion);
  font-weight: 600;
}
.rf-source-panel-meta {
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
}

.rf-source-panel-quotes { display: flex; flex-direction: column; gap: 14px; }

.rf-source-panel-item { margin: 0; }
.rf-source-panel-quote {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 18px;
  cursor: pointer;
  padding: 4px 6px 6px 8px;
  margin: -4px -6px -6px -8px;
  border-left: 2px solid transparent;
  transition: background 100ms ease, border-color 100ms ease;
}
.rf-source-panel-quote:hover {
  background: rgba(177, 59, 44, 0.10);
  border-left-color: var(--vermilion);
}
/* Click-to-expand stanza mirrors the candidate-popover pattern. */
.rf-source-panel-item .rf-lyric-stanza { margin-top: 6px; }
.rf-source-panel-item.is-open .rf-lyric-stanza { display: block; }
.rf-source-panel-line {
  font-family: var(--display);
  font-style: italic;
  font-size: 19px;
  line-height: 1.35;
  color: var(--ink);
  text-wrap: pretty;
}
.rf-source-panel-attr {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faded);
  white-space: nowrap;
}

@media (max-width: 720px) {
  /* Source-panel is already a single column; on narrow viewports the
     quote rows stack the line above the attribution. */
  .rf-source-panel-quote { grid-template-columns: 1fr; gap: 4px; }
  /* Tier-info popovers are 460px wide / max-width: 92vw — at 375vw that
     resolves to 345px and overflows the column it's anchored in (parent
     ≈ 307px). Even hidden, the absolute box widens the layout viewport
     and gives the page horizontal scroll. Let the pop span the screen
     with a fixed gutter on phones so it always fits. */
  .rf-tier-pop {
    width: auto;
    max-width: calc(100vw - 28px);
    left: 14px;
    right: 14px;
  }
}

/* ── Lyric badge + popover (Phase 1.7 — editorial cut) ────────────
   The popover only ever shows tier-1 (exact match at line end) by
   default; tier-2 (inflected end-position) lives behind a single
   faint footer toggle. Tier-3 / 4 (mid-line) are removed from this
   surface entirely — they belong in a future word-study tool. */
.rf-word.rf-has-lyrics { position: relative; cursor: pointer; }

/* Restored 1.5-style chunky dot badge: a 6px filled vermilion dot
   sits flush against the count via inline-flex + 3px gap. */
.rf-lyric-badge {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  margin-left: 5px;
  vertical-align: 1px;
  font-style: normal;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.02em;
  color: var(--vermilion);
}
.rf-lyric-badge::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;   /* attested (rhymed with the searched word): slightly bigger */
  background: var(--vermilion);
  border-radius: 50%;
  transform: translateY(-1px);
  flex: none;
}
/* In-corpus (ambient): filled vermilion dot (inherits the fill above), a touch
   smaller + a FADED count of the word's own line-end uses. The size gap is
   gentle — attested still reads as bigger, but not jarringly so; the faded
   count reinforces the distinction. */
.rf-lyric-badge.rf-lyric-badge--corpus::before {
  width: 5px; height: 5px;
}
.rf-lyric-badge.rf-lyric-badge--corpus .rf-lyric-badge-count {
  color: var(--ink-faded);
  font-weight: 400;
}

/* Standalone-uses (not-rhymed / inspiration) control at the foot of a
   popover. Collapsed by default — a faint mono toggle; the list is the
   word used at line-end without a rhyme partner. */
.rf-lyric-standalone {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--hair-soft);
}
.rf-lyric-standalone-toggle {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.02em;
  color: var(--ink-faded);
  background: none;
  border: 0;
  padding: 2px 0;
  cursor: pointer;
}
.rf-lyric-standalone-toggle:hover { color: var(--vermilion); }
.rf-lyric-standalone-list[hidden] { display: none; }
.rf-lyric-standalone-list { margin-top: 6px; }

.rf-lyric-pop {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 50;
  width: 420px;
  max-width: 92vw;
  max-height: 540px;
  overflow-y: auto;
  padding: 12px 16px 14px;
  background: var(--paper);
  border: 1px solid var(--ink);
  box-shadow: 4px 4px 0 var(--ink-ghost);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-2px);
  /* 200ms close delay gives the user ample time to traverse the gap
     into the popover. visibility: hidden blocks pointer events on its
     own — no need for a conditional pointer-events: none, which used
     to switch off instantly and stranded the bridge mid-traverse. */
  transition: opacity 160ms ease, transform 160ms ease, visibility 0s linear 200ms;
  text-align: left;
}
/* Reveal the pop on devices with a real pointer. The open trigger is
   .rf-hovering (added by JS hover-intent, not bare :hover) so a pointer
   sweeping across the dense candidate grid doesn't trail a comet of
   popovers — see the velocity sampler in main.js. focus-within (keyboard)
   and .rf-pinned (click) stay instant: those are explicit intent already.
   Touch devices skip this — there's no useful intermediate state on a
   phone (every "hover" is a tap), and showing the pop on focus-within
   after a tap fights the explicit pin/unpin toggle. */
@media (hover: hover) {
  .rf-word.rf-has-lyrics.rf-hovering .rf-lyric-pop,
  .rf-word.rf-has-lyrics:focus-within .rf-lyric-pop {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition-delay: 0s;
  }
}
.rf-word.rf-pinned .rf-lyric-pop {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
  z-index: 60;
  box-shadow: 5px 5px 0 var(--ink);
}

/* Hover-bridge: the visual gap between the word and the popover (top:
   calc(100% + 8px)) was a dead zone — moving the mouse from word into
   popover crossed it and the popover dismissed. The ::before pseudo
   extends the popover's hoverable area upward by 10px to cover the
   gap. Invisible. Desktop only — mobile reuses ::before for the
   bottom-sheet drag-handle pill. */
@media (hover: hover) {
  .rf-lyric-pop::before {
    content: "";
    position: absolute;
    top: -12px;
    left: -16px;
    right: -16px;
    height: 12px;
  }
}

.rf-lyric-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--ink-ghost);
  margin-bottom: 10px;
}
.rf-lyric-head-word {
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 22px;
  line-height: 1;
  color: var(--ink);
}
.rf-lyric-head-meta {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
  flex: 1;
}
.rf-lyric-head-pin {
  appearance: none;
  border: none;
  background: transparent;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink-faded);
  cursor: pointer;
  padding: 0 2px;
}
@media (hover: hover) {
  .rf-lyric-head-pin:hover { color: var(--vermilion); }
}
.rf-lyric-head-pin.rf-tapped { color: var(--vermilion); }
.rf-word.rf-pinned .rf-lyric-head-pin { color: var(--vermilion); }

.rf-lyric-item { margin: 0; padding: 0; }
.rf-lyric-item + .rf-lyric-item {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--ink-ghost);
}
.rf-lyric-quote {
  cursor: pointer;
  padding: 4px 8px 6px;
  margin: -4px -8px -6px;
  border-left: 2px solid transparent;
  transition: background 100ms ease, border-color 100ms ease;
}
@media (hover: hover) {
  .rf-lyric-quote:hover {
    background: rgba(177, 59, 44, 0.10);
    border-left-color: var(--vermilion);
  }
}
/* Tap feedback on mobile is JS-driven (see bindMobileTapFeedback in
   main.js) — touchstart paints nothing; only a real, fast tap (lifted
   within 300ms with no scroll) gets the highlight, applied as
   .rf-tapped for 120ms. Scroll and long-press both leave the row
   alone. Instant on/off, no transition, so the feedback follows the
   finger 1:1 without lag. */
.rf-lyric-quote.rf-tapped {
  background: rgba(177, 59, 44, 0.10);
  border-left-color: var(--vermilion);
  transition: none;
}

.rf-lyric-line,
.rf-lyric-partner {
  font-family: var(--display);
  font-style: italic;
  font-size: 17px;
  line-height: 1.4;
  color: var(--ink);
  margin: 0;
  text-wrap: pretty;
}
.rf-lyric-mark { background: transparent; color: var(--vermilion); font-weight: 600; }

.rf-lyric-attr {
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faded);
}
.rf-lyric-attr-song { font-style: italic; text-transform: none; letter-spacing: 0.04em; }

.rf-lyric-stanza {
  display: none;
  margin: 8px 0 0;
  padding: 8px 0 2px 12px;
  border-left: 1px solid var(--ink);
}
.rf-lyric-item.is-open .rf-lyric-stanza { display: block; }
.rf-lyric-stanza-line {
  font-family: var(--display);
  font-style: italic;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-faded);
  margin: 0;
}
.rf-lyric-stanza-line.is-match {
  color: var(--ink);
  background: rgba(177, 59, 44, 0.10);
  padding: 1px 6px;
  margin: 1px -6px;
}

.rf-lyric-inflected {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--ink-ghost);
}
/* When the inflected footer sits directly below the popover header
   (no tier-1 items in between), the head's own border-bottom already
   separates the two — drop the footer's top border + spacing so we
   don't render a dead band. */
.rf-lyric-inflected.rf-lyric-inflected--first {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
/* Header strip: vermilion-soft hover band signals "click anywhere on
   this row to toggle". Same affordance pattern as the quote rows. */
.rf-lyric-inflected-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  cursor: pointer;
  padding: 4px 8px;
  margin: 0 -8px;
  border-left: 2px solid transparent;
  transition: background 100ms ease, border-color 100ms ease;
}
@media (hover: hover) {
  .rf-lyric-inflected-head:hover {
    background: rgba(177, 59, 44, 0.10);
    border-left-color: var(--vermilion);
  }
  .rf-lyric-inflected-head:hover .rf-lyric-inflected-label,
  .rf-lyric-inflected-head:hover .rf-lyric-inflected-toggle { color: var(--vermilion); }
}
.rf-lyric-inflected-head.rf-tapped {
  background: rgba(177, 59, 44, 0.10);
  border-left-color: var(--vermilion);
  transition: none;
}
.rf-lyric-inflected-head.rf-tapped .rf-lyric-inflected-label,
.rf-lyric-inflected-head.rf-tapped .rf-lyric-inflected-toggle { color: var(--vermilion); }
/* The list inside reverts cursor so users can read / select. */
.rf-lyric-inflected-list { cursor: auto; }
.rf-lyric-inflected-label {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
}
.rf-lyric-inflected-toggle {
  appearance: none;
  border: none;
  background: transparent;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--vermilion);
  cursor: pointer;
  padding: 0;
}
.rf-lyric-inflected-list {
  display: none;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  width: 100%;
}
.rf-lyric-inflected.is-expanded .rf-lyric-inflected-list { display: block; }
/* Inline variant: shown directly in the popover when there's no tier-1
   collapsible footer to gate it. Always visible. */
.rf-lyric-inflected-list.rf-lyric-inflected-list--inline { display: block; }
.rf-lyric-inflected-item {
  font-family: var(--display);
  font-style: italic;
  font-size: 14.5px;
  line-height: 1.4;
  color: var(--ink-soft);
  margin: 0;
  padding: 0;
  list-style: none;
}
.rf-lyric-inflected-item + .rf-lyric-inflected-item {
  border-top: 1px dashed var(--ink-ghost);
}
/* Each row is the click target — same hover band as the tier-1 quote. */
.rf-lyric-inflected-row {
  padding: 4px 8px 6px;
  margin: 0 -8px;
  border-left: 2px solid transparent;
  transition: background 100ms ease, border-color 100ms ease;
}
@media (hover: hover) {
  .rf-lyric-inflected-row:hover {
    background: rgba(177, 59, 44, 0.10);
    border-left-color: var(--vermilion);
  }
}
.rf-lyric-inflected-row.rf-tapped {
  background: rgba(177, 59, 44, 0.10);
  border-left-color: var(--vermilion);
  transition: none;
}
.rf-lyric-inflected-line {
  display: block;
  font-family: var(--display);
  font-style: italic;
  font-size: 14.5px;
  line-height: 1.4;
  color: var(--ink-soft);
}
.rf-lyric-inflected-item .rf-lyric-stanza { margin-top: 6px; display: none; }
.rf-lyric-inflected-item.is-open .rf-lyric-stanza { display: block; }
.rf-lyric-inflected-attr {
  display: block;
  margin-top: 2px;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faded);
}

.rf-lyric-more {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 8px 10px;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--vermilion);
  background: transparent;
  border: none;
  cursor: pointer;
  text-align: left;
  border-left: 2px solid transparent;
  transition: background 100ms ease, color 100ms ease, border-color 100ms ease;
}
/* Hidden quotes are kept in the DOM but suppressed via display:none —
   used by the reversible Show-more / Collapse toggle so the second click
   restores the previous state without re-rendering. */
.rf-lyric-hidden { display: none !important; }
@media (hover: hover) {
  .rf-lyric-more:hover {
    background: rgba(177, 59, 44, 0.10);
    border-left-color: var(--vermilion);
    color: var(--vermilion-deep);
  }
}
.rf-lyric-more.rf-tapped {
  background: rgba(177, 59, 44, 0.10);
  border-left-color: var(--vermilion);
  color: var(--vermilion-deep);
  transition: none;
}

/* Mobile bottom sheet — preserved from 1.5/1.6. Pinned popover docks
   to the viewport bottom; html.rf-sheet-open scroll-locks the page
   and dims the backdrop. */
/* Drag handle is mobile-only — hide elsewhere so it doesn't bleed into
   desktop layout. */
.rf-lyric-pop-handle { display: none; }

@media (hover: none) and (max-width: 720px) {
  /* Standard (non-modal) bottom sheet: fixed at half-screen, no scrim,
     coexists with the freely-scrolling main page above. */
  .rf-lyric-pop {
    position: fixed;
    inset: auto 0 0 0;
    width: 100%;
    max-width: none;
    height: 50vh;
    max-height: none;
    border: none;
    border-top: 1px solid var(--ink);
    box-shadow: 0 -4px 24px rgba(26, 20, 14, 0.2);
    /* Keep the pop's own scroll from chaining into iOS Safari's
       viewport rubber-band — that hand-off used to swallow the
       drag-to-dismiss gesture before our touchmove handler saw it. */
    overscroll-behavior-y: contain;
    touch-action: pan-y;
    /* Suppress the iOS gray tap-highlight flash and text selection
       inside the sheet — when the user starts a touch on a quote and
       then scrolls, neither should leave a visible artifact. Quotes
       still respond to actual taps via the click handler. */
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    user-select: none;
    -webkit-user-select: none;
  }
  /* Real drag-handle element. The visible pill is centered inside a
     taller hit area (24px) so the gesture target is finger-sized. The
     swipe-to-dismiss handler binds here and only here — gestures in
     the content area below scroll the pop natively. */
  .rf-lyric-pop-handle {
    display: block;
    position: relative;
    width: 100%;
    height: 24px;
    cursor: grab;
    touch-action: none;
    flex: 0 0 auto;
  }
  .rf-lyric-pop-handle::after {
    content: "";
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    width: 36px;
    height: 4px;
    border-radius: 2px;
    background: var(--ink-ghost);
  }
  /* Bottom 50vh of page sits behind the popover. Pad the page so the
     last screen of content is still reachable via scroll. */
  html.rf-sheet-open body { padding-bottom: 50vh; }
}

/* ══════════════════════════════════════════════════════════════════
   ── Lex categories · sticky bar · Index source-panel ──────────────
   Locked-in defaults from the v2 design handoff. Source-summary
   stays static; a separate fixed-position #stickybar slides in when
   the summary leaves the viewport. Lex marker is an inline mono-caps
   superscript on tagged words. The Index source-panel is treated as
   a featured "in the corpus" pull-quote section.
   ══════════════════════════════════════════════════════════════════ */

:root {
  --lex-person:  #6b4a2b;
  --lex-place:   #2a4a5e;
  --lex-science: #3a5a3a;
}

/* ── Type-legibility floors ───────────────────────────────────────
   Bumped sizes for body words, mono caps, and the cliché flag so
   results stay readable when the page gets dense. */
.rf-word {
  font-size: 22px;
  line-height: 1.55;
}
.rf-word.rf-c-uncommon {
  /* Use rgba color, not the `opacity` property — opacity creates a
     stacking context that propagates to ALL descendants, which made
     the lyric popover render at 0.92 alpha and let neighboring words
     show through. */
  color: rgba(58, 46, 31, 0.92);
  font-weight: 500;
  font-style: italic;
}
.rf-source-tag,
.rf-source-panel-meta,
.rf-lyric-attr,
.rf-source-panel-attr,
.rf-lyric-head-meta {
  font-size: 11px;
  letter-spacing: 0.12em;
}
.rf-lyric-inflected-label,
.rf-lyric-inflected-toggle,
.rf-lyric-more {
  font-size: 10.5px;
  letter-spacing: 0.12em;
}
.rf-tier-pop-eyebrow { font-size: 10px; }
.rf-word-flag {
  font-size: 9.5px;
  letter-spacing: 0.06em;
}

/* ── Per-word lex marker · inline caps superscript ────────────────
   Em-scaled mono-caps suffix that travels with each tagged word.
   The marker stays inside the parent's line-box, so candidates that
   wrap to a new row keep tag+word together and row-gap stays clean.
   `common` is the unmarked default — no marker rendered. */
.rf-word[data-lex="person"]::after,
.rf-word[data-lex="place"]::after,
.rf-word[data-lex="science"]::after {
  content: attr(data-lex);
  font-family: var(--mono);
  font-size: 0.42em;
  font-weight: 500;
  font-style: normal;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  vertical-align: 0.7em;
  margin-left: 0.22em;
  white-space: nowrap;
  opacity: 0.7;
}
.rf-word[data-lex="person"]::after  { color: var(--lex-person); }
.rf-word[data-lex="place"]::after   { color: var(--lex-place); }
.rf-word[data-lex="science"]::after { color: var(--lex-science); }

/* Filter behaviour — chip toggle hides matching words globally. */
.rf-app[data-filter-common="false"]  .rf-word:not([data-lex])     { display: none; }
.rf-app[data-filter-common="false"]  .rf-word[data-lex="common"]  { display: none; }
.rf-app[data-filter-person="false"]  .rf-word[data-lex="person"]  { display: none; }
.rf-app[data-filter-place="false"]   .rf-word[data-lex="place"]   { display: none; }
.rf-app[data-filter-science="false"] .rf-word[data-lex="science"] { display: none; }

/* ── Inline lex filter strip (top of results, always visible) ─────
   Kept above the source-panel so the user always has a one-click
   way to toggle categories. The sticky bar carries a softer mirror
   of this filter — see the .rf-lex-filter-mirror block below. */
#lex-filter.rf-lex-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 14px 0 22px;
  padding: 0;
}
#lex-filter.rf-lex-filter:empty { display: none; }
#lex-filter.rf-lex-filter .rf-lex-filter-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faded);
  align-self: center;
  margin-right: 6px;
}

/* Lexicon filter · checkbox rows (colour-in-the-box).
   Each category is a real checkbox the reader ticks to show / hide
   that class of word. A native <input> drives the state (label-wrapped
   so the whole row is the hit target) but is visually replaced by the
   painted .rf-lex-box; when ticked, the box border + checkmark + label
   all take that category's ink (Common ink · Names brown · Places blue
   · Sciences green), so the colour code lives in the control itself.
   Unticked rows drop to an empty hairline box + dimmed label. */
#filter-content { align-items: center; gap: 5px 12px; }

.rf-lex-check {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faded);
  padding: 4px 6px;
  user-select: none;
  /* Suppress iOS double-tap zoom + 300ms click delay so a second tap
     (re-show) registers reliably. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
/* The native control stays in the tab order for keyboard + AT, but
   is taken out of layout — the painted .rf-lex-box is what shows. */
.rf-lex-check input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
  pointer-events: none;
}
.rf-lex-box {
  width: 15px;
  height: 15px;
  flex: none;
  border: 1.5px solid var(--hair);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color 130ms ease, background 130ms ease;
}
.rf-lex-box svg {
  width: 11px;
  height: 11px;
  opacity: 0;
  transition: opacity 110ms ease;
}
.rf-lex-box svg path {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.rf-lex-check input:checked ~ .rf-lex-box svg { opacity: 1; }
/* Keyboard focus ring lands on the painted box (the input is offscreen). */
.rf-lex-check input:focus-visible ~ .rf-lex-box {
  outline: 2px solid var(--vermilion);
  outline-offset: 2px;
}
/* Off state — dim the label so the ticked rows read as the lit ones. */
.rf-lex-check input:not(:checked) ~ .rf-lex-check-label { opacity: 0.5; }
.rf-lex-check-count {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.06em;
  opacity: 0.7;
  margin-left: 1px;
}

/* On state — box wash + border, checkmark stroke, and label all take
   the category ink. The checkmark colour is set unconditionally (it's
   only visible once :checked reveals the svg above). */
.rf-lex-check[data-lex="common"]  input:checked ~ .rf-lex-box { border-color: var(--ink);         background: rgba(26, 20, 14, 0.10); }
.rf-lex-check[data-lex="person"]  input:checked ~ .rf-lex-box { border-color: var(--lex-person);  background: rgba(107, 74, 43, 0.14); }
.rf-lex-check[data-lex="place"]   input:checked ~ .rf-lex-box { border-color: var(--lex-place);   background: rgba(42, 74, 94, 0.14); }
.rf-lex-check[data-lex="science"] input:checked ~ .rf-lex-box { border-color: var(--lex-science); background: rgba(58, 90, 58, 0.14); }
.rf-lex-check[data-lex="common"]  .rf-lex-box svg path { stroke: var(--ink); }
.rf-lex-check[data-lex="person"]  .rf-lex-box svg path { stroke: var(--lex-person); }
.rf-lex-check[data-lex="place"]   .rf-lex-box svg path { stroke: var(--lex-place); }
.rf-lex-check[data-lex="science"] .rf-lex-box svg path { stroke: var(--lex-science); }
.rf-lex-check[data-lex="common"]  input:checked ~ .rf-lex-check-label { color: var(--ink); }
.rf-lex-check[data-lex="person"]  input:checked ~ .rf-lex-check-label { color: var(--lex-person); }
.rf-lex-check[data-lex="place"]   input:checked ~ .rf-lex-check-label { color: var(--lex-place); }
.rf-lex-check[data-lex="science"] input:checked ~ .rf-lex-check-label { color: var(--lex-science); }

/* ── Sticky tier bar (#stickybar) ─────────────────────────────────
   A separate fixed-position bar at the very top of the viewport.
   The source-summary scrolls naturally; when it leaves the
   viewport, the bar slides in via transform+opacity. Single line,
   fixed height — no layout reflow. */
/* Empty bar (no search yet) — keep it off the page entirely so the
   IntersectionObserver, which sees the hidden sentinel as
   "not intersecting" before any search runs, can't slide a blank
   strip into view on the empty home state. Higher specificity than
   the `#stickybar.rf-stickybar` rule below so it wins. */
#stickybar.rf-stickybar:empty { display: none; }

#stickybar.rf-stickybar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 11px clamp(20px, 4vw, 56px);
  background-color: var(--paper);
  background-image: url("/rhyme-finder/xuan-bg.png");
  background-size: 600px 600px;
  background-blend-mode: multiply;
  border-bottom: 1px solid var(--ink);
  box-shadow:
    0 1px 0 rgba(177, 59, 44, 0.22),
    0 6px 16px -10px rgba(26, 20, 14, 0.22);
  transform: translate3d(0, -100%, 0);
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  transition:
    transform 260ms cubic-bezier(.2, .8, .2, 1),
    opacity 200ms ease;
}
#stickybar.rf-stickybar.is-stuck {
  transform: translate3d(0, 0, 0);
  opacity: 1;
  pointer-events: auto;
}

.rf-stickybar-meta {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: none;
  min-width: 0;
}
.rf-stickybar-eyebrow {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faded);
  line-height: 1;
}
.rf-stickybar-word {
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 22px;
  line-height: 1.05;
  color: var(--ink);
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Vertical hairline divider with a vermilion centre dot — mirrors
   the eyebrow-rule language in the source-summary so the bar reads
   as a continuation of the page typography. */
.rf-stickybar-rule {
  width: 1px;
  height: 28px;
  background: var(--ink-ghost);
  flex: none;
  position: relative;
}
.rf-stickybar-rule::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--vermilion);
  transform: translate(-50%, -50%);
  opacity: 0.85;
}

/* Tier shortcut strip on the right. Single-line, ellipsis on
   overflow. Each button has a horizontal resolve-rule beneath that
   encodes the tier's stability — solid full-width for Perfect,
   diminishing length and weight down to a faint dashed stub for
   Identity. The rule is the only stability cue. */
.rf-stickybar-tiers {
  display: flex;
  align-items: baseline;
  gap: 0;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  white-space: nowrap;
  padding-right: 4px;
}
.rf-stickybar-tiers::-webkit-scrollbar { display: none; }

#stickybar .rf-stickybar-tier {
  appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  padding: 4px 14px 11px;
  border-radius: 2px;
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
  flex: none;
  position: relative;
  transition: color 120ms ease, background 120ms ease;
}
#stickybar .rf-stickybar-tier::after {
  content: "";
  position: absolute;
  bottom: 4px;
  left: 14px; right: 14px;
  height: 1.5px;
  background: var(--vermilion);
  opacity: 0.85;
  transition: opacity 120ms ease;
}
#stickybar .rf-stickybar-tier[data-stability="5"]::after { height: 2px; opacity: 0.95; }
#stickybar .rf-stickybar-tier[data-stability="4"]::after { height: 1.5px; opacity: 0.75; left: 16px; right: 16px; }
#stickybar .rf-stickybar-tier[data-stability="3"]::after { height: 1px; opacity: 0.55; left: 22%; right: 22%; }
#stickybar .rf-stickybar-tier[data-stability="2"]::after { height: 1px; opacity: 0.4; left: 30%; right: 30%; }
#stickybar .rf-stickybar-tier[data-stability="1"]::after { height: 0; opacity: 0.4; left: 36%; right: 36%; border-top: 1px dashed var(--vermilion); background: transparent; }
#stickybar .rf-stickybar-tier[data-stability="0"]::after { height: 0; opacity: 0.3; left: 42%; right: 42%; border-top: 1px dashed var(--vermilion); background: transparent; }
#stickybar .rf-stickybar-tier:hover::after { opacity: 1; }
#stickybar .rf-stickybar-tier-label {
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 15px;
  line-height: 1;
  color: var(--ink-soft);
}
#stickybar .rf-stickybar-tier-count {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--ink-faded);
  opacity: 0.85;
  vertical-align: 0.18em;
}
#stickybar .rf-stickybar-tier:hover { background: rgba(177, 59, 44, 0.06); }
#stickybar .rf-stickybar-tier:hover .rf-stickybar-tier-label { color: var(--vermilion); }
#stickybar .rf-stickybar-tier:hover .rf-stickybar-tier-count { color: var(--vermilion); opacity: 1; }

/* ── Lex filter mirror inside the sticky bar ──────────────────────
   Inkblock chip style — solid-ink active (paper text + vermilion
   count) and light-gray ghost inactive. High-contrast, decisive,
   reads as a hard UI block on the sticky band. */
#stickybar .rf-lex-filter-mirror {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 4px;
  margin: 0 0 0 auto;
  padding: 0;
  flex: none;
}
#stickybar .rf-lex-filter-mirror .rf-lex-filter-label { display: none; }
#stickybar .rf-lex-filter-mirror .rf-lex-chip {
  border-radius: 0;
  border: 1px solid var(--ink);
  padding: 3px 9px;
  font-size: 9px;
  letter-spacing: 0.14em;
}
#stickybar .rf-lex-filter-mirror .rf-lex-chip[aria-pressed="true"] {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
#stickybar .rf-lex-filter-mirror .rf-lex-chip[aria-pressed="true"] .rf-lex-chip-count {
  color: var(--vermilion);
  opacity: 1;
}
#stickybar .rf-lex-filter-mirror .rf-lex-chip[aria-pressed="false"] {
  background: transparent;
  /* Use rgba to dim, not the `opacity` property — opacity creates a
     stacking context that cascades to descendants. */
  color: rgba(110, 90, 60, 0.85);
  border-color: var(--hair);
  border-style: solid;
}
@media (hover: hover) {
  #stickybar .rf-lex-filter-mirror .rf-lex-chip[aria-pressed="false"]:hover {
    color: var(--ink);
    border-color: var(--ink-soft);
  }
}
#stickybar .rf-lex-filter-mirror .rf-lex-chip-dot { display: none; }

.rf-source-summary-sentinel {
  height: 1px;
  margin-bottom: -1px;
  pointer-events: none;
}

@media (max-width: 720px) {
  /* Two-row grid: meta + tier-strip on row 1, lex filter on row 2.
     Single-row flex doesn't fit all four sections at 375px; stacking
     lex below the tiers keeps everything reachable without crowding. */
  #stickybar.rf-stickybar {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "meta tiers"
      "filter filter";
    column-gap: 12px;
    row-gap: 6px;
    align-items: center;
    padding: 8px 14px;
    max-width: 100vw;
    overflow: hidden;
  }
  .rf-stickybar-meta { grid-area: meta; }
  .rf-stickybar-tiers { grid-area: tiers; flex: 1 1 0; min-width: 0; }
  .rf-stickybar-rule { display: none; }
  .rf-stickybar-word { font-size: 19px; }
  #stickybar .rf-stickybar-tier { padding: 4px 8px 5px; }
  #stickybar .rf-stickybar-tier-label { font-size: 14px; }
  #stickybar .rf-lex-filter-mirror {
    grid-area: filter;
    /* Span the full second row, scroll horizontally if chips overflow.
     Drop the auto-left margin (which right-aligned it on desktop). */
    margin: 0;
    justify-content: flex-start;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  #stickybar .rf-lex-filter-mirror::-webkit-scrollbar { display: none; }
  #stickybar .rf-lex-filter-mirror .rf-lex-chip {
    /* Tighten chip padding on phones so 4 chips fit without scroll
       at 375px. */
    padding: 3px 7px;
    font-size: 8.5px;
    flex: none;
  }
}

/* ── Empty-tier state when the lex filter zeros it ────────────────
   Don't collapse — dim the tier and explain why nothing is showing
   so the page rhythm stays intact. */
.rf-tier-empty {
  margin: 0;
  padding: 14px 0 6px;
  font-family: var(--display);
  font-style: italic;
  font-size: 15px;
  color: var(--ink-faded);
  opacity: 0.75;
  text-wrap: pretty;
}
.rf-tier-empty[hidden] { display: none; }
.rf-tier-empty-hint {
  display: block;
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 9.5px;
  font-style: normal;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
  opacity: 0.7;
}
.rf-tier.rf-tier-zero { opacity: 0.55; }
.rf-tier-count[data-zero="true"] { color: var(--ink-faded) !important; }
/* When the tier has zero visible candidates, hide the body. The
   subgroup labels ("2 SYLLABLES" etc.) would otherwise float
   beneath an empty space — the empty-state hint already explains
   the situation. */
.rf-tier-zero .rf-tier-body { display: none; }

/* Pair-rhyme highlight — vermilion underline band so the eye sees
   the partner word the source line resolves to. Distinct from the
   solid-block source-word mark. */
.rf-lyric-mark.rf-lyric-mark-pair {
  color: var(--vermilion);
  font-weight: 600;
  background: linear-gradient(transparent 65%, rgba(177, 59, 44, 0.28) 65%);
  padding: 0 1px;
}

/* Source-panel index: the rhyme pair (source + partner words) reads
   thinner than the global rhyme-mark weight so the highlighted words
   sit at the same weight as the surrounding pair-line text. */
.rf-srcpanel-index-row .rf-lyric-mark { font-weight: 500; }

/* ── Source-panel · Index layout (featured "in the corpus") ───────
   Treated as a peer to the tier list below: confident chapter-style
   header, generous vertical rhythm, hero typography on the source
   line. Default-collapse to first 2 rows; rest revealed via plain
   "Show N more" link with a vermilion `+`/`−` glyph. */
.rf-srcpanel-index {
  padding: 4px 0 28px;
  margin-top: 4px;
}

.rf-srcpanel-index-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  padding-bottom: 14px;
  margin-bottom: 22px;
  position: relative;
  border-bottom: 1px solid var(--ink);
}
.rf-srcpanel-index-head::after {
  /* offset vermilion hairline below the ink rule — chapter-opener feel */
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -4px;
  height: 1px;
  background: var(--vermilion);
  opacity: 0.55;
}
.rf-srcpanel-index-headline {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.rf-srcpanel-index-eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--vermilion);
  line-height: 1;
}
.rf-srcpanel-index-title {
  margin: 0;
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(24px, 2.6vw, 30px);
  line-height: 1.15;
  letter-spacing: -0.005em;
  color: var(--ink);
  text-wrap: pretty;
}
.rf-srcpanel-index-title em {
  font-style: italic;
  font-weight: 600;
  color: var(--ink);
  background: linear-gradient(transparent 70%, rgba(177, 59, 44, 0.32) 70%);
  padding: 0 2px;
}
.rf-srcpanel-index-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  flex: none;
  text-align: right;
}
.rf-srcpanel-index-meta-num {
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 32px;
  line-height: 1;
  color: var(--vermilion);
}
.rf-srcpanel-index-meta-lbl {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faded);
}

.rf-srcpanel-index-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.rf-srcpanel-index-rest { display: contents; }
.rf-srcpanel-index-rest.rf-lyric-hidden { display: none; }

/* Pull-quote rows. Big vermilion `"` glyph anchors col 1; pair lines
   render at equal weight (this section celebrates the couplet);
   attribution lives in col 3; full row is clickable, and the hover
   state reveals a "read in context →" affordance. */
.rf-srcpanel-index-row {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr) minmax(140px, 190px);
  column-gap: 18px;
  align-items: start;
  padding: 14px 8px 14px 4px;
  border-bottom: 1px dashed var(--ink-ghost);
  position: relative;
  cursor: pointer;
  transition: background 180ms ease, padding-left 220ms ease;
  outline: none;
}
.rf-srcpanel-index-list > .rf-srcpanel-index-row:last-of-type:not(:has(~ .rf-srcpanel-index-rest:not(.rf-lyric-hidden))) {
  border-bottom: none;
}
.rf-srcpanel-index-rest .rf-srcpanel-index-row:last-child { border-bottom: none; }

.rf-srcpanel-index-row::before {
  content: "";
  position: absolute;
  left: -2px; top: 16px; bottom: 16px;
  width: 2px;
  background: var(--vermilion);
  opacity: 0;
  transition: opacity 200ms ease, width 200ms ease;
}
.rf-srcpanel-index-row:hover,
.rf-srcpanel-index-row:focus-visible {
  background: rgba(177, 59, 44, 0.045);
  padding-left: 10px;
}
.rf-srcpanel-index-row:hover::before,
.rf-srcpanel-index-row:focus-visible::before { opacity: 1; width: 3px; }
/* When the row is expanded, the stanza below carries its own vermilion
   border-left — suppress the outer row strip to avoid a double red rule. */
.rf-srcpanel-index-row.is-open::before { opacity: 0; }

.rf-srcpanel-index-quote {
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 46px;
  line-height: 0.6;
  color: var(--vermilion);
  opacity: 0.8;
  user-select: none;
  margin-top: 10px;
  text-align: center;
  letter-spacing: -0.02em;
}

.rf-srcpanel-index-pair {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.rf-srcpanel-index-a,
.rf-srcpanel-index-b {
  margin: 0;
  font-family: "Spectral", "Songti SC", "STSong", serif;
  font-style: italic;
  font-weight: 500;
  font-size: 17px;
  line-height: 1.34;
  text-wrap: pretty;
}
.rf-srcpanel-index-a { color: var(--ink-soft); }
.rf-srcpanel-index-b { color: var(--ink); }

.rf-srcpanel-index-attr {
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
  line-height: 1.5;
  text-align: right;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.rf-srcpanel-index-attr em {
  font-style: italic;
  text-transform: none;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  font-weight: 400;
}

.rf-srcpanel-index-empty {
  padding: 12px 0;
  font-family: var(--display);
  font-style: italic;
  font-size: 15px;
  color: var(--ink-faded);
}

/* Click-to-expand stanza — each Index row optionally carries the
   surrounding lyric context, hidden by default and revealed when the
   row is toggled .is-open. The stanza spans all 3 grid columns so it
   reads as a continuation of the row, not a sidebar. */
.rf-srcpanel-index-stanza {
  display: none;
  grid-column: 1 / -1;
  margin: 10px 0 4px;
  padding: 12px 16px 12px 18px;
  border-left: 2px solid var(--vermilion);
  background: rgba(177, 59, 44, 0.045);
  font-family: "Spectral", "Songti SC", "STSong", serif;
  font-style: italic;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-soft);
  text-wrap: pretty;
}
.rf-srcpanel-index-row.is-open .rf-srcpanel-index-stanza { display: block; }
.rf-srcpanel-index-stanza-line {
  margin: 0;
  padding: 1px 0;
}
.rf-srcpanel-index-stanza-line.is-match {
  color: var(--ink);
  font-weight: 550;
}

/* Plain-text show-more — vermilion `+ ` collapsed, `− ` expanded.
   Drives via aria-expanded so the same rule serves the source-panel
   toggle and any future popover toggles. */
.rf-lyric-more,
.rf-srcpanel-index-more {
  appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 6px 4px;
  transition: color 120ms ease;
}
@media (hover: hover) {
  .rf-lyric-more:hover,
  .rf-srcpanel-index-more:hover { color: var(--vermilion); }
}
.rf-srcpanel-index-more {
  display: block;
  margin: 18px auto 0;
}
.rf-srcpanel-index-more::before {
  content: "+ ";
  color: var(--vermilion);
  font-weight: 600;
}
.rf-srcpanel-index-more[aria-expanded="true"]::before { content: "− "; }

@media (max-width: 720px) {
  .rf-srcpanel-index-row {
    grid-template-columns: 32px 1fr;
    column-gap: 12px;
    row-gap: 4px;
    padding: 16px 8px 16px 4px;
  }
  .rf-srcpanel-index-quote { font-size: 40px; margin-top: 8px; }
  .rf-srcpanel-index-attr {
    grid-column: 2;
    text-align: left;
  }
  .rf-srcpanel-index-a, .rf-srcpanel-index-b { font-size: 16px; }
  .rf-srcpanel-index-meta-num { font-size: 24px; }
}

/* ── Colophon · top-right corner ─────────────────────────────────
   A small editorial trigger in the corner of the page. Anonymous on
   the surface — no name, no byline. Opens a card with a feedback
   form + a quiet support line.

   Variant systems:
     · trigger pictogram   .rf-colophon[data-trigger="notes" | "envelope" | "brush"]
     · form field style    .rf-colophon-form[data-variant="soft-card" | "notebook" | "tagged"]
   Defaults shipped: envelope + soft-card. Swap via the data-attributes
   on the markup. */
.rf-colophon {
  position: fixed;
  top: 18px;
  right: 22px;
  z-index: 6;
}
/* In the results state, the colophon docks into the right edge of
   the sticky bar as group 3 of the 3-group composition (logo+pill ·
   tools · colophon). A hairline ::before draws the divider between
   the tools group and the colophon. The bar reserves right-padding
   for it (see .rf-hero above).
   Selector lives on body because the colophon is a sibling of
   .rf-app, not a descendant — a .rf-app:has() rule would never
   match it. The trigger height (~34px) + bar height (~50px) gives a
   ~8px top inset so the icon is visually centered with the bar's
   toggle row. */
body:has(#results:not(:empty)) .rf-colophon,
body:has(#source-summary:not(:empty)) .rf-colophon {
  top: 12px;
  right: clamp(20px, 4vw, 56px);
  z-index: 41;
}
body:has(#results:not(:empty)) .rf-colophon::before,
body:has(#source-summary:not(:empty)) .rf-colophon::before {
  content: "";
  position: absolute;
  left: -16px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 26px;
  background: var(--hair);
}

/* ── Colophon · collapsed mobile ────────────────────────────────────
   Must live AFTER the base rules above to win on source order (equal
   specificity). On phones the collapsed bar pulls the ✉ in to 8px from
   the edge so it mirrors the seal's 8px left inset (edge-symmetric), and
   drops the tools↔colophon divider — the filling search bar shoves the
   tools flush against the ✉, so that divider would otherwise fall on top
   of the filter button as a stray vertical line. */
@media (max-width: 640px) {
  body:has(#results:not(:empty)) .rf-colophon,
  body:has(#source-summary:not(:empty)) .rf-colophon {
    right: 8px;
  }
  body:has(#results:not(:empty)) .rf-colophon::before,
  body:has(#source-summary:not(:empty)) .rf-colophon::before {
    display: none;
  }
}

.rf-colophon-details { position: relative; }

/* ── Trigger frame ─────────────────────────────────────────────── */
.rf-colophon-trigger {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 8px;
  border-radius: 2px;
  -webkit-tap-highlight-color: transparent;
  transition: background 140ms ease;
}
.rf-colophon-trigger::-webkit-details-marker { display: none; }
.rf-colophon-trigger::marker { content: ""; }
.rf-colophon-trigger:hover { background: rgba(177, 59, 44, 0.06); }
.rf-colophon-trigger:focus-visible {
  outline: 1px solid var(--vermilion);
  outline-offset: 2px;
}

/* Hide all trigger glyphs by default; [data-trigger] on .rf-colophon
   reveals exactly one. */
.rf-colophon-trigger-glyph { display: none; }
.rf-colophon[data-trigger="notes"] [data-glyph="notes"],
.rf-colophon[data-trigger="envelope"] [data-glyph="envelope"],
.rf-colophon[data-trigger="brush"] [data-glyph="brush"] {
  display: inline-flex;
  align-items: center;
}

/* Trigger A · notes — italic word + tiny vermilion dot. */
.rf-colophon-trigger-glyph[data-glyph="notes"] { gap: 7px; }
.rf-colophon-trigger-word {
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 15px;
  line-height: 1;
  color: var(--ink-faded);
  letter-spacing: 0.005em;
  transition: color 140ms ease;
}
.rf-colophon-trigger-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--vermilion);
  transform: translateY(-1px);
  transition: transform 200ms ease, box-shadow 200ms ease;
}
.rf-colophon-trigger:hover .rf-colophon-trigger-word,
.rf-colophon-details[open] .rf-colophon-trigger-word {
  color: var(--vermilion);
}
.rf-colophon-trigger:hover .rf-colophon-trigger-dot,
.rf-colophon-details[open] .rf-colophon-trigger-dot {
  transform: translateY(-1px) scale(1.25);
  box-shadow: 0 1px 4px rgba(177, 59, 44, 0.4);
}

/* Trigger B · envelope — small ink-line SVG. */
.rf-colophon-trigger-svg {
  display: block;
  width: 28px;
  height: 22px;
  color: var(--ink-faded);
  transition: color 140ms ease, transform 200ms ease;
}
.rf-colophon-trigger:hover .rf-colophon-trigger-svg,
.rf-colophon-details[open] .rf-colophon-trigger-svg {
  color: var(--ink);
  transform: translateY(-1px) rotate(-2deg);
}

/* Trigger C · brush seal — vermilion 笔 stamp. */
.rf-colophon-trigger-glyph[data-glyph="brush"] .rf-colophon-seal {
  transition: transform 200ms ease, box-shadow 200ms ease;
}
.rf-colophon-trigger:hover .rf-colophon-seal,
.rf-colophon-details[open] .rf-colophon-seal {
  transform: rotate(0deg) scale(1.08);
  box-shadow:
    inset 0 0 0 1px rgba(255, 240, 220, 0.18),
    inset 0 0 6px rgba(80, 10, 0, 0.45),
    0 1px 5px rgba(177, 59, 44, 0.28);
}
.rf-colophon-seal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  background: var(--vermilion);
  color: var(--paper);
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 14px;
  line-height: 1;
  border-radius: 1.5px;
  box-shadow:
    inset 0 0 0 1px rgba(255, 240, 220, 0.18),
    inset 0 0 6px rgba(80, 10, 0, 0.4);
  transform: rotate(-4deg);
  flex: none;
}
.rf-colophon-seal-glyph {
  display: inline-block;
  transform: translateY(-0.5px);
  text-shadow: 0 0 1px rgba(255, 255, 255, 0.1);
}

/* ── Card ──────────────────────────────────────────────────────── */
.rf-colophon-card {
  position: absolute;
  top: calc(100% + 12px);
  right: 0;
  width: 440px;
  max-width: calc(100vw - 28px);
  padding: 24px 26px 22px;
  background-color: var(--paper);
  background-image: url("./xuan-bg.png");
  background-size: 600px 600px;
  border: 1px solid var(--ink);
  box-shadow: 4px 4px 0 var(--ink-ghost);
  text-align: left;
}
.rf-colophon-card::before {
  content: "";
  position: absolute;
  top: -7px;
  right: 24px;
  width: 12px;
  height: 12px;
  transform: rotate(45deg);
  background-color: var(--paper);
  background-image: url("./xuan-bg.png");
  background-size: 600px 600px;
  border-left: 1px solid var(--ink);
  border-top: 1px solid var(--ink);
}

.rf-colophon-head {
  margin: 0 0 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hair-soft);
}
.rf-colophon-eyebrow {
  margin: 0 0 4px;
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--vermilion);
}
.rf-colophon-title {
  margin: 0;
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 22px;
  line-height: 1.1;
  color: var(--ink);
  letter-spacing: -0.005em;
}

.rf-colophon-prose { margin: 0 0 18px; }
.rf-colophon-prose p {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* ── Form chrome ───────────────────────────────────────────────── */
.rf-colophon-form {
  position: relative;
  margin: 0 0 18px;
}
.rf-cf-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  gap: 10px;
  margin-top: 14px;
}
.rf-cf-field { position: relative; }
.rf-cf-label {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-bottom: 6px;
  cursor: text;
}
.rf-cf-label-main {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faded);
}
.rf-cf-label-aux {
  font-family: var(--display);
  font-style: italic;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--ink-faded);
  opacity: 0.7;
  text-transform: none;
}
.rf-cf-input {
  width: 100%;
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  color: var(--ink);
  outline: none;
  box-sizing: border-box;
  transition:
    border-color 140ms ease,
    background 140ms ease,
    box-shadow 140ms ease;
}
.rf-cf-input::placeholder {
  color: rgba(107, 94, 74, 0.5);
  font-style: italic;
}
.rf-cf-input--area {
  min-height: 96px;
  resize: vertical;
  line-height: 1.45;
}

/* Variant A · soft-card (default) */
.rf-colophon-form[data-variant="soft-card"] .rf-cf-input {
  padding: 11px 13px;
  font-size: 15px;
  background: rgba(255, 248, 230, 0.55);
  border: 1px solid var(--hair);
  border-radius: 9px;
  box-shadow: inset 0 1px 2px rgba(26, 20, 14, 0.04);
}
.rf-colophon-form[data-variant="soft-card"] .rf-cf-input--area {
  padding: 12px 14px;
  font-size: 15px;
  border-radius: 11px;
}
.rf-colophon-form[data-variant="soft-card"] .rf-cf-input:hover {
  border-color: rgba(26, 20, 14, 0.35);
}
.rf-colophon-form[data-variant="soft-card"] .rf-cf-input:focus {
  border-color: var(--vermilion);
  background: rgba(255, 248, 230, 0.85);
  box-shadow:
    inset 0 1px 2px rgba(26, 20, 14, 0.04),
    0 0 0 3px rgba(177, 59, 44, 0.10);
}

/* Variant B · notebook */
.rf-colophon-form[data-variant="notebook"] .rf-cf-input {
  padding: 8px 2px 9px;
  font-size: 15.5px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--hair);
  border-radius: 0;
}
.rf-colophon-form[data-variant="notebook"] .rf-cf-input--area {
  min-height: 84px;
  padding: 6px 2px 10px;
  border-bottom: 1px solid var(--ink-faded);
}
.rf-colophon-form[data-variant="notebook"] .rf-cf-input:focus {
  border-bottom-color: var(--vermilion);
  background: linear-gradient(to top, rgba(177, 59, 44, 0.06), transparent 28%);
}
.rf-colophon-form[data-variant="notebook"] .rf-cf-label { margin-bottom: 4px; }

/* Variant C · tagged */
.rf-colophon-form[data-variant="tagged"] .rf-cf-field {
  position: relative;
  padding: 12px 14px 12px;
  background:
    linear-gradient(135deg, rgba(177, 59, 44, 0.04) 0 14px, transparent 14px),
    rgba(255, 248, 230, 0.4);
  border: 1px solid var(--hair);
  border-radius: 3px 12px 12px 12px;
  transition: border-color 140ms ease, background 140ms ease;
}
.rf-colophon-form[data-variant="tagged"] .rf-cf-field:focus-within {
  border-color: var(--vermilion);
  background:
    linear-gradient(135deg, rgba(177, 59, 44, 0.10) 0 14px, transparent 14px),
    rgba(255, 248, 230, 0.65);
}
.rf-colophon-form[data-variant="tagged"] .rf-cf-field::before {
  content: "";
  position: absolute;
  top: 8px;
  left: 8px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--vermilion);
  opacity: 0.85;
}
.rf-colophon-form[data-variant="tagged"] .rf-cf-label {
  margin-bottom: 6px;
  padding-left: 12px;
}
.rf-colophon-form[data-variant="tagged"] .rf-cf-input {
  padding: 4px 0 0;
  font-size: 15px;
  background: transparent;
  border: none;
  border-radius: 0;
}
.rf-colophon-form[data-variant="tagged"] .rf-cf-input--area {
  padding-top: 2px;
  min-height: 80px;
}

/* ── Form foot · note + Send button ────────────────────────────── */
.rf-colophon-form-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 16px;
}
.rf-colophon-form-note {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
}
.rf-colophon-form-send {
  appearance: none;
  cursor: pointer;
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 7px 16px 8px;
  background: rgba(177, 59, 44, 0.06);
  border: 1px solid rgba(177, 59, 44, 0.35);
  border-radius: 999px;
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 17px;
  letter-spacing: 0.005em;
  color: var(--vermilion);
  transition:
    color 140ms ease,
    background 140ms ease,
    border-color 140ms ease,
    transform 120ms ease,
    box-shadow 140ms ease;
}
.rf-colophon-form-send:hover,
.rf-colophon-form-send:focus-visible {
  color: var(--vermilion-deep);
  background: rgba(177, 59, 44, 0.14);
  border-color: var(--vermilion);
  box-shadow: 0 1px 6px rgba(177, 59, 44, 0.22);
  outline: none;
}
.rf-colophon-form-send:hover .rf-colophon-form-send-arrow {
  transform: translateX(5px);
}
.rf-colophon-form-send:active {
  transform: translateY(1px);
  background: rgba(177, 59, 44, 0.18);
}
.rf-colophon-form-send:disabled {
  cursor: progress;
  opacity: 0.7;
}
.rf-colophon-form-send-arrow {
  display: inline-block;
  font-style: normal;
  font-weight: 500;
  font-size: 18px;
  color: inherit;
  transition: transform 160ms ease;
}
.rf-colophon-form[data-state="sending"] .rf-colophon-form-send-arrow {
  animation: rf-colophon-arrow-pulse 700ms ease-in-out infinite;
}
@keyframes rf-colophon-arrow-pulse {
  0%, 100% { transform: translateX(0); opacity: 1; }
  50% { transform: translateX(4px); opacity: 0.4; }
}

/* Empty-textarea flash on Send. */
.rf-cf-input--area.rf-colophon-flash {
  animation: rf-colophon-flash 600ms ease-out;
}
@keyframes rf-colophon-flash {
  0% { border-color: var(--vermilion); box-shadow: 0 0 0 3px rgba(177, 59, 44, 0.15); }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ── Success state ─────────────────────────────────────────────── */
.rf-colophon-form-success {
  display: none;
  position: absolute;
  inset: 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 20px 0;
  text-align: center;
  background-color: var(--paper);
  background-image: url("./xuan-bg.png");
  background-size: 600px 600px;
}
.rf-colophon-form[data-state="sent"] .rf-colophon-form-success {
  display: flex;
  animation: rf-colophon-success-fade 320ms ease-out;
}
.rf-colophon-form[data-state="sent"] > *:not(.rf-colophon-form-success):not(.rf-colophon-form-error) {
  opacity: 0;
  pointer-events: none;
}
@keyframes rf-colophon-success-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
.rf-colophon-form-seal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  background: var(--vermilion);
  color: var(--paper);
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 38px;
  line-height: 1;
  border-radius: 2px;
  box-shadow:
    inset 0 0 0 2.5px rgba(255, 240, 220, 0.18),
    inset 0 0 14px rgba(80, 10, 0, 0.45);
  transform: rotate(-6deg);
  flex: none;
}
.rf-colophon-form[data-state="sent"] .rf-colophon-form-seal {
  animation: rf-colophon-stamp 520ms cubic-bezier(0.2, 1.6, 0.4, 1);
}
@keyframes rf-colophon-stamp {
  0%   { opacity: 0; transform: scale(2.2) rotate(-18deg); }
  55%  { opacity: 1; transform: scale(0.88) rotate(-2deg); }
  78%  { transform: scale(1.04) rotate(-7deg); }
  100% { opacity: 1; transform: scale(1) rotate(-6deg); }
}
.rf-colophon-form-success-line {
  margin: 0;
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: 16px;
  line-height: 1.4;
  color: var(--ink);
}
.rf-colophon-form-again {
  appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  padding: 4px 6px;
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faded);
  transition: color 140ms ease;
}
.rf-colophon-form-again:hover { color: var(--vermilion); }

/* ── Error state ───────────────────────────────────────────────── */
.rf-colophon-form-error {
  display: none;
  margin: 12px 0 0;
  padding: 10px 12px;
  font-family: var(--display);
  font-style: italic;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--vermilion-deep);
  background: rgba(177, 59, 44, 0.08);
  border-left: 2px solid var(--vermilion);
  border-radius: 0 1.5px 1.5px 0;
}
.rf-colophon-form[data-state="error"] .rf-colophon-form-error { display: block; }
.rf-colophon-form-error-fallback {
  color: var(--vermilion-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* ── Coffee footer ─────────────────────────────────────────────── */
.rf-colophon-foot {
  margin: 0;
  padding-top: 14px;
  border-top: 1px dashed var(--ink-ghost);
}
.rf-colophon-foot-line {
  margin: 0;
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-faded);
  text-wrap: pretty;
}
.rf-colophon-foot-prefix { margin-right: 2px; }
.rf-colophon-coffee {
  color: var(--vermilion);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(177, 59, 44, 0.4);
  font-style: italic;
  transition: text-decoration-color 140ms ease;
}
.rf-colophon-coffee:hover { text-decoration-color: var(--vermilion); }

/* ── Responsive ────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .rf-colophon { top: 12px; right: 12px; }
  .rf-colophon-trigger-word { font-size: 14px; }
  .rf-colophon-trigger-svg { width: 26px; height: 20px; }
  .rf-colophon-card {
    width: calc(100vw - 24px);
    padding: 20px 18px 16px;
    right: -10px;
  }
  .rf-colophon-card::before { right: 22px; }
  .rf-colophon-title { font-size: 20px; }
  .rf-colophon-prose p { font-size: 14px; }
  .rf-cf-row { grid-template-columns: 1fr; gap: 12px; }
  .rf-colophon-form[data-variant="soft-card"] .rf-cf-input { font-size: 14px; }
  .rf-colophon-form[data-variant="notebook"] .rf-cf-input { font-size: 15px; }
  .rf-colophon-form-foot { flex-direction: column; align-items: stretch; gap: 10px; }
  .rf-colophon-form-note { text-align: left; }
  .rf-colophon-form-send { align-self: flex-end; }
  .rf-colophon-form-seal { width: 50px; height: 50px; font-size: 32px; }
  .rf-colophon-form-success-line { font-size: 15px; }
}

@media (max-height: 640px) {
  .rf-colophon-card {
    max-height: calc(100vh - 60px);
    overflow-y: auto;
  }
}

/* ═══════════════════════════════════════════════════════════════════
   "In the corpus" tab — three-card strip gallery
   See rhyme-finder/design_handoff_corpus_gallery/README.md for the
   full design spec. Two pieces:
     · Tab chrome (.cd-tabs / .cd-tab)
     · Gallery body (.cd-prim, .cd-paircue, .cd-strip, .cd-strip-card,
       .cd-hero-couplet/-stanza/-meta, .cd-song-btn, .cd-prim-footer)
   The `cd-` prefix is the design system's namespace — kept verbatim
   from the handoff so spec selectors line up 1:1.
   ═══════════════════════════════════════════════════════════════ */

/* ── Tab chrome ──────────────────────────────────────────────── */
.cd-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--hair);
  /* D₁ "compact" — sit flush against the source-summary above; the
     ink top border is the divider between metadata and tabs. */
  margin: 0 0 24px;
}
.cd-tab {
  appearance: none;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
  padding: 14px 22px;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  transition: background 140ms ease;
  color: inherit;
}
.cd-tab + .cd-tab { border-left: 1px dotted var(--hair); }
.cd-tab[aria-selected="true"] {
  background: rgba(220, 194, 142, 0.22);
}
.cd-tab[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: var(--vermilion);
}
.cd-tab-title {
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 21px;
  line-height: 1.1;
  color: var(--ink-faded);
  letter-spacing: -0.005em;
  transition: color 140ms ease;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.cd-tab[aria-selected="true"] .cd-tab-title {
  color: var(--ink);
  font-weight: 600;
}
/* Tab-strip icon — same SVG shape as the sticky-bar toggle so the
   reader sees the same glyph in both places (book = dictionary,
   notes = corpus). Vermilion-tinted on the active tab to match the
   tab's 2 px vermilion underline. */
.cd-tab-icon {
  display: block;
  flex-shrink: 0;
  color: var(--ink-faded);
  transition: color 140ms ease;
}
.cd-tab[aria-selected="true"] .cd-tab-icon {
  color: var(--vermilion);
}
.cd-tab-counts {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
}
.cd-tab-counts b {
  color: var(--ink);
  font-weight: 500;
}
.cd-tab[aria-selected="true"] .cd-tab-counts b { color: var(--vermilion); }

@media (max-width: 720px) {
  /* Stay side-by-side on mobile (two equal cells) — the dotted left
     divider is kept. Title + counts tighten so "Rhyme dictionary" and
     "In the corpus" each sit on one line in a ~half-width cell. */
  .cd-tab {
    padding: 12px 14px;
    gap: 4px;
  }
  .cd-tab-title {
    font-size: 16px;
    gap: 7px;
  }
  .cd-tab-icon {
    width: 15px;
    height: 15px;
  }
  .cd-tab-counts {
    font-size: 9.5px;
    letter-spacing: 0.1em;
  }
}

@media (max-width: 360px) {
  /* Very narrow phones (≤360px) — shave the title once more so the
     longer "Rhyme dictionary" label still clears a single line. */
  .cd-tab { padding: 11px 11px; }
  .cd-tab-title { font-size: 14px; gap: 6px; }
  .cd-tab-icon { width: 14px; height: 14px; }
}

.rf-tab-body[hidden] { display: none; }

/* ── Gallery body ───────────────────────────────────────────── */
.cd-prim {
  padding: 4px 0;
  min-width: 0;
}
.cd-prim > * { min-width: 0; }

.cd-prim-empty {
  font-family: var(--display);
  font-style: italic;
  font-size: 17px;
  color: var(--ink-faded);
  text-align: center;
  padding: 40px 12px;
  margin: 0;
}
.cd-prim-empty em {
  font-style: italic;
  color: var(--ink);
  font-weight: 600;
}

/* ── Pair-cue (top label, hover-revealed) ──────────────────── */
.cd-paircue {
  display: flex;
  justify-content: center;
  align-items: baseline;
  gap: 16px;
  padding: 12px 0 14px;
  margin: 0 0 8px;
  position: relative;
  opacity: 0;
  transition: opacity 240ms ease;
}
.cd-prim:hover .cd-paircue,
.cd-prim:focus-within .cd-paircue {
  opacity: 1;
}
.cd-paircue-item {
  appearance: none;
  border: 0;
  background: transparent;
  cursor: default;
  font-family: var(--display);
  font-style: italic;
  letter-spacing: -0.005em;
  padding: 2px 4px;
  transition: color 200ms ease;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
}
.cd-paircue-item--current {
  color: var(--vermilion);
  font-weight: 600;
  font-size: 19px;
}
.cd-paircue-item .src {
  font-style: italic;
  color: var(--ink-soft);
  font-weight: 500;
}
.cd-paircue-item .prt {
  font-style: italic;
  color: var(--vermilion);
  font-weight: 600;
  background: linear-gradient(
    to top,
    rgba(177, 59, 44, 0.36) 0,
    rgba(177, 59, 44, 0.36) 0.32em,
    transparent 0.32em
  );
  padding: 0 3px;
}
.cd-pair-sep {
  display: inline-block;
  vertical-align: baseline;
}
.cd-pair-sep::before {
  content: "—";
  margin: 0 10px;
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  color: rgba(177, 59, 44, 0.55);
}
.cd-pair-dot {
  display: inline-block;
  margin: 0 6px 0 14px;
  color: var(--ink-ghost);
  font-family: var(--mono);
  font-style: normal;
  font-size: 0.6em;
  vertical-align: baseline;
  font-weight: 500;
}
.cd-pair-count {
  font-family: var(--mono);
  font-style: normal;
  font-size: 0.6em;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--vermilion);
  vertical-align: baseline;
}
.cd-paircue-pos {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.22em;
  color: var(--ink-faded);
  font-variant-numeric: tabular-nums;
  text-transform: uppercase;
  font-style: normal;
}
.cd-paircue-pos b {
  color: var(--ink-soft);
  font-weight: 500;
}
.cd-paircue-pos .sl {
  color: rgba(177, 59, 44, 0.5);
  margin: 0 4px;
}

/* ── Strip grid + slide animations ─────────────────────────── */
.cd-strip {
  display: grid;
  grid-template-columns: 100px minmax(0, 1fr) 100px;
  gap: 16px;
  align-items: start;
  padding: 18px 0 24px;
  min-height: 280px;
  position: relative;
  overflow: visible;
}
.cd-strip-card--center { --end-op: 1; }
.cd-strip-card--side   { --end-op: 0.55; }
.cd-strip-card--empty  { --end-op: 0; }

@keyframes cd-slide-from-right {
  0%   { opacity: 0;             transform: translateX(28px); }
  100% { opacity: var(--end-op); transform: translateX(0); }
}
@keyframes cd-slide-from-left {
  0%   { opacity: 0;             transform: translateX(-28px); }
  100% { opacity: var(--end-op); transform: translateX(0); }
}
@keyframes cd-instance-flicker {
  0%   { opacity: 0.35; }
  100% { opacity: 1; }
}
.cd-strip.is-shifting-next > .cd-strip-card {
  animation: cd-slide-from-right 380ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.cd-strip.is-shifting-prev > .cd-strip-card {
  animation: cd-slide-from-left 380ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.cd-strip.is-shifting-next > .cd-strip-card--side,
.cd-strip.is-shifting-prev > .cd-strip-card--side {
  animation-delay: 40ms;
}
.cd-strip-card--center.is-instance-changed {
  animation: cd-instance-flicker 220ms ease;
}
.cd-paircue.is-shifting-next > .cd-paircue-item,
.cd-paircue.is-shifting-prev > .cd-paircue-item {
  /* paircue rides the same direction as the strip */
}
.cd-paircue.is-shifting-next > .cd-paircue-item {
  animation: cd-slide-from-right 380ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.cd-paircue.is-shifting-prev > .cd-paircue-item {
  animation: cd-slide-from-left 380ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

@media (prefers-reduced-motion: reduce) {
  .cd-strip.is-shifting-next > .cd-strip-card,
  .cd-strip.is-shifting-prev > .cd-strip-card,
  .cd-strip-card--center.is-instance-changed,
  .cd-paircue.is-shifting-next > .cd-paircue-item,
  .cd-paircue.is-shifting-prev > .cd-paircue-item {
    animation: none !important;
  }
}

/* ── Strip cards (shared) ───────────────────────────────────── */
.cd-strip-card {
  position: relative;
  appearance: none;
  border: 0;
  background: transparent;
  text-align: left;
  padding: 14px 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  min-width: 0;
  color: inherit;
  transition: opacity 200ms ease, color 200ms ease;
}

/* Side cards — "hollow" design: thin vermilion outlined circle with the
   chevron glyph inside, partner word as a small mono caps label below.
   The whole stack is vertically padded so it sits between the couplet
   lines visually. Hidden at rest; fades in on hover/focus of the strip
   alongside the paircue + songcue. */
.cd-strip-card--side {
  cursor: pointer;
  line-height: 1;
  color: rgba(177, 59, 44, 0.55);
  padding: 44px 4px 8px;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  background: transparent;
  opacity: 0;
  pointer-events: none;
  transition: opacity 240ms ease, color 200ms ease;
}
.cd-prim:hover .cd-strip-card--side,
.cd-prim:focus-within .cd-strip-card--side {
  opacity: 1;
  pointer-events: auto;
}
.cd-strip-card--side:hover,
.cd-strip-card--side:focus-visible {
  color: var(--vermilion);
  outline: none;
}
.cd-strip-card--empty {
  visibility: hidden;
  cursor: default;
}
.cd-strip-card--prev,
.cd-strip-card--next { justify-content: flex-start; padding-left: 0; padding-right: 0; }
.cd-strip-card-word {
  display: inline-flex;
  align-items: center;
  line-height: 1;
}
.cd-strip-card-word em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faded);
  font-weight: 500;
  transition: color 140ms ease;
}
.cd-strip-card--side:hover .cd-strip-card-word em,
.cd-strip-card--side:focus-visible .cd-strip-card-word em {
  color: var(--vermilion);
}
.cd-strip-card-arrow {
  width: 36px;
  height: 36px;
  border: 1px solid var(--vermilion);
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--vermilion);
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: 19px;
  line-height: 1;
  opacity: 0.7;
  pointer-events: none;
  transition: opacity 140ms ease, background 140ms ease;
}
.cd-strip-card--side:hover .cd-strip-card-arrow,
.cd-strip-card--side:focus-visible .cd-strip-card-arrow {
  opacity: 1;
  background: rgba(177, 59, 44, 0.08);
}

/* ── Center card ────────────────────────────────────────────── */
.cd-strip-card--center {
  cursor: pointer;
  text-align: center;
  align-items: center;
  padding: 18px 8px;
  border-radius: 2px;
  transition: background 140ms ease;
}
.cd-strip-card--center:hover,
.cd-strip-card--center:focus {
  background: rgba(220, 194, 142, 0.08);
  outline: none;
}
.cd-strip-center-inner {
  display: flex;
  flex-direction: column;
  gap: 18px;
  align-items: center;
  max-width: 540px;
  margin: 0 auto;
  width: 100%;
}
.cd-strip-center-inner .cd-hero-couplet {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}
.cd-strip-center-inner .cd-hero-couplet p {
  margin: 0;
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 22px;
  line-height: 1.35;
  color: var(--ink);
  text-wrap: balance;
}
.cd-strip-center-inner .cd-hero-couplet .b mark {
  background: transparent;
  color: var(--vermilion);
  border-bottom: 0;
  font-weight: 600;
  padding: 0;
}
.cd-strip-center-inner .cd-hero-couplet .a mark {
  background: linear-gradient(
    to top,
    rgba(177, 59, 44, 0.36) 0,
    rgba(177, 59, 44, 0.36) 0.32em,
    transparent 0.32em
  );
  color: var(--vermilion);
  font-weight: 600;
  padding: 0 2px;
  text-decoration: none;
  border: 0;
  border-radius: 0;
}

/* ── Stanza unfurl (画轴 feel) ─────────────────────────────── */
.cd-strip-center-inner .cd-hero-stanza {
  display: block;
  position: relative;
  max-width: 460px;
  margin: 0 auto;
  text-align: left;
  font-family: "Spectral", "Cormorant Garamond", "Songti SC", "Times New Roman", serif;
  font-style: italic;
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink-faded);
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  padding: 0 14px;
  margin-top: 0;
  border-top: 1px solid transparent;
  background: transparent;
  transition:
    max-height   520ms cubic-bezier(0.22, 0.61, 0.36, 1),
    opacity      300ms ease 80ms,
    margin-top   520ms cubic-bezier(0.22, 0.61, 0.36, 1),
    padding-top  520ms cubic-bezier(0.22, 0.61, 0.36, 1),
    padding-bottom 520ms cubic-bezier(0.22, 0.61, 0.36, 1),
    background   400ms ease 100ms,
    border-top-color 200ms ease;
}
.cd-strip-card--center[data-open="true"] .cd-hero-stanza {
  max-height: 360px;
  opacity: 1;
  margin-top: 16px;
  padding: 14px 14px 18px;
  border-top-color: rgba(177, 59, 44, 0.55);
  background: linear-gradient(rgba(220, 194, 142, 0.45), rgba(220, 194, 142, 0.30));
}
.cd-strip-center-inner .cd-hero-stanza p { margin: 0; }
.cd-strip-center-inner .cd-hero-stanza p.match.a { color: var(--ink-soft); font-weight: 500; }
.cd-strip-center-inner .cd-hero-stanza p.match.b { color: var(--ink); font-weight: 600; }
.cd-strip-center-inner .cd-hero-stanza p.match mark {
  background: transparent;
  color: inherit;
  border-bottom: 1px solid var(--vermilion);
  padding-bottom: 1px;
}
.cd-strip-card--center[data-open="true"] .cd-hero-stanza::before {
  content: "";
  position: absolute;
  top: -2px; left: 22%; right: 22%;
  height: 3px;
  background: radial-gradient(
    ellipse at center,
    rgba(177, 59, 44, 0.30) 0%,
    rgba(177, 59, 44, 0.12) 50%,
    transparent 100%
  );
  pointer-events: none;
}
.cd-strip-card--center[data-open="true"] .cd-hero-stanza::after {
  content: "";
  position: absolute;
  right: 18px; bottom: 10px;
  width: 10px; height: 10px;
  background: var(--vermilion);
  opacity: 0;
  transform: rotate(-4deg);
  animation: cd-seal 320ms ease 380ms forwards;
  box-shadow: inset 0 0 0 1px rgba(140, 30, 22, 0.6);
}
@keyframes cd-seal {
  0%   { opacity: 0;    transform: rotate(-4deg) scale(0.6); }
  60%  { opacity: 0.92; transform: rotate(-4deg) scale(1.06); }
  100% { opacity: 0.85; transform: rotate(-4deg) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .cd-strip-center-inner .cd-hero-stanza,
  .cd-strip-card--center[data-open="true"] .cd-hero-stanza::after {
    transition-duration: 0ms !important;
    animation: none !important;
  }
}

/* ── Meta line (credit · song · year) ──────────────────────── */
.cd-strip-center-inner .cd-hero-meta {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
}
.cd-hero-meta-credit {
  color: var(--ink);
  font-weight: 500;
  letter-spacing: 0.16em;
  font-size: 11px;
}
.cd-hero-meta-song {
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 14px;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink-soft);
}
.cd-hero-meta-year {
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--ink-faded);
  letter-spacing: 0.10em;
}
.cd-hero-meta-sep { color: var(--ink-ghost); }

/* ── Song nav (within-pair) ────────────────────────────────── */
/* Hidden at rest like the paircue + side cards — fades in on hover/
   focus of the strip so the resting state is just the couplet. */
.cd-strip-songcue {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faded);
  margin-top: 6px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 240ms ease;
}
.cd-prim:hover .cd-strip-songcue,
.cd-prim:focus-within .cd-strip-songcue {
  opacity: 1;
  pointer-events: auto;
}
.cd-strip-songcue b {
  color: var(--ink);
  font-weight: 500;
}
.cd-song-btn {
  appearance: none;
  border: 1px solid rgba(177, 59, 44, 0.4);
  background: transparent;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--vermilion);
  font-family: var(--display);
  font-style: italic;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  border-radius: 50%;
  transition: background 140ms ease, border-color 140ms ease;
  padding: 0;
}
.cd-song-btn:hover {
  background: rgba(177, 59, 44, 0.08);
  border-color: var(--vermilion);
}
.cd-song-pos { font-variant-numeric: tabular-nums; }

/* ── Footer · explore link ─────────────────────────────────── */
.cd-prim-footer {
  margin-top: 6px;
  padding: 12px 0 4px;
  text-align: center;
  border-top: 1px dotted var(--hair-soft);
}
.cd-prim-explore {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faded);
  text-decoration: none;
  border-bottom: 1px dotted var(--ink-ghost);
  padding: 2px 0;
  transition: color 140ms ease, border-bottom-color 140ms ease;
}
.cd-prim-explore:hover {
  color: var(--vermilion);
  border-bottom-color: var(--vermilion);
}
.cd-prim-explore b {
  color: var(--ink);
  font-weight: 500;
}
.cd-prim-explore:hover b { color: var(--vermilion); }

/* ── Mobile — hide side cards, single-column, gesture-driven ── */
@media (max-width: 720px) {
  .cd-strip-card--side { display: none; }
  .cd-strip {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 8px 0 14px;
    min-height: 200px;
    touch-action: pan-y;
  }
  .cd-paircue {
    padding: 6px 8px 10px;
    flex-wrap: wrap;
    row-gap: 4px;
  }
  .cd-paircue-item--current { font-size: 16px; }
  .cd-paircue-item .src,
  .cd-paircue-item .prt { font-size: 16px; }
  .cd-pair-sep::before { margin: 0 6px; }
  .cd-paircue-pos { font-size: 8.5px; }

  .cd-strip-card--center { padding: 8px 4px; }
  .cd-strip-center-inner { gap: 14px; max-width: 100%; }
  .cd-strip-center-inner .cd-hero-couplet p {
    font-size: 17px;
    line-height: 1.35;
    white-space: normal;
    text-wrap: balance;
  }
  .cd-strip-center-inner .cd-hero-stanza {
    font-size: 13px;
    line-height: 1.6;
    padding: 0 8px;
  }
  .cd-strip-card--center[data-open="true"] .cd-hero-stanza {
    max-height: 340px;
    padding: 12px 12px 16px;
  }
  .cd-strip-center-inner .cd-hero-meta {
    font-size: 9px;
    gap: 6px;
  }
  .cd-hero-meta-credit { font-size: 9.5px; }
  .cd-hero-meta-song { font-size: 12px; }
  .cd-hero-meta-year { font-size: 9px; }

  /* Swipe hint — sits below the meta line. */
  .cd-strip::after {
    content: "swipe ← → for pairs";
    display: block;
    text-align: center;
    font-family: var(--mono);
    font-size: 8.5px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: rgba(177, 59, 44, 0.55);
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px dotted var(--hair);
  }
}

/* Touch / non-hover devices — there's no hover to trigger the reveal,
   so always show the paircue + songcue (side cards are already
   display:none on mobile via the rule above). */
@media (hover: none) {
  .cd-paircue { opacity: 1; }
  .cd-strip-songcue { opacity: 1; pointer-events: auto; }
}

/* ════════════════════════════════════════════════════════════════
   "Explore all partners" — full corpus view (Atlas)
   Reached from the gallery footer link. Replaces the 3-card strip
   in #corpus-gallery with an overview-then-detail layout: a
   frequency strip naming every partner word (sized by how many
   corpus songs use that pair) over a list of collapsible groups.
   Ported from briefs/demo-c-atlas.html. Tokens only; no new colors.
   ════════════════════════════════════════════════════════════════ */
.cd-explore { padding: 2px 0 8px; }

/* Back-to-browse link — returns to the 3-card strip. */
.cd-explore-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 18px;
  padding: 2px 0;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faded);
  transition: color 140ms ease;
}
.cd-explore-back:hover { color: var(--vermilion); }
.cd-explore-back::before { content: "\2039"; font-size: 14px; line-height: 1; }

/* Section header — eyebrow + title on the left, number cells right. */
.cd-explore-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  padding-bottom: 14px;
  margin-bottom: 22px;
  position: relative;
  border-bottom: 1px solid var(--ink);
}
.cd-explore-head::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -4px;
  height: 1px;
  background: var(--vermilion);
  opacity: 0.55;
}
.cd-explore-eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--vermilion);
  line-height: 1;
}
.cd-explore-title {
  margin: 6px 0 0;
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(24px, 2.6vw, 30px);
  line-height: 1.15;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.cd-explore-title em {
  font-style: italic;
  font-weight: 600;
  color: var(--ink);
  background: linear-gradient(transparent 70%, rgba(177, 59, 44, 0.32) 70%);
  padding: 0 2px;
}
.cd-explore-meta { display: flex; gap: 18px; align-items: flex-end; flex: none; }
.cd-explore-meta-cell { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.cd-explore-meta-num {
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 28px;
  line-height: 1;
  color: var(--vermilion);
}
.cd-explore-meta-lbl {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faded);
}

/* Atlas overview — partners listed inline, size scales by frequency. */
.cd-explore-atlas {
  display: block;
  padding: 4px 0 20px;
  margin-bottom: 28px;
  border-bottom: 1px dashed var(--ink-ghost);
}
.cd-explore-atlas-label {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faded);
  margin-bottom: 14px;
}
.cd-explore-atlas-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 20px;
  row-gap: 12px;
}
.cd-explore-atlas-item {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  font-family: var(--display);
  font-style: italic;
  color: var(--ink);
  cursor: pointer;
  background: transparent;
  border: none;
  padding: 2px 0;
  transition: color 120ms ease;
  line-height: 1.1;
}
.cd-explore-atlas-item:hover,
.cd-explore-atlas-item:focus-visible { color: var(--vermilion); outline: none; }
.cd-explore-atlas-word { font-weight: 600; }
.cd-explore-atlas-count {
  font-family: var(--mono);
  font-style: normal;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--ink-faded);
  vertical-align: super;
}
.cd-explore-atlas-item:hover .cd-explore-atlas-count { color: var(--vermilion); }
.cd-explore-atlas-item.tier-1 .cd-explore-atlas-word { font-size: 30px; }
.cd-explore-atlas-item.tier-2 .cd-explore-atlas-word { font-size: 24px; }
.cd-explore-atlas-item.tier-3 .cd-explore-atlas-word { font-size: 20px; }
.cd-explore-atlas-item.tier-4 .cd-explore-atlas-word { font-size: 17px; color: var(--ink-soft); }
.cd-explore-atlas-item.tier-5 .cd-explore-atlas-word { font-size: 15px; color: var(--ink-faded); }
.cd-explore-atlas-item.is-active .cd-explore-atlas-word {
  color: var(--vermilion);
  text-decoration: underline;
  text-decoration-color: var(--vermilion);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

/* Groups list. */
.cd-explore-groups { list-style: none; margin: 0; padding: 0; }
.cd-explore-group {
  border-bottom: 1px dashed var(--ink-ghost);
  scroll-margin-top: 20px;
}
.cd-explore-group:last-child { border-bottom: none; }
.cd-explore-group-head {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: baseline;
  column-gap: 16px;
  padding: 16px 4px;
  cursor: pointer;
  transition: background 160ms ease;
  outline: none;
}
.cd-explore-group-head:hover,
.cd-explore-group-head:focus-visible { background: rgba(177, 59, 44, 0.04); }
.cd-explore-group-partner {
  font-family: var(--display);
  font-style: italic;
  font-weight: 600;
  font-size: 26px;
  line-height: 1;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.cd-explore-group-head:hover .cd-explore-group-partner { color: var(--vermilion); }
.cd-explore-group-count {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faded);
}
.cd-explore-group-count b { color: var(--ink); font-weight: 500; }
.cd-explore-group-head.is-open .cd-explore-group-count b { color: var(--vermilion); }
.cd-explore-group-toggle {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--vermilion);
}
.cd-explore-group-body { display: none; padding: 0 0 18px 6px; }
.cd-explore-group.is-open .cd-explore-group-body { display: block; }

/* Instance row — quote glyph · couplet · attribution. */
.cd-explore-instance {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr) minmax(140px, 180px);
  column-gap: 16px;
  align-items: start;
  padding: 12px 6px;
  border-bottom: 1px dotted var(--ink-ghost);
  cursor: pointer;
  transition: background 160ms ease;
}
.cd-explore-instance:last-child { border-bottom: none; }
.cd-explore-instance:hover { background: rgba(177, 59, 44, 0.035); }
.cd-explore-instance.no-stanza { cursor: default; }
.cd-explore-instance.no-stanza:hover { background: transparent; }
.cd-explore-glyph {
  font-family: var(--display);
  font-style: italic;
  font-weight: 500;
  font-size: 36px;
  line-height: 0.6;
  color: var(--vermilion);
  opacity: 0.78;
  margin-top: 9px;
  text-align: center;
  letter-spacing: -0.02em;
}
.cd-explore-pair { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.cd-explore-a,
.cd-explore-b {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 500;
  font-size: 16px;
  line-height: 1.34;
}
.cd-explore-a { color: var(--ink-soft); }
.cd-explore-b { color: var(--ink); }
.cd-explore-mark-source { color: var(--vermilion); font-weight: 500; }
.cd-explore-mark-partner {
  color: var(--vermilion);
  font-weight: 500;
  background: linear-gradient(transparent 65%, rgba(177, 59, 44, 0.28) 65%);
  padding: 0 1px;
}
.cd-explore-attr {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faded);
  text-align: right;
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.5;
}
.cd-explore-attr em {
  font-style: italic;
  text-transform: none;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  font-weight: 400;
}
.cd-explore-more {
  display: block;
  margin: 14px auto 0;
  padding: 6px 4px;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: transparent;
  border: none;
  cursor: pointer;
  transition: color 120ms ease;
}
.cd-explore-more:hover { color: var(--vermilion); }
.cd-explore-more::before { content: "+ "; color: var(--vermilion); }
/* display:block above outranks the UA [hidden] rule on equal specificity,
   so restore hide-on-hidden explicitly (else a full group shows "Show 0 more"). */
.cd-explore-more[hidden] { display: none; }

/* Stanza popout — surrounding lyric context, click an instance row. */
.cd-explore-stanza {
  grid-column: 1 / -1;
  margin: 8px 0 4px;
  padding: 10px 14px;
  border-left: 2px solid var(--vermilion);
  background: rgba(177, 59, 44, 0.045);
  font-family: var(--serif);
  font-style: italic;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-soft);
  display: none;
}
.cd-explore-instance.is-open .cd-explore-stanza { display: block; }
.cd-explore-stanza p { margin: 0; padding: 1px 0; }
.cd-explore-stanza .is-match { color: var(--ink); font-weight: 550; }

@media (max-width: 720px) {
  .cd-explore-head { gap: 14px; }
  .cd-explore-meta { gap: 12px; }
  .cd-explore-meta-num { font-size: 22px; }
  .cd-explore-atlas-item.tier-1 .cd-explore-atlas-word { font-size: 24px; }
  .cd-explore-atlas-item.tier-2 .cd-explore-atlas-word { font-size: 20px; }
  .cd-explore-atlas-item.tier-3 .cd-explore-atlas-word { font-size: 17px; }
  .cd-explore-atlas-item.tier-4 .cd-explore-atlas-word { font-size: 15px; }
  .cd-explore-atlas-item.tier-5 .cd-explore-atlas-word { font-size: 14px; }
  .cd-explore-group-partner { font-size: 22px; }
  .cd-explore-instance {
    grid-template-columns: 22px 1fr;
    row-gap: 4px;
  }
  .cd-explore-attr { grid-column: 2; text-align: left; }
  .cd-explore-a,
  .cd-explore-b { font-size: 15px; }
}
