/* =========================================================
   Portfolio — Hero Section Styles
   Spec source: Figma node 319:35921 (MacBook Pro 16" / 1728 px)

   Strategy:
   - Tokens for color & font.
   - Tiered typography via fixed-step media queries
     (designed at 1728, downscaled at 1440 / 1280 / 1024 / 640).
   - Absolute "canvas" composition for the hero.
   - Bottom-center anchored card fan that overflows the frame.
   ========================================================= */

/* ---------- Design tokens ---------- */
:root {
  --bg: #ffffff;
  --ink: #101820;
  --muted: #4a4a4a;
  --border: #d9dce7;
  --surface-soft: #f4f5f7;
  --card-bg: #ffffff;

  --font-serif: "Playfair Display", "Times New Roman", serif;
  --font-sans:  "DM Sans", system-ui, -apple-system, sans-serif;

  /* Type scale (max — at 1728 design width) — reduced ~25% from Figma
     so a 1280–1440 laptop reads at the intended visual weight. */
  --fs-title:    44px;
  --fs-subtitle: 22px;
  --fs-greeting: 38px;
  --fs-body:     17px;
  --fs-quote:    24px;
  --fs-logo:     24px;
  --fs-nav:      15px;

  /* Card geometry (max) */
  --card-w: 240px;
  --card-h: 344px;

  /* Panel default surface (overridden per card) */
  --panel-bg: #f4f5f7;

  /* Per-card pastels — promoted to tokens so dark theme can flip them. */
  --suit-ace:   #eaf3ec;   /* soft sage      */
  --suit-king:  #f7e9e0;   /* warm peach     */
  --suit-queen: #efe6f5;   /* dusty lavender */
  --suit-jack:  #e6eef7;   /* powder blue    */
  --suit-joker: #fbf3df;   /* butter yellow  */

  /* Shadow base colour (single source of truth for all box-shadows). */
  --shadow-rgb: 16, 24, 32;

  /* Global decoration intensity — single knob for all scattered icons */
  --deco-opacity: 0.6;
}

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

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Lock horizontal scroll globally. The hero's deco icons and 3D card-throw
     animations can push past the viewport edge; `overflow-x: clip` prevents
     a horizontal scrollbar without establishing a scroll container (so
     `position: sticky` on the nav-bar keeps working) and, unlike
     `overflow-x: hidden`, it doesn't force `overflow-y` to compute as auto. */
  overflow-x: clip;
}

a { color: inherit; text-decoration: none; }

/* ---------- Typography helpers ---------- */
.t-title    { font-family: var(--font-serif); font-weight: 400; font-size: var(--fs-title);    line-height: 1.05; letter-spacing: -0.005em; }
.t-subtitle { font-family: var(--font-serif); font-style: italic; font-weight: 400; font-size: var(--fs-subtitle); line-height: 1.15; }
.t-greeting { font-family: var(--font-serif); font-style: italic; font-weight: 400; font-size: var(--fs-greeting); line-height: 1.1; }
.t-body     { font-family: var(--font-sans);  font-weight: 400; font-size: var(--fs-body);     line-height: 1.45; color: var(--ink); }
.t-quote    { font-family: var(--font-sans);  font-weight: 500; font-size: var(--fs-quote);    line-height: 1.25; letter-spacing: -0.005em; }
.t-logo     { font-family: var(--font-sans);  font-weight: 700; font-size: var(--fs-logo);     letter-spacing: -0.01em; }
.t-nav      { font-family: var(--font-sans);  font-weight: 400; font-size: var(--fs-nav); }

