/* AZIDI Football Academy - preview
   Black, white and #5F299B, taken from their badge file. The purple is deep,
   so it carries flat fields and never small text. Contrast comes from white
   on black and black on purple. No gradients anywhere, on purpose. */

:root {
  --ink:       #0A090D;
  --ink-2:     #131019;
  --ink-3:     #1C1726;
  --purple:    #5F299B;
  --purple-dp: #431A73;
  --chalk:     #F4F1F7;
  --chalk-mid: rgba(244, 241, 247, 0.72);
  --chalk-dim: rgba(244, 241, 247, 0.46);
  --hair:      rgba(244, 241, 247, 0.16);

  --display: "Chivo", "Arial Black", sans-serif;
  --body:    "Manrope", "Segoe UI", sans-serif;

  --gutter: clamp(20px, 5vw, 64px);
  --wide:   1240px;
  --out:    cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--chalk-mid);
  font-family: var(--body);
  font-size: 1.05rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 900;
  color: var(--chalk);
  line-height: 0.98;
  letter-spacing: -0.035em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1rem; max-width: 62ch; }
a { color: var(--chalk); }

:focus-visible { outline: 2px solid var(--chalk); outline-offset: 3px; }

.wrap { max-width: var(--wide); margin-inline: auto; }

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: var(--gutter); top: 12px; z-index: 80;
  background: var(--chalk); color: var(--ink); padding: 0.6rem 1rem;
}

/* ---------- header ---------- */

.site {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(12px, 2.2vw, 32px);
  padding: 0.7rem var(--gutter);
  background: rgba(10, 9, 13, 0.92);
  border-bottom: 1px solid var(--hair);
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  text-decoration: none;
  margin-right: auto;
}
.brand img { width: 38px; height: 38px; }
.brand span {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.02rem;
  letter-spacing: 0.02em;
  color: var(--chalk);
}

.site-nav { display: flex; gap: clamp(12px, 1.8vw, 26px); }
.site-nav a {
  text-decoration: none;
  font-size: 0.84rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--chalk-mid);
  padding-block: 0.35rem;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  transition: color 0.2s, border-color 0.2s;
}
.site-nav a:hover { color: var(--chalk); border-bottom-color: var(--purple); }
.site-nav a[aria-current="page"] { color: var(--chalk); border-bottom-color: var(--purple); }

.menu-btn { display: none; }

/* ---------- buttons ---------- */

.btn {
  display: inline-block;
  background: var(--purple);
  color: var(--chalk);
  font-family: var(--display);
  font-weight: 800;
  font-size: 0.86rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 1.05rem 1.8rem;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.25s var(--out), transform 0.25s var(--out);
}
.btn:hover { background: var(--purple-dp); transform: translateY(-2px); }
.btn-sm { padding: 0.6rem 1.05rem; font-size: 0.74rem; }

.btn-line {
  background: none;
  color: var(--chalk);
  border: 2px solid var(--chalk);
}
.btn-line:hover { background: var(--chalk); color: var(--ink); }

.btn-ink {
  background: var(--ink);
  color: var(--chalk);
}
.btn-ink:hover { background: var(--ink-3); }

/* ---------- hero ---------- */

.hero {
  position: relative;
  overflow: hidden;
  padding: clamp(56px, 9vh, 116px) var(--gutter) clamp(30px, 4.5vh, 54px);
}
.hero-mark {
  position: absolute;
  top: 50%;
  right: clamp(-220px, -14vw, -90px);
  translate: 0 -50%;
  width: clamp(420px, 46vw, 760px);
  opacity: 0.11;
  pointer-events: none;
  user-select: none;
}
.hero-inner { position: relative; max-width: var(--wide); margin-inline: auto; }

.eyebrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  margin-bottom: 1.6rem;
}
.eyebrow b {
  font-weight: 600;
  color: var(--chalk);
  background: var(--purple);
  padding: 0.34rem 0.7rem;
  border-radius: 999px;
  letter-spacing: 0.14em;
}

h1 {
  font-size: clamp(2.6rem, 9.2vw, 7.4rem);
  font-weight: 900;
  max-width: 14ch;
}
.outline {
  color: transparent;
  -webkit-text-stroke: clamp(1.5px, 0.28vw, 3px) var(--chalk);
  text-stroke: clamp(1.5px, 0.28vw, 3px) var(--chalk);
}

