/* ============================================================
   paper.css — paper-site component library

   Pairs with paper.js. Each section below is a self-contained
   component; markup uses simple class names and data-* attributes
   (paper.js auto-discovers everything on DOMContentLoaded).

   THEMING — All themeable colours use CSS custom properties
   defined in themes.css.  The three built-in themes are:
     light (default) · dark · paper
   Switch via `data-theme` on <html> or PaperThemes.set('…').
   ============================================================ */

/* Component-local knobs (not themable — layout / sizing only) */

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-body);
  color: var(--fg);
  background: var(--bg);
  line-height: 1.65;
  font-size: 17px;
}
h1, h2, h3 { font-family: var(--font-heading); line-height: 1.2; letter-spacing: -0.01em; }
h1 { font-size: 48px; margin: 0 0 16px; }
h2 { font-size: 32px; margin: 0 0 24px; }
h3 { font-size: 22px; margin: 0 0 12px; }
p  { margin: 0 0 18px; }

::selection {
  background: var(--selection-bg, var(--accent-2));
  color: var(--selection-fg, #ffffff);
}

.container { max-width: 980px; margin: 0 auto; padding: 0 24px; }
.narrow    { max-width: 720px; }
.muted     { color: var(--muted); }

section      { padding: 96px 0; }
section.alt  { background: var(--bg-soft); }

/* ---------------- Reveal-on-scroll ---------------- */
.reveal { opacity: 0; transform: translateY(24px); }

/* ---------------- Hero ---------------- */
.hero {
  position: relative;
  min-height: 90vh;
  min-height: 90svh;            /* iOS Safari: avoid jump when address bar collapses */
  display: flex; align-items: center;
  text-align: center;
  overflow: hidden;             /* clip floating background shapes */
}
.hero > .container { position: relative; z-index: 2; }
.hero > .side-card { z-index: 2; }   /* keeps the original position: absolute */

/* ---------------- Floating background geometry ----------------
   Decorative shapes scattered around the hero edges. Each
   .shape-N is a *positioning slot* (top/left/size/colour/animation);
   the visual shape is whatever <svg>/<img> you put inside.

   Built-in shapes use the `.outline` modifier so their inner
   primitives inherit fill:none + stroke: currentColor. Custom
   SVGs you drop in (without .outline) keep their own colours.

   Wrapper is aria-hidden + pointer-events:none — purely visual,
   never interferes. Animations are disabled for users who prefer
   reduced motion.
   --------------------------------------------------------------- */
.hero-bg {
  position: absolute; inset: 0;
  pointer-events: none; user-select: none;
  z-index: 0;
}
.hero-bg .shape {
  position: absolute;
  width:   var(--shape-w, 60px);
  height:  var(--shape-h, 60px);
  opacity: var(--shape-opacity, 0.18);
  will-change: transform;
  /* For <img> custom SVGs: preserve aspect ratio inside the slot box. */
  object-fit: contain;
}

/* Built-in "outline" styling — opt in via class="shape outline …".
   Custom SVGs you author yourself omit `.outline` and keep their
   own fill / stroke / colour. */
.hero-bg .shape.outline circle,
.hero-bg .shape.outline polygon,
.hero-bg .shape.outline rect,
.hero-bg .shape.outline line,
.hero-bg .shape.outline path {
  fill: none; stroke: currentColor; stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}
.hero-bg .shape.outline circle.dot { fill: currentColor; stroke: none; }
.hero-bg .shape.dotgrid circle     { fill: currentColor; stroke: none; }

/* Positioning slots. Pick one per shape — independent of what's
   inside, so swapping the SVG content keeps the same position. */
.hero-bg .shape-1  { top:    9%; left:   6%; --shape-w:  90px; --shape-h:  90px; color: var(--accent-2); animation: float-a 18s ease-in-out infinite; }
.hero-bg .shape-2  { top:    7%; right: 10%; --shape-w:  72px; --shape-h:  72px; color: var(--accent-1); animation: float-b 22s ease-in-out infinite; }
.hero-bg .shape-3  { top:   42%; left:   3%; --shape-w:  56px; --shape-h:  56px; color: var(--accent-3); animation: float-c 26s ease-in-out infinite; }
.hero-bg .shape-4  { top:   38%; right:  4%; --shape-w:  64px; --shape-h:  64px; color: var(--accent-2); --shape-opacity: 0.14; animation: float-d 20s ease-in-out infinite; }
.hero-bg .shape-5  { bottom: 14%; left:  14%; --shape-w:  60px; --shape-h:  60px; color: var(--accent-4); animation: float-e 24s ease-in-out infinite; }
.hero-bg .shape-6  { bottom: 10%; right: 12%; --shape-w: 100px; --shape-h: 100px; color: var(--accent-2); --shape-opacity: 0.20; animation: float-f 28s ease-in-out infinite; }
.hero-bg .shape-7  { top:   22%; right: 28%; --shape-w:  36px; --shape-h:  36px; color: var(--accent-3); --shape-opacity: 0.16; animation: float-g 19s ease-in-out infinite; }
.hero-bg .shape-8  { bottom: 32%; left:  22%; --shape-w:  50px; --shape-h:  50px; color: var(--accent-1); --shape-opacity: 0.14; animation: float-h 23s ease-in-out infinite; }
.hero-bg .shape-9  { bottom: 26%; right: 26%; --shape-w:  46px; --shape-h:  46px; color: var(--accent-4); --shape-opacity: 0.16; animation: float-i 21s ease-in-out infinite; }
.hero-bg .shape-10 { top:    5%; right: 30%; --shape-w: 140px; --shape-h:  38px; color: var(--accent-2); --shape-opacity: 0.45; animation: float-j 25s ease-in-out infinite; }

@keyframes float-a { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate( 20px,-20px) rotate( 15deg); } }
@keyframes float-b { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate(-18px, 22px) rotate(-12deg); } }
@keyframes float-c { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate( 22px, 14px) rotate( 20deg); } }
@keyframes float-d { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate(-20px,-16px) rotate(-15deg); } }
@keyframes float-e { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate( 16px,-24px) rotate( 10deg); } }
@keyframes float-f { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate(-22px,-12px) rotate(-18deg); } }
@keyframes float-g { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate( 14px, 18px) rotate( 25deg); } }
@keyframes float-h { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate(-16px, 20px) rotate(-22deg); } }
@keyframes float-i { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate( 18px,-14px) rotate( 18deg); } }
@keyframes float-j { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate(-12px, 16px) rotate(-25deg); } }

