/* ==========================================================================
   Kritika Jain — Portfolio
   Bootstrap 5 is loaded for its grid only; everything below is bespoke.

   Contents
   01. Tokens
   02. Base & typography
   03. Layout shell
   04. Reveal / motion utilities
   05. Header & navigation
   06. Hero
   07. Section headings
   08. Work / projects
   09. Currently exploring (playlist)
   10. About page
   11. Footer
   12. Custom cursor
   13. Reduced motion & print
   ========================================================================== */

/* 01. TOKENS ============================================================== */

:root {
  /* Palette */
  --olive: #CBC057;
  --brown: #000000;
  --cream: #FCFBF7;
  --blue:  #D7EFFF;

  /* Derived tints — rgba so rules and washes layer predictably */
  --brown-04: rgba(0, 0, 0, 0.04);
  --brown-08: rgba(0, 0, 0, 0.08);
  --brown-14: rgba(0, 0, 0, 0.14);
  --cream-60: rgba(252, 251, 247, 0.60);

  /* Muted text — neutral grays, held above 4.5:1 on cream so small labels
     and secondary copy still pass WCAG AA. */
  --ink-soft: #626262;   /* secondary copy   — 5.9:1 on --cream */
  --ink-mute: #737373;   /* small caps meta  — 4.6:1 on --cream */

  /* Muted text on the olive hero — 6.2:1 on --olive */
  --ink-on-olive: rgba(0, 0, 0, 0.7);

  /* Muted text on the light-blue exploration section */
  --ink-soft-blue: rgba(0, 0, 0, 0.80);
  --ink-mute-blue: rgba(0, 0, 0, 0.68);

  /* Type — system faces first, web fonts as the fallback */
  --font-display: "Bodoni 72", "Bodoni 72 Oldstyle", "Bodoni Moda", "Didot",
                  "Bodoni MT", "Playfair Display", Georgia, "Times New Roman", serif;
  --font-body: "Graphik", "Graphik Web", "Inter", -apple-system, BlinkMacSystemFont,
               "Helvetica Neue", Arial, sans-serif;

  /* Rhythm */
  --header-h: 5.75rem;   /* overlay header — first sections clear it themselves */
  --shell-pad: clamp(1.25rem, 5vw, 5rem);
  --section-gap: clamp(4.5rem, 9vw, 8.5rem);
  --rule: 1px solid var(--brown-14);

  /* Motion */
  --ease: cubic-bezier(0.22, 0.72, 0.2, 1);
  --dur: 420ms;
}

/* 02. BASE & TYPOGRAPHY =================================================== */

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

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

body {
  margin: 0;
  background: var(--cream);
  color: var(--brown);
  font-family: var(--font-body);
  font-weight: 500;                 /* Graphik Medium is the body default */
  font-size: clamp(0.95rem, 0.9rem + 0.2vw, 1.0625rem);
  line-height: 1.65;
  letter-spacing: 0.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}


h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.015em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

em { font-style: italic; }
strong { font-weight: 600; }

img,
svg,
video { max-width: 100%; height: auto; display: block; }

ul, ol { list-style: none; margin: 0; padding: 0; }

a {
  color: inherit;
  text-decoration: none;
  transition: color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

/* Small caps label used across the site */
.eyebrow,
.section-note,
.project-meta,
.project-index,
.playlist-cat,
.playlist-no,
.footer-label,
.timeline-year {
  font-family: var(--font-body);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.5;
}

/* Focus — always visible, never removed */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--brown);
  outline-offset: 4px;
  border-radius: 1px;
}
.site-footer :focus-visible { outline-color: var(--olive); }

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--shell-pad);
  z-index: 999;
  background: var(--brown);
  color: var(--cream);
  padding: 0.75rem 1.25rem;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  transition: top 200ms var(--ease);
}
.skip-link:focus-visible { top: 1rem; outline-color: var(--olive); }

::selection { background: var(--olive); color: var(--brown); }

