/* Selected-work fan ↔ carousel that sits between the two hero paragraphs.
   Two states tied to a single --p (0 = fan, 1 = carousel) plus a discrete
   data-state attribute that toggles overflow + reveal thresholds.
   - In FAN state cards are solid colour washes stacked in an imperfect
     hand-placed arrangement, leftmost on top.
   - In CAROUSEL state cards land vertically-centred in the viewport,
     overflow-x: auto kicks in, the colour fades out and the real video
     reels fade in, and the title + company captions appear below. */

/* Shell wrapper — holds the eyebrow + the inner scrollable as
   siblings. The eyebrow lives HERE (not inside .hero-cards-fan) so
   it doesn't pan with the carousel scroll. All the positioning,
   margins, AND the initial blur-reveal animation moved up to the
   shell since both children need to fade in together. */
.hero-cards-fan-shell {
  --p: 0;

  /* Landscape cards — 4:3 (height = 75% of width). Sizes scale with
     viewport HEIGHT but are ALSO capped at 80% of viewport WIDTH so
     phones never get cards wider than the screen. */
  --card-w: clamp(325px, min(62.5vh, 100vw), 800px);
  /* Work cards: 3:2 (height = 0.6667 × width) — slightly wider than
     the old 4:3, well short of 16:9. Reads more apt for the project
     reels (and crops less off the 16:9 Wabi reel). Experiments
     override --card-h back to the 4:3 factor below so their row is
     unaffected. */
  --card-h: calc(var(--card-w) * 0.6667);
  --card-gap: calc(var(--card-w) * 0.075);
  --card-top: clamp(110px, 14vh, 220px);

  --track-pad: 6vw;
  --step: calc(var(--card-w) + var(--card-gap));
  /* Track is anchored so card 0 sits at the viewport CENTRE; the
     remaining cards extend to the right. Work now has SIX cards
     (Wabi + the original five), so five steps between them.
     Experiments overrides this with its own count + JS tighten. */
  --track-w: calc(
      50vw + var(--card-w) / 2
      + 5 * var(--step)
      + var(--track-pad)
  );

  position: relative;
  width: 100vw;
  left: 50%;
  margin-left: -50vw;
  /* Vh-anchored so the stack always sits at roughly the same fraction
     of viewport — cards peek from the bottom on every screen size. */
  margin-top: clamp(30px, 6vh, 100px);
  /* +150 px of breathing room between the cards section and the live-
     data sentence below ("It is currently …"). −20% from original. */
  margin-bottom: calc(clamp(220px, 22vh, 330px) * 0.8);

  /* Initial blur-reveal — same recipe the .hero-cards-fan used to
     carry, now hosted by the shell so the eyebrow fades in with it. */
  opacity: 0;
  filter: blur(14px);
  transform: translateY(12px);
  transition:
    opacity 900ms cubic-bezier(.2, .7, .2, 1.0) 130ms,
    filter  900ms cubic-bezier(.2, .7, .2, 1.0) 130ms,
    transform 900ms cubic-bezier(.2, .7, .2, 1.0) 130ms;
}
.hero-cards-fan-shell.is-revealed {
  opacity: 1;
  filter: blur(0);
  transform: translateY(0);
}

.hero-cards-fan {
  /* The inner scrollable. Width comes from .cards-track; height
     accommodates the card stack + meta + the +210 px tail we
     reserve for the parallax. Margins and full-bleed positioning
     all live on the shell above. */
  position: relative;
  width: 100%;
  height: calc(var(--card-h) + var(--card-top) * 2);

  /* Vertical scroll is ALWAYS off. Horizontal scroll is off in fan
     state and unlocked to auto once cards land in carousel — see
     `data-state="carousel"` below. */
  overflow-x: hidden;
  overflow-y: hidden;
  scrollbar-width: none;
}
.hero-cards-fan::-webkit-scrollbar { display: none; }
.hero-cards-fan.is-revealed {
  /* Marker class so the existing `.hero-cards-fan.is-revealed
     .fan-card` per-card entrance rules still fire after refactor. */
}
/* Carousel state: unlock horizontal scroll so the user can pan
   sideways to see cards 1..4 once they've spread out. Vertical scroll
   stays locked off. */
.hero-cards-fan[data-state="carousel"] {
  overflow-x: auto;
}

