/* ═══════════════════════════════════════════════════════════════════════
   Bhavna Rawal — portfolio
   Every colour, radius and rhythm value lives in :root. Change it there.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* Paper */
  --paper:        #FAF6F1;   /* warm off-white ground          */
  --grid-fine:    rgba(61,62,171,.032);   /* the graph lines    */
  --grid-bold:    rgba(61,62,171,.018);  /* every 5th line     */
  --grid-step:    19px;

  /* Ink */
  --red:          #3D3EAB;   /* the one loud colour            */
  --red-deep:     #2E2F8C;   /* hover / pressed                */
  --navy:         #1B2A6B;   /* pupils, tiny accents           */
  --hot-design:   #F04E14;   /* the "designs" hover theme      */
  --hot-goals:    #17924A;   /* the "business goals" theme     */
  --muted:        #7E7E96;
  --black:        #141420;   /* eyebrow line                   */

  /* Type */
  --display: 'Instrument Serif', 'Times New Roman', serif;
  --ui:      'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --arcade:  'Anton', 'Impact', sans-serif;    /* "designs" on hover      */
  --pixel:   'Handjet', ui-monospace, monospace;   /* "goals" on hover   */
  --grotesk: 'Figtree', 'Inter', sans-serif;   /* project banner titles  */

  /* Motion */
  --ease:  cubic-bezier(.22,1,.36,1);
  --swift: cubic-bezier(.4,0,.2,1);
}

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  min-height: 100%;
  background: var(--paper);
  color: var(--red);
  font-family: var(--ui);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  overflow-x: clip;
}

/* ─── Paper: the grid texture ──────────────────────────────────────────── */

.paper { position: fixed; inset: 0; z-index: 0; pointer-events: none; }

/* Two stacked line sets: a fine 22px graph and a bolder line every 5th.
   Sizes are driven off --grid-step so one number rescales the whole sheet. */
.paper__grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--grid-bold) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-bold) 1px, transparent 1px),
    linear-gradient(var(--grid-fine) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-fine) 1px, transparent 1px);
  background-size:
    calc(var(--grid-step) * 5) calc(var(--grid-step) * 5),
    calc(var(--grid-step) * 5) calc(var(--grid-step) * 5),
    var(--grid-step) var(--grid-step),
    var(--grid-step) var(--grid-step);
}

/* Fibrous paper grain — an SVG turbulence tile, no image file. */
.paper__grain {
  position: absolute; inset: 0;
  opacity: .09;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

/* Light falloff at the edges so the sheet reads as lit, not flat. */
.paper__vignette {
  position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 50% 32%, transparent 52%, rgba(126,126,150,.11) 100%);
}

/* ─── Header ───────────────────────────────────────────────────────────
   The bar contracts from full width into a floating capsule as you scroll.
   main.js writes --p (0…1) plus the two width bounds; every property below
   is interpolated off that one number, so the morph is scroll-linked rather
   than a snap between two states. */

.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 20;
  display: flex; justify-content: center;
  padding: 20px clamp(24px, 5.5vw, 88px);
  --p: 0;
  --w-min: 640px;
  --w-max: 1200px;
}

.nav__bar {
  display: flex; align-items: center; justify-content: space-between;
  width: calc(var(--w-max) - (var(--w-max) - var(--w-min)) * var(--p));
  max-width: 100%;
  padding: calc(6px * var(--p)) calc(20px * var(--p));
  border-radius: 999px;
  background: rgba(250, 250, 254, calc(.88 * var(--p)));
  box-shadow: 0 calc(14px * var(--p)) calc(38px * var(--p))
              calc(-14px * var(--p)) rgba(45, 45, 95, .45);
  /* The hairline only exists once the capsule has something to outline. */
  outline: 1px solid rgba(61, 62, 171, calc(.16 * var(--p)));
  outline-offset: -1px;
  backdrop-filter: blur(calc(9px * var(--p)));
  -webkit-backdrop-filter: blur(calc(9px * var(--p)));
  will-change: width;
}

/* Brand — Bhavna's illustration exactly as supplied: transparent, uncropped,
   no ring. It just shrinks a little as the bar collapses. */
.brand {
  position: relative;
  display: inline-flex; flex: none; text-decoration: none;
  margin-right: calc(6px + 20px * var(--p));
}

/* Hover swaps the illustration for the real thing, same box, plus a line
   underneath that floats free of the nav's layout. */
.brand .brand__real {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 12px;
  opacity: 0;
  scale: .94;
  transition: opacity .26s var(--swift), scale .3s var(--ease);
  pointer-events: none;
}
.brand .brand__me { transition: opacity .26s var(--swift); }

.brand:hover .brand__me,
.brand:focus-visible .brand__me { opacity: 0; }
.brand:hover .brand__real,
.brand:focus-visible .brand__real { opacity: 1; scale: 1; }

.brand__cap {
  position: absolute;
  top: calc(100% + 4px);
  left: 50%;
  translate: -50% 4px;
  white-space: nowrap;
  font-family: var(--display);
  font-size: calc(13px - 2px * var(--p));
  line-height: 1;
  letter-spacing: .01em;
  color: var(--red);
  opacity: 0;
  pointer-events: none;
  transition: opacity .24s var(--swift), translate .3s var(--ease);
}
.brand:hover .brand__cap,
.brand:focus-visible .brand__cap { opacity: 1; translate: -50% 0; }

@media (max-width: 700px) {
  .brand__real, .brand__cap { display: none; }
}

.brand img {
  height: calc(80px - 30px * var(--p));
  width: auto;
  display: block;
  transition: rotate .5s var(--ease), scale .5s var(--ease);
}
.brand:hover img { rotate: -7deg; scale: 1.07; }

.nav__links { display: flex; align-items: center; gap: calc(14px - 4px * var(--p)); }

.navlink {
  position: relative; isolation: isolate;
  padding: .52em 1.15em;
  border-radius: 999px;
  color: var(--red);
  font-family: var(--display);
  font-size: clamp(16px, 1.22vw, 21px);
  line-height: 1.3;
  text-decoration: none;
  white-space: nowrap;
  transition: color .3s var(--swift);
}
/* Soft pill behind the label — it scales up from 80% rather than fading. */
.navlink::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  border-radius: 999px;
  background: rgba(61, 62, 171, .11);
  opacity: 0; scale: .78;
  transition: opacity .32s var(--swift), scale .38s var(--ease);
}
.navlink:hover::before,
.navlink:focus-visible::before,
.navlink.is-active::before { opacity: 1; scale: 1; }
.navlink:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }

/* Contact sits at the far end as the one filled pill. */
.nav__cta {
  flex: none;
  display: inline-flex; align-items: center; gap: .4em;
  padding: .54em 1.3em;
  border-radius: 999px;
  background: var(--red);
  color: #F7F7FD;
  font-family: var(--display);
  font-size: clamp(16px, 1.22vw, 21px);
  line-height: 1.3;
  text-decoration: none;
  white-space: nowrap;
  transition: background .3s var(--swift), scale .4s var(--ease);
}
.nav__cta svg { width: .62em; height: .62em; flex: none; }
.nav__cta:hover { background: var(--red-deep); scale: 1.04; }
.nav__cta:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }

/* Mobile hamburger */
.nav__toggle {
  display: none;
  width: 46px; height: 46px; padding: 0; flex: none;
  border: 1.6px solid var(--red); border-radius: 50%;
  background: transparent; cursor: pointer;
}
.nav__toggle span {
  display: block; width: 18px; height: 1.6px; margin: 4px auto;
  background: var(--red);
  transition: transform .3s var(--swift), opacity .3s var(--swift);
}
.nav__toggle[aria-expanded="true"] span:first-child { transform: translateY(3px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:last-child  { transform: translateY(-3px) rotate(-45deg); }

.drawer {
  position: fixed; inset: 96px 16px auto 16px; z-index: 19;
  display: grid; gap: 4px;
  padding: 14px;
  border-radius: 26px;
  background: rgba(250, 250, 254, .94);
  outline: 1px solid rgba(61, 62, 171, .18);
  outline-offset: -1px;
  box-shadow: 0 18px 40px -18px rgba(45, 45, 95, .45);
  backdrop-filter: blur(9px);
}
.drawer[hidden] { display: none; }
.drawer a {
  padding: .4em .6em;
  color: var(--red); text-decoration: none;
  font-family: var(--display); font-size: 26px;
}

/* ─── Sunflower cursor ─────────────────────────────────────────────────
   A DOM sprite rather than a CSS `cursor:url()`, so it can ease, spin and
   swell over links. main.js only enables it for fine pointers. */

.flower {
  position: fixed; top: 0; left: 0; z-index: 90;
  width: 22px; height: 22px;
  margin: -11px 0 0 -11px;
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s var(--swift);
  will-change: transform;
}
.flower img {
  width: 100%; height: 100%; display: block;
  transition: opacity .2s var(--swift);
}

/* Over the work-in-progress banner the flower becomes a no-entry mark.
   main.js writes --spin, so this can undo the parent's rotation and stay
   upright while the sunflower keeps turning. */
.flower__no {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 20px; line-height: 1;
  rotate: calc(var(--spin, 0) * -1deg);
  opacity: 0;
  transition: opacity .2s var(--swift);
}
.flower.is-hot .flower__no { font-size: 27px; }
.flower.is-blocked img { opacity: 0; }
.flower.is-blocked .flower__no { opacity: 1; }

/* Any element carrying data-cursor swaps the flower for that glyph. */
.flower__alt {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 20px; line-height: 1;
  rotate: calc(var(--spin, 0) * -1deg);
  opacity: 0;
  transition: opacity .2s var(--swift);
}
.flower.is-hot .flower__alt { font-size: 27px; }
.flower.is-alt img { opacity: 0; }
.flower.is-alt .flower__alt { opacity: 1; }

/* Hidden over the field, which draws its own watering-can pointer. */
.flower.is-away { opacity: 0 !important; }
.flower.is-on { opacity: 1; }
/* Swells over anything clickable. */
.flower.is-hot { width: 30px; height: 30px; margin: -15px 0 0 -15px; }
.flower { transition: opacity .3s var(--swift), width .3s var(--ease),
                      height .3s var(--ease), margin .3s var(--ease); }

html.flower-cursor, html.flower-cursor * { cursor: none !important; }

/* ─── Hero ─────────────────────────────────────────────────────────────── */

.hero {
  position: relative; z-index: 1;
  /* The heading owns the first fold. The hero stops just short of it, so
     the next section's label clears the edge and only the very top of
     "Selected projects" peeks in as a hint that there is more. */
  min-height: calc(100svh - 90px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(14px, 1.8vw, 24px);
  padding: 136px clamp(20px, 4vw, 64px) 40px;
  text-align: center;
}

/* Headline */
.headline {
  position: relative;                /* the doodles hang off this box */
  margin: 0;
  max-width: 24ch;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(44px, 7.2vw, 136px);
  line-height: 1.06;
  letter-spacing: -.015em;
}
.headline .line {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 0 .28em;
}
.headline .em { font-style: italic; }
.headline .glyph { font-size: .82em; }

/* Words and chips animate on the independent `translate` / `rotate` /
   `scale` properties, which leaves `transform` free for the idle bob. */
.rise { display: inline-block; }
.no-motion .rise { opacity: 1; translate: none; }

/* Inline image chips.
   To use a real picture:  <span class="chip" style="--img:url(assets/x.jpg)">  */
.chip {
  display: inline-block;
  height: .62em; aspect-ratio: 16 / 10;
  border-radius: .1em;
  background-color: #DEDEEA;
  background-image: var(--img);
  background-size: cover; background-position: center;
  box-shadow: 0 6px 18px -10px rgba(42,42,88,.5);
  rotate: var(--tilt, 0deg);
  transform: translateY(var(--bob, 0px));   /* idle bob, written by JS */
  transition: rotate .5s var(--ease), scale .5s var(--ease),
              box-shadow .5s var(--ease);
  will-change: transform, translate;
}
.chip:hover {
  rotate: calc(var(--tilt, 0deg) * -2);
  scale: 1.1;
  box-shadow: 0 14px 30px -12px rgba(42,42,88,.6);
}
/* Inline emoji sit on the same idle bob as the chips. */
.emoji {
  display: inline-block;
  font-size: .82em;
  transform: translateY(var(--bob, 0px));
}

/* Placeholder fills — replace with --img when the real photos arrive. */
.chip--1 { --tilt: -1.5deg; --img: linear-gradient(135deg, #E8B96A, #D9873C 60%, #B96A2A); }
.chip--2 { --tilt: 2deg;    --img: linear-gradient(135deg, #C9CBC4, #8E9189 55%, #5C5F58); }
.chip--3 { --tilt: -2.5deg; --img: linear-gradient(135deg, #B7D3A0, #7FA86A 55%, #4E7B46); }

/* ─── Work: project banners ────────────────────────────────────────────
   One banner per project, ported from the Figma frames. Each carries its
   own --tint / --pill-bg / --pill-ink inline, so a new project is a copied
   <article> with three colours changed and nothing else. */

/* One page gutter for every section, wide enough that the banners sit
   inset from the viewport edges rather than running to them. */
.section,
.stub {
  position: relative; z-index: 1;
  padding: 58px clamp(20px, 8.6vw, 130px) 82px;
}
.section {
  display: flex; flex-direction: column;
  gap: 14px;
}

.projects {
  display: grid; gap: clamp(20px, 2.4vw, 32px);
  margin-top: clamp(20px, 3vw, 44px);
}

/* Two of the three are anchors to their case study; the work-in-progress
   one stays an <article> so there is nothing to click. */
.project {
  position: relative;
  color: inherit;
  text-decoration: none;
  display: grid;
  /* 580 : 449 — the exact split from the Figma frame (1029 wide). */
  grid-template-columns: 56.4% 43.6%;
  align-items: center;
  border-radius: 20px;
  background: var(--tint);
  overflow: hidden;
  transition: translate .5s var(--ease), box-shadow .5s var(--ease);
}
.project:hover { translate: 0 -4px; }
a.project:focus-visible { outline: 2px solid var(--navy); outline-offset: 4px; }

/* The mockup. Its aspect sets the banner's height; the body centres beside it. */
.project__stage {
  position: relative;
  /* Matches the banner's left region, so the composited mockup lands at
     exactly the position it holds in the Figma frame. */
  aspect-ratio: 580 / 357;
  background: var(--tint);
  overflow: hidden;
}
.project__stage img {
  width: 100%; height: 100%;
  /* The mockups are composited to 580:357 with a transparent ground, so
     contain is a no-op at desktop and letterboxes cleanly when stacked. */
  object-fit: contain; object-position: center;
  display: block;
  transition: scale .6s var(--ease);
}
.project:hover .project__stage img { scale: 1.03; }

/* Until the export is dropped in, show the slot rather than a broken image.
   main.js adds .is-empty when the file 404s. */
.project__stage.is-empty { background: var(--tint); }
.project__stage.is-empty img { display: none; }
.project__stage.is-empty::after {
  content: attr(data-shot);
  position: absolute; inset: 14px;
  display: grid; place-items: center;
  border: 1.5px dashed rgba(42, 42, 88, .28);
  border-radius: 12px;
  color: rgba(42, 42, 88, .5);
  font-family: var(--ui); font-size: 13px;
  text-align: center; padding: 12px;
}

.project__body {
  padding: clamp(22px, 3vw, 44px) clamp(22px, 3.4vw, 52px);
}
.project__title {
  margin: 0;
  font-family: var(--grotesk);
  font-weight: 800;
  font-size: clamp(22px, 2.5vw, 38px);
  line-height: 1.15;
  letter-spacing: -.02em;
  color: #16161A;
}
.project__desc {
  margin: .7em 0 0;
  max-width: 44ch;
  font-family: var(--ui);
  font-size: clamp(13px, 1.05vw, 16px);
  line-height: 1.6;
  color: #4A4A52;
}
.project__tags {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: 1.3em 0 0; padding: 0;
  list-style: none;
}
.project__tags li {
  padding: .34em 1em;
  border-radius: 999px;
  background: var(--pill-bg);
  color: var(--pill-ink);
  font-family: var(--ui);
  font-size: clamp(12px, .95vw, 14px);
  font-weight: 500;
  white-space: nowrap;
}

/* Cursor-trailing label. JS writes the translate every frame; scale and
   opacity stay on their own properties so the entrance can transition
   without fighting the follow. */
.project__peek {
  position: absolute; top: 0; left: 0; z-index: 3;
  display: flex; align-items: center; gap: .42em;
  padding: .5em 1.1em;
  border-radius: 999px;
  background: var(--peek);
  color: #FFF;
  font-family: var(--ui);
  font-size: 14px; font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0; scale: .7;
  transform: translate(-50%, -50%);
  transition: opacity .25s var(--swift), scale .38s var(--ease);
  will-change: transform;
}
.project.is-peeking .project__peek { opacity: 1; scale: 1; }
.project__peek svg { width: .86em; height: .86em; flex: none; }


/* ─── If not design ────────────────────────────────────────────────────
   Copy left, one big photo right, and a fanned strip along the photo's
   bottom edge. Moving across the strip swaps the photo; the thumbnails
   spread apart around whichever one is under the cursor. */

.quiz {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
  margin-top: clamp(20px, 3vw, 40px);
  padding: clamp(22px, 3vw, 40px);
  border-radius: 26px;
  background: rgba(61, 62, 171, .045);
}

/* Identical to the page's other headings — size included. */
.quiz__body .quiz__title { margin: 0 0 .8em; }

.quiz__body p {
  margin: 0 0 1em;
  max-width: 56ch;
  font-family: var(--ui);
  font-size: clamp(13.5px, 1.02vw, 15.5px);
  line-height: 1.8;
  color: #4A4A52;
}
.quiz__body p:last-child { margin-bottom: 0; }
.quiz__body strong { font-weight: 600; color: var(--black); }
.quiz__body em { font-style: italic; }

/* The photo. Two stacked layers so a swap can cross-fade. */
.quiz__stage { position: relative; }

.quiz__shot {
  position: relative;
  aspect-ratio: 1;
  max-width: 420px;
  margin-inline: auto;
  border-radius: 18px;
  overflow: hidden;
  background: rgba(61, 62, 171, .05);
}
.quiz__img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  opacity: 0;
  transition: opacity .45s var(--swift);
}
.quiz__img.is-front { opacity: 1; }

/* Waiting on the photos. */
.quiz__shot.is-empty .quiz__img { display: none; }
.quiz__shot.is-empty::after,
.quiz__thumb.is-empty::after {
  content: '';
  position: absolute; inset: 8px;
  border: 1.5px dashed rgba(61, 62, 171, .3);
  border-radius: 12px;
}
.quiz__thumb.is-empty img { visibility: hidden; }

/* One stacked row under the photo. They still overlap like a dealt deck,
   just far less tightly than before — 30px of each stays visible. */
.quiz__strip {
  display: flex; justify-content: center;
  padding-left: 10px;
  margin-top: clamp(12px, 1.4vw, 18px);
}

.quiz__thumb {
  position: relative;
  width: clamp(28px, 2.6vw, 36px); aspect-ratio: 1;
  flex: none;
  margin-left: -10px;
  padding: 0;
  border: 2px solid #F9F9FE;
  border-radius: 10px;
  background: rgba(61, 62, 171, .06);
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 5px 12px -8px rgba(30, 30, 60, .55);
  transition: scale .3s var(--ease), translate .3s var(--ease),
              margin .3s var(--ease), box-shadow .3s var(--ease);
}
.quiz__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Hover only lifts it out of the stack; clicking is what puts it on the
   big screen. */
.quiz__thumb:hover,
.quiz__thumb:focus-visible {
  scale: 1.6;
  translate: 0 -8px;
  margin-left: 8px; margin-right: 14px;
  z-index: 3;
}
.quiz__thumb:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }

/* The one currently showing above. */
.quiz__thumb.is-on {
  z-index: 2;
  border-color: var(--red);
  box-shadow: 0 0 0 1.5px var(--red), 0 6px 14px -8px rgba(30, 30, 60, .5);
}

@media (max-width: 860px) {
  .quiz { grid-template-columns: 1fr; }
  .quiz__strip { flex-wrap: wrap; row-gap: 8px; }
}

/* ─── Out of office ────────────────────────────────────────────────────
   One number, --s, runs the whole scatter: at 0 every photo sits stacked
   and small in the middle, at 1 each has travelled its own --x/--y and
   settled at its own --r. main.js writes it from the scroll position. */

/* The section is taller than the viewport and its contents are pinned, so
   there is scroll runway to play the scatter through while you are looking
   at it. Without that the whole animation finished below the fold and the
   cards were already spread by the time the section arrived. */
.oo {
  position: relative; z-index: 1;
  --s: 0;
  --k: 1;                 /* travel multiplier, dialled down on small screens */
  --base: 330px;          /* the single card everything starts as */
  height: 240svh;
}
.oo__pin {
  position: sticky; top: 0;
  height: 100svh;
  display: grid; place-items: center;
  padding: 90px clamp(20px, 8.6vw, 130px);
  overflow: hidden;
}

.oo__field { position: absolute; inset: 0; pointer-events: none; }

/* At --s: 0 every card is the same box, in the same place, unrotated and
   unshadowed — so the stack reads as one photo. Everything below then
   interpolates from that shared start to the card's own end state, which
   is what makes the pile look like it fans out of a single image.
   Every card is square; --f is its final size as a share of --base. */
.oo__shot {
  position: absolute; left: 50%; top: 50%;
  width:  calc(var(--base) * (1 + (var(--f) - 1) * var(--s)));
  height: calc(var(--base) * (1 + (var(--f) - 1) * var(--s)));
  margin: 0;
  translate: calc(-50% + var(--x) * var(--s) * var(--k))
             calc(-50% + var(--y) * var(--s) * var(--k));
  rotate: calc(var(--r) * var(--s));
  /* Only grabbable once they have actually fanned out. */
  pointer-events: none;
}
.oo.is-spread .oo__shot { pointer-events: auto; }
.oo__shot:hover { z-index: 3; }

.oo__frame {
  width: 100%; height: 100%;
  border-radius: 22px;
  overflow: hidden;
  background: rgba(61, 62, 171, .05);
  box-shadow: 0 calc(18px * var(--s)) calc(40px * var(--s))
              calc(-26px * var(--s)) rgba(55, 55, 105, .5);
  transition: scale .45s var(--ease);
}
.oo__frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.oo.is-spread .oo__shot:hover .oo__frame { scale: 1.06; }

/* No photo yet — show the slot rather than a broken image. */
.oo__frame.is-empty img { display: none; }
.oo__frame.is-empty {
  display: grid; place-items: center;
  padding: 10px;
  border: 1.5px dashed rgba(61, 62, 171, .3);
  background: rgba(61, 62, 171, .045);
}
.oo__frame.is-empty::after {
  content: attr(data-shot);
  color: rgba(42, 42, 88, .45);
  font-family: var(--ui); font-size: 10px; line-height: 1.4;
  text-align: center; word-break: break-all;
}

/* Caption sits below the photo and stays upright whatever the card's tilt. */
.oo__cap {
  position: absolute; top: calc(100% + 12px); left: 50%;
  width: max-content;
  max-width: 230px;
  translate: -50% 0;
  rotate: calc(var(--r) * var(--s) * -1);
  padding: .4em .9em;
  border-radius: 14px;
  background: var(--black);
  color: #F7F7FD;
  font-family: var(--ui); font-size: 12px; line-height: 1.45;
  text-align: center;
  pointer-events: none;
  opacity: 0; scale: .82;
  transition: opacity .25s var(--swift), scale .32s var(--ease);
}
.oo.is-spread .oo__shot:hover .oo__cap { opacity: 1; scale: 1; }

/* The words sit in the gap the photos open up around them. */
.oo__mid {
  position: relative; z-index: 2;
  max-width: 520px;
  text-align: center;
  /* Nothing here until the cards have actually fanned out. */
  opacity: calc((var(--s) - .62) / .28);
  translate: 0 calc(22px * (1 - var(--s)));
}
.oo__title {
  margin: 0;
  font-family: var(--display); font-weight: 400;
  font-size: clamp(32px, 4.4vw, 64px); line-height: 1.08;
}
.oo__title em { font-style: italic; }
.oo__note {
  margin: .9em 0 0;
  font-family: var(--ui);
  font-size: clamp(13px, 1vw, 15px);
  line-height: 1.75;
  color: var(--muted);
}
.oo__cta {
  display: inline-flex; align-items: center; gap: .5em;
  margin-top: 1.5em;
  padding: .6em 1.4em;
  border-radius: 999px;
  background: var(--black);
  color: #F7F7FD;
  font-family: var(--ui);
  font-size: 15px; font-weight: 500;
  text-decoration: none;
  transition: background .3s var(--swift), scale .4s var(--ease);
}
.oo__cta svg { width: .95em; height: .95em; flex: none; }
.oo__cta:hover { background: var(--red); scale: 1.04; }
.oo__cta:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }

/* With motion off, show the settled state rather than an empty middle. */
.no-motion .oo { --s: 1; }

@media (max-width: 1100px) { .oo { --k: .72; --base: 284px; } }
@media (max-width: 760px)  { .oo { --k: .46; --base: 233px; height: 200svh; }
                             .oo__shot { border-radius: 16px; } }

/* ─── Stub sections ────────────────────────────────────────────────────── */

.stub {
  position: relative; z-index: 1;
  min-height: 62svh;
  display: flex; flex-direction: column; justify-content: center;
  gap: 14px;
}
.stub__eyebrow {
  margin: 0; font-size: 13px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted);
}
.stub__title {
  margin: 0;
  font-family: var(--display); font-weight: 400;
  font-size: clamp(40px, 6vw, 88px); line-height: 1.05;
}
.stub__title em { font-style: italic; }

/* On the home page this heading sits alongside "When I'm not designing"
   and "Got something to say?", so it matches their size rather than the
   larger one the About page headings use. */
#work .stub__title { font-size: clamp(32px, 4.5vw, 66px); }
.stub__note { margin: 0; max-width: 46ch; color: var(--muted); font-size: 15px; }

/* ─── Hero: eyebrow, note, hover swaps, doodles ────────────────────────── */

/* Block, not flex — the sunflower has to sit inline so the sentence can
   wrap around it on a phone instead of being stranded beside it. */
.eyebrow {
  margin: 0;
  font-family: var(--ui);
  font-size: clamp(13px, 1.05vw, 16px);
  font-weight: 500;
  letter-spacing: .01em;
  color: #7B7B93;
}
/* The two hover targets.

   Both renderings sit in the same box: the resting word holds the layout,
   the hot one is absolutely positioned on top of it and cross-fades in.
   Nothing reflows, so the word can never slide out from under the cursor
   and start flickering between the two states. main.js measures the pair
   and writes --fit so the wider hot word is scaled down to sit inside the
   resting word's width. */
.swap {
  position: relative;
  display: inline-block;
  white-space: nowrap;
  cursor: pointer;
}
.swap__a { transition: opacity .22s var(--swift); }
.swap__b {
  position: absolute;
  top: 50%; left: 50%;
  translate: -50% -50%;
  scale: var(--fit, 1);
  opacity: 0;
  pointer-events: none;
  transition: opacity .22s var(--swift);
}
.swap.is-hot .swap__a { opacity: 0; }
.swap.is-hot .swap__b { opacity: 1; }

.swap--design .swap__b {
  font-family: var(--arcade);
  font-style: normal;
  text-transform: uppercase;
  font-size: .94em;
  letter-spacing: .012em;
  color: #F7F7FD;
  -webkit-text-stroke: 2px var(--hot-design);
  paint-order: stroke fill;
  text-shadow: 3px 3px 0 var(--hot-design), 7px 7px 0 rgba(240, 78, 20, .3);
}
.swap--goals .swap__b {
  font-family: var(--pixel);
  font-weight: 700;
  font-style: normal;
  font-size: .92em;
  letter-spacing: -.01em;
  color: var(--hot-goals);
}

/* The mark beside "business goals" — target at rest, money in flight while
   the phrase is hot. Both are stacked so the line never jumps. */
.mark {
  position: relative;
  display: inline-grid;
  font-size: .78em;
  line-height: 1;
}
.mark__a, .mark__b {
  grid-area: 1 / 1;
  transition: opacity .28s var(--swift), rotate .45s var(--ease), scale .45s var(--ease);
}
.mark__b { opacity: 0; scale: .6; rotate: -25deg; }
.hero.hot-goals .mark__a { opacity: 0; scale: .6; rotate: 25deg; }
.hero.hot-goals .mark__b { opacity: 1; scale: 1; rotate: 0deg; }

/* Doodle scatter. Hidden until its theme is hot, then each pops in on its
   own beat so the set arrives as a flurry rather than a block. */
/* Pinned to the headline itself, so the icons tuck in close to the words
   rather than drifting out to the edges of the viewport. */
.doodles { position: absolute; inset: 0; pointer-events: none; }

.doodle {
  position: absolute;
  left: var(--x); top: var(--y);
  /* Traced from Bhavna's own icon sheets and thinned, then emitted as
     outlines on one 24x24 grid: the drawn shapes exactly, vector-crisp, at a
     lighter weight. --gap holds each icon the same distance out from the
     edge of the headline. */
  --gap: clamp(33px, 3.5vw, 54px);
  width: clamp(30px, 3.2vw, 46px);
  height: clamp(30px, 3.2vw, 46px);
  translate: -50% -50%;
  opacity: 0;
  rotate: var(--r);
  scale: .4;
  transition: opacity .3s var(--swift), scale .5s var(--ease);
}
.doodle svg { width: 100%; height: 100%; display: block; overflow: visible; }
.doodle--design { color: var(--hot-design); }
.doodle--goals  { color: var(--hot-goals); }

.hero.hot-design .doodle--design,
.hero.hot-goals  .doodle--goals { opacity: 1; scale: 1; }

/* Stagger, so they land one after another. */
.doodle:nth-of-type(6n+1) { transition-delay: .00s, .00s; }
.doodle:nth-of-type(6n+2) { transition-delay: .04s, .04s; }
.doodle:nth-of-type(6n+3) { transition-delay: .08s, .08s; }
.doodle:nth-of-type(6n+4) { transition-delay: .12s, .12s; }
.doodle:nth-of-type(6n+5) { transition-delay: .16s, .16s; }
.doodle:nth-of-type(6n)   { transition-delay: .20s, .20s; }

.no-motion .doodle,
.no-motion .mark__a,
.no-motion .mark__b { transition: none; }

/* ─── About page ───────────────────────────────────────────────────────  */

/* about.html has no fixed header — the back link leads instead. */
.page { padding-top: 78px; }

/* Section headings run smaller on this page than on the home page. */
.page .stub__title { font-size: clamp(34px, 4.8vw, 68px); }

/* Pinned, so it is reachable from anywhere on the page. It carries the
   same capsule treatment as the home page's nav so it stays legible once
   text scrolls underneath it. */
.backlink {
  position: fixed;
  top: 20px; left: clamp(20px, 8.6vw, 130px);
  z-index: 20;
  display: inline-flex; align-items: center; gap: .5em;
  padding: .5em 1.05em;
  border-radius: 999px;
  background: rgba(250, 250, 254, .88);
  outline: 1px solid rgba(61, 62, 171, .16);
  outline-offset: -1px;
  box-shadow: 0 10px 26px -16px rgba(45, 45, 95, .45);
  backdrop-filter: blur(9px);
  -webkit-backdrop-filter: blur(9px);
  color: var(--muted);
  font-family: var(--ui); font-size: 14px;
  text-decoration: none;
  transition: color .3s var(--swift), scale .35s var(--ease);
}
.backlink svg { width: 1em; height: 1em; }
.backlink:hover { color: var(--red); scale: 1.04; }
.backlink:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }

/* A long read, so: one column at a comfortable measure, generous leading,
   and the bolded phrases in the site red so they carry the eye down. */
.bio {
  max-width: 62ch;
  margin-top: clamp(20px, 3vw, 40px);
  font-family: var(--ui);
  font-size: clamp(13.5px, 1.02vw, 15.5px);
  line-height: 1.8;
  color: #4A4A52;
}
.bio p { margin: 0 0 1.35em; }
.bio p:last-child { margin-bottom: 0; }
.bio strong { font-weight: 600; color: var(--black); }
.bio em { font-style: italic; }

/* Two lines that want their own air. */
.bio__beat {
  margin: 1.9em 0 1.9em !important;
  font-family: var(--ui);
  font-weight: 600;
  font-size: 1.28em;
  line-height: 1.4;
  color: var(--black);
}
.bio__end {
  margin-top: 1.5em !important;
  font-family: var(--ui);
  font-weight: 600;
  font-size: 1.28em;
  line-height: 1.5;
  color: var(--black);
  text-wrap: balance;
}

/* ─── Working with me ──────────────────────────────────────────────────
   Native <details>, so it opens on click and on keyboard with no script.
   The height transition needs `interpolate-size`; where that is missing it
   simply snaps open, which is a fine floor. */

/* Heading on one side, rows on the other, so the section uses its width. */
.section--split {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  gap: clamp(24px, 5vw, 88px);
  align-items: start;
}
.section--split .stub__title { margin-top: -.12em; }

.facts {
  border-top: 1px solid rgba(61, 62, 171, .16);
}

@media (max-width: 860px) {
  .section--split { grid-template-columns: 1fr; gap: clamp(18px, 3vw, 28px); }
  .section--split .stub__title { margin-top: 0; }
}

.fact { border-bottom: 1px solid rgba(61, 62, 171, .16); }

.fact__q {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 1.05em 0;
  list-style: none;
  cursor: pointer;
  /* Same typeface, weight and colour as the bold phrases in the bio above. */
  font-family: var(--ui);
  font-weight: 600;
  font-size: clamp(13.5px, 1.02vw, 15.5px);
  line-height: 1.8;
  color: var(--black);
}
.fact__q::-webkit-details-marker { display: none; }

/* A shut eye that opens with the row. */
.fact__mark {
  position: relative;
  width: 22px; height: 22px; flex: none;
  color: var(--red);
}
.fact__eye {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  transition: opacity .3s var(--swift);
}
.fact__eye--shut { opacity: 1; }
.fact[open] .fact__eye--shut { opacity: 0; }
.fact[open] .fact__eye--open { opacity: 1; }

.fact__a {
  padding-bottom: 1.3em;
  max-width: 62ch;
  /* Matches the bio's body copy exactly. */
  font-family: var(--ui);
  font-size: clamp(13.5px, 1.02vw, 15.5px);
  line-height: 1.8;
  color: #4A4A52;
}
.fact__a p { margin: 0; }

@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  .fact::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size .42s var(--ease), content-visibility .42s allow-discrete;
  }
  .fact[open]::details-content { block-size: auto; }
}

.no-motion .fact::details-content { transition: none; }

/* ─── The turntable ────────────────────────────────────────────────────
   Sits beside the bio. Picking an artist drops the needle, spins the
   record with that song's sleeve at its centre, and starts the track. */

.intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: clamp(28px, 4vw, 72px);
  align-items: start;
}

.deck { position: sticky; top: 40px; }

/* Quiet caption under the faces — present, not shouting. */
.deck__sub {
  margin: clamp(14px, 1.8vw, 20px) auto 0;
  max-width: 270px;
  font-family: var(--ui);
  font-size: 12.5px;
  line-height: 1.6;
  color: rgba(126, 126, 150, .82);
  text-align: center;
}

/* Proportions come straight from the Framer component: a 119x104 frame
   with the record at right:25 and the arm at right:6. */
.deck__player {
  position: relative;
  width: 100%; max-width: 250px;
  aspect-ratio: 119 / 104;
  margin-inline: auto;
}

.deck__disc {
  position: absolute;
  width: 68.9%;                      /* 82 / 119 */
  right: 21%; top: 50%;
  translate: 0 -50%;
  animation: deck-spin 4s linear infinite;
  animation-play-state: paused;
}
.deck__disc svg { width: 100%; height: auto; display: block; }
.deck.is-playing .deck__disc { animation-play-state: running; }
@keyframes deck-spin { to { rotate: 360deg; } }

.deck__arm {
  position: absolute;
  width: 45.4%;                      /* 54 / 119 */
  right: 5%; top: 48%;
  translate: 0 -50%;
  /* The pivot is where the arm's stroke starts, near its top right. */
  transform-origin: 92% 5%;
  rotate: -13deg;                    /* parked clear of the record */
  transition: rotate .8s var(--ease);
  filter: drop-shadow(0 3px 5px rgba(40, 40, 85, .28));
}
.deck__arm svg { width: 100%; height: auto; display: block; }
.deck.is-playing .deck__arm { rotate: 8deg; }

/* ── The four artists ──────────────────────────────────────────────── */

.deck__picks {
  display: flex; justify-content: center;
  gap: clamp(8px, 1.4vw, 16px);
  margin-top: clamp(18px, 2.5vw, 28px);
}

.deck__pick {
  position: relative;
  width: clamp(42px, 4.2vw, 54px); aspect-ratio: 1;
  padding: 0;
  border: 0; border-radius: 10px;
  background: none;
  cursor: pointer;
  transition: translate .35s var(--ease), scale .35s var(--ease);
}
.deck__pick img {
  width: 100%; height: 100%;
  border-radius: 10px;
  object-fit: cover; display: block;
  box-shadow: 0 8px 18px -10px rgba(40, 40, 85, .55);
  transition: box-shadow .35s var(--ease);
}
.deck__pick:hover { translate: 0 -4px; scale: 1.05; }
.deck__pick:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }

/* Play on hover, pause once it is the one on the turntable. */
.deck__state {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  border-radius: 10px;
  background: rgba(16, 16, 26, .46);
  opacity: 0;
  transition: opacity .25s var(--swift);
}
.deck__pick:hover .deck__state,
.deck__pick:focus-visible .deck__state,
.deck__pick.is-on .deck__state { opacity: 1; }

.deck__ico { width: 42%; height: 42%; fill: #F7F7FD; display: block; }
.deck__ico--pause { display: none; }
.deck__pick.is-on .deck__ico--play { display: none; }
.deck__pick.is-on .deck__ico--pause { display: block; }

/* The one currently on the turntable. */
.deck__pick.is-on img {
  box-shadow: 0 0 0 2.5px var(--red), 0 10px 22px -10px rgba(40, 40, 85, .6);
}

/* Name, on hover or focus. */
.deck__name {
  position: absolute; bottom: calc(100% + 9px); left: 50%;
  translate: -50% 0;
  width: max-content; max-width: 160px;
  padding: .32em .7em;
  border-radius: 999px;
  background: var(--black);
  color: #F7F7FD;
  font-family: var(--ui); font-size: 11.5px; line-height: 1.3;
  pointer-events: none;
  opacity: 0; scale: .84;
  transition: opacity .22s var(--swift), scale .3s var(--ease);
}
.deck__pick:hover .deck__name,
.deck__pick:focus-visible .deck__name { opacity: 1; scale: 1; }

/* Spotify's player is the audio source but is not part of the design.
   It has to stay rendered AND on-screen — display:none stops playback,
   and a frame parked off-screen gets its autoplay blocked. So: invisible,
   behind the card, and untouchable. */
.deck__spotify {
  position: absolute; inset: auto 0 -6px 0;
  height: 80px;
  opacity: 0;
  pointer-events: none;
  z-index: -1;
}

@media (max-width: 900px) {
  .intro { grid-template-columns: 1fr; }
  .deck { position: static; max-width: 380px; margin-top: 8px; }
}

/* ─── Footer ───────────────────────────────────────────────────────────  */

.footer {
  position: relative; z-index: 1;
  display: grid; place-items: center;
  /* The still asks the question, the clip answers it — hence the gap. */
  gap: clamp(46px, 5vw, 74px);
  padding: clamp(40px, 6vw, 90px) clamp(20px, 8.6vw, 130px) clamp(50px, 7vw, 110px);
}

/* ── Contact ─────────────────────────────────────────────────────────
   A centred column: the invitation, then the email and the links under it. */

.contact {
  display: grid; justify-items: center;
  gap: clamp(26px, 3.2vw, 44px);
  text-align: center;
}
.contact__mid { max-width: none; }
.contact__title {
  margin: 0;
  font-family: var(--display); font-weight: 400;
  font-size: clamp(30px, 4.6vw, 68px); line-height: 1.05;
  color: var(--red);
  white-space: nowrap;               /* one line */
}
.contact__title em { font-style: italic; }
.contact__note {
  margin: .6em 0 0;
  font-family: var(--ui);
  font-size: clamp(13.5px, 1.02vw, 15.5px);
  line-height: 1.75;
  color: var(--muted);
  max-width: 46ch;
  margin-inline: auto;
}

.contact__row {
  display: flex; flex-wrap: wrap;
  align-items: center; justify-content: center;
  gap: clamp(14px, 1.8vw, 26px);
}

/* Email, with a copy button that confirms itself. */
.contact__mail { position: relative; display: flex; align-items: center; }
.mail {
  display: inline-flex; align-items: center; gap: .6em;
  height: 40px;                      /* matches .social__link exactly */
  padding: 0 1.05em;
  border: 1px solid rgba(61, 62, 171, .22);
  border-radius: 999px;
  background: rgba(61, 62, 171, .04);
  color: var(--black);
  font-family: var(--ui); font-size: 14px;
  cursor: pointer;
  transition: background .3s var(--swift), border-color .3s var(--swift);
}
.mail:hover { background: rgba(61, 62, 171, .09); border-color: rgba(61, 62, 171, .4); }
.mail:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }
.mail__ico { display: grid; width: 15px; height: 15px; color: var(--red); }
.mail__ico svg { width: 100%; height: 100%; grid-area: 1 / 1; }
.mail__done { display: none; }
.mail.is-copied .mail__copy { display: none; }
.mail.is-copied .mail__done { display: block; }
/* Out of flow, so it cannot shift the pill against the icons. */
.mail__said {
  position: absolute; top: calc(100% + 5px); left: 50%;
  translate: -50% 0;
  width: max-content;
  font-family: var(--ui); font-size: 11.5px;
  color: var(--muted);
  pointer-events: none;
}

