/* EuroLeague Analytics — launch site
   Design record: docs/superpowers/specs/2026-09-04-launch-website-design.md

   Two rules this file exists to keep:
     1. Colour means something. Orange is data and nothing else; blue is a club.
        There is no decorative colour anywhere.
     2. Motion is data. The only thing that moves on its own is the answer
        arriving, because that is the product. */

:root {
  /* Warm neutrals: the same paper the ball is played on, not a screen white.
     Every one of these is an orange desaturated almost to grey, which is what
     lets the single saturated orange below stay loud. */
  --paper:      #FDFAF6;
  --paper-deep: #F7F1E9;
  --ink:        #1A1512;
  --ink-soft:   #6B5F55;
  --ink-faint:  #A09284;
  --hairline:   #EBE2D7;
  --surface:    #FFFFFF;

  /* The one saturated colour on the page. Reserved for measured values and
     for the single action we want taken. Nothing decorative is ever this. */
  --ball:       #EA580C;
  --ball-deep:  #C2410C;

  --court:      rgba(26, 21, 18, 0.06);

  --display: "Gabarito", ui-sans-serif, system-ui, sans-serif;
  --text:    "Figtree", ui-sans-serif, system-ui, sans-serif;
  --figures: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --gutter: clamp(1.25rem, 5vw, 5.5rem);
  --measure: 62ch;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

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

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

.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: var(--gutter);
  top: 0.75rem;
  z-index: 10;
  background: var(--ink);
  color: var(--paper);
  padding: 0.6rem 1rem;
  border-radius: 999px;
  text-decoration: none;
}

/* ---------- top bar ---------- */

.topbar {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.4rem var(--gutter);
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(0.88rem, 3vw, 1rem);
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

/* A ball seam, not a logo: two arcs in a circle. */
.wordmark-mark {
  width: 17px;
  height: 17px;
  border-radius: 50%;
  border: 1.5px solid var(--ink);
  position: relative;
  overflow: hidden;
}
.wordmark-mark::before,
.wordmark-mark::after {
  content: "";
  position: absolute;
  inset: -30% -55%;
  border: 1.5px solid var(--ink);
  border-radius: 50%;
}
.wordmark-mark::after { inset: -30% -55%; transform: translateX(55%); }
.wordmark-mark::before { transform: translateX(-55%); }

.topnav {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 1.75rem);
}

.lang {
  font: inherit;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink-soft);
  background: none;
  border: 0;
  padding: 0.35rem 0;
  cursor: pointer;
}
.lang:hover { color: var(--ink); }

.quiet-link {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
  text-underline-offset: 4px;
}
.quiet-link:hover { color: var(--ink); text-decoration: underline; }

/* Orange is the measured value and the one action worth taking. Those are the
   only two things it is ever used for. */
.button-solid {
  display: inline-block;
  background: var(--ball);
  color: #fff;
  font-family: var(--text);
  font-weight: 600;
  font-size: 0.9rem;
  line-height: 1;
  padding: 0.7rem 1.15rem;
  border-radius: 999px;
  text-decoration: none;
}
.button-solid:hover { background: var(--ball-deep); }

.button-lg {
  font-size: 1rem;
  padding: 0.95rem 1.7rem;
}

/* ---------- hero ---------- */

.hero {
  position: relative;
  padding: clamp(2.25rem, 5vw, 4.5rem) var(--gutter) clamp(3rem, 5.5vw, 5.5rem);
  overflow: hidden;
}

/* Static. The court is structure, not an effect. */
.courtlines {
  position: absolute;
  left: -24%;
  bottom: -46%;
  width: min(76%, 860px);
  height: auto;
  color: var(--court);
  pointer-events: none;
}

.hero-inner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.12fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 4.5rem);
  max-width: 1180px;
  margin: 0 auto;
}

h1 {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(2.4rem, 5.1vw, 4rem);
  line-height: 1.04;
  letter-spacing: -0.037em;
  text-wrap: balance;
}

.lede {
  margin: 1.15rem 0 0;
  max-width: 34ch;
  font-size: clamp(1rem, 1.2vw, 1.1rem);
  color: var(--ink-soft);
}
.lede strong { color: var(--ink); font-weight: 600; }

.actions {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  margin-top: 2rem;
  flex-wrap: wrap;
}

/* ---------- the assistant window ---------- */

.hero-demo { min-width: 0; }

.window {
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  overflow: hidden;
  box-shadow:
    0 1px 2px rgba(16, 21, 28, 0.03),
    0 22px 45px -30px rgba(16, 21, 28, 0.35);
}

.window-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 0.95rem;
  border-bottom: 1px solid var(--hairline);
  background: #FDFCFB;
}

/* The assistant is named in text and drawn as a neutral initial. We do not
   reproduce anyone's logo or copy anyone's interface: naming a product to say
   we work with it is fair, dressing up as it is not. */
.window-app {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--ink);
}

/* Each assistant carries its own brand colour, which is identification rather
   than decoration — the same reasoning that puts a club's colour on a jersey
   chip. No logo is reproduced and no interface is imitated. */
.app-avatar {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  flex: none;
  background: var(--tint, var(--ink));
  color: #fff;
  font-size: 0.64rem;
  font-weight: 700;
  display: grid;
  place-items: center;
  transition: background 300ms ease;
}