.cards-track {
  position: relative;
  width: var(--track-w);
  height: 100%;
  /* Parallax with an ease-IN curve (--p²) so the stack barely
     moves at the start of the unfurl and accelerates toward the
     end. Net: most of the 120 px drop happens in the last half of
     the scroll, so the eyebrow appears to "emerge from under" the
     cards rather than sliding away from them gradually. */
  translate: 0 calc(var(--p, 0) * var(--p, 0) * 120px);
  z-index: 1;
}

/* Section eyebrow — small upright Edict Display, centred horizontally
   at the top of the heap. Sits BEHIND .cards-track (lower z-index)
   so it's covered by the stacked cards in fan state and uncovered
   as the cards translate down + spread sideways during the unfurl.
   On scroll, ALSO translates UP by 30 px so the eyebrow rises
   while the cards descend — the two diverge to a comfortable
   distance instead of just the cards leaving a gap. */
.hero-fan-eyebrow {
  position: absolute;
  top: calc(var(--card-top) + 38px);
  left: 50%;
  transform: translateX(-50%);
  /* Independent `translate` longhand composes with the transform's
     `translateX(-50%)` for horizontal centring. Rises only 10 px
     over the unfurl now (was 30) — i.e. the work eyebrow ends 20 px
     LOWER, tightening the gap to the cards. Experiments overrides
     this to -20 px (10 px lower than before) just below. */
  translate: 0 calc(var(--p, 0) * -10px);
  z-index: 0;
  margin: 0;
  font-family: 'Edict Display', Georgia, serif;
  font-style: normal;
  font-weight: 300;
  font-size: clamp(22px, 2.2vw, 30px);
  line-height: 1.15;
  letter-spacing: -0.012em;
  color: rgba(26, 26, 46, 0.62);
  white-space: nowrap;
  pointer-events: none;
  /* Fades in later in the curve — starts at --p ≈ 0.35, fully
     visible by --p ≈ 0.75. Pairs with the cards-track's ease-in
     translate so the eyebrow appears to surface from beneath the
     cards as they accelerate downward. */
  opacity: clamp(0, calc((var(--p) - 0.35) * 2.5), 1);
}

.fan-card {
  position: absolute;
  top: var(--card-top);
  width: var(--card-w);
  height: var(--card-h);
  background: transparent;
  text-decoration: none;
  overflow: visible;
  will-change: transform;
}

/* Per-card interpolation between the hand-tuned fan offsets and the
   tidy carousel slot.
   - --x-fan-base is anchored at viewport-centre so the fan cluster
     reads as a centred composition.
   - --x-car places card 0 at the same viewport-centre position; cards
     1..4 extend +i × step to the RIGHT, so the unfurl is rightward
     only (leftmost barely moves, rightmost moves furthest).
   --x-fan / --y-fan / --rot-fan are set inline from JS as per-card
   offsets relative to the anchor. */