/* Links. */
.social { display: flex; align-items: center; gap: 10px; }
.social__link {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  border: 1px solid var(--red);
  border-radius: 50%;
  background: var(--red);
  color: #F7F7FD;
  transition: background .3s var(--swift), scale .3s var(--ease),
              border-color .3s var(--swift);
}
.social__link svg { width: 17px; height: 17px; }
.social__link:hover {
  background: var(--red-deep); border-color: var(--red-deep);
  scale: 1.08;
}
.social__link:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }

/* Half the width of the card above it. The footer shares the section's
   gutters, so 50% here is 50% of that card. */
.reply {
  position: relative;
  width: max(240px, 50%);
}

.reply__play {
  display: block;
  width: 100%;
  padding: 0; border: 0;
  border-radius: 12px;
  background: none;
  cursor: pointer;
  box-shadow: 0 12px 26px -18px rgba(40, 40, 85, .6);
  transition: rotate .45s var(--ease), scale .45s var(--ease);
}
.reply:hover .reply__play { rotate: 1deg; scale: 1.02; }
.reply__play:focus-visible { outline: 2px solid var(--navy); outline-offset: 4px; }

/* The clip is a screen recording, so the menu bar, title bar and the
   letterbox are cropped away here rather than by re-encoding — the source
   file plays as-is, which a re-encode did not. Source is 2940x1912 and the
   wanted rectangle is 2472x1710 at (234,132); the numbers below are that
   rectangle expressed against the container. */
