/* ==========================================================================
   Loïc Goethals — one pager
   ========================================================================== */

:root {
  --bg:          #080c0a;
  --bg-raised:   #0e1512;
  --bg-card:     rgba(255, 255, 255, 0.035);

  --ink:         #f2efe7;
  --ink-soft:    #a8b0aa;
  --ink-faint:   #6b736d;

  --accent:      #4ade80;
  --accent-deep: #15803d;
  --accent-glow: rgba(74, 222, 128, 0.16);

  --line:        rgba(255, 255, 255, 0.10);
  --line-strong: rgba(255, 255, 255, 0.20);

  /* Podium + scoring */
  --gold:      #fbbf24;
  --silver:    #cbd5e1;
  --bronze:    #d08a4e;
  --under-par: #ff6b5e;

  --display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --body:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --gutter: clamp(1.25rem, 5vw, 5.5rem);
  --maxw:   1180px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ------------------------------------------------------------------ reset */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--body);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Page-wide green wash, fixed so it stays put while the content scrolls.
   Sits behind everything; sections paint their own surfaces on top. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(75% 50% at 82% 0%, rgba(21, 128, 61, 0.20), transparent 62%),
    radial-gradient(65% 45% at 0% 55%, rgba(21, 128, 61, 0.11), transparent 66%),
    radial-gradient(70% 40% at 60% 100%, rgba(16, 94, 45, 0.14), transparent 64%);
}

img { display: block; max-width: 100%; }
a   { color: inherit; }

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.02;
  margin: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: #05210f;
  padding: 0.75rem 1.25rem;
  font-weight: 600;
  z-index: 999;
}
.skip-link:focus { left: 0; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

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

/* -------------------------------------------------------------------- nav */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem var(--gutter);
  transition: background 0.4s var(--ease), backdrop-filter 0.4s var(--ease),
              border-color 0.4s var(--ease), padding 0.4s var(--ease);
  border-bottom: 1px solid transparent;
}

.nav.is-stuck {
  background: rgba(8, 12, 10, 0.82);
  backdrop-filter: blur(14px) saturate(150%);
  border-bottom-color: var(--line);
  padding-top: 0.8rem;
  padding-bottom: 0.8rem;
}

.nav__mark { text-decoration: none; }

.nav__initials {
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  padding: 0.4rem 0.6rem;
  border: 1.5px solid var(--line-strong);
  border-radius: 6px;
  transition: border-color 0.3s var(--ease), color 0.3s var(--ease);
}
.nav__mark:hover .nav__initials { border-color: var(--accent); color: var(--accent); }

.nav__links {
  position: relative;
  display: flex;
  gap: clamp(0.9rem, 2.5vw, 2.1rem);
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.nav__links a {
  position: relative;
  text-decoration: none;
  color: var(--ink-soft);
  padding-bottom: 2px;
  transition: color 0.25s var(--ease);
  white-space: nowrap;
}
.nav__links a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s var(--ease);
}
.nav__links a:hover { color: var(--ink); }
.nav__links a:hover::after { transform: scaleX(1); transform-origin: left; }
.nav__links a.is-active { color: var(--ink); }

/* One shared underline that glides between links as the page scrolls past
   each section (see initScrollSpy in site.js), rather than each link
   fading its own in independently — the motion is what reads as "you are
   here", not just a static highlight. Left/width are set inline in px by
   JS from the active link's own offsetLeft/offsetWidth, so this only
   needs to animate toward whatever values land there. Hidden (opacity 0)
   until JS has a section to point at, i.e. before the page has scrolled
   past the hero. */
.nav__indicator {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 1px;
  background: var(--accent);
  opacity: 0;
  pointer-events: none;
  transition: left 0.4s var(--ease), width 0.4s var(--ease), opacity 0.3s var(--ease);
}
.nav__indicator.is-visible { opacity: 1; }

@media (max-width: 560px) {
  .nav__links { font-size: 0.7rem; gap: 0.85rem; }
}

/* --- Instagram call to action ------------------------------------------ */

/* Instagram's own gradient forms a ring around the pill, with a dark fill
   sitting on top and pulling back on hover to reveal the full gradient —
   the destination is unmistakable without shouting over the green theme.
   The fill is a separate ::before inset by exactly the ring's width
   (1px), not the old box-shadow-with-huge-spread trick that used to do
   this job: that hack leaves an even rim on a plain rectangle, but on a
   fully rounded pill (border-radius: 100px) — especially at the icon-only
   width on narrow phones, where the pill is nearly a circle — the spread
   geometry doesn't round the same way the box itself does, so the
   gradient shows through unevenly at the rounded sides instead of as a
   clean, uniform ring. An inset pseudo-element is exact at any radius or
   aspect ratio because it's just "this box, minus a fixed border width"
   rather than an approximation. */
.nav__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  flex: none;
  padding: 0.55rem 1.05rem;
  border-radius: 100px;
  text-decoration: none;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: var(--ink);
  background-image: linear-gradient(
    95deg,
    #f9ce34 0%,
    #ee2a7b 48%,
    #6228d7 100%
  );
  transition: color 0.35s var(--ease), transform 0.35s var(--ease);
}

.nav__cta::before {
  content: "";
  position: absolute;
  inset: 1px;
  z-index: 0;
  border-radius: 100px;
  background: rgba(8, 12, 10, 0.86);
  transition: background 0.35s var(--ease);
}

.nav__cta:hover,
.nav__cta:focus-visible {
  transform: translateY(-1px);
  color: #fff;
}
.nav__cta:hover::before,
.nav__cta:focus-visible::before {
  background: rgba(8, 12, 10, 0);
}

.nav__cta-icon,
.nav__cta-long,
.nav__cta-short {
  position: relative;
  z-index: 1;
}

.nav__cta-icon {
  width: 17px;
  height: 17px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
}
.nav__cta-icon .nav__cta-dot { fill: currentColor; stroke: none; }

.nav__cta-short { display: none; }

