/* ── Home v2: Impulse-inspired horizontal carousel ──
   Inherits classic styles.css for the floating header and footer.
   This file adds the v2-specific layout, hero, and carousel components. */

/* Body override — only background and antialiasing; keep classic font for the header/footer */
body.v2-page {
  background: #ffffff;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* The classic script.js auto-adds `is-intro` to the body on every page load
   and styles.css hides main/footer/header during the intro overlay.
   v2 doesn't use the intro overlay — force everything visible. */
body.v2-page main,
body.v2-page.is-intro main,
body.v2-page .site-footer,
body.v2-page.is-intro .site-footer,
body.v2-page .site-header,
body.v2-page.is-intro .site-header,
body.v2-page .scroll-progress,
body.v2-page.is-intro .scroll-progress {
  opacity: 1 !important;
  pointer-events: auto !important;
}

body.v2-page,
body.v2-page.is-intro {
  overflow: visible;
}

/* Main container — give space for the floating pill header
   And scope v2 typography here so it doesn't bleed into the classic header/footer */
.v2-main {
  padding-top: calc(var(--header-height, 88px) + 4px);
  color: #111111;
  font-family: "Inter", "Helvetica Neue", Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  letter-spacing: normal;
}

.v2-main a {
  text-decoration: none;
}

/* ── Hero ── */
.v2-hero {
  text-align: center;
  padding: 32px 40p 0px;
}

.v2-hero__title {
  /* Match project detail page title style */
  font-family: "Geologica", "Helvetica Neue", Arial, sans-serif;
  font-weight: 900;
  font-size: clamp(14px, 2.1vw, 26px);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: #111;
  margin: 0 auto 16px;
  padding: 0 60px;
  max-width: 1200px;
}

.v2-hero__subtitle {
  font-family: "Georgia", "Times New Roman", serif;
  font-size: 17px;
  color: #4a4a4a;
  line-height: 1.5;
  max-width: 520px;
  margin: 0 auto 14px;
  letter-spacing: normal;
  text-transform: none;
  font-weight: 400;
}

.v2-hero__hint {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: #6a6a6a;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}

/* When user has dragged the carousel, fade out both hint elements gracefully */
body.has-dragged .v2-hero__hint,
body.has-dragged .v2-carousel-hint {
  opacity: 0;
  pointer-events: none;
}

/* ── Carousel ── */
.v2-carousel-wrap {
  position: relative;
  padding: 0 0 24px;
}

/* v2-page: remove the footer's top dividing line for a cleaner look */
body.v2-page .site-footer {
  border-top: none;
  padding-top: 16px;
}

.v2-carousel {
  display: flex;
  align-items: flex-start; /* Don't stretch cards to container height */
  gap: 18px;
  /* No parent perspective — each card gets its own perspective() in its
     transform so the vanishing point is centered on the card itself. A
     shared parent perspective creates two problems:
       1. Off-center cards get skewed wider than their original width
          (perspective rays hit them at an angle).
       2. Even the centered card with identity transform gets dragged into
          the parent's 3D rendering context, which routes glyph rendering
          through a texture and softens text. */
  /* No horizontal padding — ::before / ::after spacers below take over,
     giving the first and last cards room to scroll-snap to the center
     of the viewport (Cover Flow behavior).
     Bottom padding sized to fit the reflection's visible band (~144px) so
     overflow-y: auto (implicit from overflow-x: auto) doesn't clip it. */
  padding: 40px 0 160px;
  overflow-x: auto;
  cursor: grab;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
  will-change: scroll-position, transform;
  /* CSS-only elastic feel on supported browsers (Safari/iOS) */
  overscroll-behavior-x: contain;
}

/* Flex spacers at the start and end of the carousel — give the first and
   last cards room to scroll-snap to the viewport center. Without these,
   scroll-snap-align: center has no effect on edge cards because they hit
   scroll bounds (scrollLeft = 0 or scrollLeft = max) before truly centering.
   Width = half viewport minus half card width. */
.v2-carousel::before,
.v2-carousel::after {
  content: "";
  flex: 0 0 calc(50vw - 180px);
}

.v2-carousel::-webkit-scrollbar {
  display: none;
}

.v2-carousel.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none;
}

.v2-carousel.is-dragging * {
  pointer-events: none;
}

/* ── Card ── */
.v2-card {
  flex: 0 0 360px !important;
  width: 360px !important;
  height: 480px !important;
  min-height: 480px !important;
  max-height: 480px !important;
  border-radius: 18px;
  padding: 24px;
  position: relative;
  overflow: hidden;
  /* Snap to the CENTER of the scroll port so the visually-focal (un-tilted)
     card is also the one the browser rests on. First/last cards may not
     truly center because they hit scroll bounds — we add ::before/::after
     spacers below to fix that. */
  scroll-snap-align: center;
  /* Flex column with explicit centering — iOS Safari handles column direction more reliably with fixed heights */
  display: flex;
  flex-direction: column;
  align-items: center;       /* horizontal */
  justify-content: center;   /* vertical (main axis) */
  box-sizing: border-box;
  /* Slow, gentle easing — Shopify-style "settle" feel */
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1),
              box-shadow 0.6s cubic-bezier(0.22, 1, 0.36, 1);
  user-select: none;
  -webkit-user-drag: none;
  /* Resting state — animation only applies during entrance, then reverts to these.
     --depth-opacity dims side cards so the active card is the brightest. */
  --depth-opacity: 1;
  opacity: var(--depth-opacity);
  /* Staggered entrance: backwards fill-mode applies FROM state during delay,
     then reverts to author styles after — so hover transitions can work normally */
  animation: v2CardEnter 0.7s cubic-bezier(0.22, 1, 0.36, 1) backwards;
  /* Cover Flow tilt — JS updates --rotate-y per card based on distance from
     the viewport's horizontal center. Per-card perspective() centers the
     vanishing point on each card individually (no off-center skew) AND
     keeps the un-tilted center card in a 2D rendering path (so its text
     stays pixel-sharp instead of being routed through a 3D texture).
     --depth-scale also driven by JS: 1.0 at center, smaller at edges.
     Chained scale() lets depth + hover compose multiplicatively.
     backface-visibility:hidden helps Chromium pick crisper glyph rendering
     for the rotated cards too. */
  --rotate-y: 0deg;
  --depth-scale: 1;
  --hover-scale: 1;
  transform: perspective(700px) rotateY(var(--rotate-y)) scale(var(--depth-scale)) scale(var(--hover-scale));
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  /* Cover Flow reflection — a mirrored copy painted below the card. Inherits
     the card's transform (so tilted cards get tilted reflections, and dimmed
     side cards get dimmed reflections).
     CRITICAL: the mask gradient is applied in the ORIGINAL element's
     coordinate space (top→bottom of the source card), NOT the reflection's.
     So to make the visible band sit right below the card, the opaque stop
     must be at the BOTTOM of the gradient (= TOP of the mirrored reflection,
     which is the part touching the card). Reversing this puts the band
     480px below the card — outside the carousel's overflow boundary, clipped.
     Visible band ≈ 30% of card height (~144px). Webkit-prefixed: works in
     Chrome/Safari/Edge/iOS, Firefox silently skips. */
  -webkit-box-reflect: below 2px linear-gradient(transparent 70%, rgba(0, 0, 0, 0.5));
}

