/* ── Reset & base ──────────────────────────────────────────── */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

/*
 * ── Design tokens ─────────────────────────────────────────────
 *
 * Canonical tokens (colors, font, type scale, spacing, radii) come from the CDN:
 *   https://cdn.neorgon.org/v1.0.0/styles/base.css   (linked in index.html)
 * Do NOT redeclare them here: a local copy is how the fleet drifted. The block
 * below holds only what base.css does not define, plus the per-site accent.
 *
 * Motion: base.css still ships --ease-snap (bounce) for legacy sites, but it is
 * deprecated for new work (impeccable law: ease-out exponential, no bounce).
 * Use --ease-out below.
 */

:root {
  /* Per-site identity: set to this site's hub card accent (PROJECTS.md section 4) */
  --accent: #e11d48;
  --accent-bright: #f43f5e;

  /* Site extras base.css does not define. The file owns four literals and
     nothing else: --accent and --accent-bright above, and the two --danger
     values below, which base.css does not define at all. Every other value
     here is a color-mix of one of them. */
  /* The toast floats over content, so it has to be opaque; it is the page's own
     ground carried a tenth of the way toward the accent. */
  --surface-toast: color-mix(in srgb, var(--bg) 90%, var(--accent));
  /* Text on an accent fill: tinted toward the accent rather than pure white,
     but only just. Measured, because the two rules pull against each other
     here: the accent is light enough that #f9f9f9 already sits on it at
     4.46:1, under AA for 14px, and every step of tint costs more. 2% is
     chroma 0.0045, the tint the law asks for, at 4.57:1 on --accent and
     4.70:1 on --danger. Deepen the tint and the label stops passing. */
  --on-accent: color-mix(in oklab, white 98%, var(--accent));
  /* Destructive stays a different red from the accent, or "reset progress"
     reads as the primary action on every screen it appears on. */
  --danger: #dc2626;
  --danger-hover: #ef4444;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --control-height: 44px;
  --control-height-sm: 36px;
  --shadow-ink: color-mix(in srgb, var(--bg) 55%, transparent);
  --shadow-card: 0 12px 28px var(--shadow-ink);
  --shadow-modal: 0 24px 48px color-mix(in srgb, var(--bg) 62%, transparent);
  --z-sticky-header: 200;
  --z-modal: 400;
  --z-toast: 500;
}

/* Author display values (e.g. .section/.stack flex) would otherwise defeat the
   hidden attribute, so restore its authority once, globally. */
[hidden] { display: none !important; }

html { height: 100%; }
body {
  font-family: var(--font);
  background: var(--bg);
  min-height: 100%;
  color: var(--text-primary);
  display: flex; flex-direction: column;
}

main#main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  width: 100%;
}

/* ── Layout ────────────────────────────────────────────────── */
/*
 * GOTCHA: body { display:flex; flex-direction:column } + margin: 0 auto
 * on a child collapses its width, so always pair with width: 100%.
 *
 * GOTCHA: External images (YouTube ggpht, Gravatar, etc.) may block loading
 * when the Referer header points to localhost or an unknown origin. Fix:
 * 1. Add <meta name="referrer" content="no-referrer"> in <head> (global)
 * 2. Or add referrerpolicy="no-referrer" on each <img> tag
 */
.container {
  max-width: 900px;
  width: 100%;
  margin: 0 auto;
  padding: var(--space-6);
  flex: 1;
}

/* Vertical rhythm: use inside .container or nested regions */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}
.stack--tight { gap: var(--space-4); }
/* Major sections need a real break. At 32px a heading sits almost on top of
   the block above it and the page reads as one undifferentiated column. */
.stack--loose { gap: 56px; }

/* Page section: title row + body (replaces “card everything” for grouping) */
.section {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}
.section__header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
}
.section__titles {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}
.section__title {
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-primary);
}
.section__lead {
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: 1.6;
  max-width: 64ch;   /* 65-75 characters is the readable measure */
}
.section__lead code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
  font-size: 0.92em;
  color: var(--text-secondary);
}
.stack > .card { margin-bottom: 0; }
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* ── Header ────────────────────────────────────────────────────
 * Owned by the Neorgon Header Kit (css/neorgon-header.css, canonical
 * source: packages/neorgon-ui/header/). Do NOT style .header-bar,
 * .header-logo*, .header-title-link, .header-subtitle, .header-right,
 * .header-actions, or .header-home here. Auth styles (.auth-*) stay
 * site-owned below.
 *
 * There is deliberately no bare `nav` rule. This file used to carry
 * `nav { display: flex; align-items: center }`, written for a header that has
 * not been a <nav> since the kit landed. The two <nav> elements left on the
 * page are the footer kit's link columns and the rail, so all it did was lay
 * the rail out as a flex row: below 1180 the contents disclosure opened beside
 * the bar instead of under it, and from 1180 align-items centred a rail taller
 * than its own max-height, putting its first chapters above scrollTop 0 where
 * nothing could reach them. Style the class, never the element.
 */

/* ── Buttons (canonical) ─────────────────────────────────────
 * Use .btn + a variant. Aliases: .nav-link = toolbar ghost; .auth-* map below.
 */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--control-height);
  padding: 0 var(--space-4);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-primary);
  transition:
    background-color var(--dur) var(--ease-out),
    color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out),
    box-shadow var(--dur) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