@media (max-width: 900px) {
  .nav__cta-long  { display: none; }
  .nav__cta-short { display: inline; }
  .nav__cta { padding: 0.5rem 0.85rem; font-size: 0.72rem; }
}

@media (max-width: 420px) {
  .nav__links { gap: 0.7rem; }
  .nav__cta-short { display: none; }
  .nav__cta { padding: 0.5rem 0.6rem; gap: 0; }
}

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

.hero {
  position: relative;
  display: flex;
  align-items: center;
  padding: 6rem var(--gutter) clamp(2.5rem, 6vh, 4rem);
  overflow: hidden;
  isolation: isolate;

  /* Green wash over the black, strongest behind the portrait. */
  background:
    radial-gradient(115% 85% at 78% 22%, rgba(21, 128, 61, 0.30), transparent 62%),
    radial-gradient(85% 75% at 2% 88%, rgba(16, 94, 45, 0.24), transparent 66%),
    linear-gradient(180deg, #06120d 0%, var(--bg) 88%);
}

.hero__grain {
  position: absolute;
  inset: -50%;
  z-index: -1;
  opacity: 0.16;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.hero__inner {
  position: relative;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
}

.hero__text { position: relative; z-index: 2; }

/* --- portrait ---------------------------------------------------------- */

.hero__portrait {
  margin: 0;
  position: relative;
  overflow: hidden;
}

.hero__portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The source is a 2:3 portrait with his face ~42% down. */
  object-position: center 30%;
  transform: scale(1.05);
  animation: heroDrift 20s ease-out forwards;
}

@keyframes heroDrift {
  to { transform: scale(1); }
}

.no-hero-photo .hero__portrait {
  background:
    radial-gradient(ellipse at 30% 20%, rgba(74, 222, 128, 0.20), transparent 60%),
    radial-gradient(ellipse at 75% 70%, rgba(21, 128, 61, 0.30), transparent 55%),
    linear-gradient(160deg, #0d1a12, #050a07);
}
.no-hero-photo .hero__portrait img { display: none; }

.hero__eyebrow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0 0 1.4rem;
  font-size: clamp(0.7rem, 1.6vw, 0.82rem);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.hero__arrow { color: var(--accent); }

.hero__place {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}

/* Full "Hesston, Kansas, USA" on laptop and up, where the eyebrow has a
   whole row to itself rather than sitting on top of his face — only the
   phone layout below needs the shorter form. */
.hero__place-long { display: inline; }
.hero__place-short { display: none; }

/* On phones the eyebrow used to sit directly over his face — document order
   put it first, and the whole text block bottom-aligns against the photo,
   so with a big name pushing up from below it landed mid-image rather than
   down in the dark. Reordering (visually only, via flex + order — reading
   order for screen readers is untouched) drops it below the name and
   tagline instead, into the band the portrait scrim already renders solid.
   That solid backing is also why the pill/blur treatment isn't needed here
   any more: plain text with a shadow reads fine once it's not competing
   with sky or grass behind it. */
@media (max-width: 640px) {
  .hero__text {
    display: flex;
    flex-direction: column;
  }
  .hero__name    { order: 1; }
  .hero__tagline { order: 2; }
  /* nowrap, not the base rule's wrap: a second line here doesn't just
     reflow, it drops the location row back down over his face — the exact
     thing this block was reordered to get away from. Guaranteeing it never
     wraps means the row's width has to guarantee it fits instead: font-size
     is fluid (vw-based, not a fixed rem) so it keeps shrinking as the
     viewport narrows rather than hitting a wall on small phones, and the
     flags are sized in em (see .flag) so they shrink in step with the
     text automatically, inheriting from this font-size. */
  .hero__eyebrow {
    order: 3;
    margin: 0.9rem 0 0;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    gap: 0.45em;
    color: #fff;
    font-size: clamp(0.58rem, 3vw, 0.72rem);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85), 0 2px 10px rgba(0, 0, 0, 0.6);
  }
  .hero__stats   { order: 4; }

  .hero__place { gap: 0.35em; white-space: nowrap; }

  /* Both lines drop to their short form here — "De Haan, Belgium" and
     "Hesston, Kansas, USA" together are the widest this row gets, and each
     flag already carries the country, so the fluid font-size above only
     has to keep two short place names on one line rather than two long
     ones. */
  .hero__place-long { display: none; }
  .hero__place-short { display: inline; }
  .hero__place--to { color: var(--accent); }

  .hero__arrow {
    display: inline-block;
    flex: none;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.8));
  }
}

/* Hand-drawn, not emoji: flag emoji (🇧🇪 🇺🇸) render as bare "BE"/"US"
   letter-pairs on a lot of real Windows setups (Brave included) — the
   regional-indicator characters need a font that actually merges them
   into a flag glyph, and plenty of Windows/Chromium combinations still
   don't. A CSS shape has no font dependency, so it looks the same
   everywhere. Sized in em so it scales with the eyebrow's own fluid
   font-size (see the max-width:640 rule), same as the text next to it. */
