/* ============================================================
   Inbar Lanir - "Gold is the one colour she has not taken yet"
   ------------------------------------------------------------
   Her own words: "I'm fast, dynamic, explosive, aggressive."
   The page is built to that sentence, not to a template.

   Ground is near-black carrying a judogi-blue undertone. The
   blue is never a fill; it lives inside the dark as a tint on a
   five-step elevation ramp, because on dark surfaces lightness
   is the depth cue and a flat saturated panel reads as 2000s
   wallpaper.

   One accent: gold. It is rationed on purpose. Silver and
   bronze appear as data in the record; gold appears only where
   she has actually taken it, and on the target. Most of the
   page has no gold in it at all. That is the point.

   Logical properties throughout, so the Hebrew RTL pages reuse
   this file unchanged.
   ============================================================ */

/* ---------- fonts: self-hosted, no third-party request ---------- */
@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/heebo-hebrew-400.woff2') format('woff2');
  unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/heebo-latin-400.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/heebo-hebrew-700.woff2') format('woff2');
  unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/heebo-latin-700.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url('/assets/fonts/heebo-hebrew-900.woff2') format('woff2');
  unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url('/assets/fonts/heebo-latin-900.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- tokens ---------- */
:root {
  /* surfaces - five-step elevation ramp, blue lives here as undertone */
  --s0:  oklch(0.145 0.018 258);   /* page ground */
  --s1:  oklch(0.185 0.022 258);   /* raised band */
  --s2:  oklch(0.225 0.026 258);   /* card */
  --s3:  oklch(0.275 0.030 258);   /* hover / lifted card */
  --s4:  oklch(0.330 0.034 258);   /* popover, top of ramp */
  --hair: oklch(1 0 0 / 0.09);     /* hairline, never a solid border */
  --hair-2: oklch(1 0 0 / 0.16);
  --lift: oklch(1 0 0 / 0.07);     /* inset top-edge highlight */

  /* light inversion - used for one or two sections only */
  --gi:      oklch(0.968 0.004 258);
  --gi-2:    oklch(0.930 0.007 258);
  --gi-line: oklch(0.855 0.010 258);

  /* text */
  --on-dark:        oklch(0.975 0.004 258);
  --on-dark-muted:  oklch(0.735 0.016 258);
  --on-dark-faint:  oklch(0.605 0.018 258);  /* nudged up from 0.560: measured 4.26:1 on --s0, below the 4.5:1 floor for normal text */
  --on-gi:          oklch(0.190 0.030 258);
  --on-gi-muted:    oklch(0.435 0.024 258);

  /* the single accent. Gold, because that is the one she is going for. */
  --gold:      oklch(0.815 0.145 88);
  --gold-deep: oklch(0.680 0.130 82);
  --gold-dim:  oklch(0.815 0.145 88 / 0.16);

  /* medal swatches - data in the record, not decoration */
  --m-gold:   var(--gold);
  --m-silver: oklch(0.780 0.012 258);
  --m-bronze: oklch(0.620 0.085 55);

  /* type - one family, weight does the work. Heebo covers Hebrew and Latin,
     so the RTL pages are the same design and not a translated afterthought. */
  --display: "Heebo", "Arial Black", Helvetica, sans-serif;
  --body:    "Heebo", "Helvetica Neue", Arial, sans-serif;

  /* space */
  --pad:    clamp(1.25rem, 5vw, 5rem);
  --gutter: clamp(4.5rem, 10vw, 11rem);
  --shell:  80rem;

  /* radius - one scale, sharp end of it. A disciplined sport, not a friendly app. */
  --r:    4px;
  --r-lg: 8px;

  /* motion */
  --out:      cubic-bezier(0.23, 1, 0.32, 1);
  --out-soft: cubic-bezier(0.16, 1, 0.30, 1);
  --inout:    cubic-bezier(0.77, 0, 0.175, 1);

  /* z - semantic, never arbitrary */
  --z-grain: 1;
  --z-sticky: 100;
  --z-nav: 200;
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--s0);
  color: var(--on-dark);
  font-family: var(--body);
  font-size: clamp(1rem, 0.95rem + 0.24vw, 1.14rem);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Film grain. Fixed and pointer-events:none so it never repaints on scroll —
   it exists to stop the large dark gradients banding, not as texture for its
   own sake. */
body::after {
  content: "";
  position: fixed; inset: 0; z-index: var(--z-grain);
  pointer-events: none; opacity: 0.032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

img, svg, iframe { display: block; max-inline-size: 100%; }
img { block-size: auto; }
a { color: inherit; }
button { font: inherit; color: inherit; }

::selection { background: var(--gold); color: var(--s0); }

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

.skip {
  position: absolute; inset-block-start: -100%; inset-inline-start: var(--pad);
  z-index: var(--z-nav); background: var(--gi); color: var(--on-gi);
  padding: 0.75rem 1.25rem; font-weight: 700; border-radius: 0 0 4px 4px;
}
.skip:focus { inset-block-start: 0; }

.vh { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ---------- type ---------- */
h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 900;
  line-height: 0.94;
  letter-spacing: -0.035em;   /* floor is -0.04em; below that the letters touch */
  text-wrap: balance;
  text-transform: uppercase;  /* Latin only; Hebrew has no case, so it is a no-op there */
}
h2 { font-size: clamp(1.9rem, 1.1rem + 3.4vw, 3.8rem); }
/* CONVERSATION at display size is wider than a narrow column, and a single
   word cannot wrap, so it simply left the page. Let long words break. */
h1, h2, h3 { overflow-wrap: break-word; }
h3 { font-size: clamp(1.2rem, 1.05rem + 0.8vw, 1.6rem); line-height: 1.14; letter-spacing: -0.02em; }
p  { text-wrap: pretty; }
.lede { font-size: clamp(1.1rem, 1rem + 0.6vw, 1.45rem); line-height: 1.45; }
.prose { max-inline-size: 62ch; }
.prose p + p { margin-block-start: 1.05em; }

/* Hebrew has no ascenders or descenders to breathe with — give it more room
   and let go of the negative tracking, which only helps Latin. */
[lang="he"] { line-height: 1.75; }
[lang="he"] h1, [lang="he"] h2, [lang="he"] h3 { letter-spacing: 0; line-height: 1.18; }

/* ---------- shell ---------- */
.shell { max-inline-size: var(--shell); margin-inline: auto; padding-inline: var(--pad); }
section { padding-block: var(--gutter); }
.band-gi { background: var(--gi); color: var(--on-gi); }
.band-gi h2, .band-gi h3 { color: var(--s0); }

/* ---------- header ---------- */
.site-head {
  position: sticky; inset-block-start: 0; z-index: var(--z-sticky);
  background: color-mix(in oklab, var(--s0) 72%, transparent);
  backdrop-filter: blur(14px) saturate(140%);
  border-block-end: 1px solid color-mix(in oklab, var(--on-dark) 12%, transparent);
}
.site-head__in {
  max-inline-size: var(--shell); margin-inline: auto;
  padding: 0.75rem var(--pad);
  display: flex; align-items: center; gap: 1.5rem;
}
.mark {
  font-family: var(--display); font-weight: 900; font-size: 1.02rem;
  letter-spacing: -0.02em; text-decoration: none; white-space: nowrap;
}
.mark span { color: var(--gold); }
.site-nav { margin-inline-start: auto; display: flex; align-items: center; gap: clamp(0.85rem, 2.2vw, 1.9rem); }
.site-nav a {
  position: relative; text-decoration: none; font-weight: 600; font-size: 0.94rem;
  color: var(--on-dark-muted); padding-block: 0.3rem;
  transition: color 180ms var(--out);
}
/* The visible row stays compact (the sticky header must not eat a short
   phone screen), so the 44px tap target is an invisible hit-area layered
   over it rather than added padding that would grow the header. */
.site-nav a::before {
  content: ""; position: absolute; inset-block: -8px; inset-inline: 0;
}
/* underline grows from the leading edge — mirrors correctly in RTL */
.site-nav a::after {
  content: ""; position: absolute; inset-block-end: 0; inset-inline-start: 0;
  inline-size: 100%; block-size: 2px; background: var(--gold);
  transform: scaleX(0); transform-origin: left;
  transition: transform 220ms var(--out);
}
@media (hover: hover) {
  .site-nav a:hover { color: var(--on-dark); }
  .site-nav a:hover::after { transform: scaleX(1); }
}
[dir="rtl"] .site-nav a::after { transform-origin: right; }
.site-nav a[aria-current]::after { transform: scaleX(1); }
.lang-switch {
  position: relative;
  font-weight: 700; font-size: 0.88rem; color: var(--on-dark);
  border: 1px solid var(--hair-2); border-radius: 999px;
  padding: 0.24rem 0.8rem; text-decoration: none;
  transition: background 200ms var(--out), border-color 200ms var(--out);
}
.lang-switch::after { display: none; }
/* Same invisible hit-area trick as .site-nav a — the pill stays its own
   compact size, the tap target grows to 44px around it. */
.lang-switch::before { content: ""; position: absolute; inset-block: -6px; inset-inline: -4px; }
@media (hover: hover) { .lang-switch:hover { background: var(--gold); border-color: var(--gold); } }
@media (max-width: 640px) {
  .site-nav .hide-sm { display: none; }
  .site-nav { gap: 0.7rem; }
  .site-nav a { font-size: 0.86rem; }
  .site-head__in { gap: 0.75rem; }
}
@media (max-width: 26rem) {
  .site-nav .hide-xs { display: none; }
  .mark { font-size: 0.95rem; }
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 0.6rem;
  padding: 0.85rem 1.6rem; border-radius: 3px;
  font-weight: 700; text-decoration: none;
  transition: background 200ms var(--out), border-color 200ms var(--out),
              color 200ms var(--out), transform 160ms var(--out);
}
.btn:active { transform: scale(0.97); transition-duration: 90ms; }  /* asymmetric: press fast, release slow */
.btn--solid { background: var(--gold); color: var(--s0); }
.btn--ghost { border: 2px solid var(--hair-2); color: var(--on-dark); }
.band-gi .btn--ghost { border-color: var(--gi-line); color: var(--on-gi); }
@media (hover: hover) {
  .btn--solid:hover { background: var(--gold-deep); }
  .btn--ghost:hover { border-color: var(--on-dark); }
  .band-gi .btn--ghost:hover { border-color: var(--s0); }
}
/* the arrow sits in its own well and leans out on hover */
.btn .arw {
  inline-size: 1.55rem; block-size: 1.55rem; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-size: 0.9rem;
  background: color-mix(in oklab, currentColor 16%, transparent);
  transition: transform 260ms var(--out);
}
[dir="rtl"] .btn .arw { transform: scaleX(-1); }
@media (hover: hover) {
  .btn:hover .arw { transform: translateX(3px); }
  [dir="rtl"] .btn:hover .arw { transform: scaleX(-1) translateX(3px); }
}

/* ============================================================
   HERO — full height. The photo bleeds off three edges and the
   name overlaps it. Grid-breaking on purpose: the two planes
   fight for the same space, which is the whole sport.
   ============================================================ */
.hero {
  position: relative;
  padding-block: 0;
  display: grid;
  align-content: center;
  overflow: clip;
  background:
    radial-gradient(120% 90% at 78% 8%, color-mix(in oklab, var(--s1) 82%, white 6%) 0%, transparent 62%),
    linear-gradient(190deg, var(--s1) 0%, var(--s0) 100%);
}

@media (min-width: 60rem) { .hero { min-block-size: 100svh; } }
.hero__grid {
  max-inline-size: var(--shell); inline-size: 100%;
  margin-inline: auto; padding-inline: var(--pad);
  display: grid; grid-template-columns: 1fr;
  gap: 2.5rem; align-items: center;
  padding-block: clamp(5rem, 12vh, 7.5rem) clamp(8rem, 16vh, 10rem);
}

.hero__art { position: relative; justify-self: center; inline-size: min(100%, 26rem); }
.hero__art img {
  inline-size: 100%; aspect-ratio: 4/5; object-fit: cover; object-position: 50% 8%;
  border-radius: 2px;
}
/* the tatami line: one rust rule down the leading edge of the frame */
.hero__art::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: -0.7rem;
  inline-size: 3px; background: var(--gold);
}
.hero__credit {
  margin-block-start: 0.7rem; font-size: 0.72rem; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--on-dark-muted);
}
[lang="he"] .hero__credit { text-transform: none; letter-spacing: 0.02em; font-size: 0.8rem; }