/* ---------- Top navigation ---------- */
.nav-bar {
  position: sticky; top: 0; z-index: 50;
  width: 100%;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.nav-inner {
  max-width: 1488px;
  margin: 0 auto;
  padding: 20px clamp(20px, 4vw, 48px);
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px;
}
.nav-links { display: flex; align-items: center; gap: clamp(18px, 3vw, 56px); }

.btn-resume {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  transition: background 150ms ease;
}
.btn-resume:hover { background: var(--surface-soft); }

/* Hamburger toggle — hidden on desktop, takes over the nav on mobile */
.nav-toggle { display: none; }

/* Smooth scrolling for in-page anchor links (e.g. the "Works" nav
   link and the "View Case Studies" CTA on the home page both jump
   to #works). scroll-padding-top keeps the landing position from
   tucking under the sticky nav. */
html { scroll-behavior: smooth; scroll-padding-top: 80px; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ---------- Hero canvas ---------- */
.hero {
  position: relative;
  width: 100%;
  min-height: calc(100vh - 80px);
  /* No clip-path here on purpose: the card-fan sits at bottom: -2vw and
     intentionally breaks the frame, so anything that clips the hero would
     also slice the cards off when the user scrolls past the hero. Horizontal
     overflow from deco icons and the 3D card-throw is contained by the
     `overflow-x: clip` on html/body above. */
  /* 3D stage for the card-throw interaction */
  perspective: 1500px;
  perspective-origin: 50% 45%;
}

/* Left typography block — Figma left:120 / top:183 */
.copy-block {
  position: absolute;
  top: clamp(48px, 8vw, 130px);
  left: clamp(20px, 6.94vw, 120px);
  width: min(640px, 56vw);
  display: flex; flex-direction: column;
  z-index: 3;
}
.copy-block .gap-sub   { margin-top: 12px; }
.copy-block .gap-greet { margin-top: clamp(40px, 7vw, 110px); }

.copy-block .greet-group {
  display: flex; flex-direction: column;
  gap: 20px;
  width: min(408px, 90%);
}

/* Profile / instruction card — Rohan's photo on top, call-out below.
   Pulled in closer to the card fan (away from the far-right edge) and
   nudged slightly upward to sit above the deck rather than beside it. */
.quote-card {
  position: absolute;
  top: clamp(-40px, calc(2vw + 20px), 100px);
  right: clamp(170px, 20vw, 350px);
  width: 260px;
  max-width: 320px;
  padding: 0;
  border-radius: 16px;
  background: var(--bg);
  border: 1px solid var(--border);
  box-shadow: 0 18px 36px rgba(16,24,32,0.10);
  overflow: hidden;
  z-index: 10;
  display: flex;
  flex-direction: column;
  /* Subtle lift + tilt on hover — feels like a card you can almost pick up.
     Same transition also handles the opacity/transform fade-out when a
     home-page card gets thrown (.hero.has-active .quote-card). */
  transform: translate(0, 0) rotate(0deg);
  transition:
    transform  1080ms cubic-bezier(0.22, 0.85, 0.20, 1),
    box-shadow 1080ms ease,
    opacity     350ms ease;
}
.quote-card:hover {
  /* Up and to the right, with a clockwise tilt so the top edge swings right. */
  transform: translate(14px, -18px) rotate(2deg);
  box-shadow: 0 32px 56px rgba(16,24,32,0.18);
}
.quote-card__photo {
  display: block;
  width: 100%;
  height: 180px;
  object-fit: cover;
  object-position: center top;
  background: var(--surface-soft);
  filter: grayscale(100%);
  transition: filter 450ms ease;
}
.quote-card:hover .quote-card__photo,
.quote-card__photo:hover {
  filter: grayscale(0%);
}
.quote-card__body {
  padding: 16px 18px 18px;
  background: var(--surface-soft);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.45;
  color: var(--ink);
  position: relative;
}
.quote-card__mark {
  display: block;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 700;
  font-style: normal;
  font-size: 56px;
  line-height: 0.6;
  color: var(--ink);
  margin: 6px 0 -8px;
  user-select: none;
}
.quote-card__body p {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 400;
  font-style: normal;
}
.quote-card__body .quote-emph {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 500;
}
.quote-card p { margin: 0; }
.quote-card p + p { margin-top: 0.6em; }
.quote-card p:last-child { font-weight: 500; }

/* ---------- Decorative SVG icons (scattered) ----------
   Tweak the global intensity in one place: --deco-opacity. */
.deco-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
}
.deco-icon {
  position: absolute;
  display: block;
  width: 16px;
  height: 16px;
  opacity: var(--deco-opacity);
  user-select: none;
  -webkit-user-drag: none;
}

/* ---------- Card fan (anchored bottom-center) ---------- */
.card-fan {
  position: absolute;
  left: 50%; bottom: -2vw;
  transform: translateX(-50%);
  transform-style: preserve-3d;
  width: 0; height: 0;
  pointer-events: none;
  z-index: 20;   /* must sit above .content-stage so cards stay on top */
}

.card {
  position: absolute;
  bottom: 0; left: 0;
  width:  var(--card-w);
  height: var(--card-h);
  background: transparent center/cover no-repeat;
  border: 1px solid var(--border);    /* #D9DCE7 — container frame */
  border-radius: 12px;
  transform-origin: 50% 100%;
  transform-style: preserve-3d;
  backface-visibility: hidden;
  box-shadow:
    0 18px 30px -18px rgba(16, 24, 32, 0.30),
    0 4px 10px -4px rgba(16, 24, 32, 0.10);
  user-select: none;
  pointer-events: auto;
  cursor: pointer;
  overflow: hidden;
  will-change: transform, translate;
  /* Standalone `translate` is composed BEFORE `transform`, so we can
     animate it independently of the per-card fan transform below.
     Used by the idle "nudge" animation. */
  translate: 0 0;
  /* THIS transition governs the RETURN motion only (snap-back to the fan
     when .is-thrown is removed). The forward throw is driven by the
     multi-stop @keyframes card-throw below, which fully owns the transform
     while it runs. Return is intentionally a touch quicker than the throw
     and uses a soft ease-out so the card feels "caught" back into the hand. */
  transition:
    transform   850ms cubic-bezier(0.22, 0.85, 0.30, 1),
    translate   320ms cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow  650ms ease,
    opacity     500ms ease,
    filter      500ms ease;
}
.card:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

/* Idle "I'm interactive" nudge — small bounce that lifts the card a few px.
   JS adds .is-nudging to a random card on a loop while no card is thrown. */
@keyframes card-nudge {
  0%   { translate: 0  0; }
  30%  { translate: 0 -28px; }
  60%  { translate: 0 -20px; }
  85%  { translate: 0  3px; }
  100% { translate: 0  0; }
}
.card.is-nudging {
  animation: card-nudge 700ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Pause nudges whenever a card is thrown or the user hovers the fan area. */
.card-fan.has-active .card.is-nudging,
.card-fan:hover .card.is-nudging,
.card:hover.is-nudging {
  animation: none;
  translate: 0 0;
}

/* =========================================================
   Explicit CTA — "Click to throw!" pill docked to the
   bottom-right of the fan (just past the Joker), with a
   left-pointing arrow gesturing back at the cards.
   Visible only in the default state; dismissed by JS on first
   card interaction.
   ========================================================= */
.cta-hint {
  position: absolute;
  /* Sit just above the top edge of the card fan, horizontally centered
     over the deck. `left/right: 0 + margin: auto + width: max-content`
     centers without using `transform` — that keeps the bob animation
     (which uses `translate`) and the dismiss rule (which uses `transform`)
     free of conflicts. */
  left: 0;
  right: 0;
  bottom: calc(var(--card-h) + 32px);
  margin: 0 auto;
  width: max-content;
  z-index: 25;
  display: flex;
  flex-direction: column;          /* pill on top, arrow below pointing down */
  align-items: center;
  gap: 6px;
  pointer-events: none;
  color: var(--ink);
  opacity: 0;
  /* Mounts after a short delay so it doesn't fight the page load,
     and re-mounts quickly each time the user returns to the default state. */
  animation:
    cta-fade-in 400ms ease 250ms forwards,
    cta-bob 2200ms ease-in-out 650ms infinite;
}

.cta-hint__pill {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  box-shadow: 0 6px 14px -8px rgba(16, 24, 32, 0.18);
}

.cta-hint__arrow {
  width:  36px;
  height: 36px;
  display: block;
  /* Asset points left (←). Rotate -90° so the head points down (↓)
     at the card fan directly below. */
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
}

/* ---------- Desktop close button (× circle, top-right) ----------
   Mirrors the mobile bottom-sheet × treatment. Hidden by default;
   appears with a soft scale-in only while a card is selected. */
.card-close {
  position: fixed;
  top: 24px;
  right: 24px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--ink);
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  box-shadow: 0 6px 18px rgba(16,24,32,0.18);
  opacity: 0;
  pointer-events: none;
  transform: scale(0.85);
  transition: opacity 220ms ease, transform 220ms ease, box-shadow 220ms ease;
  z-index: 1000;
}
.card-close:hover  { box-shadow: 0 10px 24px rgba(16,24,32,0.24); }
.card-close:active { transform: scale(0.96); }
.hero.has-active .card-close {
  opacity: 1;
  pointer-events: auto;
  transform: scale(1);
}

/* Auto-hide once a card is selected (defensive — JS dismisses first) */
.hero.has-active .cta-hint,
.cta-hint.is-dismissed {
  opacity: 0 !important;
  transform: translateY(-6px);
  transition: opacity 280ms ease, transform 320ms ease;
  animation: none;
}

@keyframes cta-fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes cta-bob {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -6px; }
}