.flag {
  display: inline-flex;
  width: 1.4em;
  height: 0.95em;
  border-radius: 2px;
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.22);
  flex: none;
}
.flag__band { flex: 1; }
.flag__band--black  { background: #000000; }
.flag__band--yellow { background: #fae042; }
.flag__band--red    { background: #ed2939; }

/* 13 stripes at their real proportions (n/13 per band), not a rounded-off
   five — accurate enough to read as the actual flag rather than a generic
   striped rectangle. Stars are left out: at this size (roughly 22x15px)
   fifty of them are sub-pixel and would just turn to grey noise, so a
   plain canton in the correct navy reads cleaner than a smudged attempt
   at them. */
.flag--us { position: relative; }
.flag__stripes {
  display: block;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    to bottom,
    #b22234 0%, #b22234 7.6923%,
    #fff 7.6923%, #fff 15.3846%,
    #b22234 15.3846%, #b22234 23.0769%,
    #fff 23.0769%, #fff 30.7692%,
    #b22234 30.7692%, #b22234 38.4615%,
    #fff 38.4615%, #fff 46.1538%,
    #b22234 46.1538%, #b22234 53.8462%,
    #fff 53.8462%, #fff 61.5385%,
    #b22234 61.5385%, #b22234 69.2308%,
    #fff 69.2308%, #fff 76.9231%,
    #b22234 76.9231%, #b22234 84.6154%,
    #fff 84.6154%, #fff 92.3077%,
    #b22234 92.3077%, #b22234 100%
  );
}
.flag__canton {
  position: absolute;
  top: 0;
  left: 0;
  width: 42%;
  height: 53.8462%;
  background: #3c3b6e;
}

.hero__name {
  display: flex;
  flex-direction: column;
  font-size: clamp(3rem, 11vw, 8rem);
  font-weight: 900;
  letter-spacing: -0.045em;
  line-height: 0.86;
  text-transform: uppercase;
  margin-bottom: 1.3rem;
}

.hero__given { color: var(--ink); }

.hero__family {
  color: transparent;
  -webkit-text-stroke: 1.5px var(--accent);
  text-stroke: 1.5px var(--accent);
  padding-left: 0.06em;
}

@media (max-width: 640px) {
  .hero__family { -webkit-text-stroke-width: 1px; }
}

.hero__tagline {
  margin: 0;
  font-size: clamp(0.95rem, 2.2vw, 1.2rem);
  color: var(--ink-soft);
  font-weight: 500;
}
.dot { color: var(--accent); margin: 0 0.5rem; }

/* --- live figures, above the fold -------------------------------------- */

.hero__stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  margin-top: clamp(1.6rem, 4vh, 2.6rem);
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  max-width: 560px;
}

.hstat {
  background: rgba(8, 12, 10, 0.72);
  backdrop-filter: blur(10px);
  padding: 0.9rem 0.9rem;
  min-width: 0; /* let grid tracks shrink instead of overflowing the value */
}

.hstat__label {
  display: block;
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.3rem;
}

.hstat__row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.1rem 0.45rem;
}

.hstat__value {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(1.35rem, 2.4vw, 1.95rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.hstat__value--plain { color: var(--ink); }

.hstat__delta {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--accent);
  white-space: nowrap;
}

/* Always 2x2. The hero is width-capped, so a four-across row would leave each
   tile ~136px — too narrow for the rank and its weekly movement side by side,
   which forced the delta onto a second line. Two columns keeps them inline. */

.hero__cue {
  position: absolute;
  left: 50%;
  bottom: 1.6rem;
  transform: translateX(-50%);
  width: 1px;
  height: 46px;
  overflow: hidden;
}
.hero__cue-line {
  display: block;
  width: 1px;
  height: 100%;
  background: linear-gradient(to bottom, transparent, var(--accent));
  animation: cue 2.1s ease-in-out infinite;
}
@keyframes cue {
  0%   { transform: translateY(-100%); }
  60%  { transform: translateY(0); }
  100% { transform: translateY(100%); }
}

/* The desktop cue's own size (46px tall, 25.6px up from the bottom) reaches
   further up than the phone hero layout's bottom padding reserves — with
   hero__text bottom-aligned via flex-end there, that padding is the only
   gap between the stats ticker and the hero's edge, so the full-size cue
   cut across the bottom stat tile. Shrunk to fit inside that gap instead
   of growing the gap to fit it, since the gap is also what keeps the
   ticker off the photo's bottom edge. */
@media (max-width: 640px) {
  .hero__cue { height: 22px; bottom: 0.7rem; }
}

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

/* Phones and narrow windows: the portrait is the backdrop, text sits on top.
   A tall viewport crops the 2:3 source kindly, so this framing holds up. */
.hero {
  min-height: 100svh;
  align-items: flex-end;
}

.hero__inner { position: static; }

.hero__portrait {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero__portrait img { object-position: center 52%; }

.hero__portrait-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    var(--bg) 6%,
    rgba(8, 12, 10, 0.92) 32%,
    rgba(8, 12, 10, 0.3) 60%,
    rgba(8, 12, 10, 0.1) 78%,
    rgba(8, 12, 10, 0.5) 100%
  );
}

/* Laptops and up: side by side. A 2:3 portrait cropped into a landscape
   letterbox loses his head entirely, so it gets its own column at a sane
   aspect ratio instead, and the live figures come above the fold. */
@media (min-width: 900px) {
  .hero { align-items: center; }

  .hero__inner {
    position: relative;
    display: grid;
    /* Photo column now leads slightly — he's the point of the page. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.06fr);
    gap: clamp(1.5rem, 3.5vw, 3.5rem);
    align-items: center;
  }

  .hero__portrait {
    position: relative;
    inset: auto;
    margin-inline: auto;
    /* Both axes auto + aspect-ratio + both maxes: the browser sizes the box
       to the largest 2:3 rectangle that fits the column width AND the
       height cap, like object-fit: contain applied to the frame itself.
       (A fixed width: 100% here would let max-height win on most laptop
       screens, leaving the box wider than a 2:3 photo and forcing letterbox
       gutters — this way the frame is never a different shape than the
       photo it holds.) */
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 78svh;
    /* Matches the source photo's real 2:3 proportions (2667x4000), so the
       frame's shape is his photo's shape — no leftover strip to crop away. */
    aspect-ratio: 2 / 3;
    justify-self: center;
    border-radius: 20px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    overflow: hidden;
    background: var(--bg-raised);
    /* Depth comes from the shadow and the glow behind, not from decoration
       around the edge — the photo should be the thing you look at. */
    box-shadow:
      0 40px 80px -40px rgba(0, 0, 0, 0.95),
      0 0 0 1px rgba(0, 0, 0, 0.4);
  }

  .hero__portrait-scrim { border-radius: inherit; }

  .hero__portrait img {
    /* Contain, not cover: with the frame now matched to the photo's own
       ratio there's normally no gap to letterbox, but contain guarantees the
       whole photo stays visible even if that match ever drifts (a resize,
       a differently-shaped replacement photo, the max-height cap kicking
       in on a short window) rather than silently cropping him again. */
    object-fit: contain;
    object-position: center center;
    /* The base rule's slow zoom-in is built for a full-bleed cover crop; on
       a contained image it would clip a sliver at the start of the
       animation, which defeats the point. Off entirely here. */
    transform: none;
    animation: none;
  }

  .hero__portrait-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(8, 12, 10, 0.55), transparent 38%);
  }

  /* Soft green pool behind the photo, echoing the fairway. */
  .hero__portrait::before {
    content: "";
    position: absolute;
    inset: -14% -10% -8%;
    z-index: -1;
    border-radius: 50%;
    background: radial-gradient(
      ellipse at 50% 45%,
      rgba(34, 160, 80, 0.34),
      rgba(8, 12, 10, 0) 70%
    );
    filter: blur(6px);
    pointer-events: none;
  }

  .hero__name { font-size: clamp(2.8rem, 5.4vw, 6.4rem); }
}