/* 03. LAYOUT SHELL ======================================================== */

.shell {
  width: 100%;
  max-width: 1480px;
  margin-inline: auto;
  padding-inline: var(--shell-pad);
}

/* Bootstrap rows are used gutterless (gx-0); spacing is handled here. */
.row { --bs-gutter-x: 0; }

/* 04. REVEAL / MOTION UTILITIES =========================================== */

.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 900ms var(--ease), transform 900ms var(--ease);
  will-change: opacity, transform;
}
.reveal.is-in {
  opacity: 1;
  transform: none;
}

/* Page-load stagger: navigation → statement → supporting text → content */
[data-delay="1"] { transition-delay: 60ms; }
[data-delay="2"] { transition-delay: 140ms; }
[data-delay="3"] { transition-delay: 220ms; }
[data-delay="4"] { transition-delay: 300ms; }
[data-delay="5"] { transition-delay: 380ms; }
[data-delay="6"] { transition-delay: 500ms; }
[data-delay="7"] { transition-delay: 620ms; }
[data-delay="8"] { transition-delay: 740ms; }

.arrow {
  display: inline-block;
  transition: transform var(--dur) var(--ease);
}

/* 05. HEADER & NAVIGATION ================================================= */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 120;
  /* Transparent at rest so the olive hero runs to the top of the page;
     the cream ground fades in once the page has moved. */
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              padding var(--dur) var(--ease);
  padding-block: clamp(1.1rem, 2vw, 1.6rem);
  opacity: 0;
  animation: header-in 700ms var(--ease) 80ms forwards;
}

/* Opacity only — a transform here would become the containing block for any
   fixed descendant and trap it inside the header. */
@keyframes header-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.site-header.is-scrolled {
  background: var(--cream);
  border-bottom-color: var(--brown-14);
  padding-block: 0.85rem;
}

.site-nav {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 2.75rem;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  color: var(--brown);
  position: relative;
  z-index: 2;
  transition: opacity var(--dur) var(--ease);
}
.wordmark-logo {
  height: clamp(2.15rem, 4vw, 2.9rem);
  width: auto;
  display: block;
}
.wordmark:hover { opacity: 0.72; }

/* --- Social icons, right-hand side ---------------------------------------
   The capsule is absolutely positioned (see below), so in normal flow the
   wordmark is site-nav's only child — justify-content: space-between pushes
   this list to the opposite end for free. */
.nav-socials {
  display: flex;
  align-items: center;
  gap: clamp(0.85rem, 2vw, 1.35rem);
  position: relative;
  z-index: 2;
}
.nav-social {
  display: grid;
  place-items: center;
  width: 1.45rem;
  height: 1.45rem;
  color: var(--brown);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.nav-social svg { width: 100%; height: 100%; }
.nav-social:hover,
.nav-social:focus-visible { opacity: 0.6; transform: translateY(-2px); }

/* --- Centred collapsible capsule ---------------------------------------- */

.nav-capsule {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, var(--anchor, -50%));
  border-radius: 999px;
  padding: 0.4rem;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              padding var(--dur) var(--ease), box-shadow var(--dur) var(--ease);

  border: 1px solid rgba(255, 255, 255, 0.14);
  background: var(--brown);
}
.nav-capsule:hover,
.nav-capsule:focus-within {
  border-color: rgba(255, 255, 255, 0.32);
  padding: 0.4rem 0.85rem; /* only the width grows on expand — height stays put */
}

.nav-list {
  display: flex;
  align-items: center;
  gap: 0.5rem; /* fixed breathing room between the two tabs, collapsed or not */
}

.nav-anchor {
  display: flex;
  align-items: center;
  gap: 0;
  color: var(--cream);
  padding: 0.55rem 0.75rem; /* stays put in both states — each tab keeps its own size */
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease),
              gap var(--dur) var(--ease);
}
.nav-anchor:hover { background: rgba(255, 255, 255, 0.14); }

