/* ClickLatch — clicklatch.app
   Hand-written, no build step: what is here is what Cloudflare serves.
   Colours come from the app icon (Scripts/make-icon.swift): a slate plate and a
   white ring, which is why the accent is simply white. */

:root {
  color-scheme: dark light;

  --bg: #0f1116;
  --bg-2: #14171f;
  --surface: rgba(255, 255, 255, 0.045);
  --surface-2: rgba(255, 255, 255, 0.07);
  --line: rgba(255, 255, 255, 0.10);
  --line-strong: rgba(255, 255, 255, 0.18);
  --text: #eceff5;
  --muted: #9aa2b1;
  --accent: #8fb0ff;
  --ring: #ffffff;
  /* The ring itself is white in both themes, the way the app draws it — its
     dark halo is what keeps it readable. Interface borrowings of the shape
     need a colour that survives a light background, hence the second token. */
  --ring-ui: #ffffff;
  --btn-bg: #ffffff;
  --btn-fg: #14161c;
  --shadow: 0 20px 50px rgba(0, 0, 0, 0.45);

  --wrap: 1120px;
  --radius: 14px;
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto,
          Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #f7f8fa;
    --bg-2: #ffffff;
    --surface: rgba(15, 17, 22, 0.035);
    --surface-2: rgba(15, 17, 22, 0.06);
    --line: rgba(15, 17, 22, 0.10);
    --line-strong: rgba(15, 17, 22, 0.20);
    --text: #171a21;
    --muted: #5c6474;
    --accent: #2f5fd0;
    --btn-bg: #171a21;
    --btn-fg: #ffffff;
    --ring-ui: #171a21;
    --shadow: 0 18px 40px rgba(15, 17, 22, 0.12);
  }
}

* { box-sizing: border-box; }

/* The bar is sticky, so an anchor jump has to stop short of it. */
section[id] { scroll-margin-top: 78px; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { line-height: 1.15; letter-spacing: -0.02em; margin: 0 0 0.5em; }
h1 { font-size: clamp(2.2rem, 5.2vw, 3.5rem); font-weight: 700; }
h2 { font-size: clamp(1.6rem, 3.2vw, 2.25rem); font-weight: 650; }
h3 { font-size: 1.06rem; font-weight: 650; }
p { margin: 0 0 1em; }
a { color: inherit; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
a:hover { text-decoration-color: currentColor; }

code {
  font-family: var(--mono);
  font-size: 0.88em;
  background: var(--surface-2);
  border-radius: 5px;
  padding: 0.1em 0.35em;
}

kbd {
  font-family: var(--font);
  font-size: 0.82em;
  border: 1px solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: 0.05em 0.4em;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--btn-bg);
  color: var(--btn-fg);
  padding: 0.6em 1em;
  z-index: 10;
}
.skip:focus { left: 0.5rem; top: 0.5rem; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 24px;
}
.wrap-narrow { max-width: 760px; }

/* Buttons ---------------------------------------------------------------- */

.button {
  display: inline-block;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-weight: 600;
  font-size: 1rem;
  padding: 0.72em 1.35em;
  border-radius: 10px;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.button:hover { opacity: 0.88; }
.button:active { transform: translateY(1px); }

.button-quiet {
  background: transparent;
  color: var(--text);
  border-color: var(--line-strong);
}
.button-quiet:hover { background: var(--surface); opacity: 1; }

.button-small { padding: 0.45em 0.95em; font-size: 0.92rem; }

@media (prefers-reduced-motion: reduce) {
  .button { transition: none; }
}

/* Nav -------------------------------------------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 5;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid var(--line);
}
.nav-inner {
  display: flex;
  align-items: center;
  gap: 24px;
  height: 62px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 650;
  letter-spacing: -0.01em;
  text-decoration: none;
}
.brand img { display: block; border-radius: 7px; }
.nav-links {
  margin-left: auto;
  display: flex;
  gap: 22px;
  font-size: 0.94rem;
  color: var(--muted);
}
.nav-links a { text-decoration: none; }
.nav-links a:hover { color: var(--text); }

@media (max-width: 900px) {
  .nav-links { gap: 16px; font-size: 0.9rem; }
}
@media (max-width: 700px) {
  .nav-links { display: none; }
  .nav-inner .button-small { margin-left: auto; }
}

/* Hero ------------------------------------------------------------------- */

.hero {
  padding: clamp(48px, 8vw, 96px) 0 clamp(40px, 6vw, 72px);
  background:
    radial-gradient(1000px 460px at 15% -10%, rgba(143, 176, 255, 0.10), transparent 65%),
    linear-gradient(180deg, var(--bg-2), var(--bg));
  border-bottom: 1px solid var(--line);
}
.hero-inner {
  display: grid;
  gap: clamp(32px, 5vw, 56px);
  align-items: center;
}
@media (min-width: 940px) {
  .hero-inner { grid-template-columns: 1.05fr 1fr; }
}

.hero-mark {
  position: relative;
  width: fit-content;
  margin: 0 0 22px;
}
.hero-mark img {
  display: block;
  position: relative;
  border-radius: 19px;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.35);
}
/* A soft glow behind the icon, the same blue the hero background uses. */
.hero-mark::before {
  content: "";
  position: absolute;
  inset: -26%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(143, 176, 255, 0.35), transparent 72%);
  z-index: 0;
}

