/* ==========================================================================
   NCE — project page layout
   Pairs with static/tokens.css, which owns every colour, type step, space and
   easing. This file only does layout and the few components the paper page
   needs beyond the token layer. No dependency on any remote resource.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Lockup — the LongCat mark, in the two cuts the site needs

   The wordmark is drawn in near-black inside the SVG, so a single asset goes
   invisible once the page turns dark. Both cuts ship instead and the mask
   picks one, keyed off the same attribute the theme toggle writes and off the
   OS preference when nothing has been chosen.
   -------------------------------------------------------------------------- */
.logo {
  display: inline-block;
  background-color: var(--ink);
  flex: none;
  -webkit-mask: url("../assets/longcat-logo-white.svg") no-repeat center / contain;
  mask: url("../assets/longcat-logo-white.svg") no-repeat center / contain;
}
:root[data-theme="dark"] .logo,
:root:not([data-theme="light"]) .logo {
  background-color: #FFFFFF;
  -webkit-mask-image: url("../assets/longcat-logo.svg");
  mask-image: url("../assets/longcat-logo.svg");
}
:root:not([data-theme="light"]):not([data-theme="dark"]) .logo {
  background-color: var(--ink);
  -webkit-mask-image: url("../assets/longcat-logo-white.svg");
  mask-image: url("../assets/longcat-logo-white.svg");
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .logo {
    background-color: #FFFFFF;
    -webkit-mask-image: url("../assets/longcat-logo.svg");
    mask-image: url("../assets/longcat-logo.svg");
  }
}

.logo--header { width: 5.4rem; height: 1.43rem; }
.logo--hero  { width: 9.5rem; height: 2.51rem; margin: 0 auto var(--space-6); }
.logo--footer { width: 4.3rem; height: 1.14rem; }
.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--space-3);
  z-index: 100;
  padding: var(--space-2) var(--space-4);
  background: var(--paper-raised);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
}
.skip-link:focus { left: var(--space-4); }

/* Visually hidden but present for assistive tech. The results tables use it
   for the duplicated column label and the captions that repeat the <h3>. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(150%) blur(12px);
  border-bottom: 1px solid var(--hairline);
}
.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  min-height: 4rem;
}
.site-header__mark {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
}
.site-nav {
  display: flex;
  gap: var(--space-5);
  margin-left: auto;
  align-items: center;
  min-width: 0;
}
.site-nav a {
  font-size: var(--fs-small);
  color: var(--ink-secondary);
  text-decoration: none;
  padding-block: var(--space-2);
}
.site-nav a:hover { color: var(--brand); }
@media (max-width: 48rem) {
  .site-nav { gap: var(--space-4); }
  .site-header__mark span { display: none; }   /* the wordmark is already in the lockup */
}
@media (max-width: 40rem) {
  .site-nav { gap: var(--space-3); }
  .site-nav a.is-optional { display: none; }
  /* At phone widths the lockup is dropped and the method name carries the
     header, so all of Idea / Method / Results still fit. */
  .site-header__mark .logo { display: none; }
  .site-header__mark span { display: inline; }
}

.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-pill);
  background: var(--paper-raised);
  color: var(--ink-secondary);
  cursor: pointer;
}
.theme-toggle:hover { color: var(--brand); border-color: var(--brand); }
.theme-toggle svg { width: 1.05rem; height: 1.05rem; stroke: currentColor; fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.hero {
  padding-block: clamp(var(--space-7), 6.5vw, var(--space-9)) var(--space-6);
  text-align: center;
}

.hero__title {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--fw-regular);
  /* The three display lines are set in CONFIG. The cap only has to stop the
     longest of them from running edge to edge; it must stay above the width of
     "Teaching LLM Agents a Grammar" at the top of the fluid scale (~840px at
     84px type), or that line re-wraps into a fourth. */
  max-width: min(100%, 60rem);
  margin: 0 auto var(--space-5);
  text-wrap: balance;
}
.hero__title em { font-style: italic; }

/* On phones three hand-set lines are too tall and too narrow; let the browser
   reflow the whole title instead of keeping the display breaks. */
@media (max-width: 40rem) {
  .hero__title { max-width: none; }
  .hero__title br { display: none; }
}