.lede {
  font-size: clamp(1.05rem, 1.55vw, 1.32rem);
  max-width: 48ch;
  margin-top: 1.9rem;
  color: var(--chalk-mid);
}

.actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(12px, 1.6vw, 20px);
  margin-top: 2.3rem;
}

/* ---------- section furniture ---------- */

section { padding-inline: var(--gutter); }

.block { padding-block: clamp(52px, 8vw, 110px); }
.block-tight { padding-block: clamp(34px, 5vw, 62px); }
.block-lift { background: var(--ink-2); }

.kicker {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  margin: 0 0 1.4rem;
}
.kicker::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--hair);
}

.section-title {
  font-size: clamp(1.9rem, 5vw, 3.6rem);
  max-width: 17ch;
  margin-bottom: clamp(28px, 4vw, 52px);
}

/* ---------- ruled list ---------- */

.rows { list-style: none; margin: 0; padding: 0; }
.rows li {
  display: grid;
  grid-template-columns: minmax(54px, 92px) 1fr;
  gap: clamp(16px, 3vw, 44px);
  border-top: 1px solid var(--hair);
  padding-block: clamp(26px, 3.6vw, 44px);
}
.rows li:last-child { border-bottom: 1px solid var(--hair); }
.rows .n {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.1rem, 2vw, 1.5rem);
  color: var(--purple);
  letter-spacing: 0;
}
.rows h3 { font-size: clamp(1.25rem, 2.4vw, 1.95rem); margin-bottom: 0.65rem; }
.rows p { margin: 0; }

.more {
  display: inline-block;
  margin-top: 1rem;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--chalk);
  text-decoration: none;
  border-bottom: 2px solid var(--purple);
  padding-bottom: 3px;
  transition: border-color 0.25s;
}
.more:hover { border-bottom-color: var(--chalk); }

/* ---------- fact strip ---------- */

.facts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px;
  background: var(--hair);
  border: 1px solid var(--hair);
}
.facts li { background: var(--ink); padding: clamp(20px, 2.6vw, 30px); }
.facts dt {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  margin-bottom: 0.5rem;
}
.facts dd {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(0.98rem, 1.6vw, 1.2rem);
  color: var(--chalk);
  letter-spacing: -0.02em;
}
.block-lift .facts li { background: var(--ink-2); }

/* ---------- purple slab ---------- */

.slab {
  background: var(--purple);
  color: var(--chalk);
  padding-block: clamp(56px, 9vw, 120px);
  position: relative;
  overflow: hidden;
}
.slab-mark {
  position: absolute;
  bottom: -18%;
  left: -6%;
  width: clamp(280px, 34vw, 520px);
  opacity: 0.16;
  filter: brightness(0);
  pointer-events: none;
}
.slab .inner { position: relative; max-width: var(--wide); margin-inline: auto; }
.slab h2 { font-size: clamp(2.1rem, 6.4vw, 4.6rem); max-width: 15ch; }
.slab p { color: rgba(244, 241, 247, 0.88); font-size: clamp(1.02rem, 1.5vw, 1.24rem); margin-top: 1.2rem; }
.slab .kicker { color: rgba(244, 241, 247, 0.72); }
.slab .kicker::after { background: rgba(244, 241, 247, 0.3); }

/* ---------- split feature ---------- */

.split {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(28px, 5vw, 76px);
  align-items: center;
  max-width: var(--wide);
  margin-inline: auto;
}
.split-art {
  position: relative;
  aspect-ratio: 4 / 5;
  background: var(--ink);
  border: 1px solid var(--purple);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.split-art img {
  width: 132%;
  max-width: none;
  opacity: 0.92;
  transform: rotate(-8deg);
}
.split-art::after {
  content: attr(data-note);
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 0.85rem 1rem;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  background: var(--ink);
  border-top: 1px solid var(--purple);
  text-align: center;
}

/* ---------- bolt divider ---------- */

.bolts {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: clamp(26px, 6vw, 72px);
  padding-block: clamp(18px, 2.6vw, 34px);
}
.bolts img {
  height: clamp(74px, 9.5vw, 132px);
  width: auto;
  opacity: 0.9;
}
.bolts img:nth-child(1) { transform: rotate(-10deg); }
.bolts img:nth-child(2) { transform: scaleX(-1) rotate(-10deg); }

/* ---------- pill list ---------- */

.pills { display: flex; flex-wrap: wrap; gap: 10px; list-style: none; margin: 0; padding: 0; }
.pills li {
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.76rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--chalk);
  border: 1px solid var(--hair);
  border-radius: 999px;
  padding: 0.55rem 1rem;
  transition: border-color 0.25s;
}
.pills li:hover { border-color: var(--purple); }
.pills a { text-decoration: none; color: inherit; }