/* The active page keeps a permanent olive mark, so the capsule still says
   where you are while it is collapsed. Text flips to brown for contrast
   against the light fill. */
.nav-anchor.is-active {
  background: var(--olive);
  color: var(--brown);
}

.nav-icon {
  display: grid;
  place-items: center;
  width: 1rem;
  height: 1rem;
  flex: none;
}
.nav-icon svg { width: 100%; height: 100%; }

/* Collapsed: the label is clipped to zero width but stays in the accessibility
   tree, so each link is still announced as "Work" / "About". */
.nav-text {
  display: block;
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-width 450ms var(--ease), opacity 300ms var(--ease);
}

.nav-capsule:hover .nav-anchor,
.nav-capsule:focus-within .nav-anchor {
  gap: 0.5rem; /* room for the label next to the icon — the tab's own padding doesn't move */
}

.nav-capsule:hover .nav-text,
.nav-capsule:focus-within .nav-text {
  max-width: 9ch;
  opacity: 1;
}

/* No hover to rely on: keep the labels open permanently on touch devices. */
@media (hover: none) {
  .nav-anchor { gap: 0.5rem; }
  .nav-text { max-width: 9ch; opacity: 1; }
}

/* Below ~560px, wordmark + capsule + three social icons no longer fit on one
   line. The row becomes a two-row grid: wordmark and socials share the top
   line (space-between, for free), the capsule drops to its own centred row
   below — spanning the full width but sized to its own content, so the pill
   itself never stretches. */
@media (max-width: 560px) {
  /* The header is now two rows tall here — the hero/about top offset and
     the #work scroll-margin both read this, so bump it to match. */
  :root { --header-h: 9rem; }

  .site-nav {
    display: grid;
    grid-template-columns: auto auto;
    align-items: center;
    row-gap: 0.9rem;
  }
  .wordmark { grid-column: 1; grid-row: 1; }
  .nav-socials { grid-column: 2; grid-row: 1; justify-self: end; }
  .nav-capsule {
    grid-column: 1 / -1;
    grid-row: 2;
    justify-self: center;
    position: static;
    transform: none;
  }
  .nav-anchor { padding-inline: 0.8rem; letter-spacing: 0.06em; }
}


/* 06. HERO ================================================================ */

.hero {
  background: var(--olive);
  /* Fills the visible screen exactly — svh tracks the browser chrome on
     mobile (address bar showing/hiding) where a plain vh unit overshoots. */
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-block: calc(var(--header-h) + clamp(0.5rem, 2vw, 1.5rem)) clamp(2rem, 4vw, 3rem);
  position: relative;
}