.btn--sm {
  min-height: var(--control-height-sm);
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
}
.btn--block { width: 100%; }
.btn--icon {
  min-width: var(--control-height);
  padding: 0;
}
.btn--primary {
  background: var(--accent);
  color: var(--on-accent);
  border-color: transparent;
}
/* Derived from the accent, not a third literal: --accent-bright under white text is 3.67:1. */
.btn--primary:hover { background: color-mix(in srgb, var(--accent) 85%, black); }
.btn--secondary {
  background: var(--surface-2);
  color: var(--text-primary);
  border-color: var(--border-strong);
}
.btn--secondary:hover {
  background: color-mix(in srgb, var(--text-primary) 10%, transparent);
}
.btn--ghost {
  background: transparent;
  color: var(--text-primary);
  border-color: color-mix(in srgb, var(--text-primary) 18%, transparent);
}
.btn--ghost:hover {
  background: color-mix(in srgb, var(--text-primary) 10%, transparent);
  color: var(--text-primary);
}
.btn--danger {
  background: var(--danger);
  color: var(--on-accent);
  border-color: transparent;
}
.btn--danger:hover { background: var(--danger-hover); }

.auth-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--control-height);
  min-height: var(--control-height);
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--text-primary) 18%, transparent);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-primary);
  cursor: pointer;
  font-family: inherit;
  transition:
    background-color var(--dur) var(--ease-out),
    color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
}
.auth-toggle:hover {
  background: color-mix(in srgb, var(--text-primary) 10%, transparent);
  color: var(--text-primary);
}
.auth-toggle svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  display: block;
}
.auth-toggle.logged-in { color: var(--accent); }
.auth-toggle.logged-in svg circle:nth-of-type(2) {
  fill: currentColor;
  stroke: none;
}

/* ── Sheet (inline panel under header), not a modal ──────────
 * Use for auth, filters, compact forms. No backdrop; page scrolls.
 * For blocking overlays use .modal below.
 */
.auth-panel {
  background: color-mix(in srgb, var(--text-primary) 2%, transparent);
  border-bottom: 1px solid var(--border-subtle);
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s var(--ease-out);
}
.auth-panel.open { max-height: 300px; }
.auth-panel-inner {
  padding: var(--space-6);
  max-width: 400px;
  margin: 0 auto;
}
.auth-tabs {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.auth-tab {
  flex: 1;
  min-height: var(--control-height-sm);
  padding: 0 var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  transition:
    background-color var(--dur) var(--ease-out),
    color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
}
.auth-tab.active {
  background: var(--surface-2);
  color: var(--text-primary);
  border-color: var(--border-strong);
}
.auth-form input {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-family: inherit;
}
.auth-submit {
  width: 100%;
  min-height: var(--control-height);
  padding: 0 var(--space-4);
  border: none;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--on-accent);
  font-family: inherit;
  font-weight: 600;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-out);
}
.auth-submit:hover { background: var(--accent-bright); }
#authUser {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.auth-username {
  color: var(--text-primary);
  font-weight: 600;
}
.auth-logout {
  min-height: var(--control-height-sm);
  padding: 0 var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  transition:
    background-color var(--dur) var(--ease-out),
    color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
}
.auth-logout:hover {
  background: var(--surface-2);
  color: var(--text-primary);
}
.auth-divider {
  height: 1px;
  background: var(--border-subtle);
}

/* ── Card ──────────────────────────────────────────────────── */
/*
 * GOTCHA: backdrop-filter creates a stacking context, so dropdowns inside
 * a card can be clipped by a later card's stacking context. Fix by adding
 * position: relative; z-index: 10 to the card that owns the open dropdown.
 *
 * Default: static surface (no hover lift, avoids generic “dashboard demo”).
 * Use .card--interactive for raised hover + entrance motion.
 *
 * GOTCHA: a <button> or <a> used AS a card does not inherit body text color,
 * buttons default to canvas text (near-black), rendering invisible on the dark
 * bg. When a card is an interactive element, set color: var(--text-primary)
 * and font-family: var(--font) explicitly on it.
 */
.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  margin-bottom: var(--space-6);
  backdrop-filter: blur(10px);
  transition: border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
.card:hover {
  border-color: var(--border-strong);
  box-shadow: 0 8px 20px color-mix(in srgb, var(--bg) 50%, transparent);
}
.card--interactive {
  transition:
    transform var(--dur) var(--ease-out),
    box-shadow var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
  animation: fadeIn 0.35s var(--ease-out) both;
}
.card--interactive:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-card);
  border-color: var(--border-strong);
}
.card--enter {
  animation: fadeIn 0.35s var(--ease-out) both;
}
.card--flat:hover {
  box-shadow: none;
}
/* Card with an action row, in an equal-height grid: pin the toolbar to the
   bottom so buttons align across cards whose text wraps differently. */
.card--actions {
  display: flex;
  flex-direction: column;
}
.card--actions > .toolbar:last-child {
  margin-top: auto;
}

/* ── Button press feedback ─────────────────────────────────── */
button:active,
.btn:active,
.nav-link:active,
.auth-toggle:active,
.auth-tab:active,
.auth-submit:active,
.auth-logout:active {
  transform: scale(0.98);
  transition-duration: var(--dur-fast);
}

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

/* ── Toast ─────────────────────────────────────────────────── */
.toast {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  z-index: var(--z-toast);
  max-width: min(360px, calc(100vw - var(--space-8)));
  background: var(--surface-toast);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-primary);
  box-shadow: var(--shadow-card);
  pointer-events: none;
  transform: translateY(8px);
  opacity: 0;
  transition: opacity 0.2s var(--ease-out), transform 0.2s var(--ease-out);
}
.toast.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ── Footer ────────────────────────────────────────────────────
   Owned by the Neorgon Footer Kit (css/neorgon-footer.css).
   Don't add .neo-footer rules here. Edit packages/neorgon-ui/footer/
   and re-run sync-footer.sh. */

/* ── Focus styles ──────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 2px;
}
/* A ring the colour of the button it rings is not a ring. Every filled control
   takes the text colour instead. */
.btn--primary:focus-visible,
.btn--danger:focus-visible,
.rn-seg-btn[aria-pressed="true"]:focus-visible { outline-color: var(--text-primary); }