@media (min-width: 60rem) {
  .hero__grid {
    /* full-bleed grid: the gutter lives in padding-inline-start only, so the
       photo column runs all the way off the trailing edge. Split into two
       declarations so a bad calc can never drop both. */
    max-inline-size: none;
    inline-size: 100%;
    padding-inline-start: max(var(--pad), calc((100vw - var(--shell)) / 2 + var(--pad)));
    padding-inline-end: 0;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: 0;
  }
  .hero__copy { grid-area: 1 / 1 / 2 / 2; position: relative; z-index: 2; }
  .hero__art  {
    grid-area: 1 / 2 / 2 / 3;
    inline-size: auto;
    margin-inline-start: -9rem;   /* slides under the name */
    z-index: 1;
  }
  .hero__art img { aspect-ratio: 3/4; block-size: min(64svh, 38rem); inline-size: 100%; object-position: 50% 8%; }
  .hero__art::before { inset-inline-start: -1.2rem; }
  .hero__credit { padding-inline-start: 0.2rem; }
}

/* masked line reveal — each word rides up out of its own box */
.hero__name { font-size: clamp(3.2rem, 1.1rem + 8.4vw, 6rem); letter-spacing: -0.038em; }
.hero__name .ln { display: block; overflow: hidden; padding-block-end: 0.06em; }
.hero__name .ln > span { display: block; }
.hero__he {
  font-family: var(--display); font-weight: 700; color: var(--on-dark-muted);
  font-size: clamp(1.35rem, 0.9rem + 1.9vw, 2.15rem);
  line-height: 1; margin-block: 0.5rem 1.4rem;
}
.hero__claim {
  font-size: clamp(1.1rem, 0.95rem + 0.8vw, 1.5rem);
  font-weight: 600; line-height: 1.35; max-inline-size: 20ch;
}
.hero__claim b { color: var(--gold); font-weight: 600; }
.hero__next { margin-block-start: 1.3rem; color: var(--on-dark-muted); max-inline-size: 32ch; }
.hero__cta { margin-block-start: 2.2rem; display: flex; flex-wrap: wrap; gap: 0.85rem; }

/* ---------- scoreboard strip ---------- */
.board {
  position: relative; z-index: 2;
  border-block: 1px solid color-mix(in oklab, var(--on-dark) 14%, transparent);
  background: color-mix(in oklab, var(--s0) 55%, transparent);
  backdrop-filter: blur(6px);
}
@media (min-width: 60rem) { .hero .board { position: absolute; inset-inline: 0; inset-block-end: 0; } }
.board__in {
  max-inline-size: var(--shell); margin-inline: auto; padding-inline: var(--pad);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
}
.board dl { padding: 1.05rem 0; }
.board__in > dl + dl {
  border-inline-start: 1px solid color-mix(in oklab, var(--on-dark) 12%, transparent);
  padding-inline-start: 1.15rem;
}
.board dt {
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--on-dark-muted); font-weight: 700;
}
.board dd { font-size: 1.02rem; font-weight: 700; margin-block-start: 0.18rem; font-variant-numeric: tabular-nums; }
[lang="he"] .board dt { text-transform: none; letter-spacing: 0.01em; font-size: 0.78rem; }

