/* Strike a Chord: project page
   Light-only by intent: every animation is black ink on white, and a dark ground
   would invert the artwork against the page. */

:root{
  --ink:      #14161a;
  --ink-2:    #3d434d;
  --ink-3:    #6b7280;
  --rule:     #e2ded7;
  --rule-2:   #efece6;
  --paper:    #faf8f4;
  --card:     #ffffff;
  --ours:     #2a3f8f;   /* same blue the paper figures label "ours" with */
  --base:     #8c3a3a;   /* and the same red for the baseline */
  --accent:   #b8560f;
  --measure:  70ch;
  --gap:      clamp(1rem, 2.2vw, 1.75rem);
}

*,*::before,*::after{ box-sizing:border-box; }
/* the tabs and pagers hide things with the hidden attribute; without !important a rule like
   .cmp{display:flex} would override it and the hidden cards would still show */
[hidden]{ display:none !important; }

html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; font-size:200%; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  font-size:1.0625rem;
  line-height:1.62;
  -webkit-font-smoothing:antialiased;
  font-feature-settings:"kern" 1,"liga" 1;
}

img{ max-width:100%; display:block; }
a{ color:var(--ours); text-decoration:none; border-bottom:1px solid rgba(42,63,143,.28); }
a:hover{ border-bottom-color:var(--ours); }

/* A loose cap: wide enough that a big display is not mostly margin, tight enough that the
   column does not run edge to edge. Half the restriction of the original 1680px. */
.wrap{ width:min(2200px, calc(100% - 3rem)); margin-inline:auto; }
.narrow{ max-width:var(--measure); }

/* tight vertical rhythm: sections sit close together, the same gap as under the hero buttons */
section{ padding-block:clamp(1rem, 2vw, 1.5rem); border-top:1px solid var(--rule); }
section:first-of-type{ border-top:0; }

h2{
  font-size:clamp(1.5rem,5.8vw,2.1rem);
  line-height:1.18; letter-spacing:-.021em; font-weight:600;
  margin:0 0 .5rem;
}
h3{ font-size:1.06rem; font-weight:650; letter-spacing:-.008em; margin:0 0 .35rem; }
p{ margin:0 0 1.05em; }
p:last-child{ margin-bottom:0; }

.eyebrow{
  font-size:.72rem; font-weight:600; letter-spacing:.13em; text-transform:uppercase;
  color:var(--ink-3); margin:0 0 .9rem;
}
.lede{ font-size:1.09rem; color:var(--ink-2); max-width:var(--measure);
       text-align:center; margin-inline:auto; }
/* .wide opts a block out of the reading measure and lets it run the full column */
.lede.wide{ max-width:none; }
.section-head{ margin-bottom:clamp(1.6rem,3vw,2.4rem); }

/* ---------- hero ---------------------------------------------------------- */
.hero{ padding-top:clamp(3rem,7vw,5.5rem); padding-bottom:0; text-align:center; }
/* keep the teaser close under the Paper / Abstract buttons */
.hero .buttons{ margin-bottom:0; }

.hero h1{
  font-family:Georgia,"Iowan Old Style","Times New Roman",serif;
  font-weight:400; font-style:normal;
  font-size:clamp(2.6rem,14.4vw,5.1rem);
  line-height:1.02; letter-spacing:-.028em;
  margin:0 0 .5rem;
}
.hero h1 em{ font-style:italic; }
.hero .sub{
  font-size:clamp(1.02rem,3.4vw,1.22rem); color:var(--ink-2);
  max-width:44ch; margin:0 auto 1.6rem;
}
.byline{ font-size:.9rem; color:var(--ink-3); margin:0 0 1.5rem; }