.fan-card {
  --x-fan-base: calc(50vw - var(--card-w) / 2);
  --x-fan-res:  calc(var(--x-fan-base) + var(--x-fan, 0px));
  /* Carousel anchor sits 40% of a card-width to the LEFT of viewport-
     centre — card 0's left edge clears the left margin of the page so
     the row uses more of the screen, and cards 1..4 still splay
     rightward with the same step. */
  --x-car:      calc(50vw - var(--card-w) * 0.90 + var(--idx, 0) * var(--step));

  --x: calc(var(--x-fan-res) * (1 - var(--p)) + var(--x-car) * var(--p));
  /* y INTERPOLATES from the per-card fan offset → 0 at p=1, so when
     the cards lock into the sideways carousel they all sit on the
     SAME horizontal line (no vertical staggering left over). The fan
     state still has its hand-tuned vertical variation. */
  --y: calc(var(--y-fan, 0px) * (1 - var(--p)));
  --rot: calc(var(--rot-fan, 0deg) * (1 - var(--p)));
  /* Hover lift — nudged to -3px by the :hover rule below so the hovered
     card visibly pops up a touch above its siblings. */
  --lift: 0px;

  left: 0;
  /* Scroll-driven motion uses the individual `translate` + `rotate`
     properties so the `transform` slot is free to carry the page-load
     entrance offset (CSS spec composes the two visually). */
  translate: var(--x) calc(var(--y) + var(--lift));
  rotate: var(--rot);
  /* Entrance: each card starts ~110 px below + pulled 65% of the way
     toward the cluster centre + rotated only 30% of its final fan
     rotation + scaled to 85%. So the stack starts CLUMPED, smaller,
     and less tilted, then "unfurls" outward + scales up + rotates to
     full fan rotation. The translateX / rotate cancellations are
     partial; opacity reveals the card. */
  transform:
    translateY(110px)
    translateX(calc(var(--x-fan, 0px) * -0.65))
    rotate(calc(var(--rot-fan, 0deg) * -0.7))
    scale(0.85);
  opacity: 0;
  /* Pivot from a point below the card's bottom edge so the rotation in
     fan state reads as the cards splaying outward from a shared origin
     at the floor. */
  transform-origin: 50% 130%;

  /* Translate + rotate transitions extended 220 → 420 ms so the
     between-rAF interpolation reads as one continuous ease instead
     of the previous slightly stepped feel. With the JS lerp factor
     also slowed (0.15 → 0.10), the CSS + JS combine to produce a
     genuinely smooth glide on both the scroll-driven unfurl AND
     the hover-lift. */
  transition:
    translate 420ms cubic-bezier(.2, .7, .2, 1.0),
    rotate    420ms cubic-bezier(.2, .7, .2, 1.0),
    transform 1100ms cubic-bezier(.22, 1, .36, 1),
    opacity    700ms cubic-bezier(.22, 1, .36, 1);
  /* Cards start right after the headline block-fade lands (~700ms). First
     card begins at 800ms; subsequent cards stagger 160ms each so the
     unfurl reads as a clear sequence — pink/red first, orange second,
     then the rest splay outward — closely chained to the headline arrival
     without overlapping it. */
  transition-delay:
    0ms, 0ms,
    calc(var(--idx, 0) * 160ms + 800ms),
    calc(var(--idx, 0) * 160ms + 800ms);
}

/* Entrance "to" state — clears the entire transform offset; the card's
   final position is governed by the individual translate + rotate
   properties. */
.hero-cards-fan.is-revealed .fan-card {
  transform: translateY(0) translateX(0) rotate(0) scale(1);
  opacity: 1;
}

/* The clipping frame holds the card's solid colour background (set
   inline from JS) + a 1 px hairline stroke + the rounded corner clip.
   Border-radius is interpolated from a generous 64px in fan state down
   to 20px in carousel state.
   Default state: NO drop shadow — just an inset 1 px stroke. The drop
   shadow only appears on hover (see below), where it gets a much
   bigger y-offset and blur than the previous version. */
.fan-card-frame {
  position: absolute;
  inset: 0;
  border-radius: calc(64px - 44px * var(--p));
  overflow: hidden;
  /* background is set inline per card */
  /* Stroke alpha interpolated via --p:
     - resting (--p=0): 0.044  (20 % of the full 0.22)
     - unfurled (--p=1): 0.22  (full strength, matches hover)
     Soft drop-shadow also scales in with --p so the initial stack
     is ghostly and the cards gain weight as they land. */
  --stroke-alpha: calc(0.044 + 0.176 * var(--p, 0));
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, var(--stroke-alpha)),
    0 18px 40px rgba(0, 0, 0, 0.033),
    0  6px 15px rgba(0, 0, 0, 0.015);
  transition: box-shadow 380ms cubic-bezier(.2, .7, .2, 1.0);
}

.fan-card-img {
  position: absolute;
  inset: 0;
  /* No background here — the .fan-card-frame supplies the colour wash. */
}

/* The actual media (video / image) layers on top of the solid colour
   and only fades in at the END of the unfurl, so the colour washes
   read clearly until the cards lock in. */
.fan-card-img .fan-card-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* 0 below --p = 0.85, 1 at --p = 1.0 — CSS clamps to [0,1]. */
  opacity: calc((var(--p) - 0.85) * 6.667);
  transition: opacity 240ms cubic-bezier(.2, .7, .2, 1.0);
}

/* Title + company appear only once the carousel is locked in (not
   during the transition). */
.fan-card-meta {
  position: absolute;
  top: calc(100% + 22px);
  left: 0;
  right: 0;
  text-align: left;
  /* 0 below --p = 0.92, 1 at --p = 1.0. */
  opacity: calc((var(--p) - 0.92) * 12.5);
  transform: translateY(calc((1 - var(--p)) * -6px));
  transition: opacity 320ms ease, transform 320ms ease;
  pointer-events: none;
}
.fan-card-title {
  font-family: 'Edict Display', Georgia, serif;
  font-weight: 400;
  font-style: normal;
  font-size: 28px;
  line-height: 1.18;
  letter-spacing: -0.015em;
  color: var(--ink);
  margin: 0;
}
.fan-card-company {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  font-size: 18px;
  /* Tightened from 0.02em — Inter at body sizes reads cleaner with a
     hair of negative tracking, especially next to the tightly-set
     Edict Display title above it. */
  letter-spacing: -0.005em;
  color: var(--muted);
  margin: 10px 0 0;
}