/* ---------- page head ---------- */

.page-head {
  position: relative;
  overflow: hidden;
  padding: clamp(44px, 7vh, 88px) var(--gutter) clamp(32px, 5vh, 58px);
  border-bottom: 1px solid var(--hair);
}
.page-head h1 { font-size: clamp(2.2rem, 6.6vw, 5rem); max-width: 16ch; }
.page-head .lede { margin-top: 1.3rem; }

/* ---------- contact ---------- */

.ways {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1px;
  background: var(--hair);
  border: 1px solid var(--hair);
  margin-top: clamp(28px, 4vw, 48px);
}
.ways a, .ways div {
  background: var(--ink);
  padding: clamp(20px, 2.6vw, 30px);
  text-decoration: none;
  display: block;
  transition: background 0.25s var(--out);
}
.ways a:hover { background: var(--purple); }
.ways span {
  display: block;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  margin-bottom: 0.5rem;
}
.ways a:hover span { color: rgba(244, 241, 247, 0.8); }
.ways b {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(0.95rem, 1.5vw, 1.15rem);
  color: var(--chalk);
  letter-spacing: -0.02em;
  overflow-wrap: break-word;
}

/* ---------- footer ---------- */

.site-foot {
  background: var(--ink-2);
  border-top: 1px solid var(--hair);
  padding: clamp(48px, 7vw, 84px) var(--gutter) clamp(28px, 4vw, 40px);
}
.foot-top {
  max-width: var(--wide);
  margin-inline: auto;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(24px, 5vw, 70px);
  align-items: start;
}
.foot-badge { width: clamp(84px, 11vw, 118px); }
.foot-line {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.3rem, 3.4vw, 2.4rem);
  color: var(--chalk);
  letter-spacing: -0.035em;
  line-height: 1;
  margin: 0 0 1.6rem;
  max-width: 16ch;
}
.foot-nav, .social { display: flex; flex-wrap: wrap; gap: clamp(12px, 2vw, 24px); }
.foot-nav { margin-bottom: 1rem; }
.foot-nav a, .social a {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--chalk-mid);
  text-decoration: none;
}
.foot-nav a:hover, .social a:hover { color: var(--chalk); }
.social a { border-bottom: 2px solid var(--purple); padding-bottom: 2px; }
.copy {
  max-width: var(--wide);
  margin: clamp(32px, 5vw, 56px) auto 0;
  padding-top: 1.2rem;
  border-top: 1px solid var(--hair);
  font-size: 0.78rem;
  color: var(--chalk-dim);
}

/* ---------- motion ---------- */

/* Motion budget, set for the slowest phone we expect:
   only transform and opacity are ever animated, so every frame is handled by
   the compositor and never triggers layout or paint. No JavaScript drives any
   animation. At most two elements move continuously on a page, and both are
   promoted to their own layer once, up front. */

@keyframes turn { to { transform: rotate(1turn); } }

/* The ornament is 4-fold symmetric, so a slow turn reads as drift, not spin.
   .hero-mark centres itself with the separate `translate` property, which is
   why an animated `transform` here does not fight it. */
.hero-mark,
.slab-mark {
  animation: turn 120s linear infinite;
  will-change: transform;
}
.slab-mark { animation-duration: 190s; animation-direction: reverse; }

@keyframes rise {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}
.r1, .r2, .r3, .r4 { opacity: 0; animation: rise 0.9s var(--out) forwards; }
.r1 { animation-delay: 0.05s; }
.r2 { animation-delay: 0.16s; }
.r3 { animation-delay: 0.3s; }
.r4 { animation-delay: 0.42s; }

/* Hidden only when JS runs, so the page still reads with scripts off. */
.js .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.8s var(--out), transform 0.8s var(--out);
}
.js .reveal.in { opacity: 1; transform: none; }

/* Pointer-only flourishes. A touch screen has no hover, so it gets none of
   this and pays nothing for it. */