.reply__crop {
  display: block;
  position: relative;
  aspect-ratio: 2472 / 1710;
  overflow: hidden;
  border-radius: 12px;
}
.reply__vid {
  position: absolute;
  width: 118.932%;
  height: auto;
  left: -9.466%;
  top: -7.719%;
  display: block;
}

/* A play mark, shown only while it is paused. */
.reply__state {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  border-radius: 12px;
  background: rgba(16, 16, 26, .34);
  opacity: 0;
  transition: opacity .25s var(--swift);
  pointer-events: none;
}
.reply__state svg { width: 46px; height: 46px; fill: #F7F7FD; }
.reply.is-paused .reply__state { opacity: 1; }

/* Sound is its own button, so it never triggers play/pause. */
.reply__sound {
  position: absolute; right: 10px; bottom: 10px;
  width: 32px; height: 32px;
  display: grid; place-items: center;
  padding: 0; border: 0;
  border-radius: 50%;
  background: rgba(16, 16, 26, .6);
  color: #F7F7FD;
  cursor: pointer;
  backdrop-filter: blur(4px);
  transition: scale .3s var(--ease), background .3s var(--swift);
}
.reply__sound:hover { scale: 1.1; background: rgba(16, 16, 26, .78); }
.reply__sound:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }
.reply__ico { width: 17px; height: 17px; grid-area: 1 / 1; }
.reply__ico--on { display: none; }
.reply.is-loud .reply__ico--off { display: none; }
.reply.is-loud .reply__ico--on { display: block; }