.hero__authors {
  max-width: 46rem;
  margin: 0 auto var(--space-3);
  font-size: var(--fs-body);
  line-height: 1.9;
}
.hero__author {
  color: var(--ink);
  text-decoration-color: var(--hairline-strong);
  text-underline-offset: 0.2em;
  white-space: nowrap;
}
.hero__author:hover { color: var(--brand); text-decoration-color: var(--brand); }
.hero__author sup {
  font-size: 0.62em;
  font-weight: var(--fw-semibold);
  color: var(--brand);
  margin-left: 0.1em;
}
.hero__affil {
  font-size: var(--fs-small);
  color: var(--ink-secondary);
  margin: 0 0 var(--space-2);
}
/* Numbered institution line: the superscripts carry the paper's own numbering,
   so they take the same treatment as the marks in the author list. */
.hero__affil--list {
  max-width: 54rem;
  margin-left: auto;
  margin-right: auto;
  line-height: 1.7;
}
.hero__affil--list .affil-item { white-space: nowrap; }
.hero__affil--list sup,
.hero__author sup.affil-mark {
  font-size: 0.62em;
  font-weight: var(--fw-semibold);
  color: var(--brand);
  margin-right: 0.12em;
}
.hero__notes {
  font-size: var(--fs-caption);
  color: var(--ink-secondary);
  margin: 0 auto var(--space-6);
}
.hero__notes .marker { color: var(--brand); font-weight: var(--fw-semibold); }

.hero__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.6rem 1.1rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline-strong);
  background: var(--paper-raised);
  color: var(--ink);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  text-decoration: none;
  box-shadow: var(--shadow-xs);
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); border-color: var(--brand); color: var(--ink); }
.btn--primary {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--on-brand);
}
.btn--primary:hover { color: var(--on-brand); }
.btn svg { width: 1em; height: 1em; stroke: currentColor; fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

/* --------------------------------------------------------------------------
   Sections
   -------------------------------------------------------------------------- */
.section { padding-block: clamp(var(--space-7), 6vw, var(--space-9)); }
.section + .section { border-top: 1px solid var(--hairline); }

/* in-page navigation lands below the sticky header rather than under it */
:target, [id] { scroll-margin-top: 5rem; }

.section__head { max-width: var(--measure-narrow); margin-bottom: var(--space-7); }
.section__head h2 { margin-bottom: var(--space-4); }
.section__head .lead { max-width: 58ch; }
.section--tint { background: var(--brand-tint); }

/* --------------------------------------------------------------------------
   The film — the first block under the hero

   A paper page leads with its title, then wants one thing that answers "what
   is this" before any prose. The film is that thing, so it sits directly under
   the hero at full shell width, on its own ground, with the teaser demoted to
   the supporting role below it.
   -------------------------------------------------------------------------- */
.film {
  padding-block: 0 var(--space-7);
}
.film__rail {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-3);
  padding-inline: 2px;
}
.film__meta {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  color: var(--ink-secondary);
  font-variant-numeric: tabular-nums;
}
.film__figure { margin: 0; }

.film__stage {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--paper-sunken);
  box-shadow: var(--shadow-lg);
}
.film__stage video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  background: var(--paper-sunken);
}
.film__fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--space-6);
  text-align: center;
  color: var(--ink-secondary);
  font-size: var(--fs-small);
}

/* The poster is the play control. The native bar stays underneath (it is
   revealed on hover/focus by the UA) so keyboard, captions and scrubbing keep
   working; this button only makes the first click obvious. */
.film__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 5.25rem;
  height: 5.25rem;
  display: grid;
  place-items: center;
  gap: 0;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 50%;
  /* Solid ink rather than a blurred pane: the poster is light and busy, and a
     frosted disc over it turns grey and loses its edge. */
  background: rgba(20, 27, 42, 0.82);
  box-shadow: 0 10px 30px -8px rgba(0, 0, 0, 0.45);
  color: #FFFFFF;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease),
              opacity var(--dur-base) var(--ease);
}
.film__play svg {
  width: 1.6rem;
  height: 1.6rem;
  margin-left: 0.18em;          /* optical centring of the triangle */
  fill: currentColor;
  stroke: none;
}
.film__play-label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.film__play:hover { background: rgba(20, 27, 42, 0.95); transform: scale(1.04); }
.film__play:focus-visible { outline-offset: 4px; outline-color: #FFFFFF; }

/* Once playing, the disc is gone — including from the tab order, so a keyboard
   user never lands on an invisible control. */
.film__stage.is-playing .film__play {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--dur-base) var(--ease), visibility 0s linear var(--dur-base);
}