/* ── Skip link ─────────────────────────────────────────────── */
.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-4);
  z-index: 1000;
  padding: var(--space-2) var(--space-4);
  background: var(--accent-bright);
  color: var(--bg);
  font-weight: 600;
  font-size: var(--text-sm);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  text-decoration: none;
  transition: top var(--dur);
}
.skip-link:focus { top: 0; }

/* ── Reduced motion ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .card--interactive:hover { transform: none; }
}

/* ── Responsive ────────────────────────────────────────────── */
@media (max-width: 600px) {
  .container { padding: var(--space-4); }
  .toast {
    left: var(--space-4);
    right: var(--space-4);
    max-width: none;
  }
}

/* ── Runcible: the book ────────────────────────────────────────
 * Site-owned classes only. The header and the footer are the kits'
 * (css/neorgon-header.css, css/neorgon-footer.css) and the exercise panel is
 * the engine's (css/exercises.css, the rx- layer); nothing here styles
 * .header-*, .neo-footer-* or .rx-*. Everything below is prefixed rn- except
 * .neo-attrib, whose name is fixed by C11.3.
 *
 * The shape is a book, not a dashboard: a reading column at a real measure, a
 * table of contents in the left margin, and the drill on the facing page. No
 * cards, no side stripes, no progress bars. See docs/DESIGN-BOOK.md.
 *
 * Colour: --accent and --accent-bright (declared once at the top of this file)
 * are the only two literals the site owns. Every tint below is a color-mix of
 * one of them, so re-skinning the book is one line.
 */

:root {
  --rn-measure: 66ch;                                       /* the text itself, 65 to 75 characters */
  --rn-gutter: 0px;                                         /* the prose's left margin, where the ticks live */
  --rn-col: calc(var(--rn-measure) + var(--rn-gutter));     /* the column the grid allocates for both */
  --rn-top: calc(var(--header-h, 68px) + var(--space-4));   /* clears the sticky content header */
  --rn-rail: 220px;
  --rn-bar: 40px;    /* the sticky contents bar, below the rail width */
  --rn-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}
/* A margin wide enough to hold a tick is a margin worth having, and a phone has
   no room for one. */
@media (min-width: 700px) { :root { --rn-gutter: 2.25rem; } }
/* From the rail width the contents leave the bar, so nothing sticks under the
   header but the header. */
@media (min-width: 1256px) { :root { --rn-bar: 0px; } }

/* ── The page ────────────────────────────────────────────────── */

.rn-view {
  width: 100%;
  max-width: 62rem;
  margin: 0 auto;
  padding: var(--space-8) var(--space-6) 72px;
}
.rn-view[data-view="chapter"] { max-width: 82rem; }
.rn-view[data-view="today"] { max-width: 68rem; }
.rn-view[data-view="catalog"],
.rn-view[data-view="settings"] { max-width: 52rem; }
/* With no Book chosen, Today is the shelf, and a shelf is a narrow thing. */
.rn-view[data-view="today"]:has(.rn-shelf) { max-width: 52rem; }
.rn-view > .rn-title { margin-bottom: var(--space-6); }
.rn-loading { font-size: var(--text-sm); color: var(--text-muted); }

@media (max-width: 700px) {
  .rn-view { padding: var(--space-6) var(--space-4) 56px; }
}

/* ── Shared type ─────────────────────────────────────────────── */