.hero .eyebrow {
  color: var(--ink-on-olive);
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
.hero .eyebrow::before {
  content: "";
  width: clamp(24px, 5vw, 64px);
  height: 1px;
  background: var(--brown);
  display: inline-block;
}

.hero-statement {
  font-size: clamp(2rem, 5.6vw, 4.6rem);
  line-height: 1.1;
  letter-spacing: -0.025em;
  margin: 0;
  /* Nudges the statement up without touching the document flow, so nothing
     below it (hero-meta, the scroll cue) moves. */
  transform: translateY(-0.7rem);
}
.hero-statement .line { display: block; min-height: 1.1em; }
.hero-statement em { font-style: italic; }

/* --- Typewriter -----------------------------------------------------------
   Each .type-seg starts empty; script.js fills its textContent one
   character at a time. Under prefers-reduced-motion the JS skips straight
   to the full text with no cursor, so nothing here depends on animation. */
.type-seg { white-space: pre-wrap; }

/* Small circular photo that pops in right after "I'm" once that word has
   finished typing — see the avatar handling in initHeroType(). Sized in em
   so it scales with the hero statement at every breakpoint. vertical-align:
   middle centres it on the line rather than sitting it on the baseline —
   transform-origin follows so the pop-in grows from that same centre. */
.hero-avatar {
  display: inline-block;
  position: relative;
  top: -0.18em;
  width: 2.1em;
  height: 2.1em;
  margin: 0 0.2em;
  border-radius: 50%;
  overflow: hidden;
  background: var(--cream);
  border: 0.018em solid var(--brown);
  vertical-align: middle;
  opacity: 0;
  transform: scale(0.35);
  transform-origin: center;
  transition: opacity 260ms var(--ease), transform 460ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.hero-avatar.is-shown { opacity: 1; transform: scale(1); }
.hero-avatar-img { width: 100%; height: 100%; object-fit: cover; display: block; }

.hero-stop {
  display: inline-block;
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 200ms var(--ease), transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.hero-stop.is-typed { opacity: 1; transform: scale(1); }

.type-cursor {
  display: inline-block;
  width: 0.06em;
  min-width: 3px;
  height: 0.82em;
  margin-left: 0.05em;
  background: var(--brown);
  vertical-align: -0.1em;
  animation: type-blink 900ms step-end infinite;
}
.type-cursor.is-fading {
  animation: none;
  opacity: 0;
  transition: opacity 500ms var(--ease);
}
@keyframes type-blink {
  0%, 45% { opacity: 1; }
  46%, 100% { opacity: 0; }
}

.hero-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  margin-top: clamp(2rem, 4vw, 3rem);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-on-olive);
}
.hero-meta span { position: relative; }
.hero-meta span + span::before {
  content: "·";
  position: absolute;
  left: -0.85rem;
  color: var(--brown);
}

/* --- Right column: design words thrown into a heap ------------------------
   A dense, flat, poster-like pile. There are no drop shadows: the rule at
   the bottom states the ground outright, so depth comes purely from how
   much the chips overlap and from the order they are painted in. What each
   chip needs instead is separation — see the ring on .toss-face. */

.toss {
  position: relative;
  /* The floor matters more than the ceiling here: narrow viewports would
     otherwise collapse the heap until the labels cover each other. */
  height: clamp(18rem, 30vw, 23rem);
  margin-top: 3rem;
}
@media (min-width: 992px) {
  .toss { margin-top: 0; }
}

/* The heap has no entrance of its own — it's simply there — so the shared
   .reveal fade is neutralised here rather than removing the class outright. */
.toss.reveal {
  opacity: 1;
  transform: none;
  transition: none;
}

.toss-pile {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The heap sits in its resting position from the first frame — no throw,
   no bounce. --r and --s (the resting angle and depth scale each chip
   carries inline) are applied directly instead of being the end point of a
   keyframe. */
.toss-chip {
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: translate(-50%, var(--anchor, -50%));
}

/* The bottom row is anchored by its base rather than its centre, so however
   much a chip is scaled up or down its underside still meets the rule at
   exactly the same height. That shared edge is what makes the last row read
   as a straight line instead of a row of loosely aligned pills. */
.toss-chip--floor {
  top: auto;
  bottom: 0;
  --anchor: 0;
}
.toss-chip--floor .toss-face { transform-origin: bottom center; }

/* A layer of its own, sitting between the fall and the spin, and touched by
   nothing else — the keyframes on either side hold their transforms right
   through to the last frame, so script.js needs somewhere it can push a
   chip around without fighting them. Snappy on the way out, springy on the
   way back: the overshoot in that second curve is the bounce. */
.toss-nudge {
  display: block;
  transition: transform 720ms cubic-bezier(0.34, 1.46, 0.64, 1);
}
.toss.is-repelling .toss-nudge {
  transition: transform 200ms cubic-bezier(0.2, 0.8, 0.3, 1);
}

.toss-face {
  display: block;
  padding: 0.55rem 1.1rem;
  border-radius: 999px;
  border: 1px solid var(--brown);
  background: var(--cream);
  color: var(--brown);
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  white-space: nowrap;
  transform: rotate(var(--r)) scale(var(--s));
  /* With the shadows gone this ring is what keeps the pile legible: it is
     the hero's own olive, so it vanishes against the background and only
     shows up as a cut line where one chip laps over another. */
  outline: 2px solid var(--olive);
  transition: box-shadow var(--dur) var(--ease);
}
.toss-chip--solid .toss-face {
  background: var(--brown);
  color: var(--cream);
}

/* Plain circles dropped in among the words to break up the run of pills.
   Doubled up on purpose: the narrow-viewport block below re-sets .toss-face's
   padding, and without the extra specificity here that padding would come
   back and stretch these into ellipses. */
.toss-face.toss-face--dot {
  width: var(--size);
  height: var(--size);
  padding: 0;
  border-radius: 50%;
}
.toss-face--ring { background: transparent; }

/* The ground itself. Everything above simply rests on it. */
.toss-line {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--brown);
}

/* Below the lg breakpoint the pile spans the full column, which is narrower
   than the desktop col-lg-4 it was tuned against. The chips come down with
   it so the heap keeps the same density and the labels stay readable where
   they overlap. */
@media (max-width: 991.98px) {
  .toss-face {
    padding: 0.45rem 0.9rem;
    font-size: 0.625rem;
    letter-spacing: 0.13em;
  }
}

/* They read as buttons, so they answer to a pointer. A halo rather than a
   lift: the keyframes own transform right through to the final frame. */
.toss-chip:hover .toss-face { box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.14); }