.film__caption {
  display: grid;
  grid-template-columns: 1fr;
  margin-top: var(--space-4);
}
.film__lede {
  margin: 0;
  max-width: var(--measure);
  font-size: var(--fs-small);
  line-height: var(--lh-lead);
  color: var(--ink-secondary);
}
.film__title { color: var(--ink); font-weight: var(--fw-semibold); }

/* At phone widths the disc would swamp the frame; the native control bar is
   the better affordance there anyway. */
/* At phone widths the frame is ~200px tall and the native bar is always
   visible, so a disc on top of it is clutter rather than help. */
@media (max-width: 34rem) {
  .film__play { display: none; }
  .film__meta { display: none; }
}

/* --------------------------------------------------------------------------
   Teaser
   -------------------------------------------------------------------------- */
.section--teaser { padding-block: var(--space-6) var(--space-7); }
.teaser { margin: 0; }
.teaser__frame {
  /* The figure itself sits on the same warm paper as the page, so the frame
     has to carry the separation: a slightly stronger rim plus an inset shadow
     that darkens the figure's own margin rather than its content. */
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-lg);
  background: var(--paper-raised);
  box-shadow: var(--shadow-lg), inset 0 0 0 1px rgba(28, 34, 48, 0.02);
  overflow: hidden;
}
.teaser__frame img { width: 100%; height: auto; }

/* The figure labels are set at 15px inside a 1280px-wide drawing. Shrinking it
   to a phone width would take them under 5px, so below 32rem the figure is
   shown at a legible width and the frame scrolls sideways instead. */
@media (max-width: 32rem) {
  .teaser__frame {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }
  .teaser__frame img { width: 33rem; max-width: none; }
}
.teaser figcaption {
  margin-top: var(--space-4);
  font-size: var(--fs-small);
  color: var(--ink-secondary);
  max-width: var(--measure);
}

/* --------------------------------------------------------------------------
   The idea — three grammar components
   -------------------------------------------------------------------------- */
.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--space-5);
}
.pillar {
  background: var(--paper-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  box-shadow: var(--shadow-xs);
  display: flex;
  flex-direction: column;
}
/* Default is --fs-h3; the tighter step keeps three cards on one row at laptop
   widths without either card title wrapping mid-phrase. */
.pillar h3 { margin-bottom: var(--space-3); font-size: var(--fs-h4); line-height: var(--lh-tight); }
.pillar p { font-size: var(--fs-small); color: var(--ink-secondary); flex: 1; }
.pillar__label {
  display: block;
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--brand);
  margin-bottom: var(--space-2);
}

/* a small stack of chips used inside the pillars and the grammar block */
.chips { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.chips--stack { margin-top: var(--space-4); }

/* --------------------------------------------------------------------------
   Grammar display block
   -------------------------------------------------------------------------- */
.grammar {
  margin-top: var(--space-6);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--paper-sunken);
  padding: var(--space-5);
  overflow-x: auto;
}
.grammar__row {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: var(--space-4);
  align-items: center;
  padding-block: var(--space-3);
}
.grammar__row + .grammar__row { border-top: 1px dashed var(--hairline-strong); }
.grammar__op { justify-self: start; }
.grammar__form { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.grammar__note { font-size: var(--fs-caption); color: var(--ink-secondary); flex-basis: 100%; }

@media (max-width: 34rem) {
  .grammar { padding: var(--space-4); }
  .grammar__row { grid-template-columns: minmax(0, 1fr); gap: var(--space-2); }
  .grammar__op { margin-bottom: var(--space-1); }
}

/* --------------------------------------------------------------------------
   How it works — pipeline
   -------------------------------------------------------------------------- */
.pipeline {
  display: grid;
  /* Sized so the five steps land 5 / 3 / 1 across rather than 5 / 4 / 1:
     an orphan alone on the second row reads as a missing item. */
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-4);
  counter-reset: step;
}
.step {
  position: relative;
  background: var(--paper-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  padding: var(--space-5) var(--space-4) var(--space-4);
  box-shadow: var(--shadow-xs);
}
.step::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--brand);
  letter-spacing: 0.06em;
  display: block;
  margin-bottom: var(--space-2);
}
.step h3 { font-size: var(--fs-h4); margin-bottom: var(--space-2); }
.step p { font-size: var(--fs-caption); color: var(--ink-secondary); }