@keyframes v2CardEnter {
  /* Opacity-only entrance. Do NOT animate transform here — the .v2-card's
     author transform is `rotateY() scale() scale()` driven by JS via CSS
     variables. If the keyframe also animates transform (e.g. translateY),
     it overrides the rotation chain during the animation, then reverts at
     end. Transform function lists don't match (`translateY(0)` vs
     `rotateY(X) scale(Y) scale(Z)`), so the browser jumps discretely rather
     than interpolating — the jarring snap from flat → tilted on load.
     Animating to var(--depth-opacity) so dim side cards don't snap-dim at
     the end of the animation either. */
  from { opacity: 0; }
  to   { opacity: var(--depth-opacity, 1); }
}

/* Stagger animation delays — JS sets --i index per card */
.v2-card { animation-delay: calc(var(--i, 0) * 0.1s + 0.12s); }

.v2-card:hover {
  --hover-scale: 1.03;
  box-shadow: 0 18px 36px rgba(0, 0, 0, 0.14);
}

/* Suppress the transform transition while actively scrolling so the per-frame
   rotation updates feel snappy. Hover still gets its smooth ramp because hover
   doesn't happen during scroll. */
.v2-carousel.is-scrolling .v2-card {
  transition: box-shadow 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Suppress ALL transitions during initial setup so the first call to
   updateCardDepth() doesn't trigger a visible "flat → tilted" transform
   animation as the cards fade in. JS adds this class, runs the depth update
   synchronously, forces a reflow, then removes it. */
.v2-carousel.is-initializing .v2-card {
  transition: none !important;
}

/* Per-card color palette (assigned by JS) */
.v2-card[data-color="forest"]    { background: #2d4a3a; color: #eaf0ec; }
.v2-card[data-color="terracotta"]{ background: #c46a4f; color: #fff4ee; }
.v2-card[data-color="midnight"]  { background: #1a2342; color: #e6e9f5; }
.v2-card[data-color="cream"]     { background: #ecdfc4; color: #3a2f1c; }
.v2-card[data-color="gold"]      { background: #d9a232; color: #2a1d05; }
.v2-card[data-color="sky"]       { background: #b9d6e8; color: #1c2f3a; }
.v2-card[data-color="rose"]      { background: #e8b8c0; color: #3a1a23; }
.v2-card[data-color="charcoal"]  { background: #1a1a1a; color: #e8e8e8; }

/* Background project name (the partially-hidden big type) — absolute overlay, centered via inner flex */
.v2-card__bg-text {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Geologica", "Helvetica Neue", Arial, sans-serif;
  font-weight: 900;
  font-size: clamp(72px, 9vw, 110px);
  line-height: 0.9;
  letter-spacing: -0.04em;
  white-space: nowrap;
  opacity: 0.5;
  pointer-events: none;
  text-transform: uppercase;
  z-index: 1;
}

/* Foreground image — absolute centering via inset:0 + margin:auto, 4:3 aspect (wider than tall) */
.v2-card__image-wrap {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 72%;
  /* 4:3 aspect: card 360×480 → image 259×194 = 40.5% of height. Card 280×373 → image 201×151 = 40.5%. */
  height: 40.5%;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.25);
  transform: rotate(-2deg);
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
  z-index: 2;
}

.v2-card:nth-child(even) .v2-card__image-wrap {
  transform: rotate(2deg);
}

/* Subtle hover: just a small "settle" rotation toward neutral */
.v2-card:hover .v2-card__image-wrap {
  transform: rotate(-1deg);
}

.v2-card:nth-child(even):hover .v2-card__image-wrap {
  transform: rotate(1deg);
}

.v2-card__image-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Top tag (project type) */
.v2-card__tag {
  position: absolute;
  top: 24px;
  left: 24px;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 600;
  opacity: 0.7;
  z-index: 3;
}

/* Bottom metadata bar */
.v2-card__meta {
  position: absolute;
  bottom: 24px;
  left: 24px;
  right: 24px;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 600;
  z-index: 3;
}

.v2-card__title {
  max-width: 60%;
  line-height: 1.2;
}

.v2-card__year {
  opacity: 0.75;
}

/* ── Pure-type variant (no image, like Shopify's "Building Artifact" cards) ── */
.v2-card--type-only .v2-card__statement {
  font-family: "Geologica", "Helvetica Neue", Arial, sans-serif;
  font-weight: 900;
  font-size: clamp(40px, 4.4vw, 58px);
  line-height: 0.98;
  letter-spacing: -0.025em;
  z-index: 2;
  position: absolute;
  top: 60px; /* Sits below the tag (which is at top: 24px) with breathing room */
  left: 24px;
  right: 24px;
}

/* Optional decorative element for type-only cards — radiating concentric circles */
.v2-card--type-only::after {
  content: "";
  position: absolute;
  right: -80px;
  bottom: -80px;
  width: 320px;
  height: 320px;
  border-radius: 50%;
  border: 1px solid currentColor;
  opacity: 0.15;
  box-shadow:
    inset 0 0 0 1px currentColor,
    0 0 0 40px transparent,
    0 0 0 80px transparent;
  pointer-events: none;
}

/* ── Fan variant — absolute centering, same 4:3 aspect ── */
.v2-card--fan .v2-card__fan {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 72%;
  height: 40.5%;
  z-index: 2;
}

.v2-card__fan-item {
  position: absolute;
  inset: 0;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.3);
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.v2-card__fan-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Default rotations create a contained "stacked deck" look — back items peek out subtly */
.v2-card__fan-item--3 {
  transform: rotate(-7deg) translate(-7%, 4%);
  z-index: 1;
}

.v2-card__fan-item--2 {
  transform: rotate(5deg) translate(6%, 3%);
  z-index: 2;
}

.v2-card__fan-item--1 {
  transform: rotate(-2deg) translate(0, 0);
  z-index: 3;
}

/* Hover: subtle settle — each item shifts a hair, like the deck nudged */
.v2-card--fan:hover .v2-card__fan-item--3 {
  transform: rotate(-9deg) translate(-9%, 5%);
}
.v2-card--fan:hover .v2-card__fan-item--2 {
  transform: rotate(6deg) translate(7%, 4%);
}
.v2-card--fan:hover .v2-card__fan-item--1 {
  transform: rotate(-1deg) translate(0, -1%);
}

/* Lazy-load sentinel — invisible element after the initial cards.
   IntersectionObserver fires when the user scrolls near it, triggering
   the rest of the projects to render. Width is small so it doesn't
   create a visible gap; height matches cards so flex doesn't collapse. */
.v2-carousel-sentinel {
  flex: 0 0 1px;
  width: 1px;
  height: 1px;
  pointer-events: none;
}

/* Drag hint */
.v2-carousel-hint {
  position: absolute;
  right: 40px;
  top: -32px;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: #6a6a6a;
  display: flex;
  align-items: center;
  gap: 6px;
  transition: opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}

/* ── Responsive ── */
@media (max-width: 900px) {
  .v2-hero {
    padding: 60px 20px 40px;
  }
  .v2-carousel {
    /* Bottom padding bumped from 50px so the reflection's visible band can
       fade out fully inside the scroll container — at 50px the overflow:auto
       chopped the gradient at a hard edge on mobile. */
    padding: 30px 0 130px;
    /* Symmetric padding so cards land centered with peek of next/prev on both sides */
    padding-left: 10vw;
    padding-right: 10vw;
    scroll-padding-left: 10vw;
    scroll-padding-right: 10vw;
    gap: 12px;
    /* Snappy native swipe on mobile: mandatory snap = always lands on a card */
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    /* Disable the rubber-band JS transform on mobile so native scroll handles edges */
    overscroll-behavior-x: contain;
  }
  /* Mobile uses its own padding-inline approach for centering, so the
     desktop ::before / ::after flex spacers would over-pad. */
  .v2-carousel::before,
  .v2-carousel::after {
    display: none;
  }
  .v2-card {
    /* Taller, screen-filling cards on mobile */
    flex: 0 0 80vw !important;
    width: 80vw !important;
    height: 65vh !important;
    min-height: 65vh !important;
    max-height: 65vh !important;
    padding: 20px;
    /* Snap to center instead of start so cards land centered in viewport with peek on both sides */
    scroll-snap-align: center;
    /* Tighter reflection on mobile: mobile cards are 65vh tall (often 450+px),
       so the desktop's 30% visible band (~135px) overflowed the bottom padding.
       Pulling the fade to 20% keeps the visible band ~90px which fits
       comfortably inside the 130px padding-bottom and fades fully to nothing
       before clipping. */
    -webkit-box-reflect: below 2px linear-gradient(transparent 80%, rgba(0, 0, 0, 0.45));
  }
  .v2-card__image-wrap,
  .v2-card--fan .v2-card__fan {
    /* Maintain 4:3 aspect using vw units: 72% of 80vw = 57.6vw wide, height = 57.6vw × 3/4 = 43.2vw */
    height: 43.2vw;
  }
  .v2-card__bg-text {
    /* Bigger on mobile so edges peek past the image/fan and create the layered look */
    font-size: 88px;
  }
  .v2-carousel-hint {
    right: 20px;
  }
}

@media (max-width: 600px) {
  .v2-hero {
    padding: 16px 20px 16px;
  }
  /* Title stays at desktop size — the clamp() handles small viewports naturally */

  /* Hide BOTH drag hints on mobile — swiping is self-explanatory on touch devices */
  .v2-carousel-hint,
  .v2-hero__hint {
    display: none;
  }

  /* Flatten card image rotation on mobile so it doesn't look off-center in small cards */
  .v2-card__image-wrap,
  .v2-card:nth-child(even) .v2-card__image-wrap {
    transform: rotate(0);
  }
  .v2-card:hover .v2-card__image-wrap,
  .v2-card:nth-child(even):hover .v2-card__image-wrap {
    transform: rotate(0);
  }

  /* Tighten the fan stack on mobile so back items don't peek too far out */
  .v2-card__fan-item--3 {
    transform: rotate(-5deg) translate(-4%, 3%);
  }
  .v2-card__fan-item--2 {
    transform: rotate(4deg) translate(4%, 2%);
  }
  .v2-card__fan-item--1 {
    transform: rotate(0);
  }
  .v2-card--fan:hover .v2-card__fan-item--3 {
    transform: rotate(-6deg) translate(-5%, 4%);
  }
  .v2-card--fan:hover .v2-card__fan-item--2 {
    transform: rotate(5deg) translate(5%, 3%);
  }
  .v2-card--fan:hover .v2-card__fan-item--1 {
    transform: rotate(0) translate(0, -1%);
  }
}

/* ──────────────────────────────────────────────────────────
   Resume Modal — clean takeover with solid backdrop
   ────────────────────────────────────────────────────────── */

/* Page underneath stays visible briefly then is covered by opaque backdrop.
   Lock pointer events so nothing under is clickable while modal is open. */
body.v2-modal-open .v2-main,
body.v2-modal-open .site-header,
body.v2-modal-open .site-footer {
  pointer-events: none;
}

/* Modal container */
.v2-modal {
  position: fixed;
  inset: 0;
  z-index: 9000;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.45s cubic-bezier(0.22, 1, 0.36, 1),
              visibility 0s linear 0.45s;
}

.v2-modal.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.45s cubic-bezier(0.22, 1, 0.36, 1),
              visibility 0s linear 0s;
}

/* Backdrop — semi-transparent cream so a hint of the page peeks through */
.v2-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(245, 240, 232, 0.88);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.v2-modal.is-open .v2-modal__backdrop {
  opacity: 1;
}

/* Scroll container — fills viewport, hosts the article panel */
.v2-modal__scroll {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 64px 24px 80px;
  /* Hide system cursor on backdrop — custom cursor handles it */
  cursor: none;
}

/* Article — the actual readable content */
.v2-modal__content {
  position: relative;
  max-width: 720px;
  width: 100%;
  background: #ffffff;
  border-radius: 24px;
  padding: 64px 56px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.18),
              0 8px 20px rgba(0, 0, 0, 0.08);
  transform: translateY(40px) scale(0.96);
  opacity: 0;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1),
              opacity 0.45s cubic-bezier(0.22, 1, 0.36, 1);
  /* Restore normal cursor inside content for selecting/copying */
  cursor: text;
  /* Override main-content text styles — body has global uppercase + small caps */
  font-family: "Georgia", "Times New Roman", serif;
  font-size: 15px;
  color: #1a1a1a;
  line-height: 1.6;
  text-transform: none;
  letter-spacing: normal;
}

/* Reset all child elements to sentence case by default */
.v2-modal__content,
.v2-modal__content * {
  text-transform: none;
  letter-spacing: normal;
}

/* Bring back uppercase ONLY for explicit label/meta styles */
.v2-modal__content .v2-resume__role,
.v2-modal__content .v2-resume__section-label,
.v2-modal__content .v2-resume__job-meta {
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.v2-modal__content .v2-resume__section-label {
  letter-spacing: 0.14em;
}

.v2-modal.is-open .v2-modal__content {
  transform: translateY(0) scale(1);
  opacity: 1;
  transition-delay: 0.08s;
}

/* Allow text selection inside the modal */
.v2-modal__content,
.v2-modal__content * {
  user-select: text;
  -webkit-user-select: text;
}

/* Close X button (top right corner, always visible) */
.v2-modal__close-x {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  border: 1px solid #e6e6e6;
  background: #ffffff;
  color: #111;
  font-size: 14px;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.2s ease;
  z-index: 2;
}

.v2-modal__close-x:hover {
  background: #f5f5f5;
  transform: scale(1.05);
}

/* Custom cursor — only appears when modal is open */
.v2-modal__cursor {
  position: fixed;
  top: 0;
  left: 0;
  transform: translate(-50%, -50%);
  background: #111;
  color: #ffffff;
  border-radius: 999px;
  padding: 10px 18px;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: 8px;
  pointer-events: none;
  z-index: 10000;
  opacity: 0;
  white-space: nowrap;
  transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.22, 1, 0.36, 1);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}

.v2-modal__cursor.is-active {
  opacity: 1;
}

.v2-modal__cursor.is-over-content {
  opacity: 0;
}

/* ── Resume content layout inside modal ── */
.v2-resume__header {
  border-bottom: 1px solid #ececec;
  padding-bottom: 24px;
  margin-bottom: 28px;
}

.v2-resume__header-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 18px;
}

.v2-resume__name {
  font-family: "Geologica", "Helvetica Neue", Arial, sans-serif;
  font-weight: 900;
  font-size: 36px;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin-bottom: 6px;
  color: #0a0a0a;
}

.v2-resume__role {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6a6a6a;
}

.v2-resume__links {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 22px;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
}

.v2-resume__links a {
  color: #1a1a1a;
  text-decoration: underline;
  text-decoration-color: #c8c8c8;
  text-underline-offset: 3px;
  transition: text-decoration-color 0.2s ease;
}

.v2-resume__links a:hover {
  text-decoration-color: #1a1a1a;
}

.v2-resume__section {
  margin-bottom: 28px;
}

.v2-resume__section-label {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #6a6a6a;
  margin-bottom: 14px;
}

.v2-resume__summary {
  font-size: 15px;
  line-height: 1.65;
  color: #2a2a2a;
}

.v2-resume__job {
  margin-bottom: 22px;
}

.v2-resume__job:last-child {
  margin-bottom: 0;
}

.v2-resume__job-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}

.v2-resume__job-title {
  font-family: "Geologica", "Helvetica Neue", Arial, sans-serif;
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.005em;
  color: #0a0a0a;
}

.v2-resume__job-meta {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #6a6a6a;
  white-space: nowrap;
}

.v2-resume__job-bullets {
  list-style: disc;
  padding-left: 20px;
  font-size: 14.5px;
  line-height: 1.55;
  color: #3a3a3a;
}

.v2-resume__job-bullets li {
  margin-bottom: 4px;
}

.v2-resume__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.v2-resume__chip {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 12px;
  background: #f5f3ef;
  color: #2a2a2a;
  padding: 6px 12px;
  border-radius: 999px;
  letter-spacing: 0.02em;
}

.v2-resume__download {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: #111;
  color: #fff;
  padding: 12px 22px;
  border-radius: 999px;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: transform 0.2s ease, background 0.2s ease;
  white-space: nowrap;
}

.v2-resume__download:hover {
  transform: translateY(-1px);
  background: #2a2a2a;
}

/* Small variant for the header CTA */
.v2-resume__download--small {
  padding: 7px 14px;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  gap: 6px;
  flex-shrink: 0;
}

.v2-resume__download--small i {
  font-size: 10px;
}

@media (max-width: 700px) {
  /* ── Bottom sheet on mobile ──
     The modal becomes a sheet anchored to the bottom of the viewport,
     sliding up on open and down on close. */

  /* Scroll container: align content to bottom-end so the sheet hugs the bottom edge */
  .v2-modal__scroll {
    padding: 0;
    align-items: flex-end;
    cursor: pointer; /* whole backdrop area = "click to dismiss" affordance */
  }

  /* Content panel: full-width, 85vh tall, rounded only on the top */
  .v2-modal__content {
    width: 100vw;
    max-width: 100vw;
    max-height: 85vh;
    height: 85vh;
    padding: 28px 24px 32px;
    padding-bottom: calc(32px + env(safe-area-inset-bottom, 0px));
    border-radius: 24px 24px 0 0;
    /* Slide up from below on open, down on close */
    transform: translateY(100%);
    opacity: 1; /* override desktop's fade — only translate animates */
    transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
    box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.15);
    /* Internal scroll for resume content */
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  .v2-modal.is-open .v2-modal__content {
    transform: translateY(0);
    transition-delay: 0s;
  }

  /* Drag handle indicator at the top of the sheet — visual hint that this is a sheet */
  .v2-modal__content::before {
    content: "";
    position: sticky;
    top: 0;
    display: block;
    width: 40px;
    height: 4px;
    background: rgba(0, 0, 0, 0.18);
    border-radius: 999px;
    margin: 0 auto 18px;
    flex-shrink: 0;
  }

  /* Close button: smaller and tighter on mobile sheet */
  .v2-modal__close-x {
    top: 14px;
    right: 14px;
    width: 32px;
    height: 32px;
    font-size: 12px;
  }

  /* Resume content layout adjustments for narrow sheet */
  .v2-resume__name {
    font-size: 28px;
  }

  /* Stack the header on mobile so name has full width */
  .v2-resume__header-top {
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
  }

  .v2-resume__download--small {
    align-self: flex-start;
  }

  .v2-resume__links {
    gap: 10px 18px;
    font-size: 12px;
  }
}

/* ============================================================================
   Cover Flow toggle
   ============================================================================
   The Cover Flow effect (3D rotation, scale dim, opacity dim, reflection) is
   opt-in. When `body.cover-flow-off` is set, override the .v2-card transform
   and opacity to neutral values so the carousel reads as a clean flat row of
   cards. The transform keeps the same function list (perspective/rotateY/
   scale/scale) so toggling smoothly interpolates between modes instead of
   snapping. Reflection is removed entirely.
   ============================================================================ */
body.cover-flow-off .v2-card {
  transform: perspective(700px) rotateY(0deg) scale(1) scale(var(--hover-scale)) !important;
  opacity: 1 !important;
  /* `-webkit-box-reflect: none` is silently rejected by Chromium — use a
     fully transparent mask gradient so a reflection technically renders
     but is 100% invisible. Same effect, parsed correctly. */
  -webkit-box-reflect: below 0 linear-gradient(transparent, transparent) !important;
}
/* Without the reflection there's no need for the extra bottom padding we
   added to give the reflection room to fade out — shrink it back so the
   footer doesn't feel detached. */
body.cover-flow-off .v2-carousel {
  padding-bottom: 60px;
}
@media (max-width: 900px) {
  body.cover-flow-off .v2-carousel {
    padding-bottom: 50px;
  }
}

/* Toggle UI — small pill switch in the footer. Discreet by default (60%
   opacity), brightens on hover so users notice it's interactive. */
.cover-flow-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.02em;
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 0.2s ease;
  -webkit-tap-highlight-color: transparent;
}
.cover-flow-toggle:hover,
.cover-flow-toggle:focus-visible {
  opacity: 1;
  outline: none;
}
.cover-flow-toggle__label {
  user-select: none;
}
.cover-flow-toggle__pill {
  position: relative;
  display: inline-block;
  width: 28px;
  height: 16px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.18);
  transition: background 0.25s ease;
}
.cover-flow-toggle__dot {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}
.cover-flow-toggle[aria-pressed="true"] .cover-flow-toggle__pill {
  background: #2F2D2F;
}
.cover-flow-toggle[aria-pressed="true"] .cover-flow-toggle__dot {
  transform: translateX(12px);
}