.scroll-cue {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: clamp(3rem, 7vw, 5rem);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-on-olive);
}
.scroll-cue:hover { color: var(--brown); }
.scroll-cue-arrow { transition: transform var(--dur) var(--ease); }
.scroll-cue:hover .scroll-cue-arrow { transform: translateY(4px); }

/* 07. SECTION HEADINGS ==================================================== */

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 3rem;
  padding-bottom: clamp(2rem, 4vw, 3rem);
  border-bottom: var(--rule);
  margin-bottom: clamp(2.5rem, 6vw, 5rem);
}

.section-title {
  font-size: clamp(1.9rem, 4.6vw, 3.6rem);
  letter-spacing: -0.02em;
}

.section-note {
  color: var(--ink-soft);
  max-width: 30rem;
  text-transform: none;
  letter-spacing: 0.01em;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.6;
}

/* 08. WORK / PROJECTS ===================================================== */

.work {
  padding-block: clamp(3.5rem, 7vw, 6rem) var(--section-gap);
  scroll-margin-top: calc(var(--header-h) + 1rem);
}

.project {
  position: relative;
  padding-block: clamp(2.5rem, 6vw, 5rem);
  border-top: var(--rule);
}
.project:first-of-type { border-top: 0; padding-top: 0; }

.project-text { max-width: 30rem; }

/* The number stays readable ink; the olive lives in the rule beside it,
   because olive on cream is far too low-contrast for text. */
.project-index {
  display: block;
  color: var(--ink-mute);
  font-size: 0.75rem;
  margin-bottom: 1.1rem;
}
.project-index::after {
  content: "";
  display: inline-block;
  width: 1.75rem;
  height: 1px;
  background: var(--olive);
  margin-left: 0.6rem;
  vertical-align: middle;
}

.project-title {
  font-size: clamp(1.9rem, 3.6vw, 3.1rem);
  line-height: 1.02;
  margin-bottom: 0.9rem;
}
.project-link {
  position: relative;
  display: inline-block;
  transition: transform 500ms var(--ease);
}
/* Stretches the title link across the whole card so the image is clickable too.
   On project 03 the nearest positioned ancestor is the overlapping text block,
   so the hit area covers that block rather than the full-bleed visual. */
.project-link::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
}
.project-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -0.08em;
  width: 100%;
  height: 1px;
  background: var(--brown);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 500ms var(--ease);
}

.project-desc {
  color: var(--ink-soft);
  max-width: 34ch;
  margin-bottom: 1.4rem;
}

.project-meta {
  color: var(--ink-mute);
  margin-bottom: 1.6rem;
}