.rn-title { font-size: var(--text-2xl); font-weight: 600; line-height: 1.25; color: var(--text-primary); }
.rn-lead { font-size: var(--text-sm); line-height: 1.6; color: var(--text-muted); max-width: 62ch; }
.rn-note { font-size: var(--text-sm); line-height: 1.6; color: var(--text-muted); }
.rn-warn { font-size: var(--text-sm); line-height: 1.6; color: var(--danger-hover); }
.rn-detail {
  font-family: var(--rn-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.rn-error { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-4); max-width: var(--rn-measure); }

/* A link that reads as text. textAction() builds a <button> with this class and
   no .btn, so the reset has to be here. */
.rn-textlink {
  display: inline;
  padding: 2px 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-sm);
  line-height: 1.7;
  color: var(--accent-bright);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.rn-textlink:hover { color: var(--text-primary); }

/* Chapter state: the glyph carries the colour, the sr-only text carries the
   meaning, because a coloured dot is not a message. */
.rn-glyph-state { flex: 0 0 auto; font-size: var(--text-sm); line-height: 1.4; }
.rn-glyph-state[data-state="passed"] { color: var(--accent-bright); }
.rn-glyph-state[data-state="available"] { color: var(--text-secondary); }
.rn-glyph-state[data-state="locked"],
.rn-glyph-state[data-state="planned"] { color: var(--text-muted); }

/* Evidence is a sentence and a hairline the width of the title it belongs to,
   never a bar with a percentage pair. */
.rn-evidence { font-size: var(--text-sm); line-height: 1.6; color: var(--text-muted); max-width: 60ch; }
.rn-title-block { display: grid; grid-template-columns: minmax(0, max-content); gap: var(--space-2); max-width: 100%; }
.rn-hairline {
  height: 2px;
  border-radius: 1px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  overflow: hidden;
}
.rn-hairline > i { display: block; height: 100%; width: var(--fill, 0%); background: var(--accent); }

/* ── The chapter spread: rail, prose, facing page ────────────── */

/* On a phone the spread is the reading column alone, centred on the page. */
.rn-spread {
  display: grid;
  grid-template-columns: minmax(0, var(--rn-col));
  justify-content: center;
  gap: var(--space-6);
  align-items: start;
}
.rn-spread > .rn-spine { display: none; }

/* From 980px it is a real spread: the verso reads, the recto answers, and the
   fold between them is one hairline. Both tracks are allocated whether or not a
   drill is running, so pressing Start never moves a word of the prose.
   980 is 66ch + a fold + a 320px drill + the page padding, measured rather than
   rounded: below it the two cannot both have their width and the drill mounts
   inline instead. js/render-mount.js FACING matches this number exactly, or a
   drill mounts on a page that is not there. */
@media (min-width: 980px) {
  .rn-view[data-view="chapter"] { max-width: 66rem; }
  .rn-spread {
    /* The recto is given a floor and a ceiling, not the remainder. As 1fr it
       collapsed to 139px at 900 and 167px at 1180, which is narrower than one
       option row; the prose track is minmax(0, ...) and yields instead. */
    grid-template-columns: minmax(0, var(--rn-col)) 1px minmax(20rem, 22rem);
    justify-content: start;
    gap: var(--space-6);
  }
  .rn-spread[data-recto="none"] { grid-template-columns: minmax(0, var(--rn-col)); }
  .rn-spread > .rn-spine { display: block; align-self: stretch; background: var(--border-subtle); }
}

/* From 1256px the contents come out of the bar and into the left margin, and
   the whole spread is one grid: contents, text, fold, facing page. Same
   arithmetic with the 220px rail added. */
@media (min-width: 1256px) {
  .rn-view[data-view="chapter"] {
    display: grid;
    grid-template-columns: var(--rn-rail) minmax(0, var(--rn-col)) 1px minmax(20rem, 22rem);
    /* The reading column yields first only when nothing else can: never below
       its own floor, which is what the recto's floor used to be taken from. */
    gap: var(--space-6);
    align-items: start;
    max-width: 84rem;
  }
  .rn-spread { display: contents; }
  .rn-view[data-view="chapter"]:has(.rn-spread[data-recto="none"]) {
    grid-template-columns: var(--rn-rail) minmax(0, var(--rn-col));
  }
  .rn-view[data-view="chapter"] > .rn-warn,
  .rn-view[data-view="chapter"] > .rn-note--fallback { grid-column: 1 / -1; }
}

/* Once the page is wide enough to seat all three at full measure, the fold
   opens out. */
@media (min-width: 1500px) {
  .rn-spread { gap: var(--space-8); }
  .rn-view[data-view="chapter"] { gap: var(--space-8); }
}

.rn-prose { min-width: 0; padding-left: var(--rn-gutter); }

.rn-chapter-head { display: flex; flex-direction: column; gap: var(--space-3); }
.rn-chapter-title { font-size: var(--text-2xl); font-weight: 600; line-height: 1.25; color: var(--text-primary); }
.rn-goal { font-size: var(--text-lg); line-height: 1.5; color: var(--text-secondary); max-width: var(--rn-measure); }
.rn-state {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Everything scroll-to lands on clears the sticky header. Without this a
   scrollIntoView({ block: 'start' }) puts the target's top at viewport 0, which
   is 68px under the header: the rung title Today just sent you to measured
   y = -8. .rn-ex-host carries its own, larger, margin below. */
.rn-rung, .rn-marker, .rn-page { scroll-margin-top: calc(var(--rn-top) + var(--rn-bar) + var(--space-4)); }

/* A rung is a section of the chapter. 56px and a hairline is what separates
   one from the next; the rule belongs to the section under it. */
.rn-rung { margin-top: var(--space-8); }
.rn-rung + .rn-rung {
  margin-top: 56px;
  padding-top: var(--space-8);
  border-top: 1px solid var(--border-subtle);
}
.rn-rung-title { font-size: var(--text-xl); font-weight: 600; line-height: 1.3; color: var(--text-primary); }
.rn-unlocks { margin-top: var(--space-2); font-size: var(--text-sm); line-height: 1.6; color: var(--text-muted); }

/* A page of the chapter. Text keeps the measure; a table or a figure may run
   to the column edge, which is why the cap is on the text and not the block. */
.rn-page { margin-top: var(--space-6); }
.rn-page > h4 {
  margin-bottom: var(--space-3);
  max-width: var(--rn-measure);
  font-size: var(--text-lg);
  font-weight: 600;
  line-height: 1.35;
  color: var(--text-primary);
}
.rn-page > p { max-width: var(--rn-measure); font-size: var(--text-base); line-height: 1.65; color: var(--text-secondary); }
.rn-page > p + p { margin-top: var(--space-4); }
.rn-page > .rn-note { margin-top: var(--space-3); max-width: var(--rn-measure); }
/* Numbers that are a list live in the margin, never inside the text block,
   where a leading numeral reads as an option. */
.rn-page ol, .rn-page ul {
  margin: var(--space-4) 0 0 1.6em;
  max-width: var(--rn-measure);
  list-style-position: outside;
}
.rn-page li { line-height: 1.65; color: var(--text-secondary); }
.rn-page li + li { margin-top: var(--space-2); }
.rn-page li::marker { color: var(--text-muted); }

/* A callout is a full hairline and a wash, never a side stripe. The title is
   the only bold thing in it. */
.rn-callout {
  padding: var(--space-4) var(--space-6);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  max-width: var(--rn-measure);
}
.rn-callout > h4 { font-size: var(--text-base); }
.rn-callout--win {
  border-color: color-mix(in srgb, var(--accent) 32%, var(--border));
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.rn-callout--warn {
  /* Matches .rx-callout[data-tone="warn"] in exercises.css. A caution in a book
     is a firmer hairline, not a red panel: --danger stays for destructive
     controls, and beside the accent wash of a win callout the two reds read as
     the same thing said twice. */
  border-color: var(--border-strong);
  background: var(--surface-1);
}

.rn-scroll { margin-top: var(--space-4); overflow-x: auto; }
.rn-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.rn-table th, .rn-table td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
  text-align: left;
  white-space: nowrap;
}
.rn-table th { color: var(--text-muted); font-weight: 600; }

.rn-figure { margin-top: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-start; }
.rn-svg {
  width: 120px;
  height: 120px;
  fill: none;
  stroke: var(--text-primary);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.rn-figure figcaption { font-size: var(--text-sm); color: var(--text-muted); }

/* ── The exercise marker ─────────────────────────────────────── */
/* Where the chapter authored a drill the prose pauses on a hairline, names it
   once, and offers one button. The engine draws the title again inside its own
   panel, which is the only other place it appears. */

.rn-marker {
  position: relative;
  margin: var(--space-6) 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  max-width: var(--rn-measure);
}
.rn-marker-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); }
.rn-kicker {
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.rn-marker-state { font-size: var(--text-sm); color: var(--accent-bright); }
.rn-marker-state:empty { display: none; }
.rn-marker--running .rn-marker-state { color: var(--text-muted); }
.rn-marker-title { margin-top: var(--space-2); font-size: var(--text-lg); font-weight: 600; color: var(--text-primary); }
.rn-marker > .toolbar { margin-top: var(--space-3); }

/* Margin tick: re-reading a chapter shows what you already earned, where you
   earned it. It needs the gutter, so it appears with the gutter. */
@media (min-width: 700px) {
  .rn-marker--passed::before {
    content: '✓';
    position: absolute;
    left: calc(-1 * var(--rn-gutter));
    top: var(--space-4);
    width: var(--rn-gutter);
    font-size: var(--text-sm);
    line-height: 1.4;
    color: var(--text-muted);
  }
}

/* An inline drill scrolls its own host to the top, so the prompt is the first
   thing in view. The margin also has to leave the marker's toolbar above it on
   screen, because that is where Close lives when there is no facing bar: at
   space-8 the two buttons landed 16px behind the contents bar. */
.rn-ex-host { scroll-margin-top: calc(var(--rn-top) + var(--rn-bar) + var(--space-8) + var(--space-6)); }
.rn-ex-host:empty { display: none; }
.rn-ex-host:not(:empty) {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
  animation: rn-rise-far 220ms var(--ease-out) both;
}

/* While a drill runs inline there is one live region, so the prose recedes. */
.rn-prose[data-running] .rn-chapter-head,
.rn-prose[data-running] .rn-rung-title,
.rn-prose[data-running] .rn-unlocks,
.rn-prose[data-running] .rn-page,
.rn-prose[data-running] .neo-attrib,
.rn-prose[data-running] .rn-marker:not(.rn-marker--running) {
  opacity: 0.4;
  transition: opacity var(--dur) var(--ease-out);
}

/* ── The facing page ─────────────────────────────────────────── */
/* A page edge is a hairline, not a box: the drill sits beside the rule the
   learner just failed, and both stay readable. */

.rn-facing { min-width: 0; }
@media (min-width: 980px) {
  .rn-facing {
    position: sticky;
    top: calc(var(--rn-top) + var(--rn-bar));
    align-self: start;
    max-width: 22rem;
    max-height: calc(100dvh - var(--rn-top) - var(--rn-bar) - var(--space-6));
    overflow: auto;
    overscroll-behavior: contain;
    animation: rn-slide-in 220ms var(--ease-out) both;
  }
  /* A wrong answer adds the explanation panel, which on a 640px or 700px tall
     window pushed the drill's own foot below the bottom of the scrolling panel:
     Enter still advanced, a pointer did not. The foot rides the bottom of the
     panel instead, so Next is on screen at every height. Scoped to this media
     query because below it the panel is not a scroll container and sticky would
     pin the button to the viewport. */
  .rn-facing[data-state="running"] .rx-foot {
    position: sticky;
    bottom: 0;
    padding-block: var(--space-2);
    background: var(--bg);
  }
}
/* Resized narrow mid-drill: the panel keeps running, under the prose. */
@media (max-width: 979px) {
  .rn-facing { margin-top: var(--space-6); padding-top: var(--space-4); border-top: 1px solid var(--border); }
  /* One column, and the drills are already in the prose under the reader's
     thumb, so the idle recto has nothing to add and no room to add it in. */
  .rn-facing[data-state="idle"] { display: none; }
}
.rn-facing-bar { display: flex; justify-content: flex-end; margin-bottom: var(--space-3); }
.rn-facing[data-state="idle"] > .rn-facing-bar,
.rn-facing[data-state="running"] > .rn-facing-idle { display: none; }

/* The recto with no drill on it: where the bookmark is, what there is to
   answer there, and what the chapter is measured by. It is the page you turn
   to, so it reads as a page and not as a sidebar of controls. */
.rn-facing-idle { display: flex; flex-direction: column; gap: var(--space-3); }
.rn-facing-rung { font-size: var(--text-lg); font-weight: 600; line-height: 1.3; color: var(--text-primary); }
.rn-facing-list { list-style: none; display: flex; flex-direction: column; gap: var(--space-1); margin-top: var(--space-1); }
.rn-facing-item {
  display: grid;
  grid-template-columns: 1rem minmax(0, 1fr);
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-1) 0;
  border-top: 1px solid var(--border-subtle);
}
.rn-facing-item:first-child { border-top: 0; }
.rn-facing-tick { color: var(--text-muted); font-size: var(--text-sm); line-height: 1.5; }
.rn-facing-item--passed .rn-facing-tick { color: var(--accent-bright); }
.rn-facing-drill {
  display: block;
  min-height: 32px;
  padding: var(--space-1) 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-sm);
  line-height: 1.5;
  text-align: left;
  color: var(--text-secondary);
  cursor: pointer;
}
.rn-facing-drill:hover { color: var(--accent-bright); }
.rn-facing-earned { grid-column: 2; font-size: var(--text-xs); color: var(--text-muted); }
.rn-facing-idle > .rn-evidence { margin-top: var(--space-2); padding-top: var(--space-3); border-top: 1px solid var(--border-subtle); }
@media (pointer: coarse) { .rn-facing-drill { min-height: 44px; padding: var(--space-2) 0; } }