/* ============================================================
   IPPON — the moment. One number, one line. Everything on the
   page is quieter than this by design.
   ============================================================ */
.ippon {
  position: relative; text-align: center; overflow: clip;
  background: var(--s0);
  padding-block: clamp(6rem, 14vw, 11rem);
}
.ippon::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(60% 100% at 50% 100%, color-mix(in oklab, var(--gold) 22%, transparent) 0%, transparent 70%);
}
.ippon > * { position: relative; }
.ippon__num {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(5rem, 2rem + 17vw, 15rem);
  line-height: 0.82; letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
  color: var(--on-dark);
}
.ippon__word {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.3rem, 0.9rem + 1.8vw, 2.2rem);
  color: var(--gold); letter-spacing: 0.02em;
  margin-block-start: 0.5rem;
}
.ippon__say {
  margin-block-start: 1.6rem; margin-inline: auto; max-inline-size: 34ch;
  color: var(--on-dark-muted); font-size: clamp(1rem, 0.95rem + 0.35vw, 1.2rem);
}
.ippon__cta { margin-block-start: 2.2rem; display: flex; justify-content: center; }

/* ---------- section heads ---------- */
.head { margin-block-end: clamp(2rem, 4vw, 3.5rem); max-inline-size: 44ch; }
.head p { margin-block-start: 0.8rem; color: var(--on-dark-muted); }
.band-gi .head p { color: var(--on-gi-muted); }

/* ---------- about ---------- */
.about { display: grid; gap: clamp(2rem, 5vw, 4rem); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 56rem) {
  .about { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); }
  .about__portrait { position: sticky; inset-block-start: 6rem; }
}
.about__portrait img { inline-size: 100%; aspect-ratio: 3/4; object-fit: cover; border-radius: 2px; }
.pull {
  /* No accent side-stripe. The quote earns its weight from size and from a
     hanging quote mark, which is what a typesetter would actually do. */
  margin-block-start: 2.8rem;
  position: relative;
  font-family: var(--display); font-weight: 700;
  font-size: clamp(1.35rem, 1rem + 1.35vw, 2rem); line-height: 1.22;
  letter-spacing: -0.02em;
  max-inline-size: 26ch;
}
/* The copy already carries real typographic quotes, so a decorative glyph
   would just double them. Hang the real ones instead. */
.pull { hanging-punctuation: first; }
.pull cite { display: block; margin-block-start: 0.7rem; font: 600 0.88rem/1 var(--body); font-style: normal; color: var(--on-dark-muted); }

/* ============================================================
   HONOURS — an index, not cards. Big year, event name that
   grows into the rust on hover, medal as a physical disc.
   ============================================================ */
.honours { border-block-start: 2px solid var(--s0); }
.honour {
  display: grid; align-items: baseline;
  grid-template-columns: minmax(5rem, auto) 1fr auto;
  gap: 0.35rem clamp(1rem, 3vw, 2.5rem);
  padding-block: clamp(1.4rem, 2.4vw, 2.1rem);
  border-block-end: 1px solid var(--gi-line);
  transition: background 260ms var(--out);
}
@media (hover: hover) {
  .honour:hover { background: var(--gi-2); }
  .honour:hover .honour__year { color: var(--gold); }
}
.honour__year {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.8rem, 1.1rem + 2.4vw, 3.2rem);
  line-height: 0.9; color: var(--on-gi-muted);
  font-variant-numeric: tabular-nums;
  transition: color 260ms var(--out);
}
.honour__what { font-weight: 700; font-size: clamp(1.05rem, 0.95rem + 0.6vw, 1.4rem); color: var(--s0); line-height: 1.2; }
/* 1rem, not the 0.94rem it was: this line is a sentence someone reads
   (where and when the medal happened), not a label, so it holds the 16px
   body-text floor same as everything else in the record. */
.honour__where { color: var(--on-gi-muted); font-size: 1rem; margin-block-start: 0.25rem; }
@media (max-width: 46rem) {
  .honour { grid-template-columns: minmax(4rem, auto) 1fr; }
  .honour__medal { grid-column: 2; }
}

.medal { display: inline-flex; align-items: center; gap: 0.55rem; white-space: nowrap; font-weight: 700; font-size: 0.95rem; }
.medal::before {
  content: ""; inline-size: 0.8rem; block-size: 0.8rem; border-radius: 50%; flex: none;
  background: var(--dot, currentColor);
  box-shadow: inset 0 1px 1px color-mix(in oklab, white 45%, transparent);
}
.medal--gold   { --dot: var(--gold); }
.medal--silver { --dot: var(--m-silver); }
.medal--bronze { --dot: var(--m-bronze); }
.medal--title  { --dot: oklch(0.62 0.012 258); }   /* an award is not a gold medal */

/* ---------- results tables ---------- */
.table-wrap { position: relative; overflow-x: auto; }
/* The table scrolls sideways on a phone but nothing said so. .is-scrollable
   is set by site.js only when the table actually needs it (never guessed
   from a breakpoint), so this never paints over a table that already fits.
   The fade sits on the trailing edge — where the hidden columns are — and
   clears once scrolled to the end. */
.table-wrap.is-scrollable::after {
  content: ""; position: absolute; inset-block: 0; inset-inline-end: 0;
  inline-size: 2.75rem; pointer-events: none;
  background: linear-gradient(to right, transparent, var(--gi) 78%);
  transition: opacity 200ms var(--out);
}
[dir="rtl"] .table-wrap.is-scrollable::after {
  background: linear-gradient(to left, transparent, var(--gi) 78%);
}
.table-wrap.is-scrollable.at-end::after { opacity: 0; }
table.results { inline-size: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; min-inline-size: 34rem; }
table.results caption { text-align: start; font-weight: 600; padding-block-end: 0.85rem; color: var(--on-gi-muted); font-size: 0.94rem; }
table.results th, table.results td {
  text-align: start; padding: 0.9rem 1rem 0.9rem 0;
  border-block-end: 1px solid var(--gi-line); vertical-align: baseline;
}
table.results thead th {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.13em;
  color: var(--on-gi-muted); border-block-end: 2px solid var(--s0); padding-block-end: 0.6rem;
}
[lang="he"] table.results thead th { text-transform: none; letter-spacing: 0; font-size: 0.84rem; }
table.results tbody tr { transition: background 200ms var(--out); }
@media (hover: hover) { table.results tbody tr:hover { background: var(--gi-2); } }
table.results td:first-child { font-weight: 700; inline-size: 5.5rem; }
table.results .event { font-weight: 600; color: var(--s0); }
table.results .where { display: block; font-size: 0.85rem; color: var(--on-gi-muted); font-weight: 400; }