@media (max-width: 1024px) {
  .cta-hint {
    bottom: calc(var(--card-h) + 24px);
    gap: 4px;
  }
  .cta-hint__pill  { font-size: 12px; padding: 7px 14px; }
  .cta-hint__arrow { width: 32px; height: 32px; }
}
@media (max-width: 640px) {
  .cta-hint {
    bottom: calc(var(--card-h) + 18px);
    gap: 4px;
  }
  .cta-hint__pill  { font-size: 11px; padding: 6px 12px; }
  .cta-hint__arrow { width: 26px; height: 26px; }
}
@media (prefers-reduced-motion: reduce) {
  .cta-hint { animation: cta-fade-in 300ms ease forwards; }
}

/* Plug SVG illustrations from images/home/ */
.card-1 { background-image: url("images/home/ace.svg"); }
.card-2 { background-image: url("images/home/king.svg"); }
.card-3 { background-image: url("images/home/queen.svg"); }
.card-4 { background-image: url("images/home/jack.svg"); }
.card-5 { background-image: url("images/home/joker.svg"); }

/* Tight, hand-held fan: ≈15% offset = ~42px on a 280px card.
   Rotations from Figma exactly.

   Each card's fan position is mirrored into custom properties so the
   throw @keyframes (below) can use the card's OWN starting slot as the
   anchor for anticipation — without needing one keyframe set per card.

   Function list (translateX/Y, scale, rotateX/Y/Z) is the SAME as the
   throw keyframes' — so the return transition interpolates each property
   cleanly instead of falling back to matrix decomposition (which produces
   wonky non-linear paths). The zero-value functions are a no-op visually. */
.card-1 {
  --fan-x: calc(-50% - 30%); --fan-y: -2%; --fan-r: -9deg;
  transform:
    translateX(var(--fan-x)) translateY(var(--fan-y))
    scale(1) rotateX(0deg) rotateY(0deg) rotateZ(var(--fan-r));
  z-index: 1;
}
.card-2 {
  --fan-x: calc(-50% - 15%); --fan-y: -4%; --fan-r: -4deg;
  transform:
    translateX(var(--fan-x)) translateY(var(--fan-y))
    scale(1) rotateX(0deg) rotateY(0deg) rotateZ(var(--fan-r));
  z-index: 2;
}
.card-3 {
  --fan-x: -50%; --fan-y: -5%; --fan-r: 0deg;
  transform:
    translateX(var(--fan-x)) translateY(var(--fan-y))
    scale(1) rotateX(0deg) rotateY(0deg) rotateZ(var(--fan-r));
  z-index: 3;
}
.card-4 {
  --fan-x: calc(-50% + 15%); --fan-y: -3%; --fan-r: 7.18deg;
  transform:
    translateX(var(--fan-x)) translateY(var(--fan-y))
    scale(1) rotateX(0deg) rotateY(0deg) rotateZ(var(--fan-r));
  z-index: 4;
}
.card-5 {
  --fan-x: calc(-50% + 30%); --fan-y: 0; --fan-r: 11.84deg;
  transform:
    translateX(var(--fan-x)) translateY(var(--fan-y))
    scale(1) rotateX(0deg) rotateY(0deg) rotateZ(var(--fan-r));
  z-index: 5;
}

/* =========================================================
   3D "Card Throw" interaction (state 2 — Figma 321:14011)
   - Clicked card flies into the LEFT empty area and tilts in 3D.
   - A grey content panel slides in from the RIGHT half.
   - Click again, click outside, or press Esc to return.

   Implementation:
   - Built as a multi-stop @keyframes animation (not a transition),
     because a real throw has FOUR distinct phases — anticipation,
     launch, flight, settle — each with its own energy curve.
     A single transition cannot reproduce that.
   - Each .card-N exposes its fan position via --fan-x/y/r so the
     anticipation phase is anchored to the card's OWN slot.
   - The final dock position lives in --throw-x/y so the tablet
     override only needs to change those vars.
   ========================================================= */
.card {
  /* Final dock position (overridden per-viewport below). */
  --throw-x: calc(-50% + 18vw + 150px);
  --throw-y: calc(-34vh + 50%);
}