/* --------------------------------------------------------------- sections */

.section {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(4.5rem, 12vh, 8.5rem) var(--gutter);
}

/* Keeps a jumped-to section's own heading clear of the fixed nav bar
   instead of tucked underneath it — honoured by both scrollIntoView (the
   nav's own click-to-scroll anchors, and initSectionPager in site.js) and
   native anchor-link scrolling, independent of scroll-snap. */
@media (min-width: 900px) {
  html { scroll-padding-top: 84px; }
}

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-bottom: clamp(2rem, 5vh, 3.2rem);
  padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--line);
}

.section__title {
  font-size: clamp(1.9rem, 5.5vw, 3.4rem);
  text-transform: uppercase;
}

.section__note {
  margin: 0;
  font-size: 0.83rem;
  color: var(--ink-faint);
  letter-spacing: 0.05em;
}
.section__note a { color: var(--accent); text-decoration: none; }
.section__note a:hover { text-decoration: underline; }

.stamp { display: inline-block; }

/* --------------------------------------------------------- ranking cards */

.rank-grid {
  position: relative; /* containing block for the expanded chart overlay */
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.8rem;
}

/* WAGR is the ranking that matters, so it gets the wider column; its own
   card used to leave a lot of dead air below the numbers, so the ranking
   chart now lives in that space instead of floating separately. European
   and the 4-stat strip stay as two separate bubbles on the right rather
   than merging into one frame — align-items:stretch makes both columns the
   same height, so the stats bubble (pushed down by margin-top:auto) lines
   its own bottom edge up with the WAGR bubble's. */
@media (min-width: 780px) {
  .rank-grid { grid-template-columns: 1.5fr 1fr; align-items: stretch; }
}

/* WAGR's merged card: rank figures on top, a hairline divider, the chart
   filling the rest — one frame instead of a bordered card sitting above an
   empty gap. Only WAGR gets this treatment; European and the stat strip
   are each their own standalone bubble (see .rank-stack below). */
.rank-col {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg-card);
  overflow: hidden;
  min-width: 0;
}

/* This overflow:hidden is needed most of the time, to round off the mini
   chart's corners — but when the chart expands to a position:absolute
   overlay spanning the whole rankings grid, it was clipping the overlay to
   the WAGR column's own small box, cutting it off partway across. Lifting
   the clip only while expanded lets the overlay actually reach full width. */
.rank-grid.is-chart-expanded .rank-col--wagr { overflow: visible; }

.rank-col__divider {
  height: 1px;
  margin: 0 clamp(1.3rem, 2.6vw, 1.8rem);
  background: var(--line);
}
/* Nothing to divide until the chart has loaded in below it. */
.rank-col:has(.chart[hidden]) .rank-col__divider {
  display: none;
}

/* The card no longer carries its own frame inside .rank-col — that wrapper
   supplies it — so this strips the border/background/hover-lift that would
   otherwise double up, while keeping every other rank-card style (figures,
   meta, colours). Only applies inside .rank-col (WAGR); European's card
   sits in .rank-stack instead and keeps its own native frame. */
.rank-col .rank-card {
  border: none;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.rank-col .rank-card:hover { transform: none; }
.rank-col .rank-card::before { display: none; }

/* European's column: two independent bubbles, not one merged card. Stretch
   fills the column to match WAGR's height (see align-items:stretch above),
   and margin-top:auto on the stat strip pushes it down to the bottom of
   that space, so its own bottom edge lines up with WAGR's. */
.rank-stack {
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
  min-width: 0;
}
/* Whichever bubble is second gets pushed to the bottom of the stretched
   column, so its bottom edge lines up with WAGR's — generic to :last-child
   rather than naming stat-strip, so swapping their order doesn't need
   another CSS change. */
.rank-stack > *:last-child { margin-top: auto; }

.rank-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.2rem, 2.4vw, 1.6rem) clamp(1.3rem, 2.6vw, 1.8rem);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg-card);
  overflow: hidden;
  transition: transform 0.5s var(--ease), border-color 0.5s var(--ease);
}

.rank-card--secondary {
  background: transparent;
  border-style: dashed;
  border-color: rgba(255, 255, 255, 0.13);
}

.rank-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 85% 0%, var(--accent-glow), transparent 62%);
  opacity: 0;
  transition: opacity 0.6s var(--ease);
  pointer-events: none;
}

.rank-card:hover { transform: translateY(-5px); border-color: var(--line-strong); }
.rank-card:hover::before { opacity: 1; }

.rank-card__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.9rem;
}

.rank-card__source {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.15rem;
  letter-spacing: 0.02em;
}
.rank-card__sub {
  display: block;
  margin-top: 0.2rem;
  font-family: var(--body);
  font-weight: 400;
  font-size: 0.74rem;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
  text-transform: uppercase;
}

.rank-card__figure {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  margin-bottom: 0.9rem;
}

.rank-card__hash { font-size: 1.2rem; color: var(--ink-faint); font-weight: 600; }