/* The line, on hover. */
.reply__cap {
  position: absolute; top: calc(100% + 14px); left: 50%;
  width: max-content; max-width: 300px;
  translate: -50% 0;
  padding: .42em .95em;
  border-radius: 999px;
  background: var(--black);
  color: #F7F7FD;
  font-family: var(--ui); font-size: 12.5px; line-height: 1.45;
  text-align: center;
  pointer-events: none;
  opacity: 0; scale: .85;
  transition: opacity .25s var(--swift), scale .32s var(--ease);
}
.reply:hover .reply__cap { opacity: 1; scale: 1; }

/* ─── Reveal on scroll ─────────────────────────────────────────────────── */

[data-reveal] {
  opacity: 0; transform: translateY(22px);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}
[data-reveal].is-in { opacity: 1; transform: none; }
.no-motion [data-reveal] { opacity: 1; transform: none; transition: none; }

/* ─── Responsive ───────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  /* Mockup on top, words underneath. */
  .project { grid-template-columns: 1fr; }
  .project__stage { aspect-ratio: 16 / 10; }
}

@media (max-width: 820px) {
  .nav__links, .nav__cta { display: none; }
  /* No room to scatter without landing on the words. */
  .doodles { display: none; }
  .nav__toggle { display: block; }
  .headline { max-width: 14ch; }
}