@keyframes card-throw {
  /* ── Phase 1 · Anticipation (0% → 8%) ──
     The wrist winds back. Card dips ~14px into the table and rocks 4°
     backward FROM ITS OWN FAN POSITION. Slow ease-in so the eye registers
     intent before the launch. */
  0% {
    transform:
      translateX(var(--fan-x))
      translateY(var(--fan-y))
      scale(1)
      rotateX(0deg) rotateY(0deg)
      rotateZ(var(--fan-r));
    animation-timing-function: cubic-bezier(0.4, 0, 0.7, 0.2);
  }
  8% {
    transform:
      translateX(var(--fan-x))
      translateY(calc(var(--fan-y) + 14px))
      scale(0.96)
      rotateX(0deg) rotateY(0deg)
      rotateZ(calc(var(--fan-r) - 4deg));
    /* Sharp ease-in → fast acceleration into the launch */
    animation-timing-function: cubic-bezier(0.55, 0, 0.25, 1);
  }

  /* ── Phase 2 · Launch (8% → 38%) ──
     Explosive flick: the card leaves its slot, scales up, gains 3D tilt,
     starts spinning. This is the moment of physical commitment. */
  38% {
    transform:
      translateX(calc(-50% + 6vw))
      translateY(-28vh)
      scale(1.14)
      rotateX(18deg) rotateY(-3deg)
      rotateZ(10deg);
    /* Long deceleration into flight */
    animation-timing-function: cubic-bezier(0.3, 0.1, 0.2, 1);
  }

  /* ── Phase 3 · Flight & overshoot (38% → 72%) ──
     The card glides through air, spins past its final orientation, peaks
     in altitude. The overshoot is what sells the "it has mass" feeling. */
  72% {
    transform:
      translateX(calc(var(--throw-x) + 24px))
      translateY(calc(var(--throw-y) - 26px))
      scale(1.16)
      rotateX(33deg) rotateY(-9deg)
      rotateZ(23deg);
    /* Soft ease-out into the settle */
    animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  }

  /* ── Phase 4 · Settle (72% → 100%) ──
     Card eases back into its dock — rotation un-overshoots, scale relaxes
     slightly, position lands cleanly. */
  100% {
    transform:
      translateX(var(--throw-x))
      translateY(var(--throw-y))
      scale(1.1)
      rotateX(28deg) rotateY(-6deg)
      rotateZ(18deg);
  }
}

/* =========================================================
   Throw / Return — one class, one animation.

   Default (no class):  .card-N owns position (--fan-x/y/r) and
                        z-index (1–5). The card sits in its home.
   .is-thrown:          card-throw plays forward, card lifts to
                        z 30 (above the fan), holds at 100%.

   Return is handled in JS by calling .reverse() on the running
   animation via the Web Animations API — same .is-thrown class
   stays on the element until the reversed playback finishes,
   then JS removes the class and the card falls back to its
   native home (position + z-index) cleanly.
   ========================================================= */

.card.is-thrown {
  z-index: 30;
  cursor: zoom-out;
  box-shadow:
    0 28px 44px -18px rgba(16, 24, 32, 0.28),
    0 8px 16px -8px  rgba(16, 24, 32, 0.16);
  animation: card-throw 1200ms linear forwards;
}

/* ---------- Hide Namaskar block + quote when a card is active ---------- */
.copy-block .greet-group {
  transition: opacity 400ms ease, transform 500ms cubic-bezier(.2,.7,.2,1);
}
/* NOTE: .quote-card's transition is defined in its main block above
   (covers hover lift + box-shadow + the throw-state fade together). */
/* Namaskar block stays visible — card is now thrown into the right panel. */
.hero.has-active .quote-card {
  opacity: 0;
  transform: translateY(-12px);
  pointer-events: none;
}

/* ---------- Right-side content panel (state 2) ---------- */
.content-stage {
  position: absolute;
  top: 0;                                  /* sits below sticky nav via padding-top */
  right: 0;
  width: 50%;                              /* Figma 852/1728 ≈ 49.3% */
  height: 100%;
  padding: clamp(32px, 4.5vw, 80px) clamp(28px, 3.7vw, 64px);
  padding-top: clamp(48px, 6vw, 100px);
  background: var(--surface-soft);
  z-index: 8;
  opacity: 0;
  transform: translateX(24px);
  pointer-events: none;
  /* Times the panel arrival to the card-throw animation's settle phase:
     opens softly at ~Phase 2, lands together with the card at ~1200ms. */
  transition:
    background 400ms ease,
    opacity     900ms ease 150ms,
    transform  1050ms cubic-bezier(0.4, 0, 0.2, 1) 150ms;
}
.hero.has-active .content-stage {
  opacity: 1;
  transform: translateX(0);
  pointer-events: auto;
}

.content-panel {
  display: none;
  max-width: 720px;
}
.content-panel.is-active { display: block; }

.panel-title {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: clamp(18px, 1.6vw, 24px);
  line-height: 1.25;
  margin: 0;
  color: var(--ink);
}
.panel-body {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(14px, 1.05vw, 17px);
  line-height: 1.5;
  margin: clamp(12px, 1.1vw, 18px) 0 0;
  color: var(--ink);
}

/* ---------- Pastel hues per card (state 2 panel background) ---------- */
.hero.has-active[data-active="ace"]   .content-stage { background: var(--suit-ace);   } /* soft sage      */
.hero.has-active[data-active="king"]  .content-stage { background: var(--suit-king);  } /* warm peach     */
.hero.has-active[data-active="queen"] .content-stage { background: var(--suit-queen); } /* dusty lavender */
.hero.has-active[data-active="jack"]  .content-stage { background: var(--suit-jack);  } /* powder blue    */
.hero.has-active[data-active="joker"] .content-stage { background: var(--suit-joker); } /* butter yellow  */