/* ---------- video ---------- */
.videos { display: grid; gap: clamp(1rem, 2vw, 1.75rem); grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
@media (min-width: 62rem) {
  .videos { grid-template-columns: 1.6fr 1fr 1fr; align-items: start; }
  .videos > :first-child { grid-row: span 1; }
}
.vid { border: 0; padding: 0; background: none; text-align: start; cursor: pointer; display: block; inline-size: 100%; }
.vid__frame {
  /* display:block matters: these are <span>s inside a <button>, so without it
     the frame, the title and the meta all sit in one inline run and the text
     wraps into the same line. */
  display: block;
  position: relative; aspect-ratio: 16/9; overflow: hidden;
  border-radius: var(--r); background: var(--s2);
}
.vid__frame img {
  inline-size: 100%; block-size: 100%; object-fit: cover;
  transition: transform 700ms var(--out-soft), opacity 300ms var(--out);
}
.vid__play {
  position: absolute; inset: 0; margin: auto;
  inline-size: 3.6rem; block-size: 3.6rem; border-radius: 50%;
  background: var(--gold); display: grid; place-items: center;
  transition: transform 320ms var(--out);
}
.vid__play::after {
  content: ""; inline-size: 0; block-size: 0;
  border-inline-start: 1rem solid oklch(0.99 0 0);
  border-block: 0.64rem solid transparent;
  margin-inline-start: 0.28rem;
}
[dir="rtl"] .vid__play::after { transform: scaleX(-1); }
@media (hover: hover) {
  .vid:hover .vid__frame img { transform: scale(1.05); opacity: 0.8; }
  .vid:hover .vid__play { transform: scale(1.12); }
}
.vid:active .vid__play { transform: scale(0.97); transition-duration: 90ms; }
.vid__title { display: block; margin-block-start: 0.95rem; font-weight: 700; font-size: 1.05rem; line-height: 1.25; }
.vid__meta { display: block; margin-block-start: 0.2rem; color: var(--on-dark-muted); font-size: 0.9rem; }
.vid iframe {
  position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
  border: 0;
  /* The player fades up rather than snapping in. @starting-style gives the
     enter state without needing a class toggle in JS. */
  animation: vid-in 320ms var(--out) both;
}
@keyframes vid-in { from { opacity: 0; transform: scale(1.02); } to { opacity: 1; transform: none; } }

/* Pressed state: the poster dips and the button reads as accepting the click
   before the player has loaded, which is the whole difference between
   "nothing happened" and "it is coming". */
.vid[aria-busy="true"] .vid__frame img { opacity: 0.35; transform: scale(1.04); }
.vid[aria-busy="true"] .vid__play { opacity: 0; transform: scale(0.7); }
.vid__play { opacity: 1; transition: transform 320ms var(--out), opacity 220ms var(--out); }

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

/* ============================================================
   GALLERY — deliberately uneven. Two images earn full width;
   the rest sit in a tighter rhythm around them.
   ============================================================ */
.gallery { display: grid; gap: clamp(0.6rem, 1.4vw, 1.1rem); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 52rem) { .gallery { grid-template-columns: repeat(6, 1fr); } }
.gallery figure { margin: 0; position: relative; overflow: hidden; border-radius: 2px; }
.gallery img {
  inline-size: 100%; block-size: 100%; object-fit: cover;
  filter: saturate(0.94);
  transition: transform 900ms var(--out-soft), filter 500ms var(--out);
}
@media (hover: hover) { .gallery figure:hover img { transform: scale(1.05); filter: saturate(1.06); } }
.gallery figcaption {
  position: absolute; inset-inline: 0; inset-block-end: 0;
  padding: 2.5rem 1rem 0.85rem;
  font-size: 0.8rem; font-weight: 600; color: oklch(0.99 0 0);
  background: linear-gradient(to top, oklch(0.14 0.04 258 / 0.85), transparent);
}
@media (min-width: 52rem) {
  .g-wide  { grid-column: span 4; aspect-ratio: 16/10; }
  .g-tall  { grid-column: span 2; aspect-ratio: 4/5; }
  .g-half  { grid-column: span 3; aspect-ratio: 3/2; }
  .g-third { grid-column: span 2; aspect-ratio: 3/2; }
  .g-full  { grid-column: span 6; aspect-ratio: 21/9; }
}
@media (max-width: 51.99rem) { .gallery figure { aspect-ratio: 4/3; } .g-wide, .g-full { grid-column: span 2; } }

/* ============================================================
   PARTNERS — the one thing both elite judo sites (Riner,
   Paltchik) treat as first-class. These are dark-ink logos, so
   each sits on its own white plate rather than being inverted
   with a brightness hack that washes it out.
   ============================================================ */
.partners-grid { display: grid; gap: clamp(2rem, 5vw, 4.5rem); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 56rem) { .partners-grid { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); } }
.partners-pitch p { color: var(--on-dark-muted); margin-block-start: 0.85rem; max-inline-size: 40ch; }
.partners-pitch .btn { margin-block-start: 1.8rem; }

.partners { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.partners li { list-style: none; }
.partners a, .partners span {
  display: grid; place-items: center;
  min-inline-size: 9.5rem; min-block-size: 5rem;
  padding: 1rem 1.5rem; border-radius: 3px;
  background: var(--gi);
  transition: transform 300ms var(--out), background 300ms var(--out);
}
.partners img {
  block-size: auto; inline-size: auto;
  max-block-size: 2.4rem; max-inline-size: 100%;
  filter: saturate(0.9); transition: filter 300ms var(--out);
}
@media (hover: hover) {
  .partners a:hover { transform: translateY(-3px); }
  .partners a:hover img { filter: none; }
}

/* ---------- contact ---------- */
.routes { list-style: none; padding: 0; margin-block: 1.6rem 2rem; display: grid; gap: 0; }
.routes li { border-block-start: 1px solid color-mix(in oklab, currentColor 28%, transparent); }
.routes li:last-child { border-block-end: 1px solid color-mix(in oklab, currentColor 28%, transparent); }
.routes a {
  display: flex; align-items: baseline; gap: 1rem;
  padding-block: 0.95rem; text-decoration: none; font-weight: 700;
  transition: padding-inline-start 260ms var(--out), opacity 200ms var(--out);
}
.routes a span { margin-inline-start: auto; font-weight: 400; opacity: 0.72; font-size: 0.9rem; }
@media (max-width: 40rem) { .routes a span { display: none; } }
@media (hover: hover) { .routes a:hover { padding-inline-start: 0.6rem; } }

.contact { background: var(--s2); color: var(--on-dark); border-block-start: 1px solid var(--hair); box-shadow: inset 0 1px 0 var(--lift); }
.contact h2 { color: inherit; }
.contact__grid { display: grid; gap: clamp(2rem, 5vw, 4rem); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 52rem) { .contact__grid { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); } }
.contact a.mail {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.35rem, 0.9rem + 2.2vw, 2.6rem);
  text-decoration: none; display: inline-block; word-break: break-word;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 100% 3px; background-position: 0 100%; background-repeat: no-repeat;
  transition: background-size 320ms var(--out), opacity 200ms var(--out);
}
/* Thicken the rule and go gold. The previous version grew the underline to
   100% height, which filled the link with its own text colour and produced a
   solid white block. */
@media (hover: hover) {
  .contact a.mail:hover { background-size: 100% 6px; color: var(--gold); }
}
.socials { display: flex; flex-wrap: wrap; gap: 0.55rem; margin-block-start: 1.4rem; list-style: none; padding: 0; }
.socials a {
  position: relative;
  display: inline-block; padding: 0.5rem 1.1rem; border-radius: 999px;
  border: 1.5px solid color-mix(in oklab, currentColor 42%, transparent);
  text-decoration: none; font-weight: 700; font-size: 0.9rem;
  transition: background 220ms var(--out), border-color 220ms var(--out), transform 160ms var(--out);
}
/* Measured 41px tall at 390px — just under the 44px tap-target floor. */
.socials a::before { content: ""; position: absolute; inset-block: -2px; inset-inline: 0; }
.socials a:active { transform: scale(0.97); transition-duration: 90ms; }
@media (hover: hover) { .socials a:hover { background: oklch(0.99 0 0 / 0.17); border-color: currentColor; } }

/* ---------- footer ---------- */
.site-foot { background: var(--s0); padding-block: 2.75rem; font-size: 0.88rem; color: var(--on-dark-muted); }
.site-foot__in { display: flex; flex-wrap: wrap; gap: 1rem 2rem; align-items: center; }
.site-foot a { color: var(--on-dark); }
@media (min-width: 40rem) { .site-foot p:last-child { margin-inline-start: auto; } }