.eyebrow {
  font-size: 0.83rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1.1em;
}
.lead { font-size: 1.13rem; color: var(--muted); max-width: 34em; }
.cta { display: flex; flex-wrap: wrap; gap: 12px; margin: 1.6em 0 1em; }
.meta { font-size: 0.92rem; color: var(--muted); margin: 0; }

/* The demo --------------------------------------------------------------- */

.demo { margin: 0; }

.pad {
  position: relative;
  overflow: hidden;
  min-height: 300px;
  padding: 26px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  box-shadow: var(--shadow);
  transition: border-color 0.2s ease, background 0.2s ease;
}
.pad, .pad * { cursor: default; }
.pad-text {
  margin: 0;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--muted);
  max-width: 40em;
}
.pad.is-locked { border-color: var(--ring-ui); }
.pad.is-locked .pad-text { color: var(--text); }

.pad-hint {
  position: absolute;
  right: 14px;
  bottom: 10px;
  margin: 0;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  user-select: none;
  pointer-events: none;
}

.ring {
  position: absolute;
  left: 0;
  top: 0;
  width: 84px;
  height: 84px;
  margin: -42px 0 0 -42px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s linear;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55));
}
.ring.is-visible { opacity: 1; }
.ring circle { fill: none; }
.ring-shadow { stroke: rgba(0, 0, 0, 0.35); stroke-width: 11; }
.ring-arc {
  stroke: var(--ring);
  stroke-width: 8;
  stroke-linecap: butt;
  stroke-dasharray: 0 251.33;
}

.ring.is-pulsing .ring-arc { animation: ring-pulse 220ms ease-out; }

/* The swell the app performs the moment the button lockes: 1.7x and back. */
@keyframes ring-pulse {
  50% { stroke-width: 13.6; }
}

@media (prefers-reduced-motion: reduce) {
  .ring { transition: none; }
  .ring.is-pulsing .ring-arc { animation: none; }
}

.pad-controls { margin-top: 14px; }
.slider {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.9rem;
  color: var(--muted);
}
.slider input { flex: 1; accent-color: var(--accent); }
.slider output { font-variant-numeric: tabular-nums; min-width: 5.5em; text-align: right; }
.pad-status {
  margin: 10px 0 4px;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  min-height: 1.5em;
}
.pad-help { margin: 0; font-size: 0.88rem; color: var(--muted); }

/* Strip ------------------------------------------------------------------ */

.strip { padding: clamp(36px, 5vw, 56px) 0; border-bottom: 1px solid var(--line); }
.strip-grid { display: grid; gap: 28px; }
@media (min-width: 720px) { .strip-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .strip-grid { grid-template-columns: repeat(4, 1fr); } }
.strip h2 { font-size: 0.98rem; font-weight: 650; letter-spacing: -0.01em; }
.strip p { margin: 0; font-size: 0.94rem; color: var(--muted); }