.project-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding-bottom: 0.35rem;
  border-bottom: 1px solid var(--brown-14);
  transition: border-color var(--dur) var(--ease);
}

/* --- Hover choreography: everything moves a little, nothing moves a lot --- */
.project:hover .project-link,
.project:focus-within .project-link { transform: translateX(6px); }

.project:hover .project-link::after,
.project:focus-within .project-link::after { transform: scaleX(1); transform-origin: left; }

.project:hover .project-cta,
.project:focus-within .project-cta { border-bottom-color: var(--olive); }

.project:hover .arrow,
.project:focus-within .arrow { transform: translateX(6px); }

/* --- Figures & placeholders --- */
.project-figure {
  margin: 0;
  overflow: hidden;
  background: var(--brown-04);
}

.project-img,
.project-placeholder {
  width: 100%;
  transition: transform 700ms var(--ease);
}
.project-img { object-fit: cover; height: 100%; }

.project:hover .project-img,
.project:hover .project-placeholder,
.project:focus-within .project-img,
.project:focus-within .project-placeholder { transform: scale(1.035); }

/* Neutral, labelled placeholder — swap the markup for an <img> when ready */
.project-placeholder {
  aspect-ratio: 4 / 3;
  display: grid;
  place-items: center;
  border: 1px solid var(--brown-14);
  background-color: #F6F4EF;
  background-color: color-mix(in srgb, var(--brown) 3%, var(--cream));
  background-image: repeating-linear-gradient(
    45deg,
    transparent 0 13px,
    var(--brown-04) 13px 14px
  );
}
.project-placeholder--tall { aspect-ratio: 4 / 5; }
.project-placeholder--wide { aspect-ratio: 16 / 8; }

.project-placeholder span {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* --- Project 03: full-bleed visual with the title sitting into it --- */
.project--full .project-figure--full { width: 100%; }

.project-overlap {
  position: relative;
  background: var(--cream);
  margin-top: clamp(-5rem, -5vw, -2rem);
  padding: clamp(1.75rem, 3vw, 2.75rem) clamp(1.75rem, 3vw, 3rem) 0 0;
  width: 100%;
}
.project--full .project-title { margin-bottom: 0; }
.project--full .project-desc { margin-top: 0.75rem; }

@media (max-width: 991.98px) {
  .project-overlap {
    margin-top: -2rem;
    padding-right: 1.25rem;
  }
  .project--full .project-desc { margin-top: 1.5rem; }
  /* Text always sits above the visual on small screens for project 02 */
  .project--right .project-text { margin-bottom: 2rem; }
  .project--left .project-text { margin-bottom: 2rem; }
}

/* 09. CURRENTLY EXPLORING (playlist) ====================================== */

.explore {
  background: var(--blue);
  padding-block: var(--section-gap);
  scroll-margin-top: calc(var(--header-h) + 1rem);
}
.explore .section-head { border-bottom-color: rgba(0, 0, 0, 0.18); }
.explore .section-note { color: var(--ink-soft-blue); }

/* No top rule here — the section heading's rule already closes the space above,
   and two lines with a gap between them read as an empty row. */
.section-head--explore { margin-bottom: clamp(1.75rem, 3.5vw, 3rem); }

.playlist-item {
  border-bottom: 1px solid rgba(0, 0, 0, 0.18);
  transition: background-color var(--dur) var(--ease);
}

.playlist-button {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: 0 clamp(1rem, 3vw, 3rem);
  width: 100%;
  text-align: left;
  padding: clamp(1.3rem, 2.4vw, 2rem) 0;
  transition: padding var(--dur) var(--ease);
}

.playlist-no { color: var(--ink-mute-blue); padding-top: 0.5rem; }

.playlist-cat {
  display: block;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-mute-blue);
  margin-bottom: 0.5rem;
}

.playlist-title {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.6vw, 2.2rem);
  line-height: 1.1;
  letter-spacing: -0.015em;
  max-width: 26ch;
}