/* ── Desktop fan card sizing (work + experiments share dimensions) ─
   Bumped 25% from the legacy clamp so the row reads big on modern
   displays. Both .hero-cards-fan (work) and
   .hero-cards-fan--experiments now use the SAME --card-w / height
   recipe, so the carousel rows visually match. The container needs
   +90 px of height so the bigger meta doesn't get clipped by
   overflow:hidden (at full size a wrapping 2-line title plus the
   caption can be ~150 px tall, and only `card-top` (~110-126 px on
   common viewports) sits below the card by default). */
.hero-cards-fan {
  /* +210 px breathing room below the cards' default position so the
     meta block STILL fits inside the section after .cards-track
     translates 120 px down at full unfurl. */
  height: calc(var(--card-h) + var(--card-top) * 2 + 210px);
}
.hero-cards-fan .fan-card-meta {
  top: calc(100% + 28px);
}
/* Headline reduced a further 20% (26 → 20.8). Gap between headline
   and sub-headline also reduced 20% (13 → 10.4). Sub-headline size
   (16.5 px) is unchanged.
   padding-inline: 15% keeps the caption text from spanning the full
   card width — gives the headline more comfortable breathing room. */
.hero-cards-fan .fan-card-title {
  font-size: 22.9px;
  padding-right: 15%;
}
.hero-cards-fan .fan-card-company {
  font-size: 14.85px;
  margin-top: 10.4px;
  padding-right: 15%;
}

/* Hover — only meaningful once unfurled. The drop shadow appears here
   with double the y-offset of the previous version but at HALF the
   opacity (0.22→0.11, 0.10→0.05) so it stays soft. The card also
   lifts 3 px vertically via the --lift custom prop, giving a subtle
   pop without scaling. The 1 px stroke from the default state stays. */
.fan-card:hover,
.fan-card:focus-visible {
  z-index: 30;
  --lift: -3px;
}
.fan-card:hover .fan-card-frame,
.fan-card:focus-visible .fan-card-frame {
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, 0.22),
    /* drop-shadow alphas further reduced 40% (0.11 → 0.066, 0.05 → 0.03)
       so the lift reads as soft + airy, not heavy. */
    0 36px 80px rgba(0, 0, 0, 0.066),
    0 12px 30px rgba(0, 0, 0, 0.030);
}

/* Tablet — keep track-pad tighter; card sizing is handled by the
   viewport-height clamp on .hero-cards-fan itself. */
@media (max-width: 1100px) {
  .hero-cards-fan {
    --track-pad: 5vw;
  }
}

/* Phone — tighter track padding, smaller caption type, AND override
   the desktop xR cluster so card 0 sits centered in the viewport
   (no `xR = -0.36 × card-w` pushing it off the left edge). The
   carousel anchor moves back to viewport-centre too. !important is
   used to override the inline --x-fan set by JS. */