.rank-card__value {
  font-family: var(--display);
  font-weight: 900;
  line-height: 0.88;
  letter-spacing: -0.045em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.rank-card--primary   .rank-card__value { font-size: clamp(2.9rem, 7vw, 4.2rem); }
.rank-card--secondary .rank-card__value {
  font-size: clamp(2.1rem, 4.4vw, 2.8rem);
  color: var(--ink);
}
.rank-card--secondary .rank-card__hash { font-size: 1rem; }

.rank-card__value--muted { color: var(--ink-faint); font-size: clamp(1.5rem, 4vw, 2rem); }

.rank-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.1rem;
  margin-top: auto;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line);
  font-size: 0.78rem;
  color: var(--ink-soft);
}
.rank-card--secondary .rank-card__meta { font-size: 0.74rem; }
.rank-card__meta b {
  color: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.rank-card__link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.85rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
}
.rank-card__link:hover { gap: 0.6rem; }
.rank-card__link { transition: gap 0.3s var(--ease); }

/* movement badge */

.trend {
  display: inline-flex;
  align-items: center;
  gap: 0.28rem;
  padding: 0.28rem 0.6rem;
  border-radius: 100px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.trend--up   { background: rgba(74, 222, 128, 0.14); color: var(--accent); }
.trend--down { background: rgba(248, 113, 113, 0.14); color: #f87171; }
.trend--flat { background: rgba(255, 255, 255, 0.07); color: var(--ink-faint); }

/* empty / pending state */

.rank-card--empty { border-style: dashed; }
.rank-card--empty .rank-card__note {
  margin: 0;
  color: var(--ink-faint);
  font-size: 0.88rem;
  line-height: 1.6;
}
.rank-card--empty code {
  background: rgba(255, 255, 255, 0.06);
  padding: 0.12rem 0.4rem;
  border-radius: 4px;
  font-size: 0.85em;
  color: var(--accent);
}

/* stat strip — its own bubble in .rank-stack, next to (not inside) European's
   card. The outer border/radius is its own frame; the internal 1px gap +
   this background colour is what draws the hairlines between the four
   tiles. Always 2 columns: this lives in the narrower rankings column at
   every viewport width, not the full page width the old standalone block
   (before either of these redesigns) had room to spread across. */
.stat-strip {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
}

.stat {
  background: var(--bg-card);
  padding: 0.9rem 0.7rem;
  text-align: center;
}
.stat__value {
  display: block;
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.5rem;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.stat__label {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------------ chart */

/* Collapsed (default): no frame of its own — it lives inside .rank-col's
   shared border, below the WAGR card and the divider. */
.chart {
  position: static;
  margin: 0;
  padding: 0.85rem clamp(1.3rem, 2.6vw, 1.8rem) clamp(1rem, 2vw, 1.4rem);
  border: none;
  border-radius: 0;
  background: none;
  min-width: 0; /* let the SVG shrink with a narrow column */
}

/* Expanded: pops out of the WAGR card entirely to cover the whole rankings
   grid — WAGR and Europe (cards + stat strip) hidden behind it — visually
   and physically the same full-width block the chart used to be
   permanently. Collapsing is what buys back the vertical space; expanding
   just restores that old view on demand. Positioned absolutely (not via a
   grid-column span) because it's nested inside .rank-col now, not a direct
   grid child, so a grid-line span wouldn't reach past its own column. */
.chart.is-expanded {
  position: absolute;
  /* height: auto (no "bottom"), not inset:0 — hiding the cards below removes
     them from the flow's height calculation, so tying this box's height to
     the now-shrunken .rank-grid would squeeze the full chart into too short
     a box instead of letting it be its own natural size. */
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
  padding: clamp(1.2rem, 2.6vw, 1.7rem);
  border: 1px solid var(--line);
  border-radius: 16px;
  /* --bg-card (used everywhere else this shape appears) is only 3.5% opaque
     white — a subtle tint meant to sit on the page background, not to hide
     anything behind it. This box's whole job is to occlude the WAGR/Europe
     cards underneath, so it needs an actually solid colour: with the
     translucent one, the divider between WAGR's card and this chart still
     showed straight through as a faint line, even though the stacking
     order (z-index) was already correct. */
  background: var(--bg-raised);
  box-shadow: 0 30px 70px -25px rgba(0, 0, 0, 0.75);
}

.rank-grid.is-chart-expanded .rank-card--primary,
.rank-grid.is-chart-expanded .rank-card--secondary,
.rank-grid.is-chart-expanded .stat-strip {
  visibility: hidden;
}

.chart__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 0.6rem;
  margin: 0 0 0.6rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-soft);
  font: inherit;
  cursor: pointer;
  transition: color 0.25s var(--ease);
}
.chart__toggle:hover { color: var(--ink); }
/* The global focus ring is offset 3px from a box that spans the card's full
   width, which on this button reads as a frame rather than a focus state.
   Kept (keyboard users need it) but pulled in tight. */
.chart__toggle:focus-visible { outline-offset: 2px; border-radius: 8px; }

.chart__toggle-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.chart__toggle-icon {
  flex: none;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.3s var(--ease);
}
/* Icon reads as "expand outward" collapsed, "collapse inward" once open —
   a single arrow glyph flipped, rather than swapping icons. */
.chart.is-expanded .chart__toggle-icon { transform: rotate(180deg); }

/* Collapsed: no head/axis/legend text, just the toggle and the sparkline
   itself — the point is a glance-able shape, not a fully-labelled chart. */
.chart:not(.is-expanded) .chart__head,
.chart:not(.is-expanded) .chart__legend,
.chart:not(.is-expanded) .chart__axis {
  display: none;
}

/* What the dots actually mean, spelled out rather than left to hover-only
   <title> tooltips — those aren't discoverable at a glance, especially on
   touch devices where hover doesn't really exist. */
.chart__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.1rem;
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  font-size: 0.76rem;
  color: var(--ink-faint);
}
.chart__legend li { display: inline-flex; align-items: center; gap: 0.45rem; }

.chart__legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: var(--bg);
  border: 2px solid var(--accent);
  box-sizing: border-box;
}
.chart__legend-dot--win {
  background: var(--accent);
}
.chart__legend-dot--now {
  width: 10px;
  height: 10px;
  background: var(--accent);
  border: none;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3px var(--accent);
}