/* --------------------------------------------------------------------------
   Results
   -------------------------------------------------------------------------- */
.tables { display: grid; gap: var(--space-7); }
/* Grid and flex items default to min-width:auto, which lets a wide child (the
   min-width on the scrollable tables) push the whole page wider than the
   viewport. Pinning min-width:0 keeps the overflow inside .table-scroll. */
.tables > * { min-width: 0; }
.table-block { min-width: 0; }
.table-block h3 { margin-bottom: var(--space-2); }
.table-block > .caption { margin-bottom: var(--space-4); }

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-small);
  font-variant-numeric: tabular-nums;
}
.data-table caption {
  text-align: left;
  font-size: var(--fs-caption);
  color: var(--ink-secondary);
  padding-bottom: var(--space-3);
}
.data-table th, .data-table td {
  padding: 0.55rem 0.6rem;
  border-bottom: 1px solid var(--hairline);
  text-align: right;
  white-space: nowrap;
}
.data-table thead th {
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-secondary);
  border-bottom: 1.5px solid var(--hairline-strong);
  vertical-align: bottom;
}
/* the group row: "Success (%)" / "Tokens" — quieter than the column labels,
   with a hairline that stops short of the table edge so it reads as a brace
   over its three columns rather than as another rule */
.data-table thead tr:first-child th[colspan] {
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--ink);
  letter-spacing: 0.02em;
  text-transform: none;
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 0.35rem;
  text-align: center;          /* the label braces its own group, not the last column */
}
.data-table thead th[rowspan] { vertical-align: bottom; }
.data-table th:first-child, .data-table td:first-child { text-align: left; }
.data-table tbody tr:hover { background: var(--brand-tint); }
.data-table .is-nce { background: var(--brand-tint); font-weight: var(--fw-semibold); }
.data-table .is-nce-cell { color: var(--brand); font-weight: var(--fw-semibold); }
.data-table .delta { font-size: 0.85em; color: var(--block-note); font-weight: var(--fw-semibold); margin-left: 0.25em; }
.data-table .delta--flat { color: var(--ink-secondary); }
.data-table tfoot th, .data-table tfoot td {
  border-top: 1.5px solid var(--hairline-strong);
  border-bottom: none;
  font-weight: var(--fw-semibold);
}
.data-table tfoot th { text-align: left; }

/* The horizontal scroll is real at phone widths. A mask on the scroller fades
   the right edge so a part-visible column reads as "more to the right" rather
   than as a clipped cell; the left edge stays crisp because the sticky first
   column lives there. */
.table-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.table-scroll table { min-width: 34rem; }

@media (max-width: 47rem) {
  .table-scroll {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent 100%);
  }
}
/* Narrow widths scroll the table sideways; without this the row labels leave
   the viewport first and the numbers lose their meaning. */
@media (max-width: 47rem) {
  .data-table th:first-child,
  .data-table td:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--paper);
    box-shadow: inset -1px 0 0 var(--hairline);
  }
  .data-table tbody tr:hover td:first-child,
  .data-table tbody tr:hover th:first-child { background: var(--brand-tint); }
  .data-table thead th:first-child { background: var(--paper); }
}

/* --------------------------------------------------------------------------
   Demo CTA
   -------------------------------------------------------------------------- */
.cta-card {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--space-5);
  background: var(--paper-raised);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm);
}
@media (max-width: 44rem) {
  .cta-card { grid-template-columns: 1fr; }
  .cta-card .btn { justify-content: center; }
}

/* --------------------------------------------------------------------------
   Citation
   -------------------------------------------------------------------------- */
.citation {
  position: relative;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--paper-sunken);
}
.citation pre {
  margin: 0;
  padding: var(--space-5);
  overflow-x: auto;
  font-size: var(--fs-caption);
  line-height: 1.7;
}
.copy-btn {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  padding: 0.35rem 0.7rem;
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-sm);
  background: var(--paper-raised);
  color: var(--ink-secondary);
  cursor: pointer;
}
.copy-btn:hover { color: var(--brand); border-color: var(--brand); }
.copy-btn.is-copied { color: var(--block-note); border-color: var(--block-note); }

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
.site-footer {
  border-top: 1px solid var(--hairline);
  padding-block: var(--space-7);
  background: var(--paper-sunken);
}
.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  align-items: center;
  justify-content: space-between;
  font-size: var(--fs-small);
  color: var(--ink-secondary);
}
.site-footer__mark { display: flex; align-items: center; gap: var(--space-3); }
.site-footer__method { color: var(--ink); font-weight: var(--fw-semibold); }
.site-footer__legal { margin: 0; }
.site-footer a { color: var(--ink-secondary); }
.site-footer a:hover { color: var(--brand); }