.window-state {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.78rem;
  color: var(--ink-faint);
}

.live-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #16A34A;
  flex: none;
}

.window-body {
  padding: 1.35rem 1.35rem 1.5rem;
}

/* Your message sits on the right, the assistant answers on the left, because
   that is where a person expects to find each of them. */
.from-you {
  display: flex;
  justify-content: flex-end;
}

.bubble-user {
  margin: 0;
  display: inline-grid;
  max-width: 66%;
  background: var(--ink);
  color: #fff;
  font-size: 0.98rem;
  line-height: 1.45;
  padding: 0.6rem 0.9rem;
  border-radius: 15px 15px 5px 15px;
  text-align: left;
}

/* Both copies occupy the same cell: the hidden one holds the size open. */
.bubble-user > span { grid-area: 1 / 1; }
.ask-ghost { visibility: hidden; }

.caret {
  display: inline-block;
  width: 2px;
  height: 1em;
  margin-left: 1px;
  background: currentColor;
  vertical-align: -0.15em;
  animation: blink 1.05s steps(2, start) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* Present from the first paint and merely invisible, so the answer arriving
   changes nothing about the page's height. */
.reply {
  margin-top: 1.1rem;
  visibility: hidden;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 420ms cubic-bezier(.2,.6,.2,1),
              transform 420ms cubic-bezier(.2,.6,.2,1);
}
.reply.is-shown {
  visibility: visible;
  opacity: 1;
  transform: none;
}

.reply-line {
  margin: 0;
  font-size: 0.98rem;
}

.lineup {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.8rem 0 0;
  padding: 0;
}

.lineup li {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 0.25rem 0.75rem 0.25rem 0.25rem;
  font-size: 0.87rem;
}

/* Club colour, jersey number: both from our own data. No crests. */
.jersey {
  width: 22px;
  height: 22px;
  flex: none;
  border-radius: 50%;
  background: var(--club);
  color: #fff;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.68rem;
  display: grid;
  place-items: center;
}

.verdict {
  margin: 0.95rem 0 0;
  font-size: 0.98rem;
}

.figure {
  font-family: var(--figures);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--ball);
}

/* The number never travels without the population it was measured over. */
.qualifier {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.85rem;
  color: var(--ink-faint);
}

/* An input row, because a chat window without one does not look like a place
   you could type. It is inert on purpose: the box that actually answers is
   further down the page. */
.window-input {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0 0.9rem 0.9rem;
  padding: 0.6rem 0.55rem 0.6rem 0.85rem;
  border: 1px solid var(--hairline);
  border-radius: 11px;
  background: var(--paper);
}

.window-placeholder {
  font-size: 0.85rem;
  color: var(--ink-faint);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.window-send {
  width: 24px;
  height: 24px;
  flex: none;
  border-radius: 7px;
  background: var(--hairline);
  position: relative;
}
.window-send::after {
  content: "";
  position: absolute;
  left: 9px;
  top: 8px;
  width: 6px;
  height: 6px;
  border: solid var(--ink-faint);
  border-width: 1.5px 1.5px 0 0;
  transform: rotate(-45deg);
}

.demo-caption {
  margin: 0.9rem 0 0;
  max-width: 44ch;
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--ink-faint);
}

/* ---------- narrow screens ----------
   Short headline, then the whole window, then the explanation, then the
   action: on a phone the animation is worth more than the sentence. */

@media (max-width: 860px) {
  .hero-inner {
    grid-template-columns: 1fr;
    gap: 1.6rem;
  }
  .hero-copy { display: contents; }
  h1 { order: 1; }
  .hero-demo { order: 2; }
  .lede { order: 3; margin-top: 0; max-width: none; }
  .actions { order: 4; margin-top: 0.5rem; }
  .window-body { min-height: 0; }
}

@media (max-width: 460px) {
  .topnav .quiet-link { display: none; }
  body { font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  .caret { animation: none; opacity: 0; }
}

/* ---------- a claim and its evidence ----------
   Left column states one thing. Right column shows only that thing. Nothing in
   a section argues two points; the last attempt did and could not be read. */

.claim {
  padding: clamp(3rem, 5.5vw, 5.5rem) var(--gutter);
}

/* The two columns start together. Centring the copy against a tall court left
   the heading floating at the court's midpoint with nothing above it to explain
   the gap; starting both at the same line reads as one row rather than two
   things that happen to be side by side. */
.claim-inner {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  align-items: start;
  gap: clamp(2.5rem, 6vw, 5.5rem);
  max-width: 1180px;
  margin: 0 auto;
}

.claim h2 {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.9rem, 3.4vw, 2.9rem);
  line-height: 1.08;
  letter-spacing: -0.033em;
  max-width: 15ch;
}

.claim p {
  margin: 1rem 0 0;
  max-width: 38ch;
  color: var(--ink-soft);
}

.tally {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin-top: 1.9rem;
}

.tally-figure {
  font-family: var(--figures);
  font-weight: 500;
  font-size: clamp(2rem, 3.6vw, 2.9rem);
  font-variant-numeric: tabular-nums;
  color: var(--ball);
  line-height: 1;
}

.tally-label {
  font-size: 0.9rem;
  color: var(--ink-faint);
}