/* ── The rail: one nav, two shapes ───────────────────────────── */
/* From 1180px a 220px sticky column beside the prose. Below that a 40px bar
   under the header whose disclosure pushes the page down: not a drawer, not a
   modal, nothing to trap focus in. */

.rn-rail { position: relative; display: block; margin-bottom: var(--space-6); }

.rn-rail-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 40px;
  padding: 0 var(--space-2);
  border: 0;
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg);
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  cursor: pointer;
}
.rn-rail-bar:hover { color: var(--text-primary); }
.rn-rail-bar-label { flex: 0 0 auto; font-weight: 600; color: var(--text-primary); }
.rn-rail-bar-label::after { content: ' ▾'; color: var(--text-muted); }
.rn-rail[data-open] .rn-rail-bar-label::after { content: ' ▴'; }
.rn-rail-crumb { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; }
/* The chapter title gives way first, then the rung. */
.rn-crumb-ch { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.rn-crumb-sep { flex: 0 0 auto; color: var(--text-muted); }
.rn-crumb-rung { flex: 0 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--text-muted); }
.rn-rail-pos { flex: 0 0 auto; margin-left: auto; color: var(--text-muted); font-variant-numeric: tabular-nums; }

.rn-rail-body { display: none; padding: var(--space-4) var(--space-2) var(--space-6); }
.rn-rail[data-open] .rn-rail-body { display: block; }
.rn-rail-head {
  margin-bottom: var(--space-3);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Below the rail width the whole nav is the sticky element: a 40px bar that
   stays under the header, and a disclosure that opens under the bar and pushes
   the page down. The body is capped at the viewport so a 13-chapter contents
   list scrolls inside itself rather than burying the prose. */
@media (max-width: 1255px) {
  .rn-rail {
    position: sticky;
    top: var(--header-h, 68px);
    z-index: 3;
    background: var(--bg);
  }
  .rn-rail-body {
    max-height: calc(100dvh - var(--header-h, 68px) - var(--rn-bar));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

@media (min-width: 1256px) {
  /* The beacon kit's control is fixed to the bottom-left corner, which is the
     rail's column: without the two beacon terms the last chapter sits under it.
     The fallbacks match css/neorgon-beacon.css, so the rail is still right if
     the kit is not linked. The last term is --space-6 rather than a hairline
     because the rail is only pinned at --rn-top once the page has scrolled;
     unscrolled it sits at the view's own --space-8 padding, 16px lower, and a
     tighter gap put the last visible row under the beacon before the first
     scroll. */
  .rn-rail {
    position: sticky;
    top: var(--rn-top);
    align-self: start;
    max-height: calc(
      100dvh - var(--rn-top) - var(--beacon-size, 40px) - var(--beacon-offset, 20px) - var(--space-6)
    );
    overflow-y: auto;
    margin-bottom: 0;
    padding-right: var(--space-4);
  }
  .rn-rail-bar { display: none; }
  .rn-rail-body { display: block; padding: 0; }
}
/* Overlay scrollbars draw nothing until the pointer moves, so a nine-rung
   chapter looked like a list that simply stopped. render-mount.js sets the
   attribute while there is more below the fold and removes it at the end of the
   scroll, so the fade is a promise of more rather than a permanent dimming. */
.rn-rail[data-overflow] {
  -webkit-mask-image: linear-gradient(to bottom, currentColor calc(100% - 40px), transparent);
  mask-image: linear-gradient(to bottom, currentColor calc(100% - 40px), transparent);
}

@media (max-width: 520px) { .rn-rail-pos { display: none; } }


/* Chapters as lines, not cards. */
.rn-toc { list-style: none; display: flex; flex-direction: column; }
.rn-toc-ch { display: flex; flex-direction: column; }
/* The row is a glyph in the margin and a title that wraps inside its own
   column. It used to wrap as a flex line, which broke a long chapter into
   orphans: the glyph alone on line 1 with the title flush left underneath it,
   or "open" alone on a second line at x=0. */
.rn-toc-line {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  gap: var(--space-2);
  min-height: 28px;
  padding: var(--space-1) 0;
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--text-secondary);
  text-decoration: none;
}
a.rn-toc-line:hover { color: var(--text-primary); }
.rn-toc-title { flex: 1 1 auto; min-width: 0; }
.rn-toc-ch[aria-current="page"] > .rn-toc-line { color: var(--text-primary); font-weight: 600; }
.rn-toc-ch[data-state="locked"] .rn-toc-title,
.rn-toc-ch[data-state="planned"] .rn-toc-title { color: var(--text-muted); }
/* C3.4 keeps its override on every locked chapter, as one text link rather
   than a 36px button repeated down the rail, and on the chapter's own line
   rather than a second one: thirteen chapters spending two lines each is what
   pushed the rail past the height of its own sticky box. */
.rn-toc-override {
  flex: 0 0 auto;
  white-space: nowrap;
  margin: 0;
  font-size: var(--text-xs);
  color: var(--text-muted);
  text-decoration-color: var(--border-strong);
}
.rn-toc-override:hover { color: var(--accent-bright); }
.rn-toc-sep { flex: 0 0 auto; white-space: nowrap; color: var(--text-muted); font-size: var(--text-xs); }

.rn-toc-rungs {
  list-style: none;
  position: relative;
  margin: 0 0 0 1.5rem;
  display: flex;
  flex-direction: column;
}
.rn-toc-rung { position: relative; }
.rn-toc-rung-link {
  display: block;
  min-height: 24px;
  padding: 2px 0;
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--text-muted);
  text-decoration: none;
}
.rn-toc-rung-link:hover { color: var(--text-secondary); }
.rn-toc-rung--current > .rn-toc-rung-link { color: var(--accent-bright); }

/* The bookmark. A ribbon hanging into the line where you stopped, notched at
   the foot. It is a state, so it never animates. */
.rn-bookmark {
  position: absolute;
  left: -1.15rem;
  top: -6px;
  width: 10px;
  height: 30px;
  background: var(--accent);
  clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 72%, 0 100%);
}
/* On a touch screen the contents list is the only way through the book, so its
   rows are real targets rather than lines of text that happen to be links.
   Pointer-coarse, not a width: a 44px row on a desktop rail would be a rail
   twice as tall for no reason. */