/* --------------------------------------------------------------------------
   Scroll reveal (IntersectionObserver adds .is-visible)

   Gated on .js on <html>, which the page sets inline. With scripting off the
   rule never applies, so the whole document is readable instead of blank.
   -------------------------------------------------------------------------- */
.js .reveal { opacity: 0; transform: translateY(14px); transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease); }
.js .reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
}

/* print: keep the page readable on paper */
@media print {
  .site-header, .theme-toggle, .copy-btn, .btn, .film { display: none; }
  .section { padding-block: var(--space-5); break-inside: avoid; }
  .js .reveal { opacity: 1; transform: none; }
  .teaser__frame, .table-block, .pillar, .step { break-inside: avoid; }
  .data-table .is-nce { background: transparent; }
}

/* Shown only when arrival with #video could not autoplay: one gentle pulse,
   so the reader sees where to click without a second piece of copy. */
.film__play.is-cued { animation: film-cue 1.6s ease-out 2; }
@keyframes film-cue {
  0%   { box-shadow: 0 0 0 0 rgba(255,255,255,.55); }
  70%  { box-shadow: 0 0 0 26px rgba(255,255,255,0); }
  100% { box-shadow: 0 0 0 0 rgba(255,255,255,0); }
}
@media (prefers-reduced-motion: reduce) { .film__play.is-cued { animation: none; } }

/* Shown only when the film started muted: one tap restores the sound. */
.film__sound {
  position: absolute;
  right: 1rem;
  bottom: 1rem;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.42rem 0.8rem 0.42rem 0.6rem;
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 999px;
  background: rgba(20, 27, 42, 0.86);
  color: #FFFFFF;
  font: inherit;
  font-size: var(--fs-caption);
  cursor: pointer;
}
.film__sound svg { width: 1.05rem; height: 1.05rem; fill: currentColor; }
.film__sound:hover { background: rgba(20, 27, 42, 0.96); }
.film__sound[hidden] { display: none; }

/* ==========================================================================
   Phones — portrait layout
   --------------------------------------------------------------------------
   The desktop composition is built on wide centred lines: a three-line
   display title, an author list and a numbered institution line that is set
   `nowrap` so an institution never splits. None of that survives a 390 px
   column, and two of those rules actively break the layout: the nowrap
   institution line is wider than the viewport (which makes the whole document
   scroll sideways by a few pixels), and the display size bottoms out at 44 px,
   which turns the title into four cramped lines over a busy background.

   Everything below is scoped to portrait phones. Tablet and desktop keep the
   composition they were designed for.
   ========================================================================== */