@media (hover: hover) and (pointer: fine) {
  .brand img { transition: transform 0.6s var(--out); }
  .brand:hover img { transform: rotate(0.25turn); }
  .ways a { transition: background 0.25s var(--out), transform 0.25s var(--out); }
  .ways a:hover { transform: translateY(-2px); }
  .pills li { transition: border-color 0.25s var(--out), transform 0.25s var(--out); }
  .pills li:hover { transform: translateY(-2px); }
  .facts li { transition: transform 0.3s var(--out); }
  .facts li:hover { transform: translateY(-2px); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .r1, .r2, .r3, .r4 { animation: none; opacity: 1; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .hero-mark, .slab-mark { animation: none; will-change: auto; }
  .btn:hover, .brand:hover img, .ways a:hover,
  .pills li:hover, .facts li:hover { transform: none; }
}

/* ---------- responsive ---------- */

@media (max-width: 1000px) {
  .split { grid-template-columns: 1fr; }
  .split-art { aspect-ratio: 16 / 10; max-width: 460px; }
}

@media (max-width: 880px) {
  .site { gap: 9px; }
  .js .menu-btn {
    display: block;
    order: 2;
    background: none;
    border: 1px solid var(--hair);
    color: var(--chalk);
    font-family: var(--display);
    font-weight: 700;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.6rem 0.8rem;
    border-radius: 999px;
    cursor: pointer;
    white-space: nowrap;
  }
  .site .btn-sm { order: 3; padding: 0.6rem 0.9rem; font-size: 0.7rem; }
  .site-nav {
    order: 4;
    flex-basis: 100%;
    flex-direction: column;
    gap: 0;
    padding-top: 0.4rem;
  }
  .js .site-nav[hidden] { display: none; }
  .site-nav a { padding-block: 0.85rem; border-bottom: 1px solid var(--hair); font-size: 0.98rem; }
  .foot-top { grid-template-columns: 1fr; }
}

@media (max-width: 620px) {
  .rows li { grid-template-columns: 1fr; gap: 0.5rem; }
  .actions .btn { width: 100%; text-align: center; }
  .brand span { font-size: 0.92rem; }
  .brand img { width: 32px; height: 32px; }
  .hero-mark { opacity: 0.08; right: -34%; }
}

/* ---------- photography ---------- */
/* Real pictures from the academy's own Instagram. The site was built with a
   placeholder slot for these; the band and the rows picture are new. */

.band {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 2px;
  /* sections carry a gutter; a photo band wants the full width, and without
     this its background paints into that gutter as a pale margin */
  padding-inline: 0;
  background: var(--ink);
  border-block: 1px solid var(--hair);
}

.band figure { margin: 0; overflow: hidden; background: var(--ink-2); }

.band img {
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  display: block;
  /* the pitches are dusty and bright; settle them onto the near-black ground */
  filter: saturate(1.05) contrast(1.04) brightness(0.94);
  transition: transform 0.7s var(--out), filter 0.7s var(--out);
}

.band figure:hover img { transform: scale(1.04); filter: none; }

/* the numbered rows had an empty right column on wide screens */
.rows-art { display: none; }

@media (min-width: 1000px) {
  .block .wrap:has(.rows-art) { position: relative; }

  .rows-art {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
    width: min(30%, 340px);
    margin: 0;
    aspect-ratio: 4 / 5;
    overflow: hidden;
    border: 1px solid var(--purple);
  }

  .rows-art img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    filter: saturate(1.05) brightness(0.92);
  }

  .block .wrap:has(.rows-art) .rows { padding-right: min(34%, 390px); }
}

/* the placeholder slot, now carrying a real photograph */
.split-art.has-photo img {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  opacity: 1;
  transform: none;
  filter: saturate(1.05) brightness(0.95);
}

@media (max-width: 700px) {
  .band { grid-template-columns: repeat(3, 1fr); }
  .band figure:nth-child(n + 4) { display: none; }
}

.band-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 700px) {
  .band-3 { grid-template-columns: repeat(3, 1fr); }
  .band-3 figure:nth-child(n + 4) { display: none; }
}

/* ---------- scroll-driven motion ---------- */