/* ============================================================
   MOTION
   Three distinct reveals, chosen per element. A single uniform
   fade-up on every section is the tell we are avoiding.
   ============================================================ */

/* hero: words ride up out of their masks, staggered */
@keyframes lift { from { transform: translateY(105%); } to { transform: translateY(0); } }
@keyframes fade { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes plate { from { opacity: 0; transform: translateY(28px) scale(1.04); } to { opacity: 1; transform: none; } }

.hero__name .ln > span { animation: lift 1s var(--out-soft) both; }
.hero__name .ln:nth-child(2) > span { animation-delay: 90ms; }
.hero__he    { animation: fade 700ms var(--out) 260ms both; }
.hero__claim { animation: fade 700ms var(--out) 340ms both; }
.hero__next  { animation: fade 700ms var(--out) 420ms both; }
.hero__cta   { animation: fade 700ms var(--out) 500ms both; }
.hero__art   { animation: plate 1.1s var(--out-soft) 120ms both; }
.hero .board { animation: fade 700ms var(--out) 620ms both; }

/* Scroll reveals only exist once JS has confirmed it can undo them.
   Without JS every element renders in its final state. */
html.js .rv-mask,
html.js .rv-rise,
html.js .rv-zoom { --d: calc(var(--i, 0) * 28ms); }

/* The resting state is deliberately NOT invisible. These used to start at
   opacity 0 with a clip-path covering the element, which meant that if the
   observer had not fired yet, or the reveal was slow, an entire section read
   as an empty page. A reveal has to enhance something already legible. */
html.js .rv-mask { clip-path: inset(0 0 24% 0); opacity: 0.55; }
html.js .rv-mask.in {
  clip-path: inset(0 0 0 0); opacity: 1;
  transition: clip-path 380ms var(--out-soft) var(--d), opacity 260ms var(--out) var(--d);
}

html.js .rv-rise { opacity: 0.5; transform: translateY(12px); }
html.js .rv-rise.in {
  opacity: 1; transform: none;
  transition: opacity 340ms var(--out) var(--d), transform 420ms var(--out-soft) var(--d);
}

html.js .rv-zoom > img,
html.js .rv-zoom.rv-self { opacity: 0.6; transform: scale(1.03); }
html.js .rv-zoom.in > img,
html.js .rv-zoom.rv-self.in {
  opacity: 1; transform: none;
  transition: opacity 700ms var(--out) var(--d), transform 1.1s var(--out-soft) var(--d);
}

@media (prefers-reduced-motion: reduce) {
  /* Keep a gentle fade — removing all motion entirely is its own failure. */
  *, *::before, *::after {
    animation-duration: 260ms !important;
    animation-delay: 0ms !important;
    transition-duration: 200ms !important;
    transition-delay: 0ms !important;
  }
  @keyframes lift  { from { opacity: 0; transform: none; } to { opacity: 1; transform: none; } }
  @keyframes plate { from { opacity: 0; transform: none; } to { opacity: 1; transform: none; } }
  @keyframes fade  { from { opacity: 0; transform: none; } to { opacity: 1; transform: none; } }
  html.js .rv-mask { clip-path: none; opacity: 0; }
  html.js .rv-mask.in { clip-path: none; opacity: 1; transition: opacity 260ms linear; }
  html.js .rv-rise { transform: none; filter: none; }
  html.js .rv-rise.in { transform: none; filter: none; }
  html.js .rv-zoom > img, html.js .rv-zoom.rv-self { transform: none; }
  html.js .rv-zoom.in > img, html.js .rv-zoom.rv-self.in { transform: none; }
  .btn:active, .socials a:active, .vid:active .vid__play { transform: none; }
}

/* ---------- print ---------- */
@media print {
  body { background: #fff; color: #000; }
  body::after, .site-head, .hero__art, .videos, .contact, .gallery, .ippon { display: none; }
}

/* ============================================================
   THE VERBS
   Four words that describe how she fights. They are the site's
   own plain statement, not a quoted self-description, because
   attributing them to her was what made them read as a boast
   rather than a fact. Hard cuts rather than crossfades: the
   motion should read like a scoreboard flipping.
   ============================================================ */
.hero__words { --hw-frame: 2.5rem; margin-block-start: 1.5rem; }
@media (min-width: 48rem) { .hero__words { --hw-frame: 3.4rem; } }

.hw__slot {
  display: block; overflow: hidden;
  block-size: var(--hw-frame);
  border-inline-start: 2px solid var(--gold);
  padding-inline-start: 0.9rem;
}
.hw__reel { display: block; }
.hw__reel b {
  display: flex; align-items: center;
  block-size: var(--hw-frame);
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.55rem, 1.05rem + 2.2vw, 2.7rem);
  line-height: 1; letter-spacing: -0.03em;
  color: var(--gold);
}

/* Four frames. translateY wraps back to 0 at the end of the cycle, which is
   a jump, so the last hold is where the reel is idle longest and the reset
   lands during that hold rather than mid-motion. */
@keyframes reel {
   0%,  20% { transform: translateY(0); }
  25%,  45% { transform: translateY(calc(-1 * var(--hw-frame))); }
  50%,  70% { transform: translateY(calc(-2 * var(--hw-frame))); }
  75%, 100% { transform: translateY(calc(-3 * var(--hw-frame))); }
}
.hw__reel { animation: reel 11s var(--inout) infinite; }

/* ============================================================
   SCROLL-DRIVEN MOTION
   Native CSS timelines where the browser has them. No library,
   no scroll listener, nothing to jank. Everything below is an
   enhancement on top of content that is already visible.
   ============================================================ */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* The nine seconds get longer as you come down on them. The number
       is the event, so the scroll position is allowed to drive it. */
    .ippon__num {
      animation: ippon-grow linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 55%;
    }
    @keyframes ippon-grow {
      from { transform: scale(0.72); letter-spacing: 0.06em; opacity: 0.35; }
      to   { transform: scale(1);    letter-spacing: -0.04em; opacity: 1; }
    }

    /* The gold under the ippon rises with it rather than sitting there. */
    .ippon::before {
      animation: ippon-glow linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 60%;
    }
    @keyframes ippon-glow {
      from { opacity: 0; transform: translateY(30%); }
      to   { opacity: 1; transform: translateY(0); }
    }

    /* The hero photo holds still while the page moves past it. One
       subtle layer, not a parallax hero. Desktop only: on a phone the
       photograph leads the hero rather than sitting beside it, so drifting
       it just scales the image past its frame for no gain. */
    @media (min-width: 68rem) {
    .hero__art img {
      animation: hero-drift linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    }
    @keyframes hero-drift {
      from { transform: scale(1.06) translateY(-1.5%); }
      to   { transform: scale(1.06) translateY(1.5%); }
    }
  }
}

/* ============================================================
   SURFACE RAMP IN USE
   Sections sit at different heights instead of one flat fill.
   On a dark ground lightness is the depth cue, so this is what
   stops the page reading as a coloured wallpaper.
   ============================================================ */
.band-1 { background: var(--s1); }
.band-2 { background: var(--s2); }

/* Hairline separators instead of solid borders, and an inset top
   highlight so a raised band reads as edge-lit rather than pasted. */
.band-1, .band-2 {
  border-block-start: 1px solid var(--hair);
  box-shadow: inset 0 1px 0 var(--lift);
}

@media (prefers-reduced-motion: reduce) {
  .hw__reel { animation: none; }
  /* Without the reel, show one fact rather than a blank slot. */
  .hw__slot { block-size: auto; }
  .hw__reel b:not(:first-child) { display: none; }
}