.chart__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.2rem;
}

.chart__title {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.chart__note {
  margin: 0;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  color: var(--accent);
  font-weight: 600;
}

.chart__plot svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.chart__line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.chart__dot {
  fill: var(--bg);
  stroke: var(--accent);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  transition: r 0.2s var(--ease);
  cursor: help;
}
.chart__dot:hover { r: 7; }
.chart__dot--win { fill: var(--accent); }

.chart__now {
  fill: var(--accent);
  stroke: var(--bg);
  stroke-width: 3;
  vector-effect: non-scaling-stroke;
}

.chart__axis {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.6rem;
  font-size: 0.74rem;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
}
.chart__axis b { color: var(--accent); }

/* ------------------------------------------------------------------ about */

.about {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2.1fr);
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: start;
}

@media (max-width: 780px) {
  .about { grid-template-columns: 1fr; }
  /* The timeline is a laptop-width extra; on a stacked phone layout it would
     land awkwardly between the label and the facts, so it's hidden there. */
  .timeline { display: none; }
}


.about__label { display: flex; align-items: center; gap: 0.9rem; }
.about__label h2 {
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.rule { display: block; width: 34px; height: 1px; background: var(--accent); flex: none; }

.about__body p {
  margin: 0 0 1.15rem;
  font-size: clamp(0.98rem, 2vw, 1.1rem);
  line-height: 1.62;
  color: var(--ink-soft);
}
.about__body p:last-child { margin-bottom: 0; }

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1.6rem 1.2rem;
  margin: 0 0 clamp(2.5rem, 6vh, 4rem);
  padding-bottom: clamp(2.5rem, 6vh, 4rem);
  border-bottom: 1px solid var(--line);
}
.fact dt {
  font-size: 0.7rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.35rem;
}
.fact dd {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.02rem;
  letter-spacing: -0.01em;
}

/* --- career timeline, in the aside column ------------------------------ */

.timeline {
  list-style: none;
  margin: clamp(2rem, 6vh, 3.2rem) 0 0;
  padding: 0 0 0 1.1rem;
  border-left: 1px solid var(--line);
}

.timeline__item {
  position: relative;
  padding-bottom: clamp(1.6rem, 4vh, 2.4rem);
}
.timeline__item:last-child { padding-bottom: 0; }

.timeline__item::before {
  content: "";
  position: absolute;
  left: -1.37rem;
  top: 0.3rem;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--accent);
}

.timeline__item--peak::before {
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}

.timeline__date {
  display: block;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.3rem;
}

.timeline__title {
  margin: 0 0 0.25rem;
  font-family: var(--display);
  font-weight: 800;
  font-size: 0.98rem;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.timeline__detail {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--ink-faint);
}

/* ---------------------------------------------------------------- results */

.legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 1rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.legend li { display: inline-flex; align-items: center; gap: 0.4rem; }

.legend__dot {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  flex: none;
}
.legend__dot--gold   { background: var(--gold); }
.legend__dot--silver { background: var(--silver); }
.legend__dot--bronze { background: var(--bronze); }
.legend__dot--top10  { background: var(--accent); }

.legend__swatch {
  color: var(--under-par);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.results-wrap { overflow-x: auto; }

.results {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
  min-width: 560px;
}
.results th {
  text-align: left;
  padding: 0 1rem 0.85rem 0;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-bottom: 1px solid var(--line);
}
.results td {
  padding: 1rem 1rem 1rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.055);
  color: var(--ink-soft);
  vertical-align: top;
}
.results tr:hover td { color: var(--ink); }