@media (max-width: 560px) {
  /* A 19px grid reads coarse on a phone; tighten the sheet. */
  :root { --grid-step: 14px; }
  /* The trailing chip lands on a line of its own down here — drop it. */
  .chip--2 { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}


/* Headline entrance. JS arms .headline with .is-armed before first paint,
   then flips to .is-lit on load; each word carries its own --d delay. */
.headline.is-armed .rise,
.headline.is-armed .chip {
  opacity: 0;
  translate: 0 .55em;
}
.headline.is-lit .rise,
.headline.is-lit .chip {
  opacity: 1;
  translate: 0 0;
  transition: opacity .7s var(--ease) var(--d, 0s),
              translate .95s var(--ease) var(--d, 0s),
              rotate .5s var(--ease),
              scale .5s var(--ease),
              box-shadow .5s var(--ease);
}


/* ─── The field ────────────────────────────────────────────────────────
   A full-bleed band of sunflowers at the foot of the home page, drawn
   from one illustration. --g (0…1) is the growth: it lets more of the
   art show and scales it up a little, so the blooms climb. The band is
   capped short of the top so the hint in the corner is never covered. */

.field {
  --g: 0;                                   /* growth, 0 → 1 */
  --tallest: clamp(84px, 10.6vw, 149px);    /* height of a fully grown plant */
  position: relative;
  z-index: 1;
  width: 100%;
  height: clamp(186px, 20.5vw, 300px);
  margin-top: clamp(30px, 5vw, 70px);
  overflow: hidden;
  isolation: isolate;
  cursor: none;
}

/* Bottom-anchored and always full width. Growing raises the crop line,
   which reveals more stem and lifts the heads: no squashing anywhere. */
/* Each sunflower is a real plant: a stem that lengthens, leaves that ride
   up it, and a head that opens on top. Watering raises --g, which grows
   the stem and blooms the head. Nothing is ever stretched: the head only
   scales uniformly, in place, about the point where it meets the stem. */
.field__plants {
  position: absolute;
  inset: auto 0 0 0;
  height: 100%;
}

.plant {
  position: absolute;
  left: var(--x);
  bottom: -2px;
  width: 0;
  height: calc(var(--tall) * var(--k) * (.40 + .60 * var(--g)));
  rotate: var(--lean);
  transform-origin: 50% 100%;
  transition: height 1.5s var(--ease) var(--d);
  will-change: height;
}
.plant--back  { --tall: calc(var(--tallest) * .74); z-index: 1; }
.plant--front { --tall: var(--tallest);             z-index: 3; }

/* The stem itself: a stroke, so a longer one is genuinely longer. */
.plant__stem {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: calc(var(--tallest) * var(--sw));
  height: 100%;
  translate: -50% 0;
  border-radius: 999px 999px 0 0;
  background: #486439;
}

/* The head rides the top of the stem and opens as it grows. */
.plant__head {
  position: absolute;
  left: 50%;
  bottom: 100%;
  width: calc(var(--tall) * var(--wm));
  height: auto;
  translate: -50% 22%;
  scale: calc(.44 + .56 * var(--g));
  transform-origin: 50% 78%;
  transition: scale 1.5s var(--ease) var(--d);
  will-change: scale;
}

.plant__leaf {
  position: absolute;
  left: 50%;
  width: calc(var(--tall) * var(--wm) * .46);
  height: auto;
  transform-origin: 0 100%;
  scale: calc(.34 + .66 * var(--g));
  transition: scale 1.5s var(--ease) var(--d);
}
/* One leaf each side. Both are pinned at their stalk end, which sits at
   the stem, so scaling can never drag them off it; the left one is simply
   the same leaf mirrored. */
.plant__leaf--l {
  bottom: 40%;
  rotate: -14deg;
  scale: calc(-.34 - .66 * var(--g)) calc(.34 + .66 * var(--g));
}
.plant__leaf--r { bottom: 62%; rotate: 14deg; }

/* A tuft at the foot of each stem, so the plant is rooted in something
   rather than a bare line stopping at the edge of the band. */
.plant__leaf--base-l,
.plant__leaf--base-r {
  width: calc(var(--tall) * var(--wm) * .34);
  /* Lifted by a slice of their own size, so swinging them out never
     drops a corner past the foot of the band and gets it clipped. */
  bottom: calc(var(--tall) * var(--wm) * .18);
}
.plant__leaf--base-l {
  rotate: -28deg;
  scale: calc(-.40 - .60 * var(--g)) calc(.40 + .60 * var(--g));
}
.plant__leaf--base-r {
  rotate: 28deg;
  scale: calc(.40 + .60 * var(--g));
}

/* Some plants start as a closed bud and open into a flower: the two swap
   over the middle of the watering, so you watch them bloom. */
.plant__bud {
  position: absolute;
  left: 50%;
  bottom: 100%;
  width: calc(var(--tall) * var(--wm) * .46);
  height: auto;
  translate: -50% 10%;
  scale: calc(.44 + .56 * var(--g));
  transform-origin: 50% 90%;
  opacity: clamp(0, calc((.50 - var(--g)) / .08), 1);
  transition: scale 1.5s var(--ease) var(--d), opacity 1.5s var(--ease) var(--d);
}
.plant--bud .plant__head {
  opacity: clamp(0, calc((var(--g) - .48) / .10), 1);
  transition: scale 1.5s var(--ease) var(--d), opacity 1.5s var(--ease) var(--d);
}

/* A gentle sway, so the field is alive before anyone waters it. */
@keyframes plant-sway {
  0%, 100% { rotate: var(--lean); }
  50%      { rotate: calc(var(--lean) + 1.8deg); }
}
.plant { animation: plant-sway 7s ease-in-out infinite alternate;
         animation-delay: calc(var(--d) * -4); }
.no-motion .plant { animation: none; transition: none; }
.no-motion .plant__head, .no-motion .plant__leaf { transition: none; }

/* ── The nudge ───────────────────────────────────────────────────────
   Top-left, above the tallest the field can ever reach. Just a line of
   text: no pill, no border, no icon. */
.field__hint {
  position: absolute;
  top: clamp(14px, 2.4vw, 26px);
  left: clamp(16px, 2.6vw, 38px);
  z-index: 6;
  margin: 0;
  color: rgba(78, 78, 102, .34);
  font-family: var(--ui);
  font-size: clamp(11px, 1.05vw, 13px);
  letter-spacing: .01em;
  pointer-events: none;
  transition: color .4s var(--swift);
}
.field.is-done .field__hint { color: rgba(78, 78, 102, .48); }

/* ── The can ─────────────────────────────────────────────────────────
   Replaces the pointer over the band. It sits straight at rest and only
   tilts while a pour is in flight. */
.field__can {
  --canw: clamp(56px, 5.2vw, 80px);
  position: absolute;
  top: 0;
  left: 0;
  width: var(--canw);
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  translate: calc(var(--cx, 0px) - .30 * var(--canw))
             calc(var(--cy, 0px) - .44 * var(--canw));
  transition: opacity .18s var(--swift);
  will-change: translate;
}
.field:hover .field__can,
.field__can.is-visible { opacity: 1; }

.field__can-img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: auto;
  display: block;
  transition: opacity .16s var(--swift);
  user-select: none;
  -webkit-user-drag: none;
}
.field__can-img--tilt { opacity: 0; }
.field__can.is-pouring .field__can-img--straight { opacity: 0; }
.field__can.is-pouring .field__can-img--tilt     { opacity: 1; }