@media (pointer: coarse) {
  .rn-toc-line, .rn-toc-rung-link { min-height: 44px; padding: var(--space-3) 0; }
  .rn-toc-override { padding: var(--space-2) 0; }
  .rn-shelf-title, .rn-contents-title { display: block; min-height: var(--control-height); padding: var(--space-2) 0; }
  .rn-bookmark { top: 4px; }
}


/* ── Today: where the book lies open ─────────────────────────── */

.rn-open-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-8);
}
.rn-open-book {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-3);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text-primary);
  text-decoration: none;
}
.rn-open-book:hover { color: var(--accent-bright); }
.rn-book-glyph { font-size: var(--text-2xl); line-height: 1; color: var(--accent-bright); }

.rn-open { display: grid; gap: var(--space-8); }
.rn-open-page { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-4); min-width: 0; }
.rn-open-kicker,
.rn-open-label {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.rn-open-title { font-size: var(--text-2xl); font-weight: 600; line-height: 1.25; color: var(--text-primary); }
.rn-open-rung { font-size: var(--text-base); color: var(--text-secondary); }
/* The words the bookmark is sitting on, four lines of them. Clamped rather than
   truncated with a rule: this is a reminder of the page, and the page itself is
   one press away. */
.rn-open-quote {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-width: var(--rn-measure);
  font-size: var(--text-base);
  line-height: 1.65;
  color: var(--text-secondary);
}
.rn-open-today { font-size: var(--text-xl); font-weight: 600; color: var(--text-primary); }
.rn-open-list { list-style: none; display: flex; flex-direction: column; gap: var(--space-6); width: 100%; }
.rn-open-item { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); }
.rn-open-item-title { font-size: var(--text-lg); font-weight: 600; color: var(--text-primary); }
.rn-open-sub {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--text-muted);
}
.rn-open-sub a { color: var(--text-primary); }
/* The chapter's own pages, indented far enough that the bookmark ribbon has a
   margin to hang in, exactly as it does in the rail. */