.halfcourt {
  width: 100%;
  height: auto;
  display: block;
}

/* Made shots are filled, misses are open. The only two states there are. */
.shot-made { fill: var(--ball); fill-opacity: 0.88; }
.shot-miss { fill: none; stroke: var(--ink-faint); stroke-width: 6; stroke-opacity: 0.5; }

/* The progress bar under the shot chart. It is a hairline that fills, in the
   one colour this page reserves for measured values, because what it is
   filling with is measured values. It disappears once the chart is complete:
   a finished bar sitting under a finished chart is furniture. */
.chartbar {
  margin: 0.9rem 0 0;
  opacity: 0;
  transition: opacity 260ms ease;
}
.chartbar.is-running,
.chartbar.is-settling { opacity: 1; }

.chartbar-label {
  margin: 0 0 0.55rem;
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
}

.chartbar-track {
  position: relative;
  height: 2px;
  background: var(--hairline);
  overflow: hidden;
}

.chartbar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--ball);
}

/* While shots are landing the width is set per shot and should follow with no
   easing of its own. The final run to full is the one deliberate glide, and it
   lasts exactly as long as the pause before the card opens. */
.chartbar.is-settling .chartbar-fill {
  transition: width 650ms cubic-bezier(.4, 0, .2, 1);
}

/* A caption is a footnote, not a paragraph. It was set at 60ch and ran the
   width of the figure, which made two sentences of provenance look like the
   point of the section. Narrow measure, smaller, closer to what it annotates. */
/* A caption is a footnote, not a paragraph. It was three lines at 60ch under a
   figure twice that wide, so it read as the point of the section and left a
   band of dead space beside it. Two lines at most, set smaller, running the
   width it is annotating rather than a column of its own. */
.figure-note {
  margin: 0.8rem 0 0;
  /* Runs the width of the figure it annotates. A narrower measure would be
     easier to read as prose, but this is one sentence of provenance and the
     column of dead space beside it cost more than the line length saves. */
  max-width: none;
  font-size: 0.78rem;
  line-height: 1.55;
  color: var(--ink-faint);
}

@media (max-width: 860px) {
  .claim-inner {
    grid-template-columns: 1fr;
    gap: 2rem;
  }
  .claim h2, .claim p { max-width: none; }
}

/* ---------- the game behind the chart ---------- */

.scoreline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 1.4rem;
  margin-top: 1.6rem;
  padding-top: 1.3rem;
  border-top: 1px solid var(--hairline);
}

.side {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 0.98rem;
  color: var(--ink);
}
.side b {
  font-family: var(--figures);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  margin-left: 0.15rem;
}

/* A club is identified by its colour and its name. No crest is reproduced. */
.crest {
  width: 11px;
  height: 11px;
  border-radius: 3px;
  background: var(--club);
  flex: none;
}

.scoreline-meta {
  flex-basis: 100%;
  font-size: 0.82rem;
  color: var(--ink-faint);
}

/* While one shot is being talked about, the rest step back. */
#shot-marks { transition: opacity 320ms ease; }
#shot-marks.is-dimmed { opacity: 0.22; }

.shot-halo {
  fill: none;
  stroke: var(--ball);
  stroke-width: 5;
  stroke-opacity: 0.55;
}

/* ---------- three exchanges, one window ----------
   They share a single grid cell, so the window is as tall as the tallest of
   them from the first paint and never resizes when one replaces another. */

.window-body {
  display: grid;
}
.window-body > .exchange {
  grid-area: 1 / 1;
  visibility: hidden;
  opacity: 0;
  transition: opacity 300ms ease;
}
.window-body > .exchange.is-current {
  visibility: visible;
  opacity: 1;
}

/* The middle beat: the thing the visitor is being asked to connect, doing the
   work. Named the way a person would name it - never by a function name. */
.working {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
  font-size: 0.82rem;
  color: var(--ink-faint);
  visibility: hidden;
  opacity: 0;
  transition: opacity 280ms ease;
}
.working.is-shown { visibility: visible; opacity: 1; }

.working-what {
  font-weight: 600;
  color: var(--ink-soft);
}