@media (max-width: 600px) {
  .hero-cards-fan {
    --track-pad: 4vw;
  }
  .fan-card {
    --x-fan: 0px !important;
    --x-car: calc(50vw - var(--card-w) / 2 + var(--idx, 0) * var(--step));
  }
  .fan-card-title { font-size: 17.6px; }
  .fan-card-company { font-size: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-cards-fan { transition-duration: 0ms; scroll-behavior: auto; }
}

/* ── Experiments fan (between the live-data paragraph and the footer)
   Differs from the work-cards fan in several ways:
     - 6 cards instead of 5 → 5 horizontal steps in the carousel.
     - Per-card aspect-ratio (1/1, 4/3, 3/4) — cards have variable
       HEIGHTS but are bottom-anchored in the section so their bottom
       edges line up and the captions below all sit on the same line.
     - No entrance animation: cards are "just there" as a stack the
       moment you scroll to them (no slide-up/fade-in, which was what
       caused the "appears out of the blue" feel).
     - No vertical splay in fan state (--y-fan = 0) — fan effect comes
       purely from x-offset + rotation, so the bottom edges stay
       visually aligned even mid-stack.
     - Generous top + bottom margins.
*/
.hero-cards-fan-shell--experiments {
  /* Keep the experiments row at the prior 4:3-height basis — its
     cards derive width from --card-h × (aw/ah) and the JS
     cumulative-offset packing assumes H_R = 0.75. (The work-card
     3:2 change above must not bleed into here.) */
  --card-h: calc(var(--card-w) * 0.75);
  /* Track holds 6 cards PLUS the "More experiments ↗" text slot at
     idx=6 → seven slots total, six steps between them. (JS later
     overrides this with a measured, content-tight value via
     tightenTrackW().) */
  --track-w: calc(
      50vw + var(--card-w) / 2
      + 6 * var(--step)
      + var(--track-pad)
  );
  /* +150 px breathing room above the experiments section, on top of
     the normal between-paragraph clamp — trimmed 20% twice (×0.64)
     to tighten gap 2 (live para → experiments) by a further 20%.
     margin-bottom also trimmed a further 20% (gap 3: experiments →
     last para). */
  margin-top: calc((clamp(140px, 22vh, 320px) + 150px) * 0.64);
  margin-bottom: calc(clamp(160px, 18vh, 280px) * 0.64);
}

/* Experiments eyebrow rises 20 px over the unfurl (vs the work
   eyebrow's 10 px) — i.e. it ends 10 px lower than the original
   30 px rise, a slightly tighter "Latest experiments → cards" gap. */
.hero-cards-fan-shell--experiments .hero-fan-eyebrow {
  translate: 0 calc(var(--p, 0) * -20px);
}
/* Experiments sub-headlines: capitalise the first letter only
   (the captions are authored all-lowercase). ::first-letter caps
   just the opening glyph; the rest stays as written — sentence
   case, not Title Case. */
.hero-cards-fan--experiments .fan-card-company::first-letter {
  text-transform: uppercase;
}

/* Per-card overrides: no entrance animation, no inline color panel,
   media always at full opacity, AND per-card width derived from
   each card's own aspect ratio.

   Width formula: --card-h × (--aw / --ah). HEIGHT stays at --card-h
   (same as the work carousel), so the row aligns on a uniform top
   + bottom baseline. Portraits (3/4) come out narrow, landscapes
   (4/3) take the full slot, 4/5 + 1/1 land in between. The slot
   step (--step, used by --x-car) is still --card-w, so portraits
   leave natural breathing room on either side — reads as a curated
   gallery rather than a uniform grid. */
.hero-cards-fan--experiments .fan-card {
  width: calc(var(--card-h) * var(--aw, 4) / var(--ah, 3));
  /* Cumulative-offset carousel positioning. Each card's --offset-r
     is set by JS to the sum of preceding cards' widths + gaps
     (expressed as fractions of --card-w). Replaces the base
     uniform `--idx * --step` formula so portraits don't leave huge
     empty space after them — gaps stay consistent regardless of
     card width. */
  --x-car: calc(50vw - var(--card-w) * 0.90 + var(--card-w) * var(--offset-r, 0));
  /* Skip the entrance animation. Cards don't slide up or fade in —
     they're at their final fanned position from page load. */
  transform: none;
  opacity: 1;
  transition-delay: 0ms, 0ms, 0ms, 0ms;
  /* Translate transition was previously off here to avoid layout-
     shift double-smoothing; with the live paragraph's reserved
     min-height in place, that's no longer a hazard. Match the
     work-cards' 420 ms translate + rotate so the experiments unfurl
     reads as smoothly as the work one. */
  transition:
    translate 420ms cubic-bezier(.2, .7, .2, 1.0),
    rotate    420ms cubic-bezier(.2, .7, .2, 1.0);
}
.hero-cards-fan--experiments.is-revealed .fan-card {
  transform: none;
}

/* No colored panel behind the media (the "color overlay" effect of
   the work cards is removed for experiments). The frame is a
   neutral dark fallback for the brief moment before the image
   decodes — the image then fully covers the frame. */
.hero-cards-fan--experiments .fan-card-frame {
  background: #0f0f17;
}
/* Media always at full opacity — the work-cards' formula that fades
   in only at the end of the unfurl is overridden so the image is
   visible from frame one. */
.hero-cards-fan--experiments .fan-card-img .fan-card-media {
  opacity: 1;
  transition: none;
}
/* Make any inline SVG fill its slot like the work cards' video/img. */
.hero-cards-fan--experiments svg.fan-card-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* "More experiments ↗" — text-only "card" sitting inside the
   .cards-track at idx=EXPERIMENTS.length (=6). Uses the same
   fan/carousel position math as a real card so it lives in the
   same row, lands at the end of the scroll, and follows the
   unfurl. No frame — just large italic typography.
   The underline is only on the label, never on the arrow. */
.hero-exp-more {
  /* Match the cards' position math + vertical alignment. */
  position: absolute;
  top: var(--card-top);
  left: 0;
  height: var(--card-h);
  --x-fan-base: calc(50vw - var(--card-w) / 2);
  --x-fan-res:  calc(var(--x-fan-base) + var(--x-fan, 0px));
  /* Same cumulative-offset positioning the cards use, so the link
     lands immediately after the last card's right edge + one gap. */
  --x-car:      calc(50vw - var(--card-w) * 0.90 + var(--card-w) * var(--offset-r, 0));
  --x: calc(var(--x-fan-res) * (1 - var(--p)) + var(--x-car) * var(--p));
  translate: var(--x) 0;
  /* Size to content (no fixed width). The previous 1.15 × card-w
     left a big empty rectangle to the right of the link. With
     width:auto + display:inline-flex, the box is exactly the
     measured width of the label + arrow + gap. */
  width: auto;
  /* Reveal at the end of the unfurl, like the work cards' meta. */
  opacity: calc((var(--p) - 0.92) * 12.5);
  pointer-events: none;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  /* +70 px breathing room on each side of the link (was 8 px left,
     0 right). The left padding opens the gap between the last card
     and the link; the right padding is folded into the element's
     measured width, so tightenTrackW() extends the scroll to keep
     it after the link too. */
  padding-left: 78px;
  padding-right: 70px;
}
.hero-cards-fan--experiments[data-state="carousel"] .hero-exp-more {
  pointer-events: auto;
}

/* Inner link wraps the label + arrow. text-decoration: none on the
   wrapper so only the .label child gets the underline (the arrow
   stays unmarked). */
.hero-exp-more-link {
  display: inline-flex;
  align-items: baseline;
  gap: 14px;
  font-family: 'Edict Display', Georgia, serif;
  font-style: italic;
  font-weight: 300;
  /* −30% from clamp(44px, 5.2vw, 72px). */
  font-size: clamp(31px, 3.6vw, 50px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--ink, #1a1a2e);
  text-decoration: none;
}
.hero-exp-more-label {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.12em;
  text-decoration-color: currentColor;
  transition: text-decoration-color 220ms ease;
}
.hero-exp-more-link:hover .hero-exp-more-label {
  text-decoration-color: transparent;
}
.hero-exp-more-arrow {
  display: inline-block;
  font-family: 'Edict Display', Georgia, serif;
  font-style: normal;
  font-size: 0.9em;
  line-height: 1;
  /* Explicit none — the arrow is NEVER underlined. */
  text-decoration: none;
  transition: transform 220ms cubic-bezier(.2, .7, .2, 1.0);
}
.hero-exp-more-link:hover .hero-exp-more-arrow {
  transform: translate(6px, -6px);
}

/* "See more experiments" CTA card — light cream, italic display
   title, big diagonal arrow. The frame uses flexbox layout so the
   three pieces (caption, title, arrow) center cleanly inside the
   card's full height. */
.fan-card--see-more .fan-card-frame {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
  text-align: center;
}
.fan-card-see-more {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  width: 100%;
}
.fan-card-see-more-sub {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: clamp(12px, 1.2vw, 16px);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: lowercase;
  opacity: 0.7;
  margin: 0;
}
.fan-card-see-more-title {
  font-family: 'Edict Display', Georgia, serif;
  font-weight: 300;
  font-style: italic;
  font-size: clamp(26px, 3.4vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.015em;
  margin: 0;
  max-width: 14ch;
}
.fan-card-see-more-arrow {
  display: inline-block;
  font-family: 'Edict Display', Georgia, serif;
  font-weight: 300;
  font-size: clamp(36px, 5vw, 64px);
  line-height: 1;
  margin-top: 8px;
  transition: transform 280ms cubic-bezier(.2, .7, .2, 1.0);
}
.fan-card--see-more:hover .fan-card-see-more-arrow,
.fan-card--see-more:focus-visible .fan-card-see-more-arrow {
  transform: translate(6px, -6px);
}