.playlist-sub {
  display: block;
  font-size: 0.8125rem;
  color: var(--ink-soft-blue);
  margin-top: 0.45rem;
}

.playlist-arrow {
  font-size: 1.1rem;
  color: var(--ink-mute-blue);
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
  align-self: center;
}

/* Expanding note — grid-rows trick animates to auto height */
.playlist-detail {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 500ms var(--ease);
}
.playlist-detail > p {
  overflow: hidden;
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-soft-blue);
  max-width: 46ch;
  padding-left: clamp(0rem, 4vw, 4.4rem);
}
.playlist-item.is-open .playlist-detail { grid-template-rows: 1fr; }
.playlist-item.is-open .playlist-detail > p { padding-bottom: 1.75rem; }

.playlist-item.is-open,
.playlist-item:focus-within { background: rgba(252, 251, 247, 0.55); }
.playlist-item.is-open .playlist-arrow { opacity: 1; transform: rotate(90deg); }

@media (hover: hover) {
  .playlist-item:hover { background: rgba(252, 251, 247, 0.6); }
  .playlist-item:hover .playlist-button { padding-inline: clamp(0.5rem, 1.5vw, 1.25rem); }
  .playlist-item:hover .playlist-arrow { opacity: 1; transform: translateX(0); }
  .playlist-item:hover .playlist-detail { grid-template-rows: 1fr; }
  .playlist-item:hover .playlist-detail > p { padding-bottom: 1.75rem; }
  .playlist-item:hover .playlist-cat { color: var(--brown); }
}

@media (max-width: 575.98px) {
  .playlist-button { grid-template-columns: auto 1fr; }
  .playlist-arrow { display: none; }
  .playlist-detail > p { padding-left: 2.6rem; }
}

/* 10. ABOUT PAGE ========================================================== */

.about-intro {
  padding-block: calc(var(--header-h) + clamp(1rem, 4vw, 3rem)) var(--section-gap);
}

.about-intro .eyebrow {
  color: var(--ink-mute);
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
}

.about-statement {
  font-size: clamp(2.4rem, 6.6vw, 5.75rem);
  line-height: 1.0;
  letter-spacing: -0.025em;
  margin-bottom: clamp(3rem, 8vw, 6rem);
  max-width: 16ch;
}
.about-statement em { font-style: italic; }

.about-body { align-items: start; }

.about-copy {
  max-width: 36rem;
  color: var(--ink-soft);
}
.about-copy .lead-para {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 2.2vw, 1.85rem);
  line-height: 1.32;
  letter-spacing: -0.01em;
  color: var(--brown);
  margin-bottom: 1.6rem;
}
.about-copy strong { color: var(--brown); }

.about-figure { margin: 0 0 2.5rem; }
.about-figure figcaption {
  margin-top: 0.9rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.about-figure .project-placeholder { max-width: 26rem; }

@media (min-width: 992px) {
  .about-figure { margin-bottom: 0; }
}

/* --- What I work with --- */
.disciplines { padding-bottom: var(--section-gap); }

.discipline-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  column-gap: clamp(1.5rem, 4vw, 4rem);
}
.discipline-list li {
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.3vw, 2rem);
  line-height: 1.1;
  letter-spacing: -0.015em;
  padding-block: clamp(1rem, 1.8vw, 1.4rem);
  border-bottom: var(--rule);
  position: relative;
  transition: padding-left var(--dur) var(--ease);
}
.discipline-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 0.6rem;
  height: 0.6rem;
  background: var(--olive);
  transform: translateY(-50%) scale(0);
  transition: transform var(--dur) var(--ease);
}
@media (hover: hover) {
  .discipline-list li:hover { padding-left: 1.5rem; }
  .discipline-list li:hover::before { transform: translateY(-50%) scale(1); }
}

/* --- Timeline --- */
.timeline-section { padding-bottom: var(--section-gap); }