.working-dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--ball);
  animation: pulse 1.15s ease-in-out infinite;
}
.working.is-done .working-dot { animation: none; background: #16A34A; }
.working.is-done .working-state { opacity: 0.65; }

@keyframes pulse {
  0%, 100% { transform: scale(0.7); opacity: 0.45; }
  50%      { transform: scale(1);   opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .working-dot { animation: none; }
}

/* ---------- the shot that decided it ----------
   One card, once, over the dot it describes. It is placed from that shot's own
   coordinates rather than from a hand-picked offset, so it cannot drift away
   from the thing it points at when the chart is resized. */

.courtwrap { position: relative; }

.callout {
  position: absolute;
  width: min(17rem, 74%);
  transform: translate(-50%, 0);
  opacity: 0;
  transition: opacity 340ms ease, transform 340ms cubic-bezier(.2,.7,.3,1);
  pointer-events: none;
}
.callout.is-open {
  opacity: 1;
  transform: translate(-50%, 0.4rem);
}

/* The line from the card up to the shot, so the two are one object. */
.callout-leader {
  position: absolute;
  left: 50%;
  bottom: 100%;
  width: 1px;
  height: 2.1rem;
  background: linear-gradient(to bottom, transparent, var(--ball));
  opacity: 0.55;
}

.callout-body {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--ball);
  border-radius: 9px;
  padding: 0.8rem 0.95rem 0.85rem;
  box-shadow: 0 18px 38px -26px rgba(26, 21, 18, 0.5);
}

.callout-flag {
  align-self: flex-start;
  background: var(--ball);
  color: #fff;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.7rem;
  line-height: 1;
  letter-spacing: 0.01em;
  padding: 0.28rem 0.5rem;
  border-radius: 4px;
}

.callout-who {
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.12rem;
  letter-spacing: -0.025em;
  line-height: 1.1;
}

.callout-what {
  font-size: 0.83rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

.callout-score {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.15rem;
  padding-top: 0.55rem;
  border-top: 1px solid var(--hairline);
  font-size: 0.8rem;
  color: var(--ink-soft);
}
.callout-score i {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--club);
  flex: none;
}
.callout-score b {
  font-family: var(--figures);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  margin-right: 0.35rem;
}

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

/* ---------- one substitution ---------- */

/* The claim sits on the right here and the evidence on the left, so two
   full-width sections in a row do not read as the same section twice. */
.claim-flip .claim-inner { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); }
.claim-flip .claim-copy { order: 2; }
.claim-flip .claim-figure { order: 1; }

.figure-note-tight { margin-top: 1.1rem; max-width: 38ch; }

/* ---------- the floor ----------
   The substitution is drawn on a court because the substitution is a change of
   shape, not a change of name. Birch is the only centre in the strong five and
   Baldwin is a guard, so taking one off for the other empties the paint - and
   an empty paint is a thing you can see, where "-34.1" is a thing you have to
   be told.

   Positions are measured; spots are a convention. The figure note under this
   says so, and nothing in here may quietly imply otherwise. */

.floor {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 0.75rem;
  /* A marker walking on or off travels past the sideline. Nothing it does may
     end up drawn on the page outside this card. */
  overflow: hidden;
}

.floor-court {
  display: block;
  width: 100%;
  height: auto;
}

/* Lit only when it empties. It is the one thing on this court that reacts, so
   it is the one thing the eye is sent to. */
.floor-paint {
  fill: transparent;
  transition: fill 520ms ease;
}
.floor-paint.is-empty { fill: rgba(234, 88, 12, 0.10); }

.floor-players {
  position: absolute;
  /* Matches the .floor padding, so a percentage here is a percentage of the
     court rather than of the card around it. */
  inset: 0.75rem;
  pointer-events: none;
}

/* Each marker is positioned by its centre, and left/top are what move. The
   transition is on the position itself, so a player walks rather than jumps -
   which is the whole difference between this and the version it replaces. */
.player {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.28rem;
  transition:
    left 620ms cubic-bezier(.4, 0, .2, 1),
    top 620ms cubic-bezier(.4, 0, .2, 1),
    opacity 380ms ease;
}

.player-disc {
  display: grid;
  place-items: center;
  width: clamp(28px, 3.4vw, 38px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--club);
  color: #fff;
  font-family: var(--figures);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 1px 0 rgba(26, 21, 18, 0.18);
  transition: background 380ms ease, transform 380ms ease;
}

.player-name {
  font-size: 0.76rem;
  font-weight: 600;
  line-height: 1.1;
  white-space: nowrap;
  color: var(--ink);
}

.player-role {
  font-size: 0.66rem;
  line-height: 1;
  letter-spacing: 0.03em;
  color: var(--ink-faint);
}

/* Off the floor: still drawn, at the side, faded. Removing the marker would
   make the substitute appear from nowhere; leaving it there is what makes
   arriving read as arriving. */
.player.is-off {
  opacity: 0;
}

/* The two players the substitution is about carry the measured-value colour
   while they are moving, and only while they are moving. */
.player.is-leaving .player-disc,
.player.is-arriving .player-disc {
  background: var(--ball);
  transform: scale(1.12);
}

/* Scoped to .floor so it outranks `.claim p`, which sets the section's body
   colour and was turning this white-on-orange badge into grey-on-orange. */
.floor .floor-empty {
  position: absolute;
  left: 50%;
  bottom: 1.1rem;
  transform: translateX(-50%);
  margin: 0;
  padding: 0.35rem 0.8rem;
  border-radius: 999px;
  background: var(--ball);
  color: #fff;
  max-width: none;
  font-size: 0.74rem;
  font-weight: 600;
  white-space: nowrap;
}

@media (max-width: 520px) {
  /* The names stop fitting between five markers long before the court does. */
  .player-name, .player-role { display: none; }
}

.unit-verdict {
  display: grid;
  grid-template-columns: auto auto minmax(8rem, 1fr);
  align-items: end;
  gap: 1rem;
  margin-top: 1.35rem;
  padding-top: 1.15rem;
  border-top: 1px solid var(--hairline);
}

/* The number leaves upward and the new one drops in, and the metric behind it
   pulses once. The text is swapped at the 30% mark, where the figure is
   invisible, so the reader never sees the change itself - only the arrival.
   SWAP_OUT_MS in lineups.js is that mark and the two have to agree. */