/* Sections --------------------------------------------------------------- */

.section { padding: clamp(64px, 9vw, 112px) 0; }
.section-alt { background: var(--bg-2); border-block: 1px solid var(--line); }
.section-eyebrow {
  margin: 0 0 0.9em;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.section-title { margin-bottom: 0.7em; }
.section-lead { color: var(--muted); max-width: 46em; margin-bottom: 2.2em; }

.cards { display: grid; gap: 18px; }
@media (min-width: 700px) { .cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .cards { grid-template-columns: repeat(3, 1fr); } }
.card {
  padding: 26px 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  transition: border-color 0.2s ease, transform 0.2s ease;
}
.card:hover { border-color: var(--line-strong); transform: translateY(-2px); }

/* One badge treatment for every icon on the page. The glyphs are line art at a
   single weight so six of them together read as one set. */
.icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-bottom: 16px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--surface-2);
  color: var(--text);
}
.icon svg { width: 21px; height: 21px; }
.icon svg, .strip-icon svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon svg .fill, .strip-icon svg .fill { fill: currentColor; stroke: none; }

.strip-icon { display: block; margin-bottom: 12px; color: var(--muted); }
.strip-icon svg { width: 20px; height: 20px; }

@media (prefers-reduced-motion: reduce) {
  .card, .card:hover { transition: none; transform: none; }
}
.card p { margin: 0; color: var(--muted); font-size: 0.96rem; }

/* The mechanism diagram ---------------------------------------------------
   Inline SVG so it takes the page's colour tokens and its font. It scrolls
   sideways rather than shrinking: below about 700 px the labels would stop
   being readable, which defeats the point of drawing it. */