.timeline-row {
  display: grid;
  grid-template-columns: minmax(8rem, 14rem) 1fr;
  gap: 1rem clamp(1.5rem, 4vw, 4rem);
  padding-block: clamp(1.75rem, 3.5vw, 2.75rem);
  border-bottom: var(--rule);
}

.timeline-year { color: var(--ink-mute); padding-top: 0.45rem; }

.timeline-title {
  font-size: clamp(1.35rem, 2.2vw, 1.9rem);
  margin-bottom: 0.4rem;
}
.timeline-place {
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--brown);
  margin-bottom: 0.6rem;
}
.timeline-note {
  color: var(--ink-soft);
  max-width: 44ch;
  font-size: 0.9375rem;
}

@media (max-width: 575.98px) {
  .timeline-row { grid-template-columns: 1fr; gap: 0.6rem; }
  .timeline-year { padding-top: 0; }
}

/* 11. FOOTER ============================================================== */

.site-footer {
  background: var(--brown);
  color: var(--cream);
  padding-block: clamp(4.5rem, 11vw, 9rem) clamp(2rem, 4vw, 3rem);
}

.footer-statement {
  font-size: clamp(3rem, 11.5vw, 9.5rem);
  line-height: 0.92;
  letter-spacing: -0.03em;
  margin-bottom: clamp(3.5rem, 9vw, 7rem);
}

.footer-grid {
  border-top: 1px solid rgba(252, 251, 247, 0.18);
  padding-top: clamp(2rem, 4vw, 3rem);
  row-gap: 2.5rem;
}

.footer-label {
  color: rgba(252, 251, 247, 0.45);
  margin-bottom: 1.1rem;
}

.footer-mail {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 2.6vw, 2rem);
  letter-spacing: -0.015em;
  line-height: 1.2;
  position: relative;
  display: inline-block;
  word-break: break-word;
}
.footer-mail::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -0.12em;
  width: 100%;
  height: 1px;
  background: var(--olive);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 500ms var(--ease);
}
.footer-mail:hover { color: var(--olive); }
.footer-mail:hover::after { transform: scaleX(1); transform-origin: left; }

.footer-links li + li { margin-top: 0.65rem; }
.footer-links a {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9375rem;
  color: var(--cream-60);
}
.footer-links a:hover { color: var(--olive); }
.footer-links a:hover .arrow { transform: translate(3px, -3px); }

.footer-base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem 2rem;
  margin-top: clamp(4rem, 10vw, 8rem);
  padding-top: 1.5rem;
  border-top: 1px solid rgba(252, 251, 247, 0.14);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(252, 251, 247, 0.45);
}
.footer-base p { margin: 0; }

/* 12. CUSTOM CURSOR ======================================================= */
/* Enabled by script.js only on fine-pointer devices with motion allowed. */

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 200;
  width: 5.5rem;
  height: 5.5rem;
  margin: -2.75rem 0 0 -2.75rem;
  border-radius: 50%;
  background: var(--olive);
  color: var(--brown);
  display: none;
  place-items: center;
  pointer-events: none;
  opacity: 0;
  /* Position is written to --x / --y by script.js; the transition on
     transform gives the disc a soft trail behind the pointer. */
  transform: translate3d(var(--x, 50vw), var(--y, 50vh), 0) scale(0.25);
  transition: opacity 300ms var(--ease), transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.cursor span {
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.cursor.is-enabled { display: grid; }
.cursor.is-active {
  opacity: 1;
  transform: translate3d(var(--x, 50vw), var(--y, 50vh), 0) scale(1);
}

/* 13. REDUCED MOTION & PRINT ============================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  .reveal { opacity: 1; transform: none; }
  .site-header { opacity: 1; animation: none; }
  .hero-avatar { opacity: 1; transform: none; }
  .cursor { display: none !important; }
  .toss-nudge { transition: none !important; }
}

@media print {
  .site-header,
  .cursor,
  .scroll-cue { display: none; }
  .reveal { opacity: 1; transform: none; }
  body { background: #fff; }
}