@keyframes figure-swap {
  0%   { transform: translateY(0);       opacity: 1; }
  29%  { transform: translateY(-0.32em); opacity: 0; }
  30%  { transform: translateY(0.38em);  opacity: 0; }
  60%  { transform: translateY(0);       opacity: 1; }
  74%  { transform: translateY(0) scale(1.06); }
  100% { transform: translateY(0) scale(1); }
}

@keyframes figure-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(234, 88, 12, 0.22); }
  70%  { box-shadow: 0 0 0 14px rgba(234, 88, 12, 0); }
  100% { box-shadow: 0 0 0 0 rgba(234, 88, 12, 0); }
}

.unit-metric { border-radius: 8px; }
.unit-metric.is-changing { animation: figure-pulse 760ms ease-out; }
.unit-figure.is-changing {
  animation: figure-swap 640ms cubic-bezier(.4, 0, .2, 1);
  transform-origin: left center;
}

.unit-figure {
  display: block;
  font-family: var(--figures);
  font-weight: 500;
  font-size: clamp(2.1rem, 4vw, 3rem);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--ball);
  transition: color 380ms ease;
}
/* Both numbers are measured, so both are the measured-value colour. Muting the
   negative one would be the page taking a side about which unit is the real
   Fenerbahce, which is exactly the judgement the reader is here to make. */
.unit-figure-quiet { color: var(--ink); font-size: clamp(1.5rem, 2.6vw, 2rem); }

.unit-label {
  display: block;
  margin-top: 0.55rem;
  font-size: 0.82rem;
  color: var(--ink-faint);
}

/* The third column shares the compact evidence row with the two figures. It
   still reserves its height whether or not there is anything to say, because
   an appearing caption would move the copy every few seconds. */
.unit-swap {
  margin: 0;
  min-height: 1.3em;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--ink-soft);
}

@media (max-width: 860px) {
  .claim-flip .claim-copy { order: 1; }
  .claim-flip .claim-figure { order: 2; }
}

@media (max-width: 520px) {
  .unit-verdict { grid-template-columns: auto auto; }
  .unit-swap { grid-column: 1 / -1; }
}

@media (prefers-reduced-motion: reduce) {
  /* The markers still get placed, they just stop travelling to get there, and
     the figures still change, they just stop announcing it. */
  .player { transition: none; }
  .floor-paint { transition: none; }
  .unit-figure.is-changing,
  .unit-metric.is-changing { animation: none; }
}

/* THE SECTION RHYTHM, measured rather than felt, 2026-09-04.
   Every section carried 128px of padding above and below on a 1280px screen,
   so 256px of nothing sat between any two of them. On the owner's 1536 by 730
   screen that was 272px - more than a third of the viewport spent on emptiness
   between one claim and the next. The scale is now 5.5vw capped at 5.5rem,
   which is a gap of about 170px: still air, no longer a wait.

   These four paddings are one decision and move together. Changing one of them
   alone reintroduces the uneven rhythm they exist to keep. */

/* ---------- the one place the visitor acts ---------- */

.ask {
  padding: clamp(3rem, 5.5vw, 5.5rem) var(--gutter);
  background: var(--paper-deep);
}

.ask-inner { max-width: 780px; margin: 0 auto; }

.ask h2 {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(2rem, 3.6vw, 3rem);
  line-height: 1.06;
  letter-spacing: -0.035em;
}

.ask-lede {
  margin: 1rem 0 0;
  max-width: 46ch;
  color: var(--ink-soft);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
  margin-top: 2rem;
}

.chip {
  font: inherit;
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 0.6rem 1.05rem;
  cursor: pointer;
  transition: border-color 180ms ease, background 180ms ease, color 180ms ease;
}
.chip:hover { border-color: var(--ink-faint); }
.chip.is-chosen {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

.ask-answer {
  margin-top: 1.6rem;
  min-height: 9.5rem;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 1.4rem 1.5rem;
}

.ask-empty { margin: 0; color: var(--ink-faint); font-size: 0.92rem; }

.ask-working {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.85rem;
  color: var(--ink-faint);
}

.ask-line { margin: 0 0 0.7rem; font-size: 1rem; }

.ask-verdict {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0.9rem 0 0;
  font-size: 1rem;
  color: var(--ink-soft);
}

.ask-figure {
  font-family: var(--figures);
  font-weight: 500;
  font-size: clamp(1.9rem, 3.4vw, 2.6rem);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--ball);
}

.ask-qualifier {
  margin: 0.55rem 0 0;
  font-size: 0.85rem;
  color: var(--ink-faint);
}

.ask .lineup { margin-top: 0; }
.ask .lineup li { background: var(--paper); }

/* ---------- sidelines, the length of the page ----------
   The two rails frame the content and the short outward ticks mark section
   boundaries. Interior court furniture was removed after the owner found the
   arcs, keys and centre circle too busy behind the content. */

body { position: relative; }

.courtgrid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}

.rail {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--hairline);
}
.rail-left  { left: max(var(--gutter), calc(50% - 640px)); }
.rail-right { right: max(var(--gutter), calc(50% - 640px)); }