/* The sub-minute tournament. A second fact, deliberately quieter than
   the 0:09, so the section still has one loud thing in it and not two.
   Quieter is colour and weight, not the 16px body-text floor — it stays
   a full sentence, so the size holds at 1rem. */
.ippon__also {
  margin-block-start: 1.1rem;
  color: var(--on-dark-faint);
  font-size: 1rem;
  max-inline-size: 46ch; margin-inline: auto;
}
.ippon__also b { color: var(--on-dark-muted); font-weight: 700; }

/* ============================================================
   HERO OVERLAP
   The two-column hero was polite: a text box next to a picture
   box, both rectangles, a clean seam down the middle. Breaking
   the seam is what stops it reading as a template. The name now
   crosses into the photograph, the photograph runs off the
   trailing edge, and a scrim keeps the type readable where the
   two planes overlap.
   ============================================================ */
@media (min-width: 68rem) {
  .hero__grid { grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr); }

  .hero__copy {
    position: relative; z-index: 2;
    margin-inline-end: clamp(-9rem, -7vw, -4rem);
  }
  .hero__art {
    /* auto, not 100%: with a negative start margin, a percentage width resolves
       against the column and drags the whole box inward, leaving a gap at the
       trailing edge. auto + stretch pins the trailing edge to the viewport. */
    inline-size: auto; justify-self: stretch; align-self: stretch;
    margin-inline-start: clamp(-11rem, -8vw, -5rem);
    /* Cancel the grid's own vertical padding so the photograph runs the full
       height of the hero. Three edges bleed; only the leading one is a seam,
       and the scrim softens that one. */
    margin-block: calc(-1 * clamp(5rem, 12vh, 7.5rem)) calc(-1 * clamp(8rem, 16vh, 10rem));
    position: relative;
  }
  .hero__art img { aspect-ratio: auto; block-size: 100%; min-block-size: 34rem; }

  /* Scrim. Logical properties cannot express a gradient direction, so this is
     the one place the RTL page needs an explicit override. */
  .hero__art::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(to right,
      var(--s0) 0%,
      color-mix(in oklab, var(--s0) 62%, transparent) 26%,
      transparent 58%);
  }
  [dir="rtl"] .hero__art::after {
    background: linear-gradient(to left,
      var(--s0) 0%,
      color-mix(in oklab, var(--s0) 62%, transparent) 26%,
      transparent 58%);
  }

  /* The gold edge-line belongs on the outside of the frame, not under a scrim. */
  .hero__art::before { display: none; }

  /* The credit sat on top of the photograph and was unreadable. Move it out
     to the bottom of the frame with its own footing. */
  .hero__credit {
    position: absolute; inset-block-end: 1rem; inset-inline-end: 1.25rem;
    margin: 0; z-index: 3;
    color: var(--on-dark);
    text-shadow: 0 1px 6px oklch(0.12 0.02 258 / 0.9);
  }

  /* Bigger. The name is the loudest thing on the page and it should be. */
  .hero__name { font-size: clamp(4rem, 1rem + 9.6vw, 8.2rem); }
}

/* ============================================================
   NARROW SCREENS
   Two real defects at 390px: the nav ran past the trailing edge
   and body{overflow-x:hidden} silently clipped the last links,
   and the two hero buttons sat on one row wider than the screen.
   Hiding overflow is not fixing it, so both now fit.
   ============================================================ */