@media (prefers-reduced-motion: reduce) {
  .hero-bg .shape { animation: none; }
}
@media (max-width: 720px) {
  .hero-bg .shape   { --shape-opacity: 0.11; }
  .hero-bg .shape-3,
  .hero-bg .shape-4,
  .hero-bg .shape-7,
  .hero-bg .shape-10 { display: none; }   /* trim a few on mobile to reduce clutter */
  .hero-annot { white-space: normal; }
}
.hero-annot { position: relative; white-space: nowrap; }
.hero h1 { position: relative; }  /* positioning context for rough-notation SVGs */
.hero .authors { color: var(--muted); margin-bottom: 8px; }

/* ---------------- Action buttons (arXiv / GitHub / LinkedIn / …) ----
   Branded outline buttons. Each variant sets --btn-color, which is
   used for the border, icon, and label, and as the fill on hover.
   Add new variants the same way:
     .btn-link.openreview { --btn-color: #8c1b13; }
   --------------------------------------------------------------- */
.actions {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 10px;
  margin-top: 20px;
}
.btn-link {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 16px;
  border: 2px solid var(--btn-color, var(--rule));
  border-radius: 8px;
  font-size: 14px; font-weight: 600; line-height: 1;
  color: var(--btn-color, var(--fg));
  background: var(--bg);
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}
.btn-link:hover { background: var(--btn-color); color: #fff; }
.btn-link svg   { width: 16px; height: 16px; flex: 0 0 auto; fill: currentColor; }
.btn-link i     { font-size: 18px; line-height: 1; }   /* academicons / fontawesome */

.btn-link.arxiv    { --btn-color: #B31B1B; }  /* arXiv Cornell red  */
.btn-link.github   { --btn-color: #181717; }  /* GitHub near-black  */
.btn-link.linkedin { --btn-color: #0A66C2; }  /* LinkedIn blue      */

/* ---------------- Scroll cue (bouncy "↓ scroll" hint) ----------
   Markup: <p class="scroll-cue">scroll</p>
   The label stays still; the arrow (rendered via ::after) bounces.
   The whole element fades in after the hero annotations finish.
   --------------------------------------------------------------- */
.scroll-cue {
  display: inline-flex; flex-direction: column; align-items: center;
  gap: 6px;
  margin-top: 64px;
  color: var(--muted);
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase;
  pointer-events: none;
  opacity: 0;
  animation: scroll-cue-in 0.8s ease 3.4s forwards;
}
.scroll-cue::after {
  content: '↓';
  display: block;
  font-size: 22px; line-height: 1; font-weight: 400;
  animation: scroll-cue-bounce 1.4s ease-in-out infinite;
}
@keyframes scroll-cue-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes scroll-cue-bounce {
  0%, 100% { transform: translateY(0);    opacity: 0.5; }
  50%      { transform: translateY(8px);  opacity: 1; }
}

/* Hero side cards. Per-card knobs via inline `style="--card-*: ..."`. */
.side-card {
  --card-width:           240px;
  --card-padding:         14px 16px;
  --card-font-size:       13.5px;
  --card-line-height:     1.55;
  --card-radius:          10px;
  --card-border-accent:   4px;
  --kicker-font-size:     11px;
  --body-font-size:       inherit;

  position: absolute;
  width: var(--card-width);
  background: var(--bg);
  border: 1px solid var(--rule);
  border-left-width: var(--card-border-accent);
  border-radius: var(--card-radius);
  padding: var(--card-padding);
  font-size: var(--card-font-size);
  line-height: var(--card-line-height);
  text-align: left;
  box-shadow: var(--card-shadow);
  opacity: 0;
}
.side-card .kicker {
  font-size: var(--kicker-font-size); font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  margin-bottom: 6px;
}
.side-card .body  { color: var(--card-body-fg); margin: 0; font-size: var(--body-font-size); }
.side-card .body p { margin: 0 0 8px; }
.side-card .body p:last-child { margin: 0; }
.side-card .swatch {
  display: inline-block; width: 10px; height: 10px; border-radius: 2px;
  margin-right: 6px; vertical-align: middle;
}
.side-card .mini-fig {
  margin-top: 10px; height: 60px; border-radius: 6px;
  background: linear-gradient(135deg, var(--card-color, #ef4444), var(--card-color-2, #f59e0b));
}
@media (max-width: 1100px) {
  .side-card {
    position: static;
    width: auto; max-width: 420px;
    margin: 12px auto 0;
    display: block;
  }
}
/* Mobile (≤720px): cards stack inline as colored callouts visually linked
   to their annotated phrase via the kicker color and a "↳ <phrase>" prefix.
   The data-annot-ref attribute is set by initHero(); cards without it
   (standalone cards in non-hero sections) just get the wider colored border. */
@media (max-width: 720px) {
  .side-card {
    position: static !important;
    width: auto !important;
    max-width: none;
    margin: 18px 0 0 !important;
    transform: none !important;
    opacity: 1 !important;
    border-left-width: 6px;
    border-left-color: var(--card-color, var(--rule));
  }
  .side-card[data-annot-ref]::before {
    content: "↳ " attr(data-annot-ref);
    display: block;
    font-size: 12px;
    color: var(--card-color, var(--muted));
    font-weight: 600;
    margin-bottom: 8px;
    letter-spacing: 0.02em;
    text-transform: none;
    line-height: 1.4;
  }
}

/* ---------------- Annotations ---------------- */
.annot { cursor: help; transition: background-color .25s ease; border-radius: 3px; padding: 0 2px; }
.annot.is-active {
  background-color: var(--annot-bg, var(--annotation-highlight));
}

/* ---------------- Scrollytelling ---------------- */
.scrolly { position: relative; }
.scrolly .stage {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 48px;
  align-items: center;
  min-height: 100vh;
  height: 100vh;
}
.scrolly .text-col {
  max-height: 100vh;
  overflow: hidden;
  padding: 0 8px;
}
.scrolly .text-col p { margin-bottom: 22px; transition: color .15s ease; }
.scrolly .text-col [data-slide] {
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 6px;
  color: color-mix(in srgb, var(--muted) 45%, transparent);
  transition: background-color .12s ease, color .15s ease;
}
.scrolly .text-col [data-slide]:hover { background-color: var(--hover-bg); }
.scrolly .text-col .is-active-para {
  color: var(--fg);
  background-color: var(--hover-bg);
  font-weight: 500;
}
.scrolly .text-col .is-active-para strong { color: var(--accent, #3b82f6); }
.scrolly .text-col [data-slide].is-skip {
  cursor: pointer;
  font-style: italic;
}
/* Prevent italic from inheriting into nested (non-skip) child items */
.scrolly .text-col [data-slide].is-skip [data-slide] { font-style: normal; }

/* Nested-list scrolly text. Authors can use a real <ol>/<ul> tree:
     <ol class="scrolly-list">
       <li data-slide="1">…<ul><li data-slide="1.1">…</li></ul></li>
     </ol>
   The list-style is suppressed because the <strong>1.</strong> markers in
   the source already act as visible numbering, but you can re-enable
   list-style on .scrolly-list to use native bullets/numbers. */
.scrolly .text-col ol,
.scrolly .text-col ul {
  list-style: none;
  padding-left: 0;
  margin: 0;
}
.scrolly .text-col li { margin: 0 0 10px; }
.scrolly .text-col li > ol,
.scrolly .text-col li > ul {
  /* Collapsed by default; the JS adds .is-open to the parent <li> when
     the active step is itself or one of its descendants. */
  max-height: 0;
  overflow: hidden;
  margin-top: 0;
  padding-left: 1.4em;
  border-left: 2px solid var(--rule);
  transition: max-height 0.4s ease, margin-top 0.4s ease, opacity 0.3s ease;
  opacity: 0;
}
.scrolly .text-col li.is-open > ol,
.scrolly .text-col li.is-open > ul {
  max-height: 600px;  /* tall enough for any nested list */
  margin-top: 8px;
  opacity: 1;
}

.scrolly .figure-col {
  height: 100vh;
  display: flex; align-items: center; justify-content: center;
}
.figure-frame {
  position: relative;
  width: 100%; height: 70vh;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--figure-shadow);
}
.figure-frame.flat {
  border: none;
  box-shadow: none;
  background: transparent;
}
.figure-slide {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 32px;
  opacity: 0; transform: scale(0.98);
  transition: opacity .5s ease, transform .5s ease;
}
.figure-slide.is-active { opacity: 1; transform: scale(1); }
.figcaption {
  color: var(--muted);
  font-size: 14px;
  text-align: center;
  margin-top: 1em;
}
.figure-slide .placeholder {
  width: 100%; height: 100%;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  font-size: 60px; font-weight: 700; color: white;
}
.figure-progress {
  position: absolute; left: 16px; right: 16px; bottom: 14px;
  display: flex; gap: 6px;
}
.figure-progress span {
  flex: 1; height: 3px; background: var(--rule); border-radius: 2px;
}
.figure-progress span.is-active { background: var(--fg); }

/* ---------------- Embla carousel ---------------- */
.embla { overflow: hidden; }
.embla__container { display: flex; }
.embla__slide {
  flex: 0 0 100%; min-width: 0;
  padding: 24px;
}
.embla__slide .card {
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 32px;
  min-height: 280px;
  background: var(--bg);
}
.embla-controls { display: flex; gap: 8px; justify-content: center; margin-top: 16px; }
.embla-controls button {
  border: 1px solid var(--rule); background: var(--bg);
  border-radius: 999px; padding: 8px 14px; cursor: pointer;
  font: inherit;
}
.embla-dots { display: flex; gap: 6px; justify-content: center; margin-top: 12px; }
.embla-dots button {
  width: 8px; height: 8px; border-radius: 999px; border: 0;
  background: var(--rule); cursor: pointer; padding: 0;
}
.embla-dots button.is-active { background: var(--fg); }

/* ---------------- Demo (interactive box) ---------------- */
.demo {
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 24px;
  background: var(--bg);
}
.demo .row { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.demo select, .demo button {
  font: inherit; padding: 8px 12px;
  border: 1px solid var(--rule); border-radius: 8px; background: var(--bg);
}
.demo .panel {
  padding: 24px; min-height: 180px;
  background: var(--bg-soft); border-radius: 8px;
  font-family: var(--font-mono); font-size: 14px; white-space: pre-wrap;
}

/* ---------------- Inline SVG diagram ---------------- */
.svg-diagram {
  width: 100%; max-width: 720px; margin: 0 auto;
  display: block;
}
.svg-diagram .node       { fill: var(--bg); stroke: var(--fg); stroke-width: 1.5; }
.svg-diagram .node-label { font-family: var(--font-body); font-size: 13px; fill: var(--fg); }
.svg-diagram .flow {
  fill: none; stroke: var(--accent-2); stroke-width: 2;
  stroke-linecap: round;
}
.svg-diagram .flow.alt { stroke: var(--accent-1); }

/* External Inkscape SVG, fetched inline. */
.svg-holder { width: 100%; max-width: 900px; margin: 0 auto; }
.svg-holder svg { width: 100%; height: auto; display: block; }

/* ---------------- SVG expand-to-fullscreen (mobile) ---------------
   A small button below the SVG that opens it in a landscape-oriented
   fullscreen overlay, so wide diagrams are readable on phones.
   --------------------------------------------------------------- */
.svg-expand-btn {
  display: none;
  margin: 16px auto 0;
  padding: 6px 16px;
  font: inherit; font-size: 13px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--bg);
  color: var(--muted);
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.svg-expand-btn:hover { background: var(--bg-soft); color: var(--fg); }

@media (max-width: 720px) {
  .svg-holder[data-fullscreen] + .svg-expand-btn { display: block; }
}

/* Fullscreen overlay for SVG diagrams. */
.svg-fs-overlay {
  position: fixed; inset: 0; z-index: 10000;
  background: #fff;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none;
  transition: opacity .25s ease;
}
.svg-fs-overlay.is-open { opacity: 1; pointer-events: auto; }
.svg-fs-overlay .svg-fs-content {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  padding: 48px 16px;
}
.svg-fs-overlay .svg-fs-content svg {
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
  display: block;
}
/* Landscape hint: on phones rotate the SVG zone so wide diagrams
   use the long edge of the screen. Only applied when the overlay
   is open and the viewport is portrait-ish. */
.svg-fs-overlay.is-landscape .svg-fs-content {
  transform: rotate(90deg);
  width: 100vh; height: 100vw;
  position: absolute;
  top: 50%; left: 50%;
  transform-origin: center center;
  margin-top: -50vw;
  margin-left: -50vh;
}
.svg-fs-close {
  position: absolute; top: 16px; right: 16px; z-index: 10;
  width: 40px; height: 40px;
  border: none; border-radius: 999px;
  background: rgba(0,0,0,0.08);
  color: #333;
  font-size: 24px; line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background-color .15s ease;
}
.svg-fs-close:hover { background: rgba(0,0,0,0.15); }

/* ---------------- Explorer ---------------- */
.thumb-strip {
  position: relative;
  border: 1px solid var(--rule); border-radius: 12px;
  background: var(--bg);
  padding: 10px 44px;
  margin-bottom: 32px;
}
.thumb-strip .embla__container { gap: 10px; }
.thumb-strip .embla__slide      { flex: 0 0 auto; padding: 0; }
.thumb {
  width: 88px; height: 64px;
  border-radius: 8px; border: 2px solid transparent;
  background: var(--bg-soft);
  cursor: pointer; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  color: white; font-weight: 600; font-size: 13px;
  transition: border-color .2s ease, transform .2s ease;
}
.thumb:hover     { transform: translateY(-2px); }
.thumb.is-active { border-color: var(--fg); }
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 32px; height: 32px; border-radius: 999px;
  border: 1px solid var(--rule); background: var(--bg);
  cursor: pointer; font: inherit;
  display: flex; align-items: center; justify-content: center;
}
.thumb-nav.prev { left: 8px; }
.thumb-nav.next { right: 8px; }

.detail {
  border: 1px solid var(--rule); border-radius: 12px;
  background: var(--bg-soft);
  padding: 24px;
  min-height: 360px;
}
.detail .detail-title { font-weight: 600; margin-bottom: 14px; }
.detail .detail-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px;
}
.detail .detail-header .detail-title { margin-bottom: 8px; flex: 1 1 auto; }

/* Animation toggle button (desktop). Hidden on mobile (animation forced on). */
.detail-toolbar { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.anim-toggle {
  font: inherit; font-size: 13px;
  padding: 4px 12px; border-radius: 999px;
  border: 1px solid var(--rule); background: var(--bg); cursor: pointer;
  color: var(--fg);
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.anim-toggle:hover { background: var(--bg-soft); }
.anim-toggle[aria-pressed="true"] {
  background: var(--accent-2); color: #fff; border-color: var(--accent-2);
}

/* Animation-mode layout adjustments. The transposed (`columns`) layout has
   one cell per row; the merged (`rows`) layout has one row of GIF cells. */
.explorer[data-anim-mode="columns"] .detail-cell .media { aspect-ratio: 1 / 1; }
.explorer[data-anim-mode="columns"] .detail-row { align-items: center; }
.explorer[data-anim-mode="columns"] .detail-row .row-label {
  font-weight: 600; color: var(--fg);
  flex: 0 0 80px; min-width: 80px;
  word-break: break-word; overflow-wrap: break-word;
  font-size: 12px;
}
.explorer[data-anim-mode="columns"] .detail-row .cells {
  flex: 1; width: 100%; min-width: 0;
}
.explorer[data-anim-mode="columns"] .detail-cell {
  width: 100%; max-width: 100%;
}

/* In "rows" animation mode (desktop toggle), embed labels as captions, one row. */
.explorer[data-anim-mode="rows"] .detail-cell .media {
  aspect-ratio: 1 / 1;
}
.explorer[data-anim-mode="rows"] .detail-cell .caption {
  font-weight: 600;
  font-size: 12px;
  text-align: center;
  padding: 6px 4px;
  color: var(--fg);
}

/* On desktop, keep animation rows compact so images stay in proportion */
@media (min-width: 721px) {
  .explorer[data-anim-mode="columns"] .detail-row .cells {
    max-width: 50%;
  }
  .explorer[data-anim-mode="columns"] .detail-row .row-label {
    flex: 0 0 140px;
  }
}
/* Explorer grid-gap. Controlled by --explorer-cell-gap / --explorer-row-gap.
   Set via the `data-grid-gap` attribute on .explorer (e.g. data-grid-gap="6").
   Defaults: 4px cell gap, 8px row gap. */
.explorer {
  --explorer-cell-gap: 4px;
  --explorer-row-gap: 8px;
  --explorer-radius: 0px;
}
.detail-grid { display: flex; flex-direction: column; gap: var(--explorer-row-gap, 8px); }
.detail-row  { display: flex; align-items: stretch; gap: var(--explorer-cell-gap, 4px); }
.detail-row .row-body { flex: 1; display: flex; flex-direction: column; gap: calc(var(--explorer-cell-gap, 4px) - 1px); }
.detail-row .row-label {
  flex: 0 0 80px;
  display: flex; align-items: center; justify-content: flex-end;
  padding: 0 8px 0 4px; color: var(--muted); font-size: 13px;
  text-align: right;
}
.detail-row .cells { display: flex; gap: var(--explorer-cell-gap, 4px); flex: 1; }
.detail-cell {
  flex: 1 1 0; min-width: 0; max-width: 100%;
  border-radius: var(--explorer-radius, 0px);
  overflow: hidden;
  background: var(--bg);
  border: 1px solid var(--rule);
  display: flex; flex-direction: column;
  opacity: 0; transform: translateY(8px) scale(0.98);
}
.detail-cell.is-shown {
  opacity: 1; transform: none;
  transition: opacity .45s ease, transform .45s ease;
}
.detail-cell .media {
  flex: 1; aspect-ratio: 4/3;
  display: flex; align-items: center; justify-content: center;
  color: white; font-weight: 700; font-size: 18px;
  background: var(--bg-soft);
  position: relative;
}
.detail-cell .media img,
.detail-cell .media video {
  width: 100%; height: 100%; object-fit: cover; display: block;
}

/* Loading spinner shown on .media.is-loading for image/video cells.
   Hidden automatically when the media fires its load / loadedmetadata event. */
.detail-cell .media.is-loading::after {
  content: '';
  position: absolute; inset: 0;
  margin: auto;
  width: 28px; height: 28px;
  border: 3px solid var(--rule);
  border-top-color: var(--fg);
  border-radius: 50%;
  animation: media-spin .6s linear infinite;
}
@keyframes media-spin { to { transform: rotate(360deg); } }

/* Sequence cell: layered, pre-loaded frames cycle via opacity (not src swap)
   so the cell stays its own — no white-flash, no decode jitter, the rest of
   the explorer never re-renders just because one cell ticked forward. */
.detail-cell .media.media-sequence { position: relative; }
.detail-cell .media.media-sequence .media-frame {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  display: block;
  opacity: 1;
  transition: opacity 180ms ease;
  will-change: opacity;
  backface-visibility: hidden;
  background: var(--bg-soft);
}
.detail-cell .media.media-sequence .media-frame.is-hidden { opacity: 0; }
.detail-cell .caption {
  font-size: 12px; color: var(--muted);
  padding: 6px 10px; border-top: 1px solid var(--rule);
  background: var(--bg);
}
.col-labels {
  display: flex; gap: 8px; padding-left: 88px; margin-bottom: 6px;
  color: var(--muted); font-size: 12px;
}
.col-labels span { flex: 1 1 0; min-width: 0; text-align: center; overflow-wrap: break-word; word-break: break-word; hyphens: auto; }
.row-col-labels {
  display: flex; gap: 8px;
  color: var(--muted); font-size: 12px;
}
.row-col-labels span { flex: 1 1 0; min-width: 0; text-align: center; overflow-wrap: break-word; word-break: break-word; hyphens: auto; }

/* ---------------- Author list + affiliations ---------------- */
.author-list {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 6px 18px; margin: 0 auto 6px;
  font-size: 16px;
}
.author-list .author { white-space: nowrap; }
.author-list .author a { color: inherit; text-decoration: none; }
.author-list .author a:hover { text-decoration: underline; }
.author-list .author sup {
  font-size: 0.72em; color: var(--muted); margin-left: 2px;
  font-weight: 500;
}
.author-list .author.equal::after {
  content: '*'; color: var(--accent-2); margin-left: 2px;
}
.affiliations {
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: center;
  gap: 6px 22px; margin: 6px auto 6px;
  font-size: 14.5px; color: var(--affiliations-fg);
}
.affiliations span {
  display: inline-flex; align-items: center; gap: 6px;
}
.affiliations span sup {
  font-size: 0.85em; font-weight: 600;
  color: var(--muted); margin: 0;
}
.affil-logo {
  height: 24px; width: auto; max-width: 80px;
  object-fit: contain; vertical-align: middle;
}
.eq-note {
  font-size: 12px; color: var(--muted); text-align: center; margin: 4px 0 0;
}

/* ---------------- Callout / pull-quote ---------------- */
.callout {
  border-left: 4px solid var(--accent-2);
  background: var(--bg-soft);
  padding: 14px 18px;
  border-radius: 6px;
  margin: 24px 0;
  font-size: 15.5px;
  line-height: 1.6;
}
.callout .callout-label {
  display: inline-block;
  font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; font-size: 11px;
  margin-right: 8px; color: var(--accent-2);
  vertical-align: 1px;
}
.callout p:last-child { margin: 0; }
.callout[data-kind="tldr"]    { border-left-color: var(--accent-2); }
.callout[data-kind="tldr"]    .callout-label { color: var(--accent-2); }
.callout[data-kind="note"]    { border-left-color: var(--muted); }
.callout[data-kind="note"]    .callout-label { color: var(--muted); }
.callout[data-kind="warning"] { border-left-color: var(--accent-4); background: rgba(245,158,11,0.08); }
.callout[data-kind="warning"] .callout-label { color: var(--accent-4); }
.callout[data-kind="key"]     { border-left-color: var(--accent-1); background: rgba(239,68,68,0.05); }
.callout[data-kind="key"]     .callout-label { color: var(--accent-1); }

/* ---------------- Bridge — thin transitional separator ---------------- */
.bridge {
  padding: 20px 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.bridge-text {
  text-align: center;
  font-size: 15.5px;
  line-height: 1.7;
  color: var(--muted);
  max-width: 560px;
  margin: 0 auto;
}
.bridge-label {
  display: inline-block;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 11px;
  margin-right: 9px;
  color: var(--accent-2);
  vertical-align: 1px;
}
.bridge-text strong { color: var(--fg); font-weight: 600; }
.bridge-text em     { font-style: italic; color: var(--fg); }

/* ---------------- Image + text split ---------------- */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
  align-items: center;
  margin: 32px 0;
}
.split[data-layout="img-right"] .split-media { order: 2; }
.split[data-layout="img-right"] .split-text  { order: 1; }
.split-media img,
.split-media video,
.split-media .svg-holder {
  width: 100%; height: auto; display: block;
  border-radius: 12px;
  border: 1px solid var(--rule);
}
.split-media .svg-holder svg {
  display: block;
  border-radius: 12px;
}
.split-media .placeholder {
  aspect-ratio: 4/3; border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  color: white; font-weight: 700; font-size: 28px;
  background: linear-gradient(135deg, var(--accent-1), var(--accent-4));
}
.split-text h3 { margin-top: 0; }
.split-text p:last-child { margin: 0; }

/* ---------------- Figure grid ---------------- */
.figure-grid {
  display: grid;
  grid-template-columns: repeat(var(--figure-grid-cols, 3), 1fr);
  gap: 16px;
  margin: 16px 0;
}
.figure-grid figure {
  margin: 0;
  border: 1px solid var(--rule);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg);
}
.figure-grid figure img,
.figure-grid figure video {
  width: 100%; height: auto; display: block;
}
.figure-grid figure .placeholder {
  aspect-ratio: 4/3;
  display: flex; align-items: center; justify-content: center;
  color: white; font-weight: 700; font-size: 22px;
}
.figure-grid figcaption {
  font-size: 12px; color: var(--muted);
  padding: 8px 12px; border-top: 1px solid var(--rule);
  background: var(--bg);
}

/* ---------------- Comparison slider ---------------- */
.compare {
  position: relative;
  width: 100%; aspect-ratio: 16/9;
  border-radius: 12px; overflow: hidden;
  border: 1px solid var(--rule);
  user-select: none;
  touch-action: pan-y;
  cursor: ew-resize;
  background: var(--bg-soft);
}
.compare img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  display: block; pointer-events: none;
}
.compare .compare-handle {
  position: absolute; top: 0; bottom: 0; left: 50%;
  width: 2px; background: var(--compare-handle-bg);
  transform: translateX(-50%);
  pointer-events: none;
  box-shadow: var(--compare-handle-shadow);
}
.compare .compare-handle::before {
  content: ''; position: absolute; top: 50%; left: 50%;
  width: 36px; height: 36px;
  transform: translate(-50%, -50%);
  background: var(--compare-knob-bg); border-radius: 999px;
  box-shadow: var(--compare-knob-shadow);
}
.compare .compare-handle::after {
  content: '⇆';
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  font-size: 18px; color: var(--fg);
  pointer-events: none; font-weight: 700;
}
.compare .compare-label {
  position: absolute; top: 12px;
  padding: 4px 10px; border-radius: 999px;
  background: var(--compare-label-bg); color: var(--compare-label-fg);
  font-size: 12px; font-weight: 600;
  pointer-events: none;
}
.compare .compare-label.before { left: 12px; }
.compare .compare-label.after  { right: 12px; }

/* ---------------- Code block (BibTeX, code samples) ---------------- */
.code-block {
  position: relative;
  background: var(--code-dark-bg);
  color: var(--code-dark-fg);
  border-radius: 10px;
  margin: 24px 0;
  overflow: hidden;
}
.code-block pre {
  margin: 0;
  padding: 20px 24px;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 13px; line-height: 1.55;
  color: inherit;
  background: transparent;
}
.code-block[data-lang] pre { padding-top: 36px; }
.code-block .code-lang {
  position: absolute; top: 8px; left: 14px;
  font-size: 11px; letter-spacing: 0.08em;
  color: var(--code-dark-muted); text-transform: uppercase;
  font-weight: 600;
  pointer-events: none;
}
.code-block .code-copy {
  position: absolute; top: 8px; right: 8px;
  background: var(--code-dark-btn-bg); color: var(--code-dark-fg);
  border: 1px solid var(--code-dark-btn-border);
  border-radius: 6px;
  padding: 4px 10px;
  font: inherit; font-size: 12px;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease;
}
.code-block .code-copy:hover { background: var(--code-dark-btn-hover); }
.code-block .code-copy.is-ok {
  background: var(--accent-3); border-color: var(--accent-3); color: white;
}

/* Side-card anchor — section needs to be a positioned ancestor */
.has-side-card { position: relative; }

/* ---------------- Results table ---------------- */
.results-table-wrapper {
  width: 100%;
  max-width: var(--table-max-width, none);
  margin: 16px 0;
}
.results-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  margin: 0;
}
.results-table th, .results-table td {
  padding: 10px 14px;
  border-bottom: 1px solid var(--rule);
  text-align: center;
}
.results-table thead th {
  font-weight: 600;
  border-bottom: 2px solid var(--fg);
  background: var(--bg-soft);
}
.results-table tbody tr:hover { background: var(--table-hover-bg); }
.results-table .num     { font-variant-numeric: tabular-nums; }
.results-table .best    { font-weight: 700; color: #16a34a; }
.results-table .second  { text-decoration: underline; text-underline-offset: 3px; }
.results-table .row-divider td { border-top: 2px solid var(--fg); }

/* Caption inside the table wrapper */
.results-table-caption {
  text-align: left;
  font-size: 12px;
  color: var(--muted);
  margin-top: 8px;
  margin-bottom: 0;
}

/* markdown-table source element — hidden, replaced by <table> at init */
.markdown-table[data-table] { display: none; }

/* ---------------- Plain video frame ---------------- */
.paper-video {
  width: 100%;
  border-radius: 12px;
  border: 1px solid var(--rule);
  display: block;
  background: var(--bg-soft);
}

/* ---------------- Video player (local file or YouTube) ----------
   Markup: <div class="video-player" data-src="…"></div>
   - data-src      : path/to/video.mp4  OR  any YouTube URL
   - data-aspect   : "16/9" | "4/3" | "1/1" | "21/9" (default 16/9)
   - data-autoplay : "true" (forces muted on YouTube too)
   - data-loop     : "true"
   - data-muted    : "true" (default false, but auto-set by autoplay)
   - data-controls : "false" to hide controls (default shown)
   - data-poster   : local-video thumbnail
   The init script swaps in <video> or <iframe> automatically.
   --------------------------------------------------------------- */
.video-player {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  overflow: hidden;
  background: var(--bg-soft);
  border: 1px solid var(--rule);
  box-shadow: var(--card-shadow);
}
.video-player video,
.video-player iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0; display: block;
}

/* ---------------- Thin footer bar ---------------- */
.footer-bar {
  border-top: 1px solid var(--rule);
  background: var(--bg);
  padding: 10px 16px;
  text-align: center;
  font-size: 12px;
  color: var(--muted);
  line-height: 1.5;
}
.footer-bar a { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
.footer-bar a:hover { color: var(--fg); }

/* ============================================================
   Mobile (≤720px)
   ============================================================ */
@media (max-width: 720px) {
  body { font-size: 16px; line-height: 1.6; }
  h1 { font-size: 30px; }
  h2 { font-size: 24px; }
  h3 { font-size: 18px; }
  .container { padding: 0 16px; }
  section { padding: 56px 0; }

  .hero {
    min-height: auto;
    padding: 64px 0 32px;
    /* Stack the container + side-cards vertically; on desktop the cards are
       absolutely positioned, but on mobile they need to flow inline below. */
    flex-direction: column;
    align-items: stretch;
  }
  .hero > .container { width: 100%; }
  .hero h1 { overflow-wrap: break-word; hyphens: manual; padding: 0 4px; }
  .hero-annot { white-space: normal; }
  .actions    { gap: 6px; }
  .btn-link   { padding: 7px 12px; font-size: 13px; }
  .btn-link svg { width: 14px; height: 14px; }
  .affiliations { font-size: 13.5px; gap: 4px 16px; }
  .affil-logo   { height: 20px; }

  /* Mobile scrollytelling: sticky-text + inline-figure per step.
     The original `.figure-col` is hidden via JS-set data attribute; each
     [data-slide] gets its content wrapped in `.scrolly-mobile-text` (sticky
     unless the item has nested [data-slide] children) and a clone of the
     resolved figure as `.scrolly-mobile-figure` injected inline. */
  .scrolly .stage {
    display: block;
    height: auto; min-height: 0;
    gap: 0;
  }
  .scrolly .figure-col[data-scrolly-mobile-hidden] { display: none; }
  .scrolly .text-col {
    max-height: none;
    overflow: visible;
    padding: 0;
  }
  .scrolly .text-col p { opacity: 1; }
  .scrolly .text-col [data-slide] {
    padding: 0;
    min-height: 0;
    opacity: 1;
    touch-action: manipulation;
    background: transparent;
    border-radius: 0;
    cursor: default;
    color: var(--fg);                 /* override desktop dimming */
  }
  .scrolly .text-col [data-slide]:hover { background: transparent; }

  .scrolly-mobile-text {
    background: var(--bg);
    padding: 16px 14px;
    line-height: 1.55;
    border: 1px solid var(--rule);
    border-radius: 12px;
    margin: 6px 2px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.07), 0 1px 3px rgba(0,0,0,0.05);
  }
  .scrolly-mobile-text.scrolly-mobile-skip { font-style: italic; color: var(--muted); }
  .scrolly-mobile-text.scrolly-mobile-skip [data-slide] { font-style: normal; }
  .scrolly .text-col [data-slide].is-active-para > .scrolly-mobile-text {
    background: var(--hover-bg);
  }

  .scrolly-mobile-figure {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 0 8px 8px;
    margin-top: 24px;
    width: 90%;
    margin-left: auto;
    margin-right: auto;
    opacity: 1;
    transform: none;
    position: static;
    inset: auto;
  }
  .scrolly-mobile-figure .svg-holder { max-width: 100%; }
  .scrolly-mobile-figure .figcaption { margin-top: 12px; padding: 0 6px; }

  /* Top-level steps get extra breathing room between sections. */
  .scrolly .text-col > ol > li[data-slide] + li[data-slide],
  .scrolly .text-col > ul > li[data-slide] + li[data-slide] { margin-top: 18px; }

  /* Force nested lists open on mobile (desktop collapses by default), with a
     subtle indent + left rule to convey hierarchy. */
  .scrolly .text-col li > ol[data-scrolly-mobile-force-open],
  .scrolly .text-col li > ul[data-scrolly-mobile-force-open] {
    max-height: none;
    opacity: 1;
    margin-top: 10px;
    padding-left: 14px;
    border-left: 2px solid var(--rule);
  }
  .scrolly .text-col li > ol[data-scrolly-mobile-force-open] li,
  .scrolly .text-col li > ul[data-scrolly-mobile-force-open] li { margin: 0; }
  .scrolly .text-col li > ol[data-scrolly-mobile-force-open] li + li,
  .scrolly .text-col li > ul[data-scrolly-mobile-force-open] li + li { margin-top: 10px; }

  .embla { touch-action: pan-x; }
  .embla__slide { padding: 12px; }
  .embla__slide .card { padding: 20px; min-height: 180px; }

  .demo .row { flex-wrap: wrap; gap: 8px; }
  .demo .row label { font-size: 14px; }
  .demo .row select, .demo .row button { flex: 0 0 auto; }

  .thumb-strip { padding: 8px 36px; }
  .thumb       { width: 56px; height: 42px; font-size: 12px; }
  .thumb-nav   { width: 28px; height: 28px; }

  .detail                 { padding: 12px; min-height: 240px; }
  .detail .detail-toolbar { display: none; }
  .detail-row .row-label  { flex: 0 0 48px; font-size: 11px; padding: 0 6px 0 2px; }
  .detail-row .cells      { gap: 4px; justify-content: flex-start; }
  .detail-cell .caption   { font-size: 11px; padding: 4px 6px; }
  .explorer               { --explorer-radius: 8px !important; }
  /* On mobile, un-constrain maxWidth-limited static cells so all images are uniform size */
  .detail-cell .media[data-constrained] {
    aspect-ratio: auto !important;
    flex: 1 1 0 !important;
    align-self: stretch !important;
  }
  .detail-cell .media[data-constrained] img,
  .detail-cell .media[data-constrained] video {
    max-width: 100% !important;
    max-height: none !important;
  }
  .col-labels             { padding-left: 56px; }
  /* Transposed mode: row labels stay compact; method names wrap naturally. */
  .explorer[data-anim-mode="columns"] .detail-row .row-label {
    flex: 0 0 80px; min-width: 80px; font-size: 12px; padding: 0 6px 0 2px; word-break: break-word;
  }
  .explorer[data-anim-mode="columns"] .detail-row .cells {
    flex: 1; min-width: 0; justify-content: flex-start !important;
  }
  .explorer[data-anim-mode="columns"] .detail-cell {
    flex: 0 0 auto; min-width: 0; max-width: 85%;
  }
  .explorer[data-anim-mode="columns"] .detail-cell .media { aspect-ratio: 1 / 1; }

  /* Per-row opt-in: stack cells vertically on mobile (configured via JSON
     `stackOnMobile: true`). The row label is vertically centered across the
     stacked cells so labels like "Input" still read as a single group. */
  .detail-row[data-stack-mobile] {
    align-items: flex-start;
  }
  .detail-row[data-stack-mobile] .cells {
    flex-direction: column;
    gap: 8px;
  }

  .svg-diagram { max-width: 100%; }

  .author-list  { font-size: 14px; gap: 4px 12px; }

  .callout      { padding: 12px 14px; font-size: 14px; }

  .bridge       { padding: 16px 0; }
  .bridge-text  { font-size: 14px; }

  .split { grid-template-columns: 1fr; gap: 20px; margin: 20px 0; }
  .split[data-layout="img-right"] .split-media,
  .split[data-layout="img-right"] .split-text { order: initial; }

  .figure-grid { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .figure-grid figcaption { font-size: 11px; padding: 6px 8px; }

  .compare .compare-handle::before { width: 28px; height: 28px; }
  .compare .compare-handle::after  { font-size: 14px; }
  .compare .compare-label { font-size: 11px; padding: 3px 8px; top: 8px; }
  .compare .compare-label.before { left: 8px; }
  .compare .compare-label.after  { right: 8px; }

  .code-block pre { font-size: 12px; padding: 16px; }
  .code-block[data-lang] pre { padding-top: 32px; }

  .results-table { font-size: 12.5px; }
  .results-table th, .results-table td { padding: 6px 8px; }
  /* Wide tables: scroll horizontally instead of overflowing the container. */
  .results-table {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    white-space: nowrap;
  }
  .results-table caption { white-space: normal; }
}

/* ============================================================
   Very narrow phones (≤480px)
   ============================================================ */
@media (max-width: 480px) {
  h1 { font-size: 26px; }
  h2 { font-size: 22px; }
  .container { padding: 0 14px; }

  /* Trim more decorative shapes for visual breathing room. */
  .hero-bg .shape-5,
  .hero-bg .shape-6,
  .hero-bg .shape-8,
  .hero-bg .shape-9 { display: none; }

  .actions { gap: 4px; }
  .btn-link { padding: 6px 10px; font-size: 12.5px; }

  .markdown-block.tight { font-size: 15px; }
}