/* WHERE ONE SECTION ENDS: the throw-in line, not a rule across the page.

   A real court has one. It is a short mark on each sideline, 8.325 m from the
   endline, and a throw-in in the last two minutes is taken from it. That
   distance is not a coincidence of this page's arithmetic: the ring is 157.5
   from the baseline and the arc is 675 from the ring, so the top of the
   three-point arc is 157.5 + 675 = 832.5 - the same 8.325 m. The mark and the
   top of the arc line up on a real floor, which is why the owner asked for this
   one and not for a divider.

   It replaces a hairline that ran the full width of the page. That rule
   separated sections the way a horizontal rule separates anything, which is to
   say it said nothing; this says "sideline" and marks the change at the same
   time.

   The length is chosen to be legible, not scaled. A real mark reaches 0.15 m
   onto a 15 m floor - a hundredth of the width, about 11px here - which at this
   size would read as dirt on the screen rather than as a mark. */
.claim, .ask, .connect, .how, .footer { position: relative; }
.claim::before, .claim::after,
.ask::before, .ask::after,
.connect::before, .connect::after,
.how::before, .how::after,
.footer::before, .footer::after {
  content: "";
  position: absolute;
  top: 0;
  width: 34px;
  height: 1px;
  /* The same hairline as the rails and the court. It was drawn in --ink-faint,
     which made it darker than every other line on the page and read as a
     different kind of thing. A court line is a court line. */
  background: var(--hairline);
}
/* Outside the sideline, not inside it: the mark sits off the floor so nothing
   ever reaches into the column the content occupies. */
.claim::before, .ask::before, .connect::before, .how::before, .footer::before {
  right: calc(100% - max(var(--gutter), calc(50% - 640px)));
}
.claim::after, .ask::after, .connect::after, .how::after, .footer::after {
  left: calc(100% - max(var(--gutter), calc(50% - 640px)));
}

main, .topbar { position: relative; z-index: 1; }

/* ---------- the ask window ---------- */

.ask-window { margin-top: 2rem; }

/* A transcript, so it scrolls its own box rather than growing the page under
   the visitor's cursor. The floor keeps the window from collapsing before the
   first question; the ceiling keeps a long conversation from pushing the chips
   off the screen, which is where the next question comes from. */
.ask-body {
  display: block;
  min-height: 12rem;
  max-height: 26rem;
  overflow-y: auto;
  scroll-behavior: smooth;
}
.ask-body > * + * { margin-top: 1.1rem; }
.ask-body .reply { margin-top: 0.75rem; }

/* The tool call. A connected assistant really does pick one of the eleven
   el_* tools and run it, so this row is a report, not an ornament. */
.toolcall {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 0.8rem;
  font-family: var(--figures);
  color: var(--ink-faint);
  background: var(--paper-deep);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 0.5rem 0.75rem;
}
.toolcall-name { color: var(--ink-soft); }
.toolcall-source {
  margin-left: auto;
  font-family: var(--text);
  font-size: 0.76rem;
}

.toolcall-spinner {
  width: 9px;
  height: 9px;
  flex: none;
  border-radius: 50%;
  border: 1.5px solid var(--ink-faint);
  border-top-color: transparent;
  animation: toolspin 700ms linear infinite;
}
.toolcall.is-done .toolcall-spinner {
  border: 0;
  background: #16A34A;
  animation: none;
}

@keyframes toolspin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .toolcall-spinner { animation: none; }
  .ask-body { scroll-behavior: auto; }
  /* He is still there, he is just still. */
  .mascot-eyes, .mascot-body { animation: none; }
}

/* The invitation, and the one thing on the page that is waiting for you. */
.ask-empty {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  margin: 0;
}

.mascot {
  flex: none;
  width: 78px;
  height: 78px;
  overflow: visible;
}

.ask-invite { margin: 0; }
.ask-invite b {
  display: block;
  font-family: var(--display);
  font-weight: 600;
  font-size: 1rem;
  color: var(--ink);
}
.ask-invite span {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.9rem;
  color: var(--ink-faint);
}

/* Waiting, not performing. Two slow movements, both small enough that they
   register at the edge of vision rather than asking to be watched: a breath,
   and a glance that keeps coming back to you. The page's other motion happens
   ONCE and stops, and this is the deliberate exception - a character that
   stops moving is a character that has left, and the whole job here is to look
   like somebody is still there. */
@keyframes mascot-glance {
  0%, 42%   { transform: translateX(0); }
  52%, 74%  { transform: translateX(2.2px); }
  84%, 100% { transform: translateX(-1.6px); }
}
@keyframes mascot-breathe {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2.5px); }
}
.mascot-eyes { animation: mascot-glance 4.6s ease-in-out infinite; }
.mascot-body { animation: mascot-breathe 3.8s ease-in-out infinite; }

.ask-working {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 1rem 0 0;
  font-size: 0.85rem;
  color: var(--ink-faint);
}

/* The chips live where the text field would be: suggestions, and the only
   input this window can safely accept. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0;
  padding: 0.9rem 1rem 1rem;
  border-top: 1px solid var(--hairline);
  background: var(--paper);
}

.chip {
  font: inherit;
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 0.5rem 0.9rem;
  cursor: pointer;
  transition: border-color 180ms ease, background 180ms ease, color 180ms ease;
}
.chip:hover { border-color: var(--ink-faint); color: var(--ink); }
/* Spent, not disabled. It stays clickable, and the mark is only a record of
   what has already been asked. */