/* ---------- Tablet — softer 3D, panel becomes full-width below ---------- */
@media (max-width: 1024px) {
  .card {
    /* Same throw animation, just docked at a different final position. */
    --throw-x: -50%;
    --throw-y: calc(-50vh + 50%);
  }
  .content-stage {
    position: fixed;
    inset: auto 0 0 0;
    width: 100%;
    height: auto;
    max-height: 70vh;
    border-top-left-radius: 18px;
    border-top-right-radius: 18px;
    padding: 28px clamp(20px, 5vw, 40px) 40px;
    overflow: auto;
    transform: translateY(24px);
  }
  .hero.has-active .content-stage { transform: translateY(0); }
}

/* ---------- Mobile ---------- */
@media (max-width: 640px) {
  /* Mobile thrown-card behavior is defined in the mobile layout block
     below (see "Active state — a card has been thrown"). This stub is
     intentionally empty so the tablet rules above don't leak into mobile. */
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .card { transition: transform 250ms ease, opacity 250ms ease; }
  .content-stage,
  .copy-block .greet-group,
  .quote-card { transition: opacity 200ms ease, transform 200ms ease; }
  .card.is-nudging { animation: none; translate: 0 0; }
  /* Skip the multi-phase throw choreography — just fade & dock. */
  .card.is-thrown {
    animation: none;
    transform:
      translateX(var(--throw-x)) translateY(var(--throw-y))
      scale(1.05)
      rotateX(0deg) rotateY(0deg) rotateZ(0deg);
  }
}

/* =========================================================
   Responsive — stepped down from the 1728 design baseline
   ========================================================= */

/* Large desktop / smaller-than-design (1440px) */
@media (max-width: 1536px) {
  :root {
    --fs-title:    40px;
    --fs-subtitle: 20px;
    --fs-greeting: 34px;
    --fs-body:     16px;
    --fs-quote:    22px;
    --fs-logo:     22px;
    --fs-nav:      14px;
    --card-w: 210px;
    --card-h: 300px;
  }
}

/* Laptop (1280px) */
@media (max-width: 1280px) {
  :root {
    --fs-title:    34px;
    --fs-subtitle: 18px;
    --fs-greeting: 30px;
    --fs-body:     15px;
    --fs-quote:    20px;
    --fs-logo:     20px;
    --fs-nav:      14px;
    --card-w: 190px;
    --card-h: 272px;
  }
  .quote-card { max-width: 300px; padding: 16px; }
}

/* Tablet (≤1024) — flow to normal document order, fan stays anchored */
@media (max-width: 1024px) {
  :root {
    --fs-title:    30px;
    --fs-subtitle: 16px;
    --fs-greeting: 26px;
    --fs-body:     14px;
    --fs-quote:    18px;
    --fs-logo:     18px;
    --fs-nav:      13px;
    --card-w: 170px;
    --card-h: 244px;
  }

  .hero {
    display: flex; flex-direction: column;
    min-height: auto;
    padding-bottom: 380px; /* room for the absolute fan */
  }

  .copy-block {
    position: static;
    width: 100%;
    padding: 32px clamp(20px, 5vw, 40px) 0;
  }
  .copy-block .gap-greet { margin-top: 32px; }

  .quote-card {
    position: static;
    margin: 24px clamp(20px, 5vw, 40px) 0 auto;
    max-width: 360px;
  }

  /* Hide most decorative icons on tablet for clarity */
  .deco-3, .deco-4, .deco-5, .deco-7, .deco-9 { display: none; }
  .deco-1 { top: 4%;  right: 5%;  width: 28px; height: 28px; }
  .deco-2 { top: 9%;  right: 18%; width: 22px; height: 22px; }
  .deco-6 { top: 38%; right: 4%;  width: 20px; height: 20px; }
  .deco-8 { top: 54%; right: 8%;  width: 28px; height: 28px; }
  .deco-10{ top: 70%; right: 4%;  width: 18px; height: 18px; }

  .card-fan { bottom: 28px; }
  .card-1 { transform: translateX(calc(-50% - 28%)) translateY(-2%) rotate(-9deg); }
  .card-2 { transform: translateX(calc(-50% - 14%)) translateY(-4%) rotate(-4deg); }
  .card-4 { transform: translateX(calc(-50% + 14%)) translateY(-3%) rotate(7.18deg); }
  .card-5 { transform: translateX(calc(-50% + 28%)) translateY(0)   rotate(11.84deg); }
}

/* ============================================================
   Mobile (≤640) — single-screen idle, scrollable selected mode
   Order: nav (logo + hamburger) → title → subtitle → [20vh gap] →
          Namaskar → body → quote → cards → fixed bottom FAB.
   When a card is selected:
     - body scroll is re-enabled
     - active card shows at 60vh at the top
     - pastel panel flows beneath it (scroll to read)
     - sticky × close button top-right
   ============================================================ */