@media (max-width: 40rem) {
  /* A phone column is narrow, so the horizontal padding is tightened a little;
     this alone buys ~12 px of measure on a 390 px screen. */
  .shell { padding-inline: var(--space-4); }

  /* --- title -------------------------------------------------------------
     The desktop display size bottoms out far too large for one column. Scale
     with the viewport, but keep the display face and its tight leading: the
     title should read as a title, not as body copy. */
  .hero__title {
    font-size: clamp(1.9rem, 8.2vw, 2.4rem);
    line-height: 1.08;
    letter-spacing: -0.01em;
    margin-bottom: var(--space-4);
  }

  /* --- authors and institutions -----------------------------------------
     Names wrap between people, never inside one; institutions now wrap inside
     themselves, because a nowrap institution is wider than the screen. */
  .hero__authors {
    font-size: var(--fs-small);
    line-height: 1.8;
    padding-inline: var(--space-2);
  }
  .hero__affil--list { line-height: 1.9; }
  /* Institutions must wrap (a nowrap line overflows the phone), but the
     number must never be orphaned from the name it labels: the knot is
     forced with a non-breaking space by the script. */
  .hero__affil--list .affil-item { white-space: normal; }
  .hero__affil--list .affil-item sup { display: inline; }

  /* --- header ------------------------------------------------------------
     Four section links plus the mark and the toggle only just fit at 390 px
     and overflow below 360 px. Tighten the type and the gap, and drop the
     wordmark so the links keep their full labels. */
  .site-header__inner { gap: var(--space-3); min-height: 3.5rem; }
  .site-nav { gap: var(--space-2); }
  .site-nav a { font-size: var(--fs-caption); }
  .site-header__mark { font-size: var(--fs-small); }
  .theme-toggle { width: 2rem; height: 2rem; }

  /* --- hero background ---------------------------------------------------
     At phone width the block field sits directly behind the title, and its
     card edges cross the letterforms. Push the wash up so the cards read as
     texture at the edges of the band, never as columns behind the type. */
  .hero-bg {
    --hero-veil-size: 132% 86%;
    --hero-veil-color: rgba(251, 250, 247, 0.82);
    --hero-field-opacity: 0.42;
  }
  :root[data-theme="dark"] .hero-bg { --hero-veil-color: rgba(13, 20, 36, 0.86); }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not([data-theme="dark"]) .hero-bg {
      --hero-veil-color: rgba(13, 20, 36, 0.86);
    }
  }

  /* --- buttons -----------------------------------------------------------
     Three pills side by side do not fit; let them wrap and share the row
     evenly so they read as one control group rather than as a ragged stack. */
  /* Equal-width pills pushed "Live demo" onto two lines; keep the labels on
     one line and let the row wrap instead. */
  .hero__links { gap: var(--space-2); }
  .hero__links .btn {
    flex: 0 1 auto;
    justify-content: center;
    white-space: nowrap;
    padding-inline: var(--space-3);
  }

  /* --- film --------------------------------------------------------------
     The player is fine at 16:9; only its caption needs a touch more room. */
  .film__caption { margin-top: var(--space-3); }
  .film__lede { font-size: var(--fs-caption); }

  /* --- sections ----------------------------------------------------------
     Vertical rhythm was tuned for a 1200 px column; on a phone it reads as
     too much air between short blocks. */
  .section { padding-block: var(--space-6); }
  .section__head { margin-bottom: var(--space-5); }
  .hero { padding-block: var(--space-6) var(--space-5); }

  /* --- results tables ----------------------------------------------------
     The tables keep their horizontal scroll (a sticky first column and a
     fading right edge), but the minimum width can come down: at 34 rem every
     row showed a quarter of a column it did not need. */
  .table-scroll table { min-width: 28rem; }
  .data-table { font-size: var(--fs-small); }
  .data-table th,
  .data-table td { padding: 0.5rem 0.55rem; }

  /* --- figures and code --------------------------------------------------
     The teaser keeps its sideways scroll at a legible label size; the code
     blocks simply need a little less padding so the longest line fits. */
  .grammar { padding: var(--space-3); }
  .cf, pre, code { font-size: 0.8125rem; }

  /* --- citation ---------------------------------------------------------- */
  .citation { font-size: var(--fs-caption); }
}

/* Small phones (iPhone SE and similar): the header links have to give up a
   little more before the row overflows. */
@media (max-width: 23rem) {
  .site-nav a { font-size: 0.7rem; }
  .site-nav { gap: var(--space-1); }
  .site-header__mark { display: none; }
}

/* Belt and braces against any future horizontal overflow: nothing on this
   page is meant to scroll sideways at the document level. */
html { overflow-x: clip; }

/* --------------------------------------------------------------------------
   Teaser figure — one figure, two grounds
   --------------------------------------------------------------------------
   The teaser is a raster drawn on paper. On the dark theme a white-ground
   raster is the brightest object on the page, so it carried its own light
   rectangle while everything around it went navy. Both cuts are shipped and
   the theme picks one; they are pixel-identical in geometry, so swapping them
   changes the colour and nothing else. Keyed off the same attribute the theme
   toggle writes, and off the OS preference when nothing has been chosen —
   exactly the pattern .logo already uses.
   -------------------------------------------------------------------------- */
.teaser__fig--dark { display: none; }

:root[data-theme="dark"] .teaser__fig--light { display: none; }
:root[data-theme="dark"] .teaser__fig--dark  { display: block; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .teaser__fig--light { display: none; }
  :root:not([data-theme="light"]):not([data-theme="dark"]) .teaser__fig--dark  { display: block; }
}