.chip.is-asked {
  color: var(--ink-faint);
  background: var(--paper-deep);
  border-style: dashed;
}


/* ---------- connect ---------- */

.connect {
  position: relative;
  padding: clamp(3rem, 5.5vw, 5.5rem) var(--gutter);
}
.connect-inner { max-width: 780px; margin: 0 auto; }

.connect h2, .how h2 {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(2rem, 3.6vw, 3rem);
  line-height: 1.06;
  letter-spacing: -0.035em;
}

.connect-lede {
  margin: 1rem 0 0;
  max-width: 48ch;
  color: var(--ink-soft);
}

.address {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 2rem;
  padding: 0.75rem 0.75rem 0.75rem 1.05rem;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 10px;
}
.address code {
  font-family: var(--figures);
  font-size: clamp(0.78rem, 1.5vw, 0.95rem);
  color: var(--ink);
  overflow-x: auto;
  white-space: nowrap;
}

.copy {
  margin-left: auto;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  color: #fff;
  background: var(--ink);
  border: 0;
  border-radius: 999px;
  padding: 0.5rem 0.95rem;
  cursor: pointer;
  flex: none;
}
.copy:hover { background: #000; }
.copy.is-done { background: #16A34A; }

/* One panel per client, because the four setups are genuinely different and a
   single averaged instruction would be wrong for all of them. Each panel says
   which kind of claim it is making before it says anything else: verified means
   somebody connected that client and called a tool; expected means the client's
   own specification says this works and nobody here has run it. */
.clients { margin-top: 2rem; }

.client-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  border-bottom: 1px solid var(--hairline);
}

.client-tab {
  font: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--ink-soft);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 0.6rem 0.85rem;
  margin-bottom: -1px;
  cursor: pointer;
}
.client-tab:hover { color: var(--ink); }
.client-tab[aria-selected="true"] {
  color: var(--ink);
  border-bottom-color: var(--ball);
}

.client-panel {
  padding: 1.5rem 0 0;
}

.client-status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.client-status::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex: none;
}
.client-status-verified { color: #15803D; }
.client-status-verified::before { background: #16A34A; }
/* Amber, and it is the only amber on the page: it means a claim that has not
   been run yet, and nothing else is allowed to borrow it. */
.client-status-review,
.client-status-expected { color: #92400E; }
.client-status-review::before,
.client-status-expected::before { background: #D97706; }

.client-note {
  margin: 1rem 0 0;
  font-size: 0.92rem;
  color: var(--ink-soft);
  max-width: 56ch;
}

.howto {
  list-style: none;
  counter-reset: howto;
  margin: 1.1rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.55rem;
  max-width: 56ch;
}
/* The number hangs in the margin and the step reads as one sentence.
   This was a grid with a 1.6rem marker column, copied from the block-level
   list it replaced. Grid makes every child its own item, and these steps are
   inline content - "Open ", <b>Settings</b>, ", then ", <b>Connectors</b> - so
   each fragment was laid into the next cell and the sentence came apart, one
   bold word per line, overlapping the line above. Inline content needs inline
   flow; the marker gets out of the way instead. */
.howto li {
  counter-increment: howto;
  position: relative;
  padding-left: 2.3rem;
  font-size: 0.94rem;
  line-height: 1.55;
  color: var(--ink-soft);
}
.howto li::before {
  content: counter(howto);
  position: absolute;
  left: 0;
  top: 0.08em;
  width: 1.6rem;
  font-family: var(--figures);
  font-size: 0.8rem;
  color: var(--ink-faint);
}
.howto b { color: var(--ink); font-weight: 600; }

/* Inline code is for short things only - a command name, a flag. A long
   command in here breaks mid-word and its box splits across two lines with a
   border down the middle of a URL, so long commands are block-level instead
   (.howto-code below). `break-word` rather than `break-all`: it breaks a word
   only when the word alone will not fit, which is what stops a short token
   being chopped for no reason. */
.howto code,
.howto-alt code {
  font-family: var(--figures);
  font-size: 0.82em;
  background: var(--paper-deep);
  border: 1px solid var(--hairline);
  border-radius: 5px;
  padding: 0.1em 0.4em;
  overflow-wrap: break-word;
}

/* The Gemini steps are numbered across a code block, so the second list has to
   carry on counting rather than start again at one. */
.howto-continued { counter-reset: howto 1; }

.howto-alt {
  margin: 1.4rem 0 0;
  font-size: 0.88rem;
  color: var(--ink-faint);
  max-width: 56ch;
}

/* One command per line, never broken with a backslash continuation: that is a
   shell-ism that fails in PowerShell and survives a copy badly. A command too
   wide for the card scrolls inside the card instead, which is the one place
   horizontal scrolling is the right answer. */
.howto-code {
  margin: 1.1rem 0 0;
  padding: 1rem 1.15rem;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  overflow-x: auto;
  font-family: var(--figures);
  font-size: 0.82rem;
  line-height: 1.65;
  color: var(--ink-soft);
}
.howto-code code { font: inherit; }

.connect-note {
  margin: 1.6rem 0 0;
  font-size: 0.88rem;
  color: var(--ink-faint);
}

/* ---------- what is behind it ---------- */

/* ---------- ask it something hard ----------

   Three cases, each a block of copy beside a window, alternating side to side
   so the eye has somewhere to go on the way down. The owner asked for the
   windows LARGE and said the page may get much longer for it; they take the
   wider of the two columns and the section is the tallest on the site.

   The window is the same component as the hero's. Nothing here is a screenshot:
   a PNG of a conversation goes stale silently, cannot be translated with the
   rest of the page, and blurs on a display the author did not own. */
.deep {
  padding: clamp(3rem, 5.5vw, 5.5rem) var(--gutter);
}
.deep-inner { max-width: 1180px; margin: 0 auto; }

.deep-head { max-width: 640px; }
.deep-head h2 {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.9rem, 3.6vw, 2.8rem);
  line-height: 1.06;
  letter-spacing: -0.035em;
}
.deep-lede {
  margin: 1rem 0 0;
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--ink-soft);
}

.deep-case {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  align-items: start;
  gap: clamp(1.75rem, 4vw, 3.5rem);
  margin-top: clamp(2rem, 3.5vw, 3.25rem);
}
/* The copy and the window swap sides on the middle case. The COLUMNS swap with
   them - ordering alone would have left the window in the narrow column and
   made the middle case's evidence smaller than the other two, which is the
   opposite of what was asked for. Source order stays copy-then-window, so a
   screen reader and a phone both read the claim before the evidence for it. */
.deep-case-flip {
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr);
}
.deep-case-flip .deep-copy { order: 2; }
.deep-case-flip .deep-window { order: 1; }

.deep-copy { padding-top: 0.4rem; }
.deep-copy h3 {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
}
.deep-copy p {
  margin: 0.8rem 0 0;
  font-size: 0.95rem;
  line-height: 1.65;
  color: var(--ink-soft);
}

.deep-window { margin: 0; }
.deep-body {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding: 1.1rem 1.25rem 1.25rem;
}

/* The visitor needs to see that the assistant is working with this warehouse,
   not the implementation names and arguments behind that work. One restrained
   thought replaces the internal transcript; the exact calls remain beside the
   case in source comments so the figures can still be replayed. */
.deep-thought {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--ink-faint);
}
.deep-thought::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--ball);
}
.deep-thought span { color: var(--ink-soft); font-weight: 600; }