@media (max-width: 46rem) {
  /* The nav scrolls rather than being clipped. Every link stays reachable. */
  .site-head__in { gap: 0.9rem; }
  .site-nav {
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    min-inline-size: 0;
    padding-block: 0.15rem;
    /* Fade only the trailing edge, where links actually go out of view.
       Fading the leading edge too clipped the first link even when the
       nav had not been scrolled at all. */
    mask-image: linear-gradient(to right, #000 calc(100% - 1.4rem), transparent 100%);
  }
  .site-nav::-webkit-scrollbar { display: none; }
  [dir="rtl"] .site-nav {
    mask-image: linear-gradient(to left, #000 calc(100% - 1.4rem), transparent 100%);
  }
  .site-nav a { white-space: nowrap; }
  /* Sticky inside the scroller keeps the language switch reachable without
     scrolling the nav, which is what made it look cut off at the edge. */
  .lang-switch {
    position: sticky; inset-inline-end: 0;
    margin-inline-start: 0.35rem;
    background: var(--s0);
    box-shadow: -0.7rem 0 0.7rem var(--s0);
  }
  [dir="rtl"] .lang-switch { box-shadow: 0.7rem 0 0.7rem var(--s0); }
  .lang-switch { flex: 0 0 auto; }

  /* Buttons go full width and stack. A cut-off CTA is a dead CTA. */
  .hero__cta { display: grid; grid-template-columns: 1fr; gap: 0.7rem; }
  .hero__cta .btn { justify-content: center; inline-size: 100%; }
}

/* A button label must never wrap: shorten the label, do not let it break. */
.btn { white-space: nowrap; }

/* The hero is a grid, and its implicit column was `auto`, so it sized to the
   max-content of its widest child. The scoreboard strip never wraps, so at
   390px it demanded 720px and dragged the entire hero out with it, where
   overflow-x:hidden quietly clipped the buttons instead of showing a bug.
   minmax(0, 1fr) forbids a track from exceeding its container. */
.hero { grid-template-columns: minmax(0, 1fr); }

@media (max-width: 46rem) {
  /* Two columns of stats rather than five in a clipped row. */
  .board__in { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .board__in > dl + dl { border-inline-start: 0; padding-inline-start: 0; }
  .board dl { padding-block: 0.8rem; }
}

/* The portrait column was a short image above a tall empty gap. Letting it
   travel with the prose fills the column instead of leaving a hole. */
@media (min-width: 60rem) {
  .about__portrait { position: sticky; inset-block-start: 6rem; }
}

/* On the light band a pale gold dot nearly vanishes, so the medal swatches
   use their deeper cuts there. Same meaning, readable ground. */
.band-gi .medal--gold  { --dot: var(--gold-deep); }
.band-gi .medal--silver { --dot: oklch(0.62 0.012 258); }

/* ============================================================
   HERO PHOTO — NARROW SCREENS
   Below the desktop overlap breakpoint (68rem) the base rule caps
   the photo at 26rem and centres it, so on a phone it rendered as
   a small floating rectangle with dead space either side,
   disconnected from the name above it. Full-bleed it to the
   viewport edge instead, in a wider-but-shorter crop, so it reads
   as part of the hero rather than an afterthought under it. The
   desktop treatment (>=68rem, photo bleeding off the trailing
   edge under a scrim) is untouched — this only overrides the
   base centred-plate rule below it.
   ============================================================ */
@media (max-width: 67.99rem) {
  /* On a phone the two-column hero used to fold: copy first, then a slab of
     photograph underneath it with a hard edge. That reads as a collapsed
     desktop layout rather than a designed one. So the order is reversed. You
     meet her first and then read her name, which is how a magazine opens, and
     the bottom of the frame dissolves into the page so there is no seam
     between the picture and the words. */
  .hero__art {
    order: -1;
    justify-self: stretch;
    /* auto, not 100vw: 100vw counts the scrollbar and overshoots. A block
       element with auto width plus symmetric negative margins fills the
       container's padding exactly, whatever the scrollbar is doing. */
    inline-size: auto;
    margin-inline: calc(-1 * var(--pad));
    margin-block: calc(-1 * clamp(2rem, 6vh, 4rem)) clamp(0.5rem, 2vh, 1.5rem);
  }
  .hero__art img {
    aspect-ratio: 1 / 1;
    object-position: 50% 0%;
    block-size: clamp(17rem, 46svh, 26rem);
    inline-size: 100%;
    -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
  }
  .hero__grid { padding-block: clamp(2rem, 6vh, 4rem) clamp(3rem, 9vh, 5rem); }
  .hero__art::before { display: none; }
  /* The credit belongs under the picture, inside the page gutter again. */
  .hero__credit { padding-inline: var(--pad); margin-block-start: 0.4rem; }
}


/* ============================================================
   PARTNERS PAGE
   Its job is different from the rest of the site: a brand is
   deciding whether to spend money, so every section has to
   answer "what would we actually get" rather than impress.
   Logos are deliberately NOT the first thing, and each partner
   gets a story rather than a bare mark, because a logo wall
   reads as an afterthought.
   ============================================================ */
.crumb {
  font-size: 0.9rem; color: var(--on-dark-muted);
  margin-block-end: 1.25rem;
}
.crumb span { margin-inline: 0.4rem; opacity: 0.5; }

.pt-hero { padding-block: clamp(3rem, 8vw, 6rem) clamp(3rem, 7vw, 5rem); }
.pt-hero h1 {
  font-size: clamp(2.8rem, 1.2rem + 6.4vw, 6rem);
  letter-spacing: -0.038em;
}
.pt-lede { margin-block-start: 1.4rem; max-inline-size: 46ch; color: var(--on-dark-muted); }

/* The four numbers a brand scans for before reading a word. */
.pt-facts {
  list-style: none; padding: 0; margin-block-start: clamp(2.5rem, 5vw, 3.5rem);
  display: grid; gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  border-block-start: 1px solid var(--hair);
  padding-block-start: 1.5rem;
}
.pt-facts b {
  display: block; font-family: var(--display); font-weight: 900;
  font-size: clamp(1.9rem, 1.3rem + 2.2vw, 3rem); line-height: 1;
  letter-spacing: -0.035em; font-variant-numeric: tabular-nums;
}
.pt-facts span {
  display: block; margin-block-start: 0.45rem;
  font-size: 0.82rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--on-dark-faint);
}
[lang="he"] .pt-facts span { text-transform: none; letter-spacing: 0.02em; font-size: 0.9rem; }

.pt-why { display: grid; gap: clamp(2rem, 5vw, 4rem); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 60rem) { .pt-why { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); } }

/* One partner per row: logo on its own plate, story beside it. Not a grid of
   equal cards, because the partnerships are not equal and pretending they are
   is what makes these pages read as filler. */
.pt-list { list-style: none; padding: 0; margin: 0; }
.pt-card {
  display: grid; gap: clamp(1.25rem, 3vw, 2.5rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  padding-block: clamp(1.75rem, 4vw, 2.75rem);
  border-block-start: 1px solid var(--hair);
}
.pt-card:last-child { border-block-end: 1px solid var(--hair); }
@media (min-width: 46rem) {
  .pt-card { grid-template-columns: 14rem minmax(0, 1fr); }
}
/* Logos are supplied on white backgrounds, so they get a white plate rather
   than being knocked out onto the dark ground where they would look broken. */
.pt-card__logo {
  background: var(--gi); border-radius: var(--r);
  padding: 1rem 1.25rem; display: grid; place-items: center;
  inline-size: 14rem; max-inline-size: 100%;
  aspect-ratio: 5 / 2;
}
.pt-card__logo img { max-block-size: 100%; inline-size: auto; object-fit: contain; }
.pt-card__meta {
  font-size: 0.78rem; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--on-dark-faint); margin-block-end: 0.5rem;
}
[lang="he"] .pt-card__meta { text-transform: none; letter-spacing: 0.02em; font-size: 0.88rem; }
.pt-card h3 { margin-block-end: 0.6rem; }
.pt-card__body p:last-child { color: var(--on-dark-muted); max-inline-size: 60ch; }

/* Press: a link list, not logo soup. Every row goes somewhere checkable. */
.pt-press { list-style: none; padding: 0; margin: 0; display: grid; gap: 0; }
.pt-press li { border-block-start: 1px solid var(--hair); }
.pt-press li:last-child { border-block-end: 1px solid var(--hair); }
.pt-press a {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem 1rem;
  padding-block: 1.05rem; text-decoration: none;
  transition: color 200ms var(--out);
}
.pt-press b { font-family: var(--display); font-weight: 900; font-size: 1.15rem; letter-spacing: -0.02em; }
.pt-press span { color: var(--on-dark-muted); font-size: 0.95rem; }
.pt-press a::after {
  content: "\2192"; margin-inline-start: auto; color: var(--on-dark-faint);
  transition: transform 200ms var(--out), color 200ms var(--out);
}
[dir="rtl"] .pt-press a::after { content: "\2190"; }
@media (hover: hover) {
  .pt-press a:hover { color: var(--gold); }
  .pt-press a:hover::after { color: var(--gold); transform: translateX(3px); }
  [dir="rtl"] .pt-press a:hover::after { transform: translateX(-3px); }
}

.pt-comeback .prose { max-inline-size: 60ch; }
.pt-comeback .btn { margin-block-start: 2rem; }



/* ============================================================
   PRESS: HOVER-PREVIEW LIST
   The list stays scannable, which is what a sponsor actually
   uses, and hovering a row lights a photograph in the pane
   beside it. The photographs are hers, not the outlets': an
   article's hero image belongs to the publisher or the agency
   that shot it, so lifting them would be someone else's
   copyright on a commercial page. Pairing her own image with
   the outlet's name says the same thing and is hers to say.

   Pure CSS. :has() does the matching, so there is no JS and no
   third-party request.
   ============================================================ */
.pr { display: grid; gap: clamp(2rem, 4vw, 3.5rem); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 60rem) and (hover: hover) {
  .pr { grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); align-items: start; }
}

.pr-cols { display: grid; gap: clamp(2rem, 4vw, 3rem); }
@media (min-width: 46rem) and (max-width: 59.99rem) {
  .pr-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.pr-group__title {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--gold);
  font-family: var(--body);
  padding-block-end: 0.7rem;
  border-block-end: 1px solid var(--hair-2);
}
[lang="he"] .pr-group__title { text-transform: none; letter-spacing: 0.03em; font-size: 0.92rem; }

.pr-list { list-style: none; padding: 0; margin: 0; }
.pr-list li + li { border-block-start: 1px solid var(--hair); }

.pr-row {
  display: grid; gap: 0.1rem 0.9rem; padding-block: 0.85rem;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; text-decoration: none;
  transition: color 180ms var(--out);
}
.pr-out  { grid-column: 2; font-weight: 700; font-size: 0.95rem; }
.pr-when {
  grid-column: 3; grid-row: 1;
  font-size: 0.78rem; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--on-dark-faint); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
[lang="he"] .pr-when { text-transform: none; letter-spacing: 0.02em; font-size: 0.86rem; }
.pr-ttl { grid-column: 2; grid-row: 2; color: var(--on-dark-muted); font-size: 0.95rem; line-height: 1.4; }

/* The thumbnail is the touch fallback: with no hover there is no pane, so the
   picture has to live in the row itself rather than being unreachable. */
.pr-thumb {
  grid-column: 1; grid-row: 1 / 3;
  inline-size: 3rem; block-size: 3rem;
  object-fit: cover; border-radius: var(--r);
}

.pr-pane { display: none; }