.results .pos {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.05rem;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.results .event {
  color: var(--ink);
  font-weight: 500;
  /* Every row reserves this padding + border-left slot (see below), so the
     table's true left edge has one fixed line regardless of finish colour. */
  padding-left: 0.75rem;
  box-shadow: inset 3px 0 0 transparent;
}
.results tr.is-counting .event { font-weight: 700; }
.results .event a { text-decoration: none; }
.results .event a:hover { color: var(--accent); text-decoration: underline; }

/* Hand-written note (resultAnnotations in profile.json) for a row whose
   scraped position is his real place on the full scratch leaderboard, but
   he actually won his age category — gold, not the row's own finish
   colour, so it reads as its own distinct claim ("won something") rather
   than blending into whatever colour the overall position already has. */
.result-badge {
  display: inline-block;
  margin-left: 0.6em;
  padding: 0.15em 0.55em;
  border-radius: 999px;
  background: rgba(251, 191, 36, 0.14);
  color: var(--gold);
  font-size: 0.68em;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  vertical-align: middle;
}

/* --- medal column, trailing the row after Rounds ------------------------ */

.col-medal,
.results td.medal {
  width: 1.6em;
  padding-right: 0.25rem;
  text-align: center;
}

.medal__trophy {
  display: inline-block;
  font-size: 0.95rem;
  line-height: 1;
  filter: drop-shadow(0 1px 4px rgba(251, 191, 36, 0.45));
}

/* --- finishing position ------------------------------------------------ */

.pos__suffix {
  font-size: 0.62em;
  font-weight: 700;
  margin-left: 0.05em;
  vertical-align: super;
  opacity: 0.75;
}

/* Podium, then the rest of the top ten. */
.results tr.is-first  .pos { color: var(--gold); }
.results tr.is-second .pos { color: var(--silver); }
.results tr.is-third  .pos { color: var(--bronze); }
.results tr.is-top10  .pos { color: var(--accent); }

/* A faint left edge so the good weeks read down the table at a glance.
   Applied via the .event rule's own box-shadow (transparent by default
   above), so every row shares the same padding and only the colour changes.
   Lives on the true first column (event), independent of where the position
   column itself sits. */
.results tr.is-first  .event,
.results tr.is-second .event,
.results tr.is-third  .event,
.results tr.is-top10  .event {
  box-shadow: inset 3px 0 0 currentColor;
}
.results tr.is-first  .event { color: var(--gold); }
.results tr.is-second .event { color: var(--silver); }
.results tr.is-third  .event { color: var(--bronze); }
.results tr.is-top10  .event { color: var(--accent); }

/* --- round scores ------------------------------------------------------ */

.round { color: var(--ink-soft); }

/* Golf convention: red for a round under par. The source flags these, so it
   is accurate per course rather than assumed from a fixed par. */
.round--under {
  color: var(--under-par);
  font-weight: 700;
}

.round--wd {
  color: var(--ink-faint);
  font-style: italic;
  letter-spacing: 0.08em;
}

.round__sep { color: var(--ink-faint); margin: 0 0.4rem; opacity: 0.6; }
.results .rounds { font-variant-numeric: tabular-nums; letter-spacing: 0.06em; white-space: nowrap; }
.results .col-date { white-space: nowrap; }

@media (max-width: 700px) {
  .col-venue { display: none; }
  .results td.col-venue { display: none; }
}

/* Phones: stop being a table. Five columns of live data will not fit across
   a 375px screen at a readable size — squeezing them into percentage widths
   only traded the horizontal scrollbar for mid-word breaks ("Championshi /
   p"), a date wrapping into three lines and a trophy jammed against the
   screen edge. There is plenty of room vertically, so each result becomes a
   stacked block instead: finish and event on the top line, then the date,
   then the round scores, each on their own line and each with the whole
   width to itself. The header row has nothing left to label, so it goes.

   Built with grid on the <tr> (display:grid overrides table-row) and
   explicit placement per cell, so the source order of the <td>s — which
   still has to make sense as a real table on wider screens — doesn't
   constrain the phone layout. */
/* 640px, not 560: below ~620 the 560px-min-width table no longer clears the
   page gutters either, so it would still scroll sideways in that band. */
@media (max-width: 640px) {
  .results-wrap { overflow-x: visible; }

  .results { min-width: 0; width: 100%; }
  .results thead { display: none; }

  .results tr {
    display: grid;
    grid-template-columns: 2.9rem minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: 0.5rem;
    padding: 0.95rem 0 1rem 0.75rem;
    /* The finish-colour edge moves off .event (a cell that no longer spans
       the row's full height here) onto the row itself. */
    border-left: 3px solid transparent;
    border-bottom: 1px solid rgba(255, 255, 255, 0.055);
  }
  .results tr.is-first  { border-left-color: var(--gold); }
  .results tr.is-second { border-left-color: var(--silver); }
  .results tr.is-third  { border-left-color: var(--bronze); }
  .results tr.is-top10  { border-left-color: var(--accent); }

  /* The desktop finish-colour indicator is a box-shadow on .event itself
     (see the un-media-queried rule below), which outranks the plain
     ".results .event { box-shadow: none }" reset above on specificity
     alone — media query or not, the more specific selector wins. Without
     this it survives here as a stray 3px stripe on .event's own left edge,
     sitting just before the event name, duplicating the border-left colour
     already moved onto the row itself above. */
  .results tr.is-first  .event,
  .results tr.is-second .event,
  .results tr.is-third  .event,
  .results tr.is-top10  .event {
    box-shadow: none;
  }

  .results td {
    display: block;
    padding: 0;
    border: 0;
  }

  .results .pos { grid-column: 1; grid-row: 1; }
  .results .event {
    grid-column: 2;
    grid-row: 1;
    padding-left: 0;
    box-shadow: none;
    line-height: 1.35;
    overflow-wrap: break-word;
  }
  .results td.medal { grid-column: 3; grid-row: 1; width: auto; padding: 0; }

  .results .col-date {
    grid-column: 2 / -1;
    grid-row: 2;
    margin-top: 0.35rem;
    font-size: 0.78rem;
    letter-spacing: 0.06em;
    color: var(--ink-faint);
    white-space: nowrap;
  }
  .results .rounds {
    grid-column: 2 / -1;
    grid-row: 3;
    margin-top: 0.2rem;
    white-space: nowrap;
  }
}

/* ------------------------------------------------------------------- feed */

/* flex-start, not space-between: the Follow button used to anchor to the
   row's far edge, stranding it a full container-width away from the
   handle it belongs to. Left-aligning both as a group keeps them read as
   one unit, with the row's spare width simply left empty on the right. */
.ig-header {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 1.1rem;
  margin-bottom: clamp(1.8rem, 4.5vh, 2.8rem);
  padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--line);
}

.ig-header__id {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  border-radius: 10px;
  transition: opacity 0.2s var(--ease);
}
.ig-header__id:hover { opacity: 0.8; }
.ig-header__id:hover .ig-header__handle { text-decoration: underline; }