/* ── The water ───────────────────────────────────────────────────────
   The spray illustration, mirrored so it fans down and to the right, and
   pinned by its nozzle end to the tilted can's spout tip. It is revealed
   top-down, so the stream starts thin at the spout and only spreads out
   once it is near the ground. */
.field__water {
  position: absolute;
  width: calc(2.9 * var(--canw));
  height: auto;
  left: calc(.735 * var(--canw));           /* spout tip, minus the apex inset */
  top: calc(.772 * var(--canw));
  opacity: 0;
  clip-path: inset(0 0 100% 0);
  user-select: none;
  -webkit-user-drag: none;
}
.field__can.is-pouring .field__water {
  animation: field-pour 1s var(--ease) forwards;
}
@keyframes field-pour {
  0%   { opacity: 0; clip-path: inset(0 0 100% 0); }
  14%  { opacity: 1; }
  50%  { opacity: 1; clip-path: inset(0 0 0 0); }
  78%  { opacity: 1; clip-path: inset(0 0 0 0); }
  100% { opacity: 0; clip-path: inset(0 0 0 0); }
}

.no-motion .field__art { transition: none; }
.no-motion .field__can { display: none; }
.no-motion .field { cursor: auto; }

@media (max-width: 700px) {
  .field { height: clamp(190px, 40vw, 260px); }
  .field__hint { left: 20px; top: 12px; }
}