/* Everything below is tied to scroll position rather than to a clock, so the
   page answers the reader instead of playing at them. It is all CSS: the
   browser runs these off the main thread, which is why five photographs can
   drift at once on a cheap phone without dropping the scroll.

   The whole block is gated twice. Browsers without scroll timelines get the
   site exactly as it was, and anyone who has asked for less motion gets the
   static page. Nothing here is load-bearing. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* --- how far down the page you are ------------------------------- */

    /* Drawn on the sticky header, so it costs no markup and is always in
       view. It grows from the left edge as the document scrolls. */
    .site::after {
      content: "";
      position: absolute;
      left: 0;
      right: 0;
      bottom: -1px;
      height: 2px;
      background: var(--purple);
      transform-origin: left center;
      scale: 0 1;
      animation: rail linear both;
      animation-timeline: scroll(root block);
    }
    @keyframes rail { to { scale: 1 1; } }

    /* --- photographs move inside their frames ------------------------ */

    /* The timeline is declared on the frame, not on the picture. A frame
       clips, and `overflow: hidden` makes an element a scroll container, so
       a bare `view()` on the picture measures the picture against the frame
       it is already inside and never moves. Naming the timeline on the frame
       measures the frame against the page, which is the thing that scrolls.
       That cost an hour; leave it named. */
    .band figure,
    .rows-art,
    .split-art { view-timeline-name: --frame; }

    /* Three drifts, alternating, so the band reads as five separate pictures
       passing rather than one wide one sliding.

       `scale` and `translate` are separate properties from `transform`, so
       the hover zoom and the scroll drift run at once without overwriting
       each other.

       Held 12% oversized, so there is 6% of the frame height spare at either
       end. A `translate` percentage resolves against the unscaled box, so the
       drifts below stay just inside that. Any more zoom and the crop starts
       eating the picture. */
    .band img,
    .rows-art img,
    .split-art.has-photo img {
      scale: 1.12;
      transform: none;
      animation: drift-down linear both;
      animation-timeline: --frame;
      transition: scale 0.7s var(--out), filter 0.7s var(--out);
    }
    .band figure:nth-child(3n + 2) img { animation-name: drift-up; }
    .band figure:nth-child(3n)     img { animation-name: drift-far; }
    .rows-art img                      { animation-name: drift-up; }

    .band figure:hover img { scale: 1.18; transform: none; }

    @keyframes drift-down { from { translate: 0 -5%;   } to { translate: 0 5%;    } }
    @keyframes drift-up   { from { translate: 0 3.5%;  } to { translate: 0 -3.5%; } }
    @keyframes drift-far  { from { translate: 0 -5.5%; } to { translate: 0 5.5%;  } }

    /* --- the hero hands over to the page ----------------------------- */

    /* .hero clips too, so the same named-timeline trick applies. It fades and
       lifts only on its way out, so the first thing a visitor sees is never
       mid-animation.

       .page-head has to be named as well, not just .hero: the inner pages
       reuse .hero-inner inside it, and an animation whose timeline resolves
       to nothing does not sit idle, it holds its end state. Miss this and
       every inner page loads with its heading at one fifth opacity. */
    .hero,
    .page-head { view-timeline-name: --hero; }
    .hero-inner {
      animation: hero-exit linear both;
      animation-timeline: --hero;
      /* nothing moves until the heading is already a quarter gone, so the
         buttons are never half-faded while they are still the obvious thing
         to click */
      animation-range: exit 25% exit 95%;
    }
    @keyframes hero-exit {
      to { opacity: 0.2; translate: 0 -30px; }
    }

    /* --- blocks arrive with the scroll rather than on a trigger ------- */

    /* This replaces the one-shot fade the script does. An animation beats the
       `.in` class in the cascade, so the script can keep running untouched
       for browsers that land in the fallback.

       The range is stated in `entry`, which assumes these blocks are shorter
       than the viewport. Every .reveal on this site is a list row or a short
       card, so that holds. */
    .js .reveal {
      animation: reveal-rise linear both;
      animation-timeline: view();
      animation-range: entry 8% entry 68%;
    }
    @keyframes reveal-rise {
      from { opacity: 0; transform: translateY(26px); }
      to   { opacity: 1; transform: none; }
    }

    /* The numeral slides in ahead of its row: no fade, so it reads as its own
       gesture inside a block that is already fading. */
    .rows .n {
      animation: n-slide linear both;
      animation-timeline: view();
      animation-range: entry 8% entry 85%;
    }
    @keyframes n-slide {
      from { translate: -16px 0; }
      to   { translate: 0 0; }
    }
  }
}

/* --- pointer flourishes that do not need scroll ---------------------- */

@media (hover: hover) and (pointer: fine) {
  /* The link steps in the direction it is about to take you. `translate` is
     used rather than `transform` so it never fights anything else. */
  .more { transition: border-color 0.25s, translate 0.3s var(--out); }
  .more:hover { translate: 5px 0; }
}

@media (prefers-reduced-motion: reduce) {
  .more:hover { translate: none; }
}