.rn-open-sub--rungs { margin-left: 1.5rem; gap: 0; }
.rn-open-rung-row { position: relative; }
/* A button dressed as the rail's rung link, so the same thing reads the same
   way in the contents and on Today. */
.rn-open-rung-link {
  display: block;
  min-height: 28px;
  padding: 2px 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-sm);
  line-height: 1.5;
  text-align: left;
  color: var(--text-muted);
  cursor: pointer;
}
.rn-open-rung-link:hover { color: var(--text-primary); }
.rn-open-rung-row--at > .rn-open-rung-link { color: var(--accent-bright); }
@media (pointer: coarse) { .rn-open-rung-link { min-height: 44px; padding: var(--space-2) 0; } }

/* Today's two pages are both text, so they lie open sooner than the chapter
   spread, which has to fit a drill beside the prose. */
@media (min-width: 800px) {
  .rn-open { grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr); align-items: start; }
  .rn-open > .rn-spine { align-self: stretch; background: var(--border-subtle); }
}
@media (max-width: 799px) {
  .rn-open > .rn-spine { height: 1px; background: var(--border-subtle); }
}

/* ── The shelf, and a Book's contents page ───────────────────── */

.rn-shelf { list-style: none; display: flex; flex-direction: column; }
.rn-shelf-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-6);
  padding: var(--space-6) 0;
  border-bottom: 1px solid var(--border-subtle);
}
.rn-shelf-row:first-child { border-top: 1px solid var(--border-subtle); }
.rn-shelf-glyph { flex: 0 0 2.25rem; font-size: var(--text-2xl); line-height: 1; color: var(--accent-bright); }
.rn-shelf-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.rn-shelf-title { font-size: var(--text-xl); font-weight: 600; color: var(--text-primary); text-decoration: none; }
a.rn-shelf-title:hover { color: var(--accent-bright); }
.rn-shelf-tag { font-size: var(--text-sm); line-height: 1.6; color: var(--text-muted); }
.rn-shelf-state { flex: 0 0 auto; font-size: var(--text-sm); color: var(--text-muted); }
.rn-shelf-row--planned .rn-shelf-glyph,
.rn-shelf-row--planned .rn-shelf-title { color: var(--text-muted); }

.rn-book-head { display: flex; align-items: baseline; gap: var(--space-6); margin-bottom: var(--space-8); }
.rn-book-head .rn-book-glyph { font-size: 3rem; }
.rn-book-titles { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }

.rn-tracks { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3); margin-bottom: var(--space-8); }
.rn-seg { display: inline-flex; flex-wrap: wrap; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.rn-seg-btn {
  min-height: 36px;
  padding: 0 var(--space-4);
  border: 0;
  border-right: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
}
.rn-seg-btn:last-child { border-right: 0; }
.rn-seg-btn:hover { background: var(--surface-2); color: var(--text-primary); }
.rn-seg-btn[aria-pressed="true"] { background: color-mix(in srgb, var(--accent) 22%, transparent); color: var(--text-primary); }

.rn-contents { list-style: none; display: flex; flex-direction: column; }
.rn-contents-row {
  display: flex;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--border-subtle);
}
.rn-contents-row:first-child { border-top: 1px solid var(--border-subtle); }
.rn-contents-row > .rn-glyph-state { flex: 0 0 1.25rem; padding-top: 3px; }
.rn-contents-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); }
.rn-contents-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-3); }
.rn-contents-title { font-size: var(--text-lg); font-weight: 600; color: var(--text-primary); text-decoration: none; }
a.rn-contents-title:hover { color: var(--accent-bright); }
.rn-contents-row[data-state="locked"] .rn-contents-title,
.rn-contents-row[data-state="planned"] .rn-contents-title { color: var(--text-muted); font-weight: 500; }
.rn-contents-note { font-size: var(--text-xs); color: var(--text-muted); }
/* The ladder's "I already know this" takes the rail's muted link, not the
   accent one: an escape hatch should be findable, never the brightest thing
   on a page of thirteen chapters. */
.rn-contents-text > .rn-toc-override { font-size: var(--text-sm); }
.rn-contents-statement { font-size: var(--text-sm); line-height: 1.6; color: var(--text-secondary); max-width: 62ch; }

/* ── Settings ────────────────────────────────────────────────── */

.rn-setting {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-6) 0;
  border-bottom: 1px solid var(--border-subtle);
}
.rn-setting:first-of-type { border-top: 1px solid var(--border-subtle); }
.rn-setting-title { font-size: var(--text-lg); font-weight: 600; color: var(--text-primary); }
.rn-setting .rn-tracks { margin-bottom: 0; }

/* ── The Rappel embed ────────────────────────────────────────── */
/* The escape link sits beside every deck, always: a link to the unpartitioned
   top-level origin is the one path that always works (C6.5). */

.rn-deck-wrap { display: flex; flex-direction: column; gap: var(--space-2); width: 100%; }
.rn-deck {
  width: 100%;
  height: 420px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-1);
}
.rn-deck-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.rn-deck-status { font-size: var(--text-sm); color: var(--text-muted); }
.rn-deck-out { font-size: var(--text-sm); color: var(--accent-bright); }
.rn-deck-warn { font-size: var(--text-sm); color: var(--danger-hover); }

/* C11.3: the licence acknowledgement, at the foot of the main content region,
   in this site's own copy. Not in the footer kit, which is shared by 60 sites
   and budgeted at one line, and not behind a modal, because a link to a modal
   is not the acknowledgement. */
.neo-attrib {
  margin-top: 56px;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
  max-width: var(--rn-measure);
  font-size: var(--text-xs);
  line-height: 1.6;
  color: var(--text-muted);
}
/* A licence URL is one unbreakable token and some of them are long: the bunka.go.jp
   one is 78 characters. Without this it runs off the right edge of the page, and
   an acknowledgement that is partly off screen is not on screen. */
.neo-attrib a {
  color: var(--text-muted);
  margin-left: var(--space-2);
  overflow-wrap: anywhere;
}

/* Every remaining control a thumb has to find. The small button is the site's
   own size on a mouse and the full 44px on a touch screen; a control that reads
   as text still needs a box to be hit, so it takes one here and only here. */
@media (pointer: coarse) {
  .btn--sm, .rn-seg-btn { min-height: var(--control-height); }
  .rn-rail-bar { min-height: var(--control-height); }
  .rn-toc-override,
  .rn-open-book,
  .rn-open-head .rn-textlink,
  .toolbar .rn-textlink {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-height);
  }
}

/* ── Motion ──────────────────────────────────────────────────── */
/* Ease out, no bounce, and no layout property is ever animated. Turning a page
   is worth 180ms; repainting the same page after an answer is not, which is
   what render() arms .rn-enter for. */

@keyframes rn-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes rn-rise-far { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes rn-slide-in { from { opacity: 0; transform: translateX(12px); } to { opacity: 1; transform: none; } }

/* The reading column is named rather than inherited: from 1180px .rn-spread is
   display:contents, so its children are not children of the view for a `>`
   selector. The rail does not turn with the page and the facing page has its
   own entry, so neither is caught by this. */
.rn-view.rn-enter > *:not(.rn-rail):not(.rn-spread),
.rn-view.rn-enter .rn-prose {
  animation: rn-rise 180ms var(--ease-out) both;
}

@media (prefers-reduced-motion: reduce) {
  .rn-view.rn-enter > *,
  .rn-view.rn-enter .rn-prose,
  .rn-facing,
  .rn-ex-host:not(:empty) { animation: none; }
}
html[data-reduce-motion] .rn-view.rn-enter > *,
html[data-reduce-motion] .rn-view.rn-enter .rn-prose,
html[data-reduce-motion] .rn-facing,
html[data-reduce-motion] .rn-ex-host:not(:empty) { animation: none; }
html[data-reduce-motion] *, html[data-reduce-motion] *::before, html[data-reduce-motion] *::after {
  animation-duration: 0.01ms !important;
  transition-duration: 0.01ms !important;
}

/* The EN / ES toggle's two halves. The kit owns the button; these spans are the
   site's, and the one that is not current should say so quietly. */
.rn-lang { color: var(--text-muted); font-weight: 500; }
.rn-lang--on { color: inherit; font-weight: 700; }

/* The one auth class the template does not style: the sheet's one-line note. */
.auth-note { margin: 0; color: var(--text-muted); font-size: 0.9rem; }
/* The template caps the open sheet at 300px with overflow hidden, which clips Clerk's form. */
.auth-panel.open { max-height: min(80vh, 640px); overflow: auto; }