.deep-body .reply-line {
  margin: 0 0 0.7rem;
  font-size: 0.92rem;
  line-height: 1.6;
}
.deep-body .reply-line:last-of-type { margin-bottom: 0; }

@media (max-width: 900px) {
  .deep-case,
  .deep-case-flip { grid-template-columns: minmax(0, 1fr); }
  /* On one column the swap would put the window above its own claim. */
  .deep-case-flip .deep-copy { order: 0; }
  .deep-case-flip .deep-window { order: 0; }
}

.how {
  padding: clamp(2.75rem, 5vw, 5rem) var(--gutter);
}
.how-inner { max-width: 780px; margin: 0 auto; }

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1.6rem 2.5rem;
  margin: 2rem 0 0;
}
.facts dt {
  font-family: var(--figures);
  font-weight: 500;
  font-size: clamp(1.7rem, 3vw, 2.3rem);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--ball);
}
.facts dd {
  margin: 0.6rem 0 0;
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--ink-soft);
}

.how-note {
  margin: 2.2rem 0 0;
  max-width: 62ch;
  font-size: 0.88rem;
  line-height: 1.65;
  color: var(--ink-faint);
}
.how-note .quiet-link { margin-left: 0.3rem; }

/* The marker, used exactly once on the page.

   It is NOT the orange. The palette above reserves that for measured values
   and for the action we want taken, and this phrase is neither - it is a
   statement about where the numbers come from. The band is the same hairline
   the court is drawn in, so the mark belongs to the page rather than shouting
   over it.

   Drawn as a background that grows from the left, which is the direction a pen
   moves, and sitting a little low and a little uneven because a marker does
   not stop at the cap height. The text itself never moves: only the band
   behind it arrives. */
.marker {
  /* The band is a background on the text itself rather than a box behind it,
     and `box-decoration-break: clone` is what makes that the right choice: the
     phrase is long enough to wrap, and a single absolutely-positioned rectangle
     would span from the start of the first line to the end of the second and
     paint a block over everything between. Cloned, each line gets its own band,
     which is what a pen would leave. */
  padding: 0 0.15em;
  border-radius: 3px;
  color: var(--ink-soft);
  background-image: linear-gradient(var(--hairline), var(--hairline));
  background-repeat: no-repeat;
  /* Low, and shorter than the line: a marker does not stop at the cap height
     and does not reach the line above. */
  background-position: 0 84%;
  background-size: 0 0.92em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-size 620ms cubic-bezier(.2, .7, .3, 1), color 420ms ease;
}
.marker.is-marked {
  color: var(--ink);
  background-size: 100% 0.92em;
}

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

/* ---------- footer ---------- */

.footer {
  position: relative;
  z-index: 1;
  padding: 2.5rem var(--gutter) 3rem;
}
.footer-inner {
  max-width: 1180px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.9rem 1.6rem;
  font-size: 0.85rem;
  color: var(--ink-faint);
}
.footer nav { display: flex; gap: 1.2rem; }
.footer-note { flex-basis: 100%; }