@media (max-width: 640px) {
  :root {
    --fs-title:    38px;
    --fs-subtitle: 18px;
    --fs-greeting: 32px;
    --fs-body:     16px;
    --fs-quote:    16px;
    --fs-logo:     17px;
    --fs-nav:      13px;
    --card-w: 168px;
    --card-h: 240px;
  }

  /* Natural vertical scroll on mobile — the home page is a vertical stack,
     not a locked single-screen canvas. Horizontal scroll stays locked so
     nothing can drift off-screen to the right. */
  html, body { overflow-x: hidden; max-width: 100%; }
  html:has(body.home-page), body.home-page {
    height: auto;
    overflow-y: visible;
    overflow-x: hidden;
    overscroll-behavior: auto;
  }

  /* Hero becomes a vertical flex stack. We use `display: contents` on
     .copy-block and .greet-group so their children (the intro text and
     the CTA button) become direct flex children of .hero — that lets us
     reorder the CTA to sit AFTER the card fan via flex `order`, without
     touching the HTML (desktop keeps its original DOM order intact). */
  .hero {
    perspective: none;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: 100vh;
    height: auto;
    width: 100%;
    max-width: 100vw;
    padding: 24px 20px 32px;
    overflow-x: hidden;
    overflow-y: visible;
    box-sizing: border-box;
  }

  /* 1. Copy block — flattened so its children participate in .hero's flex. */
  .copy-block { display: contents; }
  .copy-block .greet-group { display: contents; }

  /* Stack order: title → subtitle → Namaskar → body → photo card → card fan → CTA */
  .t-title    { order: 1; }
  .t-subtitle { order: 2; }
  .t-greeting { order: 3; margin-top: 5vh; }
  .t-body     { order: 4; }
  .quote-card { order: 5; }
  .card-fan   { order: 6; }
  .greet-group .btn-cta { order: 7; }

  /* `gap-greet` margin no longer applies (greet-group is `contents`). */
  .copy-block .gap-greet { margin-top: 0; }

  /* 2. Photo / quote card — sits between the intro copy and the deck.
     Vertical stack on mobile: photo on top, text below. Constrained
     width + shorter photo so it doesn't dominate the stack. */
  .quote-card {
    position: static;
    margin: 24px auto 0;
    max-width: 280px;
    width: 100%;
    background: var(--bg);
    flex-direction: column;
    align-items: stretch;
  }
  .quote-card__photo {
    width: 100%;
    height: 260px;
    flex-shrink: 0;
  }
  .quote-card__body {
    padding: 14px 16px;
    flex: 1 1 auto;
  }
  /* Disable hover/lift + grayscale→color on mobile (touch devices). */
  .quote-card:hover {
    transform: none;
    box-shadow: 0 18px 30px rgba(16,24,32,0.10);
  }
  .quote-card:hover .quote-card__photo,
  .quote-card__photo:hover {
    filter: grayscale(100%);
  }

  /* 3. "Tap to throw!" chip — hidden on mobile */
  .cta-hint { display: none !important; }

  /* Desktop × button — hidden on mobile (the bottom-sheet has its own ×). */
  .card-close { display: none !important; }

  /* 4. Card fan — flows in the document on mobile. The cards inside are
     absolutely positioned around the fan's horizontal center, so the
     fan needs a fixed height to reserve vertical space. Tapping a card
     still opens the bottom-sheet (.m-sheet) — that's handled in JS. */
  .card-fan {
    position: relative;
    left: auto; right: auto; bottom: auto;
    width: 100%;
    height: 260px;
    margin: 28px 0 8px;
    transform: none;
    z-index: 1;
  }
  .card { border-radius: 10px; }
  /* Individual fan placements (these reference the fan's center via 50%). */
  .card-1 { left: 50%; transform: translateX(calc(-50% - 26%)) translateY(-2%) rotate(-9deg); }
  .card-2 { left: 50%; transform: translateX(calc(-50% - 13%)) translateY(-4%) rotate(-4deg); }
  .card-3 { left: 50%; transform: translateX(-50%)             translateY(-5%) rotate(0); }
  .card-4 { left: 50%; transform: translateX(calc(-50% + 13%)) translateY(-3%) rotate(7.18deg); }
  .card-5 { left: 50%; transform: translateX(calc(-50% + 26%)) translateY(0)   rotate(11.84deg); }

  .deco-layer { display: none; }

  /* 5. "View Case Studies" — natural button at the bottom of the stack
     (no longer a fixed/sticky FAB). */
  .greet-group .btn-cta {
    position: static;
    left: auto; right: auto; bottom: auto;
    width: 100%;
    margin: 24px 0 0;
    z-index: auto;
    justify-content: center;
    padding: 14px 22px;
    font-size: 15px;
    box-shadow: 0 10px 28px rgba(16,24,32,0.18);
  }

  /* Selected-mode is replaced by the bottom-sheet modal (.m-sheet).
     The hero stays idle; the sheet opens over it on card tap.
     Keep the off-canvas content-stage hidden on mobile. */
  .content-stage { display: none; }
}

/* ============================================================
   Mobile bottom-sheet modal — replaces the in-place card-throw
   on small screens. Slides up over the entire hero, showing the
   tapped card image at top and the pastel content below.
   ============================================================ */
.m-sheet { display: none; }

@media (max-width: 640px) {
  .m-sheet {
    display: block;
    position: fixed;
    inset: 0;
    background: var(--bg);
    z-index: 2000;             /* above FAB (999) and hamburger */
    transform: translateY(100%);
    transition: transform 360ms cubic-bezier(.2,.7,.2,1);
    visibility: hidden;
    pointer-events: none;
    overscroll-behavior: contain;
  }
  .m-sheet.is-open {
    transform: translateY(0);
    visibility: visible;
    pointer-events: auto;
  }

  .m-sheet__scroll {
    height: 100%;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(48px + env(safe-area-inset-bottom, 16px));
  }

  .m-sheet__image {
    display: block;
    width: 60%;
    max-width: 240px;
    margin: 40px auto 24px;
    aspect-ratio: 168 / 240;
    object-fit: contain;
    border-radius: 14px;
    background: var(--surface-soft);
    box-shadow: 0 12px 32px rgba(16,24,32,0.18);
  }

  .m-sheet__panel {
    margin: 0 16px;
    padding: 28px 22px 32px;
    border-radius: 24px;
    background: var(--surface-soft);   /* per-card overrides below */
  }
  .m-sheet__panel .panel-title {
    font-family: var(--font-serif);
    font-size: 24px;
    line-height: 1.2;
    color: var(--ink);
    margin: 0 0 14px;
    font-weight: 500;
  }
  .m-sheet__panel .panel-body {
    font-family: var(--font-sans);
    font-size: 15px;
    line-height: 1.55;
    color: var(--muted);
    margin: 0;
  }

  /* Per-card pastel hue (mirrors desktop content-stage palette). */
  .m-sheet[data-active="ace"]   .m-sheet__panel { background: var(--suit-ace);   }
  .m-sheet[data-active="king"]  .m-sheet__panel { background: var(--suit-king);  }
  .m-sheet[data-active="queen"] .m-sheet__panel { background: var(--suit-queen); }
  .m-sheet[data-active="jack"]  .m-sheet__panel { background: var(--suit-jack);  }
  .m-sheet[data-active="joker"] .m-sheet__panel { background: var(--suit-joker); }

  /* Sticky × button — top-right corner. */
  .m-sheet__close {
    position: absolute;
    top: max(16px, env(safe-area-inset-top, 16px));
    right: 16px;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--bg);
    border: 1px solid var(--ink);
    color: var(--ink);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
    box-shadow: 0 6px 18px rgba(16,24,32,0.18);
    z-index: 2;
  }

  /* While the sheet is open: lock body scroll, hide hamburger + FAB
     so the modal feels like a true full-screen takeover. */
  body.m-sheet-open { overflow: hidden; }
  body.m-sheet-open .nav-bar,
  body.m-sheet-open .nav-toggle,
  body.m-sheet-open .greet-group .btn-cta {
    opacity: 0;
    pointer-events: none;
    transition: opacity 200ms ease;
  }
}