.ig-header__names {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Instagram's "story ring" treatment: a gradient circle with a dark gap,
   then the glyph sitting inside — instantly reads as an Instagram identity
   rather than a generic social icon. */
.ig-avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  padding: 2.5px;
  background: linear-gradient(135deg, #f9ce34 0%, #ee2a7b 48%, #6228d7 100%);
}

.ig-avatar__glyph {
  width: 100%;
  height: 100%;
  padding: 8px;
  border-radius: 50%;
  background: var(--bg);
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.7;
  box-sizing: border-box;
}
.ig-avatar__dot { fill: var(--ink); stroke: none; }

.ig-header__handle {
  margin: 0;
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ig-header__sub {
  margin: 0.1rem 0 0;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Instagram's own "Follow" button — a solid blue rounded-rect, not a pill —
   is the button convention already visible inside the real embeds above it
   on this page, so this matches that rather than the site's own green. */
.ig-header__cta {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: 0.5rem 1.15rem;
  border-radius: 8px;
  border: none;
  background: #0095f6;
  color: #fff;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  transition: background 0.2s var(--ease), transform 0.3s var(--ease);
}
.ig-header__cta:hover {
  background: #1a87d1;
  transform: translateY(-1px);
}

/* --- warm-up: real posts embedded via Instagram's own oEmbed widget ---- */

.ig-embeds {
  display: grid;
  /* Fixed 3-up rather than auto-fit: with a hard aspect-ratio on each card
     (below), auto-fit at this min-width still gave 3 columns in practice,
     but pinning it removes any chance of an odd 2-then-1 wrap on the one
     width where it wouldn't. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.9rem;
}

.ig-embed-card {
  position: relative;
  /* Instagram's own embed height depends on the post's own shape (square,
     portrait, carousel...) and how much caption/chrome it decides to show —
     left alone, three different posts render three different heights and
     the "grid" stops looking like one. Locking every card to the same
     aspect ratio and clipping the overflow is what actually makes it a
     grid, at the cost of cropping a sliver of whichever post runs long. */
  aspect-ratio: 4 / 5;
  border-radius: 14px;
  overflow: hidden;
  background: var(--bg-raised);
  border: 1px solid var(--line);
}

/* The official embed manages its own sizing once instagram.com/embed.js
   processes it; pinned to the top of the fixed-height card (not centered),
   so what gets clipped is the bottom chrome, not the photo itself. */
.ig-embed-card iframe,
.ig-embed-card blockquote.instagram-media {
  position: absolute;
  top: 0;
  left: 0;
  width: 100% !important;
  max-width: 100% !important;
  margin: 0 !important;
  border-radius: 0 !important;
}

.ig-embed-card__fallback {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  padding: 2.5rem 1rem;
  color: var(--ink-soft);
  font-size: 0.85rem;
  text-align: center;
}
.ig-embed-card__fallback a {
  color: var(--accent);
  font-weight: 700;
  text-decoration: none;
}
.ig-embed-card__fallback a:hover { text-decoration: underline; }

.ig-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr));
  gap: 0.7rem;
}

.ig-post {
  position: relative;
  display: block;
  aspect-ratio: 1;
  border-radius: 12px;
  overflow: hidden;
  background: var(--bg-raised);
  text-decoration: none;
}
.ig-post img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease), filter 0.5s var(--ease);
}
.ig-post:hover img { transform: scale(1.07); filter: brightness(0.55); }

.ig-post__caption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 1.5rem 1rem 1rem;
  font-size: 0.82rem;
  line-height: 1.45;
  color: #fff;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.85), transparent);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);

  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ig-post:hover .ig-post__caption { opacity: 1; transform: translateY(0); }

.ig-post__badge {
  position: absolute;
  top: 0.6rem;
  right: 0.7rem;
  font-size: 0.85rem;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
}

/* follow card, shown until the feed is connected */

.follow-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 1rem;
  padding: clamp(2.5rem, 8vw, 4.5rem) 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: 18px;
  background:
    radial-gradient(circle at 50% 0%, var(--accent-glow), transparent 65%),
    var(--bg-card);
}

.follow-card__icon {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  padding: 3px;
  background: linear-gradient(135deg, #f9ce34 0%, #ee2a7b 48%, #6228d7 100%);
}
.follow-card__icon svg {
  width: 100%;
  height: 100%;
  padding: 10px;
  border-radius: 50%;
  background: var(--bg);
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.7;
  box-sizing: border-box;
}
.follow-card__icon svg circle:last-child { fill: var(--ink); stroke: none; }

.follow-card__title {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.3rem, 4vw, 1.9rem);
  letter-spacing: -0.02em;
}
.follow-card__text {
  margin: 0;
  max-width: 46ch;
  color: var(--ink-soft);
  font-size: 0.95rem;
}
.follow-card__cta {
  margin-top: 0.6rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 1.7rem;
  border-radius: 100px;
  background: var(--accent);
  color: #052e16;
  font-weight: 700;
  font-size: 0.88rem;
  letter-spacing: 0.04em;
  text-decoration: none;
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.follow-card__cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 30px -8px var(--accent-glow);
}

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

.footer {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 3rem var(--gutter) 4rem;
  border-top: 1px solid var(--line);
  text-align: center;
}
.footer__name {
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.1rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin: 0 0 0.4rem;
}
.footer__meta { margin: 0; font-size: 0.76rem; color: var(--ink-faint); letter-spacing: 0.05em; }
.footer__copyright {
  margin: 0.9rem 0 0;
  font-size: 0.72rem;
  color: var(--ink-faint);
  opacity: 0.7;
}

/* ---------------------------------------------------------------- reveals */

.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.85s var(--ease), transform 0.85s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .hero__media img { animation: none; transform: none; }
  .hero__cue-line { animation: none; }
  *, *::before, *::after { transition-duration: 0.01ms !important; }
}

/* -------------------------------------------------------------------- 404 */

.notfound {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 6rem var(--gutter) 4rem;
  text-align: center;
  background:
    radial-gradient(75% 50% at 82% 0%, rgba(21, 128, 61, 0.20), transparent 62%),
    radial-gradient(65% 45% at 0% 55%, rgba(21, 128, 61, 0.11), transparent 66%),
    var(--bg);
}

.notfound__code {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(4rem, 16vw, 9rem);
  letter-spacing: -0.04em;
  line-height: 0.9;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--accent);
  text-stroke: 1.5px var(--accent);
}

.notfound__title {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.3rem, 3vw, 1.8rem);
  color: var(--ink);
}

.notfound__text {
  max-width: 34ch;
  color: var(--ink-soft);
  font-size: 1rem;
  line-height: 1.6;
  margin: 0 0 0.8rem;
}

.notfound__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  border-radius: 100px;
  background: var(--accent);
  color: #06120d;
  font-weight: 700;
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: transform 0.3s var(--ease), background 0.3s var(--ease);
}
.notfound__cta:hover { background: #6ee89a; transform: translateY(-1px); }