@media (min-width: 60rem) and (hover: hover) {
  /* With a pane, the row thumbnails would be redundant noise. */
  .pr-thumb { display: none; }
  .pr-row { grid-template-columns: minmax(0, 1fr) auto; }
  .pr-out, .pr-ttl { grid-column: 1; }
  .pr-when { grid-column: 2; }

  .pr-pane {
    display: block; position: sticky; inset-block-start: 6rem;
    aspect-ratio: 3 / 4; border-radius: var(--r-lg);
    overflow: hidden; background: var(--s2);
    box-shadow: inset 0 1px 0 var(--lift);
  }
  .pr-shot {
    position: absolute; inset: 0; margin: 0;
    opacity: 0; transform: scale(1.04);
    transition: opacity 260ms var(--out), transform 520ms var(--out-soft);
  }
  .pr-shot img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
  /* A photograph on its own does not say what the piece was about. The line
     under it is pulled from the article itself, so five words is enough. */
  .pr-shot figcaption {
    position: absolute; inset-inline: 0; inset-block-end: 0;
    padding: 2.6rem 1.1rem 1.1rem;
    background: linear-gradient(to top, oklch(0.08 0.01 258 / 0.94) 38%, transparent);
  }
  .pr-shot__out {
    display: block; font-size: 0.68rem; font-weight: 700;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--gold);
    margin-block-end: 0.35rem;
  }
  [lang="he"] .pr-shot__out { text-transform: none; letter-spacing: 0.04em; font-size: 0.8rem; }
  .pr-shot__hl {
    display: block; color: var(--on-dark);
    font-family: var(--display); font-weight: 900;
    font-size: 1.12rem; line-height: 1.16; letter-spacing: -0.02em;
  }
  .pr-shot__hl.is-quote { font-weight: 700; font-style: italic; letter-spacing: -0.01em; }
  /* Resting state: the first photograph sits at low opacity so the pane never
     reads as a broken empty box before anyone has hovered anything. */
  .pr-pane .pr-shot:first-child { opacity: 0.5; transform: scale(1); }

.pr:has(.pr-row[data-k="r0"]:hover) .pr-shot[data-k="r0"],
.pr:has(.pr-row[data-k="r0"]:focus-visible) .pr-shot[data-k="r0"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r1"]:hover) .pr-shot[data-k="r1"],
.pr:has(.pr-row[data-k="r1"]:focus-visible) .pr-shot[data-k="r1"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r2"]:hover) .pr-shot[data-k="r2"],
.pr:has(.pr-row[data-k="r2"]:focus-visible) .pr-shot[data-k="r2"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r3"]:hover) .pr-shot[data-k="r3"],
.pr:has(.pr-row[data-k="r3"]:focus-visible) .pr-shot[data-k="r3"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r4"]:hover) .pr-shot[data-k="r4"],
.pr:has(.pr-row[data-k="r4"]:focus-visible) .pr-shot[data-k="r4"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r5"]:hover) .pr-shot[data-k="r5"],
.pr:has(.pr-row[data-k="r5"]:focus-visible) .pr-shot[data-k="r5"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r6"]:hover) .pr-shot[data-k="r6"],
.pr:has(.pr-row[data-k="r6"]:focus-visible) .pr-shot[data-k="r6"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r7"]:hover) .pr-shot[data-k="r7"],
.pr:has(.pr-row[data-k="r7"]:focus-visible) .pr-shot[data-k="r7"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r8"]:hover) .pr-shot[data-k="r8"],
.pr:has(.pr-row[data-k="r8"]:focus-visible) .pr-shot[data-k="r8"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r9"]:hover) .pr-shot[data-k="r9"],
.pr:has(.pr-row[data-k="r9"]:focus-visible) .pr-shot[data-k="r9"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r10"]:hover) .pr-shot[data-k="r10"],
.pr:has(.pr-row[data-k="r10"]:focus-visible) .pr-shot[data-k="r10"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r11"]:hover) .pr-shot[data-k="r11"],
.pr:has(.pr-row[data-k="r11"]:focus-visible) .pr-shot[data-k="r11"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r12"]:hover) .pr-shot[data-k="r12"],
.pr:has(.pr-row[data-k="r12"]:focus-visible) .pr-shot[data-k="r12"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r13"]:hover) .pr-shot[data-k="r13"],
.pr:has(.pr-row[data-k="r13"]:focus-visible) .pr-shot[data-k="r13"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r14"]:hover) .pr-shot[data-k="r14"],
.pr:has(.pr-row[data-k="r14"]:focus-visible) .pr-shot[data-k="r14"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r15"]:hover) .pr-shot[data-k="r15"],
.pr:has(.pr-row[data-k="r15"]:focus-visible) .pr-shot[data-k="r15"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r16"]:hover) .pr-shot[data-k="r16"],
.pr:has(.pr-row[data-k="r16"]:focus-visible) .pr-shot[data-k="r16"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r17"]:hover) .pr-shot[data-k="r17"],
.pr:has(.pr-row[data-k="r17"]:focus-visible) .pr-shot[data-k="r17"] { opacity: 1; transform: scale(1); }
.pr:has(.pr-row[data-k="r18"]:hover) .pr-shot[data-k="r18"],
.pr:has(.pr-row[data-k="r18"]:focus-visible) .pr-shot[data-k="r18"] { opacity: 1; transform: scale(1); }

  @media (hover: hover) {
    .pr-row:hover .pr-out { color: var(--gold); }
    .pr-row:hover .pr-ttl { color: var(--on-dark); }
  }
}

@media (prefers-reduced-motion: reduce) {
  .pr-shot { transition-duration: 1ms; }
}

/* ============================================================
   INSTAGRAM
   Self-hosted stills, not an embed. Instagram's Basic Display
   API was shut off in December 2024 and everything left needs a
   third-party script in the visitor's browser, which this site
   does not do. So the posts are fetched once, resized, committed
   and rendered as plain HTML by tools/build-social.py.

   No lightbox on purpose: a tile opens the real post, so the
   engagement lands where it counts rather than being trapped
   here.
   ============================================================ */
.ig-head {
  display: flex; flex-wrap: wrap; gap: 1.5rem 2rem;
  align-items: end; justify-content: space-between;
  margin-block-end: clamp(1.75rem, 3vw, 2.5rem);
}
.ig-cta { display: flex; flex-direction: column; align-items: flex-start; gap: 0.6rem; }
.ig-count {
  font-size: 0.8rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--on-dark-faint);
}
[lang="he"] .ig-count { text-transform: none; letter-spacing: 0.02em; font-size: 0.88rem; }

.ig-grid {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: clamp(0.4rem, 1vw, 0.7rem);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 34rem) { .ig-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 56rem) { .ig-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 80rem) { .ig-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); } }

.ig-cell a {
  display: block; position: relative; overflow: hidden;
  border-radius: var(--r); background: var(--s2);
  aspect-ratio: 1;
}
.ig-cell img {
  inline-size: 100%; block-size: 100%; object-fit: cover;
  transition: transform 620ms var(--out-soft), opacity 260ms var(--out);
}
/* A gold wash on hover rather than a logo overlay: the accent already means
   "this is hers", and a pasted Instagram glyph on every tile is noise. */
.ig-cell a::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, color-mix(in oklab, var(--gold) 55%, transparent), transparent 60%);
  opacity: 0; transition: opacity 260ms var(--out);
}
@media (hover: hover) {
  .ig-cell a:hover img { transform: scale(1.06); }
  .ig-cell a:hover::after { opacity: 1; }
}
.ig-cell a:focus-visible::after { opacity: 1; }
.ig-cell a:active img { transform: scale(0.99); transition-duration: 90ms; }

/* Reels get a marker so a still does not silently misrepresent a video. */
.ig-reel {
  position: absolute; inset-block-start: 0.5rem; inset-inline-end: 0.5rem;
  inline-size: 0; block-size: 0;
  border-inline-start: 0.62rem solid oklch(1 0 0 / 0.92);
  border-block: 0.4rem solid transparent;
  filter: drop-shadow(0 1px 3px oklch(0.1 0 0 / 0.6));
}
[dir="rtl"] .ig-reel { transform: scaleX(-1); }

@media (prefers-reduced-motion: reduce) {
  .ig-cell img { transition-duration: 1ms; }
}