/* ============================================================
   CTA pill button — "View Case Studies"
   Dark fill, base text, fully rounded.
   ============================================================ */
.btn-cta {
  display: inline-flex;
  align-self: flex-start;       /* hug content inside flex parents */
  width: fit-content;           /* hug content as a block fallback */
  align-items: center;
  gap: 10px;
  margin-top: 24px;
  padding: 12px 22px;
  background: var(--ink);
  color: var(--bg);
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  border-radius: 999px;
  border: 1px solid var(--ink);
  cursor: pointer;
  transition: transform 200ms ease, background 200ms ease, box-shadow 200ms ease;
  box-shadow: 0 6px 18px rgba(16, 24, 32, 0.18);
  z-index: 4;
  position: relative;
}
.btn-cta:hover  { transform: translateY(-1px); box-shadow: 0 10px 24px rgba(16, 24, 32, 0.24); }
.btn-cta:active { transform: translateY(0); }
.btn-cta svg    { transition: transform 200ms ease; }
.btn-cta:hover svg { transform: translateX(3px); }

@media (max-width: 640px) {
  .btn-cta { font-size: 14px; padding: 10px 18px; margin-top: 18px; }
}

/* ============================================================
   Page swipe transition — used between home and case-studies.
   Outgoing page: slides off to the left.
   Incoming page: starts off-screen right, slides in.
   ============================================================ */
body.is-leaving-left  { animation: page-leave-left  420ms cubic-bezier(.7,0,.3,1) forwards; }
body.is-leaving-right { animation: page-leave-right 420ms cubic-bezier(.7,0,.3,1) forwards; }
body.is-entering      { animation: page-enter       520ms cubic-bezier(.2,.7,.2,1) both; }

@keyframes page-leave-left {
  from { transform: translateX(0);     opacity: 1; }
  to   { transform: translateX(-12vw); opacity: 0; }
}
@keyframes page-leave-right {
  from { transform: translateX(0);    opacity: 1; }
  to   { transform: translateX(12vw); opacity: 0; }
}
@keyframes page-enter {
  from { transform: translateX(100vw); }
  to   { transform: translateX(0);     }
}
@media (prefers-reduced-motion: reduce) {
  body.is-leaving-left, body.is-leaving-right, body.is-entering { animation: none; }
}

/* ============================================================
   Mobile navigation — circular hamburger + slide-down drawer
   Applies to viewports ≤ 768px on every page that uses .nav-bar.
   ============================================================ */
@media (max-width: 768px) {

  /* The bar stays as a row but goes transparent — logo + circular button only. */
  .nav-bar {
    background: transparent;
    border-bottom: none;
    pointer-events: none;   /* let underlying canvas receive input */
  }
  .nav-inner {
    padding: 16px;
    justify-content: space-between;
    gap: 12px;
  }
  .nav-inner > .t-logo {
    pointer-events: auto;
    color: var(--ink);
  }

  /* ---- The hamburger button ---- */
  .nav-toggle {
    pointer-events: auto;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--bg);
    border: 1px solid var(--ink);
    color: var(--ink);
    cursor: pointer;
    box-shadow: 0 6px 18px rgba(16, 24, 32, 0.14);
    transition: transform 200ms ease, box-shadow 200ms ease;
    z-index: 60;
    padding: 0;
  }
  .nav-toggle:hover  { transform: translateY(-1px); box-shadow: 0 10px 22px rgba(16,24,32,0.22); }
  .nav-toggle:active { transform: translateY(0); }

  .nav-toggle__bar {
    width: 18px;
    height: 1.5px;
    background: var(--ink);
    border-radius: 1px;
    transition: transform 250ms ease, opacity 200ms ease;
  }
  /* Morph into an × when open */
  .nav-bar.is-open .nav-toggle__bar:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
  .nav-bar.is-open .nav-toggle__bar:nth-child(2) { opacity: 0; }
  .nav-bar.is-open .nav-toggle__bar:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

  /* ---- The drawer (the existing .nav-links becomes a fullscreen panel) ---- */
  .nav-links {
    pointer-events: none;
    position: fixed;
    inset: 0;
    background: var(--bg);
    display: flex !important;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 28px;
    padding: 96px 32px 32px;
    margin: 0;
    opacity: 0;
    transform: translateY(-12px);
    transition: opacity 280ms ease, transform 280ms ease;
    z-index: 55;
  }
  .nav-bar.is-open .nav-links {
    pointer-events: auto;
    opacity: 1;
    transform: translateY(0);
  }
  .nav-links a {
    font-family: var(--font-serif);
    font-size: 28px;
    line-height: 1.2;
    color: var(--ink);
    text-decoration: none;
  }
  .nav-links .btn-resume {
    border-radius: 999px;
    padding: 10px 18px;
    font-size: 16px;
    font-family: var(--font-sans);
  }

  /* Body scroll lock while menu is open */
  body.nav-open { overflow: hidden; }
}