.buttons{ display:flex; flex-wrap:wrap; gap:.55rem; justify-content:center; margin-bottom:clamp(2rem,4vw,3rem); }
.btn{
  display:inline-flex; align-items:center; gap:.5rem;
  padding:.55rem 1.05rem; border-radius:999px;
  background:var(--ink); color:#fff; border:1px solid var(--ink);
  font-size:.88rem; font-weight:550; letter-spacing:.005em;
}
.btn:hover{ background:#000; border-color:#000; }
.btn.ghost{ background:transparent; color:var(--ink); border-color:var(--rule); }
.btn.ghost:hover{ background:#fff; border-color:var(--ink-3); }
.btn[aria-disabled="true"]{ opacity:.45; pointer-events:none; }
.btn.soon{ cursor:default; color:var(--ink-3); border-color:var(--rule); }
.btn.soon:hover{ background:transparent; border-color:var(--rule); }   /* the Code button: present, but nothing to open yet */

/* the marquee strip of results under the title */
.strip{ display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:.6rem; }
.strip figure{ margin:0; background:var(--card); border:1px solid var(--rule); border-radius:12px; overflow:hidden; }
.strip img{ width:100%; aspect-ratio:1; object-fit:contain; background:#fff; }
.strip figcaption{
  font-size:.7rem; color:var(--ink-3); padding:.4rem .55rem .5rem;
  border-top:1px solid var(--rule-2); text-align:left; line-height:1.35;
}
.strip figcaption b{ color:var(--ink); font-weight:600; }

/* ---------- generic card / grid ------------------------------------------- */
.grid{ display:grid; gap:var(--gap); }
.cols-2{ grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); }
/* comparison pairs carry two animations side by side, so they need the width */
.cols-pair{ grid-template-columns:repeat(auto-fit,minmax(440px,1fr)); }
@media (min-width:1000px){ .cols-pair{ grid-template-columns:1fr 1fr; } }
.cols-3{ grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); }
.cols-4{ grid-template-columns:repeat(auto-fit,minmax(190px,1fr)); }

.card{
  background:var(--card); border:1px solid var(--rule); border-radius:14px;
  overflow:hidden;
}
.card .body{ padding:.85rem 1rem 1rem; }
.card .cap{ font-size:.85rem; color:var(--ink-2); line-height:1.45; }
.card .meta{ font-size:.72rem; color:var(--ink-3); margin-top:.4rem; letter-spacing:.01em; }

.badge{
  display:inline-block; min-width:1.55em; text-align:center;
  font-weight:700; font-size:.78rem; padding:.1em .45em; border-radius:5px;
  background:var(--rule-2); color:var(--ink); margin-right:.4rem;
}

/* ---------- abstract ------------------------------------------------------ */
.abstract{
  font-size:.9rem; line-height:1.65; color:var(--ink-2);   /* abstract */
  text-align:center;
  max-width:96ch; margin-inline:auto;   /* centred, and short enough to stay readable */
}
.abstract p{ margin:0 0 1em; }

/* ---------- pipeline figures ---------------------------------------------- */
figure.fig{ margin:0 0 clamp(1.6rem,3vw,2.4rem); }
figure.fig:last-child{ margin-bottom:0; }   /* the section padding already spaces it */
figure.fig img{
  width:100%; background:#fff;
  border:1px solid var(--rule); border-radius:14px; padding:clamp(.6rem,1.6vw,1.4rem);
}
figure.fig.plain img{ padding:.6rem; }
/* teaser at 70% of the column width, centred; the caption keeps to the same width */
#teaser figure.fig{ width:70%; margin-inline:auto; }
@media (max-width:1000px){ #teaser figure.fig{ width:100%; } }
figure.fig figcaption{
  font-size:.8rem; line-height:1.55; color:var(--ink-3);
  max-width:var(--measure); margin-top:.7rem;
}
figure.fig figcaption.wide{ max-width:none; }
figure.fig figcaption b{ color:var(--ink-2); font-weight:600; }

.facts{ margin-top:clamp(.6rem,2vw,1.4rem); }
.facts > div{
  background:var(--card); border:1px solid var(--rule); border-radius:14px;
  padding:1rem 1.1rem 1.1rem;
}
.facts h3{ margin:0 0 .45rem; font-size:.95rem; }
.facts p{ margin:0; font-size:.83rem; line-height:1.55; color:var(--ink-3); }
.facts b{ color:var(--ink); font-weight:650; }

.drawer{ margin-top:clamp(1.6rem,3vw,2.4rem); border-top:1px solid var(--rule); padding-top:1.1rem; }
.drawer summary{
  cursor:pointer; font-size:.86rem; font-weight:550; color:var(--ours);
  list-style:none; display:inline-flex; align-items:center; gap:.45rem;
}
.drawer summary::-webkit-details-marker{ display:none; }
.drawer summary::before{ content:"+"; font-weight:700; }
.drawer[open] summary::before{ content:"\2212"; }
.drawer summary:hover{ text-decoration:underline; }

/* ---------- comparison ---------------------------------------------------- */
.compare{ background:var(--card); border:1px solid var(--rule); border-radius:16px; overflow:hidden; }
.compare .prompt{
  padding:.9rem 1.15rem; border-bottom:1px solid var(--rule-2);
  font-size:.92rem; color:var(--ink-2); display:flex; gap:.55rem; align-items:baseline;
}
.compare .prompt .badge{ flex:none; }
.pair{ display:grid; grid-template-columns:1fr 1fr; }
.pair > div{ position:relative; }
.pair > div + div{ border-left:1px solid var(--rule-2); }
.pair img{ width:100%; aspect-ratio:1; object-fit:contain; background:#fff; }
.tag{
  position:absolute; top:.6rem; left:.6rem; z-index:2;
  font-size:.66rem; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  padding:.22em .55em; border-radius:5px; background:#fff; border:1px solid var(--rule);
}
.tag.ours{ color:var(--ours); border-color:rgba(42,63,143,.35); }
.tag.base{ color:var(--base); border-color:rgba(140,58,58,.3); }
.compare .foot{
  display:flex; flex-wrap:wrap; gap:1.1rem; padding:.7rem 1.15rem .85rem;
  border-top:1px solid var(--rule-2); font-size:.74rem; color:var(--ink-3);
}
.compare .foot b{ color:var(--ink); font-weight:650; font-variant-numeric:tabular-nums; }

/* ---------- gallery ------------------------------------------------------- */
.controls{
  display:flex; flex-wrap:wrap; gap:.75rem 1.1rem; align-items:center;
  padding:.85rem 0 1.35rem; margin-bottom:1.2rem; border-bottom:1px solid var(--rule);
  position:sticky; top:0; background:var(--paper); z-index:20;
}
.controls input[type=search], .controls select{
  font:inherit; font-size:.86rem; padding:.42rem .7rem;
  border:1px solid var(--rule); border-radius:8px; background:#fff; color:var(--ink);
}
.controls input[type=search]{ min-width:min(260px,55vw); }
.letters{ display:flex; flex-wrap:wrap; gap:.22rem; }
.letters button{
  font:inherit; font-size:.76rem; font-weight:600; width:1.85rem; height:1.85rem;
  border:1px solid var(--rule); border-radius:6px; background:#fff; color:var(--ink-3);
  cursor:pointer; padding:0;
}
.letters button:hover:not(:disabled){ border-color:var(--ink-3); color:var(--ink); }
.letters button[aria-pressed=true]{ background:var(--ink); border-color:var(--ink); color:#fff; }
.letters button:disabled{ opacity:.3; cursor:default; }

.switch{ display:inline-flex; align-items:center; gap:.45rem; font-size:.83rem; color:var(--ink-2); cursor:pointer; user-select:none; }
.switch input{ accent-color:var(--ours); width:1rem; height:1rem; }

.count{ font-size:.78rem; color:var(--ink-3); margin-left:auto; font-variant-numeric:tabular-nums; }

.tile{ position:relative; background:var(--card); border:1px solid var(--rule); border-radius:12px; overflow:hidden; }
.tile .stage{ position:relative; background:#fff; }
.tile .stage img{ width:100%; aspect-ratio:1; object-fit:contain; }
.tile .stage img.glyph{ position:absolute; inset:0; opacity:0; transition:opacity .18s ease; }
.tile.show-glyph .stage img.glyph, .tile:hover .stage img.glyph{ opacity:1; }
.tile .body{ padding:.6rem .75rem .7rem; border-top:1px solid var(--rule-2); }
.tile .cap{ font-size:.78rem; line-height:1.4; color:var(--ink-2); }
.tile .meta{ font-size:.68rem; color:var(--ink-3); margin-top:.35rem; }
.tile .hint{
  position:absolute; right:.5rem; top:.5rem; z-index:2;
  font-size:.62rem; letter-spacing:.07em; text-transform:uppercase; color:var(--ink-3);
  background:rgba(255,255,255,.9); border:1px solid var(--rule); border-radius:5px; padding:.16em .45em;
  opacity:0; transition:opacity .18s ease;
}
.tile:hover .hint, .tile.show-glyph .hint{ opacity:1; }

.more{ display:flex; justify-content:center; margin-top:1.8rem; }

/* ---------- table --------------------------------------------------------- */
.tablewrap{ overflow-x:auto; border:1px solid var(--rule); border-radius:14px; background:var(--card); }
table{ border-collapse:collapse; width:100%; font-size:.87rem; min-width:640px; }
caption{ caption-side:bottom; text-align:left; font-size:.76rem; color:var(--ink-3); padding:.8rem 1rem; line-height:1.5; }
th,td{ padding:.55rem .85rem; text-align:right; border-bottom:1px solid var(--rule-2); }
th:first-child,td:first-child{ text-align:left; }
thead th{ font-size:.72rem; font-weight:600; letter-spacing:.03em; color:var(--ink-3); white-space:nowrap; }
tbody tr.group td{
  font-size:.72rem; letter-spacing:.09em; text-transform:uppercase; color:var(--ink-3);
  padding-top:1rem; border-bottom:0; font-weight:600;
}
tbody td{ font-variant-numeric:tabular-nums; }
tbody tr.win td{ background:rgba(42,63,143,.045); }
tbody tr.win td b{ color:var(--ours); }
tr:last-child td{ border-bottom:0; }

/* A standing note about how to read the results grids: full width and set larger than
   body copy, so it is read before the examples rather than skimmed past. */
.callout{
  max-width:96ch; margin-inline:auto;
  font-size:clamp(.89rem, 2.08vw, 1.15rem);   /* the section intros */
  line-height:1.5; letter-spacing:-.008em; color:var(--ink);
  text-align:center;
  padding:0;
  margin-bottom:clamp(1.8rem,3vw,2.6rem);
}
/* the accent that used to run down the left edge, now a short rule centred above the text */
.callout::before{
  content:""; display:block; width:2.6rem; height:3px; border-radius:2px;
  background:var(--accent); margin:0 auto .85rem;
}
.callout b{ font-weight:650; }
/* the note now sits outside any section, above the tab bar, so it carries its own spacing
   and the rule that divides it from the section above */
.results-note{ border-top:1px solid var(--rule); padding-block:clamp(1rem,2vw,1.5rem); }
.results-note .callout{ margin-block:0; }

/* ---------- word results -------------------------------------------------- */
.words{
  display:grid; grid-template-columns:repeat(3,1fr);
  gap:clamp(.7rem,1.4vw,1.1rem); margin-top:clamp(1.4rem,3vw,2rem);
}
@media (max-width:1000px){ .words{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:620px){  .words{ grid-template-columns:1fr; } }
.word{ margin:0; }
/* the word above the clip, so it is clear which letter of which word is animated: the word in
   dark grey, the animated letter tinted */
.wordmark{
  display:flex; justify-content:center; gap:.02em;
  font-size:.72rem; font-weight:650; letter-spacing:.24em; text-indent:.24em;
  color:var(--ink-2); margin:0 0 .4rem;
}
.wordmark .on{ color:var(--ours); background:rgba(42,63,143,.11); border-radius:4px; }
/* Every clip is cropped to its own content, so aspect ratios run from 1.4 (YAY) to 4.5
   (ACROBAT). Boxing them to one ratio and letting each sit inside it evens the grid out;
   the letterboxing is white on a white card, so it reads as padding, not as bars. */
.word img{
  width:100%; aspect-ratio:var(--word-ratio, 5/2); object-fit:contain;
  background:#fff; border:1px solid var(--rule); border-radius:14px;
}
/* the prompt reads as a plate caption under the clip: the title's serif, italic and centred
   under the centred word */
.word figcaption{
  font-family:Georgia,"Iowan Old Style","Times New Roman",serif;
  font-style:italic; font-size:.86rem; line-height:1.5; color:var(--ink-2);
  text-align:center; text-wrap:balance;
  margin-top:.55rem; padding:0 .4rem;
}

/* ---------- baseline comparisons ------------------------------------------ */
/* Two comparisons per row. Each is a prompt, then three square panels: the input glyph,
   the baseline, ours. Panels are square with the clip contained, so every method is shown
   at the scale it produced, centred, with nothing cropped. */
.cmp-grid{
  display:grid; grid-template-columns:repeat(2,1fr);
  gap:clamp(1rem,2vw,1.6rem); margin-top:clamp(1.4rem,3vw,2rem);
}
@media (max-width:1100px){ .cmp-grid{ grid-template-columns:1fr; } }
/* flex column with the panels pushed to the bottom, so two cards in a row line their panels
   up even when one prompt wraps to two lines and the other doesn't */
.cmp{ margin:0; background:var(--card); border:1px solid var(--rule); border-radius:14px; overflow:hidden;
      display:flex; flex-direction:column; }
.cmp .prompt{ flex:1 0 auto; }
.cmp .prompt{
  font-family:Georgia,"Iowan Old Style","Times New Roman",serif;
  font-style:italic; font-size:.88rem; line-height:1.5; color:var(--ink-2);
  padding:.75rem .95rem; border-bottom:1px solid var(--rule-2);
}
.cmp .panels{ display:grid; grid-template-columns:repeat(3,1fr); }
.cmp .panels.two{ grid-template-columns:repeat(2,1fr); }   /* interaction cards: input + ours */
/* merged baseline cards: input, the two baselines and ours, two across on a phone */
.cmp .panels.four{ grid-template-columns:repeat(4,1fr); }
@media (max-width:700px){ .cmp .panels.four{ grid-template-columns:repeat(2,1fr); } }
/* the single ablation card: input, full model and the four arms in one row, folding to three
   across on narrower screens so the panels stay big enough to read */
.cmp .panels.six{ grid-template-columns:repeat(6,1fr); }
@media (max-width:1500px){ .cmp .panels.six{ grid-template-columns:repeat(3,1fr); } }
@media (max-width:700px){ .cmp .panels.six{ grid-template-columns:repeat(2,1fr); } }
.cmp .panels.six .panel + .panel{ border-left:1px solid var(--rule-2); }
.cmp-grid.one{ grid-template-columns:1fr; }
.cmp .panel + .panel{ border-left:1px solid var(--rule-2); }
/* A long label like "Astra (font only)" would otherwise widen or shorten its own clip: with
   plain 1fr tracks the label's min-content sets the column width, and the square clip follows
   it. min-width:0 pins every column to an equal share, and letting the label fill the space
   above the clip keeps the clips level when one label wraps to two lines. */
.cmp .panel{ display:flex; flex-direction:column; min-width:0; }
.cmp .panel .lab{ flex:1 0 auto; }
.cmp .panel .lab{
  font-size:.56rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  color:var(--ink-3); padding:.45rem .6rem 0;
}
.cmp .panel.ours .lab{ color:var(--ours); }
.cmp .panel.base .lab{ color:var(--base); }
.cmp .panel img{ width:100%; aspect-ratio:1; object-fit:contain; background:#fff; display:block; }

/* ---------- result tabs --------------------------------------------------- */
/* Four buttons, one per result section. The bar sticks to the top of the window so you can
   flip sections from anywhere in a long grid; the active tab is filled like the Paper button. */
.tabbar{
  position:sticky; top:0; z-index:10;
  background:var(--paper); border-top:1px solid var(--rule); border-bottom:1px solid var(--rule);
  padding-block:.8rem;
}
/* every group's buttons sit in one row, however many there are */
.tabs{ display:grid; grid-auto-flow:column; grid-auto-columns:1fr; gap:.55rem; }
/* the Analysis group scrolls with the page: only the main results bar sticks to the top,
   so the two bars never stack over each other */
.tabbar.analysis{ position:static; }
.analysis-head{ border-top:1px solid var(--rule); padding-block:clamp(1.6rem,3vw,2.4rem) .4rem; }
.analysis-head h2{ margin:0; }
.tab{
  font:inherit; font-size:.82rem; font-weight:550; line-height:1.3; letter-spacing:.005em;
  padding:.65rem 1rem; border-radius:999px; cursor:pointer;
  background:transparent; color:var(--ink); border:1px solid var(--rule);
}
.tab:hover{ background:#fff; border-color:var(--ink-3); }
.tab[aria-selected="true"]{ background:var(--ink); color:#fff; border-color:var(--ink); }
.tab:focus-visible{ outline:2px solid var(--ours); outline-offset:2px; }
@media (max-width:1100px){ .tabs{ grid-auto-flow:row; grid-template-columns:repeat(2,1fr); } }
@media (max-width:620px){ .tab{ font-size:.7rem; padding:.55rem .6rem; border-radius:14px; } }
/* the Abstract button under the teaser: one tab-style button that opens and closes the abstract */
.reveal-bar{ display:flex; justify-content:center; }
.tab.reveal{ min-width:min(22rem,100%); display:inline-flex; align-items:center; justify-content:center; gap:.6rem; }
.tab.reveal::after{ content:""; width:.45em; height:.45em; border-right:2px solid currentColor;
  border-bottom:2px solid currentColor; transform:translateY(-.15em) rotate(45deg); transition:transform .15s; }
.tab.reveal[aria-expanded="true"]{ background:var(--ink); color:#fff; border-color:var(--ink); }
.tab.reveal[aria-expanded="true"]::after{ transform:translateY(.1em) rotate(-135deg); }
#abstract-body{ margin-top:clamp(1rem,2vw,1.5rem); }

/* the bar already draws the line above the shown section */
.tabbar + .tab-panel, .tab-panel{ border-top:0; }

/* ---------- paged grids --------------------------------------------------- */
/* prev | grid | next, with the "1-6 of 36" counter centred under the grid. On a phone the
   two buttons drop below the grid, either side of the counter. */
.pager{
  display:grid; grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-areas:"prev grid next" ". count .";
  column-gap:clamp(.6rem,1.5vw,1.2rem); row-gap:1rem; align-items:center;
}
.pager > .words, .pager > .cmp-grid{ grid-area:grid; }
.pager-btn.prev{ grid-area:prev; }
.pager-btn.next{ grid-area:next; }
.pager-count{ grid-area:count; text-align:center; font-size:.8rem; color:var(--ink-3); font-variant-numeric:tabular-nums; }
.pager-btn{
  width:2.6rem; height:2.6rem; border-radius:50%; cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center;
  font:inherit; font-size:1.5rem; line-height:1; padding:0 0 .12em;
  background:var(--card); color:var(--ink); border:1px solid var(--rule);
}
.pager-btn:hover{ background:var(--ink); color:#fff; border-color:var(--ink); }
.pager-btn:focus-visible{ outline:2px solid var(--ours); outline-offset:2px; }
@media (max-width:620px){
  .pager{ grid-template-columns:auto 1fr auto; grid-template-areas:"grid grid grid" "prev count next"; }
}

/* ---------- title ---------------------------------------------------------- */
/* A slow highlight travels across the title every few seconds and the ! rocks once in a
   while. Both are small on purpose: the page is about the animations below. The shine only
   paints where background-clip:text works, so the plain colour stays the fallback. */
@supports (-webkit-background-clip: text) or (background-clip: text){
  .hero h1.title{
    background:linear-gradient(100deg,
      var(--ink) 40%, #6f7680 48%, #7d848e 50%, #6f7680 52%, var(--ink) 60%);
    background-size:200% 100%;
    background-position:100% 0;
    -webkit-background-clip:text; background-clip:text;
    color:transparent;
    animation:title-shine 9s ease-in-out infinite;
  }
}
/* the highlight sits mid-gradient, so sweeping the position from 100% to 0% carries it across
   the words once, then the title rests for most of the cycle */
@keyframes title-shine{
  0%, 6%   { background-position:100% 0; }
  34%,100% { background-position:0% 0; }
}
.hero h1 .bang{
  display:inline-block; transform-origin:50% 88%;
  animation:bang-wobble 6s ease-in-out infinite;
  /* the ! is transformed, so it paints outside the title's clipped background and would come
     out invisible: give it the ink colour back */
  color:var(--ink); -webkit-text-fill-color:var(--ink);
}
@keyframes bang-wobble{
  0%, 62%, 100% { transform:rotate(0deg); }
  68%  { transform:rotate(7deg); }
  74%  { transform:rotate(-5deg); }
  80%  { transform:rotate(3deg); }
  86%  { transform:rotate(-1.5deg); }
}
@media (prefers-reduced-motion:reduce){
  .hero h1.title{ animation:none; background:none; color:var(--ink); }
  .hero h1 .bang{ animation:none; }
}

/* ---------- teaser video --------------------------------------------------- */
/* 70% of the column like the paper's teaser figure, and never taller than the window */
.video-fig{ width:70%; margin:0 auto; }
.video-fig video{ width:100%; height:auto; max-height:80vh; display:block;
  background:#fff; border:1px solid var(--rule); border-radius:14px; }
@media (max-width:1000px){ .video-fig{ width:100%; } }

/* region analysis: two rows of four, each partition over the motion it produces */
.cmp .panels.regions{ grid-template-columns:repeat(4,1fr); }
@media (max-width:700px){ .cmp .panels.regions{ grid-template-columns:repeat(2,1fr); } }

/* a single-card grid that should not run the full page width */
.cmp-grid.narrow-card{ max-width:1100px; margin-inline:auto; }

/* ---------- phones and small tablets --------------------------------------- */
/* The page is authored at a doubled root size for big displays. On a narrow screen that
   leaves a few words per line, and the 3rem gutters eat a quarter of the width, so the root
   size and the gutters come back down and the wide card grids fold to two columns. */
@media (max-width:900px){
  html{ font-size:125%; }
  .wrap{ width:calc(100% - 1.5rem); }
  .tabs{ gap:.4rem; }
  .cmp .panels, .cmp .panels.four, .cmp .panels.six{ grid-template-columns:repeat(2,1fr); }
  .cmp .panels.two{ grid-template-columns:repeat(2,1fr); }
  .video-fig{ width:100%; }
}
@media (max-width:520px){
  html{ font-size:105%; }
  .wrap{ width:calc(100% - 1rem); }
  .tabs{ grid-auto-flow:row; grid-template-columns:1fr; }
  .words{ grid-template-columns:1fr; }
  .cmp .prompt{ font-size:.86rem; }
  .pager-btn{ width:2.1rem; height:2.1rem; font-size:1.2rem; }
}

/* Further Analysis: the whole card is shown at 70% of the column, so these sit quieter
   than the result galleries */
#analysis-speed .cmp-grid,
#analysis-interaction .cmp-grid,
#analysis-harmonic .cmp-grid,
#analysis-regions .cmp-grid{ width:70%; margin-inline:auto; }
@media (max-width:900px){
  #analysis-speed .cmp-grid,
  #analysis-interaction .cmp-grid,
  #analysis-harmonic .cmp-grid,
  #analysis-regions .cmp-grid{ width:100%; }
}

/* ---------- bibtex -------------------------------------------------------- */
pre.bib{
  background:var(--card); border:1px solid var(--rule); border-radius:12px;
  padding:1.1rem 1.25rem; overflow-x:auto; margin:0;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:.79rem; line-height:1.6; color:var(--ink-2);
}

footer{ padding-block:2.5rem 4rem; border-top:1px solid var(--rule); color:var(--ink-3); font-size:.8rem; }

.note{ font-size:.78rem; color:var(--ink-3); margin-top:1rem; }
.empty{ padding:3rem 1rem; text-align:center; color:var(--ink-3); font-size:.9rem; }