.diagram { margin: 0 0 40px; }
.diagram-scroll {
  overflow-x: auto;
  padding: 4px 0 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.diagram svg {
  display: block;
  width: 100%;
  min-width: 700px;
  height: auto;
  font-family: var(--font);
}
@media (max-width: 780px) {
  .diagram-scroll {
    -webkit-mask-image: linear-gradient(90deg, #000 0 88%, transparent);
    mask-image: linear-gradient(90deg, #000 0 88%, transparent);
  }
}

.diagram figcaption {
  margin-top: 16px;
  color: var(--muted);
  font-size: 0.94rem;
  max-width: 48em;
}

.dg-grid line { stroke: var(--line); stroke-width: 1; stroke-dasharray: 3 5; }
.dg-lane { fill: var(--surface-2); }
.dg-lane-key { fill: color-mix(in srgb, var(--accent) 12%, transparent); }

.dg-tick text {
  fill: var(--muted);
  font-size: 13px;
  font-weight: 550;
  text-anchor: middle;
}
.dg-row text {
  fill: var(--text);
  font-size: 14px;
  font-weight: 600;
  text-anchor: end;
}
.dg-note {
  fill: var(--muted);
  font-size: 12.5px;
  text-anchor: middle;
}
.dg-note-start { text-anchor: start; }
.dg-note-end { text-anchor: end; }

.dg-hold { fill: var(--line-strong); }
.dg-loose { stroke: var(--line-strong); stroke-width: 2; stroke-dasharray: 2 7; stroke-linecap: round; }
.dg-dot { fill: var(--text); }
.dg-dot-open { fill: var(--bg); stroke: var(--text); stroke-width: 2.5; }

.dg-ring circle, .dg-ring path {
  fill: none;
  stroke: var(--ring-ui);
  stroke-width: 2.5;
  stroke-linecap: round;
}
.dg-ring circle { stroke: var(--line-strong); }
.dg-ring .dg-ring-full { stroke: var(--ring-ui); }

.dg-pill rect { fill: var(--ring-ui); }
.dg-pill text {
  fill: var(--bg);
  font-size: 14px;
  font-weight: 700;
  text-anchor: middle;
}

.dg-playhead { opacity: 0; }
.dg-playhead line { stroke: var(--ring-ui); stroke-width: 1.5; stroke-dasharray: 4 5; opacity: 0.55; }
.dg-playhead circle { fill: var(--ring-ui); }

.dg-down { fill: var(--accent); }
.dg-key-dot { fill: var(--accent); }
.dg-key-label {
  fill: var(--accent);
  font-size: 13px;
  font-weight: 600;
  text-anchor: middle;
}

.steps {
  list-style: none;
  margin: 0 0 44px;
  padding: 0;
  display: grid;
  gap: 18px;
}
@media (min-width: 860px) { .steps { grid-template-columns: repeat(3, 1fr); } }
.steps li {
  position: relative;
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.step-n {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-bottom: 14px;
  border-radius: 50%;
  border: 2px solid var(--ring-ui);
  font-size: 0.85rem;
  font-weight: 650;
  color: var(--text);
}
.steps p { margin: 0; color: var(--muted); font-size: 0.95rem; }

.notes { display: grid; gap: 18px; }
@media (min-width: 860px) { .notes { grid-template-columns: repeat(2, 1fr); } }
.note {
  padding: 20px 22px;
  border-left: 2px solid var(--line-strong);
  background: var(--surface);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.note p { margin: 0; color: var(--muted); font-size: 0.95rem; }

/* Tabs (screenshots and install) ----------------------------------------- */

.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 20px;
  padding: 5px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--surface);
  width: fit-content;
  max-width: 100%;
}
.tabs button {
  font: inherit;
  font-size: 0.92rem;
  font-weight: 550;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: 7px;
  padding: 0.42em 0.9em;
  cursor: pointer;
}
.tabs button:hover { color: var(--text); }
.tabs button[aria-selected="true"] {
  background: var(--surface-2);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--line);
}

/* The settings window is a 480 pt portrait panel and the menu is smaller again,
   so the shots sit on a stage at their own size instead of being stretched
   across the column. */
.stage {
  display: grid;
  place-items: center;
  padding: clamp(24px, 4vw, 52px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background:
    radial-gradient(600px 320px at 50% 0%, rgba(143, 176, 255, 0.10), transparent 70%),
    var(--surface);
}
.stage img {
  display: block;
  width: auto;
  max-width: min(100%, 480px);
  height: auto;
  border-radius: 10px;
  box-shadow: var(--shadow);
}
.shot p { margin: 16px 0 0; color: var(--muted); font-size: 0.94rem; }
.aside { margin-top: 28px; color: var(--muted); font-size: 0.94rem; }

/* Install ---------------------------------------------------------------- */

.install-steps { margin: 0; padding-left: 1.3em; }
.install-steps > li { margin-bottom: 1.8em; }
.install-steps > li::marker { color: var(--muted); font-variant-numeric: tabular-nums; }
.panel { max-width: 62em; }
.panel > p { color: var(--muted); }
.panel strong { color: var(--text); }

.code {
  position: relative;
  margin: 0 0 1.2em;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--bg);
  overflow: hidden;
}
.code pre {
  margin: 0;
  padding: 16px 84px 16px 18px;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: 0.86rem;
  line-height: 1.7;
}
.code code { background: none; padding: 0; font-size: inherit; }
.copy {
  position: absolute;
  top: 10px;
  right: 10px;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 7px;
  padding: 0.25em 0.7em;
  cursor: pointer;
}
.copy:hover { color: var(--text); }

.callout {
  margin-top: 36px;
  padding: 24px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
}
.callout h3 { margin-bottom: 0.6em; }
.callout p { color: var(--muted); }
.callout p:last-child { margin-bottom: 0; }

/* FAQ -------------------------------------------------------------------- */

details {
  border-bottom: 1px solid var(--line);
  padding: 4px 0;
}
summary {
  cursor: pointer;
  padding: 16px 0;
  font-weight: 600;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 12px;
}
summary::-webkit-details-marker { display: none; }
summary::before {
  content: "+";
  font-weight: 400;
  font-size: 1.2em;
  color: var(--muted);
  width: 1em;
  text-align: center;
}
details[open] summary::before { content: "–"; }
details p { color: var(--muted); margin: 0 0 16px; padding-left: calc(1em + 12px); font-size: 0.96rem; }

/* Closing and footer ----------------------------------------------------- */

.closing {
  padding: clamp(60px, 9vw, 110px) 0;
  text-align: center;
  background:
    radial-gradient(700px 320px at 50% 120%, rgba(143, 176, 255, 0.12), transparent 70%),
    var(--bg-2);
  border-top: 1px solid var(--line);
}
.closing p { color: var(--muted); }
.closing .cta { justify-content: center; }

.footer { padding: 32px 0 48px; border-top: 1px solid var(--line); }
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  justify-content: space-between;
  font-size: 0.92rem;
  color: var(--muted);
}
.footer p { margin: 0; }

/* Someone who asks the system for more contrast gets firmer borders and body
   text at full strength instead of the muted grey. */
@media (prefers-contrast: more) {
  :root {
    --muted: #c8cedb;
    --line: rgba(255, 255, 255, 0.24);
    --line-strong: rgba(255, 255, 255, 0.42);
  }
  @media (prefers-color-scheme: light) {
    :root {
      --muted: #333a47;
      --line: rgba(15, 17, 22, 0.28);
      --line-strong: rgba(15, 17, 22, 0.48);
    }
  }
  .pad-hint { color: var(--text); }
  .card, .steps li, .stage, .diagram-scroll { border-width: 1px; }
}

/* Motion -------------------------------------------------------------------
   All of it lives behind prefers-reduced-motion, and all of it is CSS: the
   reveals use scroll-driven timelines rather than a class toggled by script, so
   nothing has to start hidden and nothing flashes if the JavaScript is slow or
   blocked. Browsers without view() timelines simply play each animation once on
   load, which nobody sees for content below the fold. */

@media (prefers-reduced-motion: no-preference) {

  @keyframes rise {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: none; }
  }

  @keyframes halo {
    0%, 100% { opacity: 0.55; transform: scale(1); }
    50%      { opacity: 0.9;  transform: scale(1.09); }
  }

  /* The hero arrives in one short stagger, top to bottom. */
  .hero-mark,
  .hero-copy .eyebrow,
  .hero-copy h1,
  .hero-copy .lead,
  .hero-copy .cta,
  .hero-copy .meta,
  .demo {
    animation: rise 0.75s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
  .hero-mark          { animation-delay: 0.02s; }
  .hero-copy .eyebrow { animation-delay: 0.10s; }
  .hero-copy h1       { animation-delay: 0.16s; }
  .hero-copy .lead    { animation-delay: 0.24s; }
  .hero-copy .cta     { animation-delay: 0.32s; }
  .hero-copy .meta    { animation-delay: 0.38s; }
  .demo               { animation-delay: 0.30s; animation-duration: 0.9s; }

  .hero-mark::before {
    animation: halo 7s ease-in-out 1.2s infinite;
  }

  /* Everything below the fold arrives as it scrolls in. */
  .strip-grid > *,
  .card,
  .steps li,
  .note,
  .diagram,
  .shots,
  .stage,
  .panel,
  .callout,
  details,
  .closing h2,
  .closing p {
    animation: rise 0.6s ease-out both;
    animation-timeline: view();
    animation-range: entry 8% cover 24%;
  }

  /* The diagram, scrubbed by the scroll ------------------------------------
     One named view timeline on the figure, referenced by everything inside it,
     so the whole sequence stays in step: scrolling moves the playhead from the
     press to the closing click, and each stage appears exactly as it passes.

     The timing lives in keyframe percentages rather than delays, because a
     progress-based timeline ignores time delays — and because it means the
     fallback, where scroll-driven timelines are unsupported and the same
     keyframes simply play once, is choreographed identically. Each percentage
     below is where that mark sits along the timeline: the ring at x = 272 and
     335, the threshold at 400, letting go at 530, the move at 690, the click
     at 850, out of a track that runs 210 to 850. */

  .diagram {
    view-timeline-name: --dg;
    view-timeline-axis: block;
  }

  .dg-playhead,
  .dg-hold,
  .dg-down,
  .dg-loose,
  .dg-dot-open,
  .dg-ring circle,
  .dg-ring path,
  .dg-pill g,
  .dg-key-label,
  .dg-note.at-press,
  .dg-note.at-early,
  .dg-note.at-move,
  .dg-note.at-release,
  .dg-note.at-click,
  .dg-dot.at-click,
  .dg-key-dot.at-click {
    animation-duration: 2.8s;
    animation-fill-mode: both;
    animation-timing-function: linear;
    animation-timeline: --dg;
    /* Starts as the figure peeks in at the bottom and finishes while it is
       still in the upper half, so a reader who stops scrolling is looking at a
       finished diagram rather than half of one. */
    animation-range: cover 15% cover 50%;
  }

  .dg-hold, .dg-down, .dg-loose {
    transform-box: fill-box;
    transform-origin: left center;
  }
  .dg-pill g, .dg-dot-open, .dg-ring circle, .dg-ring path,
  .dg-dot.at-click, .dg-key-dot.at-click, .dg-note, .dg-key-label {
    transform-box: fill-box;
    transform-origin: center;
  }

  @keyframes dg-sweep {
    0%   { transform: translateX(210px); opacity: 0; }
    4%   { opacity: 1; }
    95%  { opacity: 1; }
    100% { transform: translateX(850px); opacity: 0; }
  }
  @keyframes dg-hold {
    0%   { transform: scaleX(0); }
    50%  { transform: scaleX(1); }
    100% { transform: scaleX(1); }
  }
  @keyframes dg-down {
    from { transform: scaleX(1e-5); }
    to   { transform: scaleX(1); }
  }
  @keyframes dg-loose {
    0%, 50%   { opacity: 0; }
    58%, 100% { opacity: 1; }
  }

  /* One stage each: hidden, then a small pop as the playhead arrives. */
  @keyframes dg-s1 { 0%, 4%  { opacity: 0; transform: scale(0.86); } 12%, 100% { opacity: 1; transform: scale(1); } }
  @keyframes dg-s2 { 0%, 16% { opacity: 0; transform: scale(0.86); } 24%, 100% { opacity: 1; transform: scale(1); } }
  @keyframes dg-s3 { 0%, 26% { opacity: 0; transform: scale(0.86); } 34%, 100% { opacity: 1; transform: scale(1); } }
  @keyframes dg-s4 { 0%, 46% { opacity: 0; transform: scale(0.86); } 55%, 100% { opacity: 1; transform: scale(1); } }
  @keyframes dg-s5 { 0%, 71% { opacity: 0; transform: scale(0.86); } 79%, 100% { opacity: 1; transform: scale(1); } }
  @keyframes dg-s6 { 0%, 78% { opacity: 0; transform: scale(0.86); } 87%, 100% { opacity: 1; transform: scale(1); } }
  @keyframes dg-s7 { 0%, 92% { opacity: 0; transform: scale(0.86); } 100%     { opacity: 1; transform: scale(1); } }

  .dg-playhead { animation-name: dg-sweep; }
  .dg-hold     { animation-name: dg-hold; }
  .dg-down     { animation-name: dg-down; }
  .dg-loose    { animation-name: dg-loose; }

  .dg-ring .at-press,   .dg-note.at-press   { animation-name: dg-s1; }
  .dg-ring .at-early,   .dg-note.at-early   { animation-name: dg-s2; }
  .dg-ring .at-threshold                    { animation-name: dg-s3; }
  .dg-dot-open,
  .dg-pill .at-release, .dg-note.at-release { animation-name: dg-s4; }
  .dg-pill .at-move,    .dg-note.at-move    { animation-name: dg-s5; }
  .dg-key-label                             { animation-name: dg-s6; }
  .dg-pill .at-click,   .dg-note.at-click,
  .dg-dot.at-click,     .dg-key-dot.at-click { animation-name: dg-s7; }

  /* A quiet lift under the bar once the page has moved at all. */
  .nav { transition: box-shadow 0.25s ease, border-color 0.25s ease; }
  .nav.is-scrolled {
    border-bottom-color: var(--line-strong);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.22);
  }
}