/* ============================================================
   ===  WORKS section (home page, in-page case-studies grid)  ==
   --------------------------------------------------------------
   Lives below the .hero on index.html. The "Works" nav link and
   the "View Case Studies" CTA both scroll here via #works.
   The 4 cards reuse the .cs-card primitive from case-studies.css,
   laid out as a 2x2 grid on desktop / single column on mobile.
   ============================================================ */
.works {
  position: relative;
  z-index: 5;                                 /* above .hero deco-layer */
  background: var(--bg);
  /* Hairline divider at the hero/works boundary — matches the nav-bar's
     bottom border. The card-fan still "breaks the frame" and floats over
     this line, which is the intended effect (the cards visually pierce
     the divider on either side of the deck). */
  border-top: 1px solid var(--border);
  padding: clamp(64px, 8vw, 112px) clamp(20px, 6vw, 64px);
}
.works__inner {
  max-width: 1280px;
  margin: 0 auto;
}
.works__title {
  /* Match the hero's "AI native UX Designer" headline (.t-title): same
     family, weight, size token, line-height and tracking — so the two
     section heads on the home page read as a pair. */
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: var(--fs-title);
  line-height: 1.05;
  letter-spacing: -0.005em;
  color: var(--ink);
  margin: 0 0 clamp(32px, 4vw, 56px);
}
.works__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;             /* 2x2 desktop */
  gap: 24px;
}
/* Give each card a definite height so its .cs-card__media (flex: 1 1 auto)
   has room to fill — without this the cards collapse to their text height
   since they're not inside a fixed-height carousel slide here. */
.works__grid .cs-card { min-height: 520px; }

@media (max-width: 1024px) {
  .works__grid .cs-card { min-height: 460px; }
}
@media (max-width: 768px) {
  .works { padding: 56px 16px 80px; }
  /* Font size now flows from --fs-title (mobile :root override sets it
     to 38px), so only the margin needs a mobile-specific tweak. */
  .works__title { margin: 0 0 32px; }
  .works__grid { grid-template-columns: 1fr; gap: 16px; }
  .works__grid .cs-card { min-height: 0; }    /* let content set height */
  .works__grid .cs-card__media { aspect-ratio: 16 / 10; flex: 0 0 auto; }
}


/* ============================================================
   ===  DARK THEME  ===========================================
   Activated by <html data-theme="dark"> (set by theme.js).
   Every painted surface in light mode is built from these
   tokens, so a single override block flips the whole site.
   ============================================================ */
:root[data-theme="dark"] {
  --bg:           #0e1116;   /* page background */
  --ink:          #e8ecf2;   /* primary text */
  --muted:        #a4adba;   /* secondary text */
  --border:       #2a3140;   /* hairlines */
  --surface-soft: #161b24;   /* soft panels / fills */
  --card-bg:      #161b24;   /* card body */
  --panel-bg:     #161b24;

  /* Same hues, deeper values — keep the "suit" identity but cooperate
     with a dark surface. Tested for AA contrast against --ink. */
  --suit-ace:   #1e2f25;     /* deep sage      */
  --suit-king:  #38271d;     /* deep peach     */
  --suit-queen: #2b2235;     /* deep lavender  */
  --suit-jack:  #1c2738;     /* deep navy      */
  --suit-joker: #34301e;     /* deep amber     */
}

/* Smooth the moment-of-switch so nothing jumps. */
html, body, .nav-bar, .content-stage, .panel, .card,
.theme-toggle, .btn-resume, .nav-toggle, .m-sheet__panel {
  transition: background-color 220ms ease, color 220ms ease,
              border-color 220ms ease;
}

/* "More work on Behance" tile — the light-mode gradient
   (#e8eaff → #d6e0ff → #e4d9f7) is far too pale for the white
   --ink in dark mode (contrast ≈ 1.3:1, fails WCAG AA). Swap
   in the same indigo→violet hue family at deep values; the
   resulting gradient hits ~12:1 contrast with --ink while
   keeping the card visually distinct from neighbouring
   --card-bg tiles in the Works grid. */
:root[data-theme="dark"] .cs-card--behance {
  background: linear-gradient(135deg, #1a1f3a 0%, #231a3a 45%, #2b1d3a 100%);
}

/* ============================================================
   THEME TOGGLE BUTTON  (sun / moon)
   Appears next to Resume on desktop; in the hamburger drawer
   on mobile (under Resume).
   ============================================================ */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--ink);
  cursor: pointer;
  padding: 0;
  margin-left: 4px;
  transition: background 180ms ease, transform 180ms ease,
              box-shadow 180ms ease, border-color 180ms ease;
}
.theme-toggle:hover {
  background: var(--surface-soft);
  border-color: var(--ink);
  transform: translateY(-1px);
}
.theme-toggle:active { transform: translateY(0); }
.theme-toggle:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}
.theme-toggle svg { width: 18px; height: 18px; display: block; }
.theme-toggle .icon-sun  { display: none; }
.theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-sun  { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* ---- Mobile: live inside the drawer as a labelled pill ---- */
@media (max-width: 768px) {
  .nav-links .theme-toggle {
    width: auto;
    height: auto;
    border-radius: 999px;
    padding: 10px 18px;
    gap: 10px;
    font-family: var(--font-sans);
    font-size: 16px;
    margin-left: 0;
  }
  .nav-links .theme-toggle::after {
    content: "Dark mode";
  }
  :root[data-theme="dark"] .nav-links .theme-toggle::after {
    content: "Light mode";
  }
}
