/* ============================================================
   Homepage v2 — "keep it snappy" direction, from Figma
   (Portfolio 3 – Simplified, frame "MacBook Pro 16" - 13",
   node 1629:17200 for the work-samples row — pulled via
   Figma MCP design context, so colors/sizes/copy below are
   taken directly from the file, not eyeballed.)
   Isolated from style.css so the case-study pages are untouched
   while we iterate on just the homepage.
   ============================================================ */

:root {
  --v2-peach: #fbe8cf;
  --v2-black: #111110;
  --v2-gray: #8a8a86;
  --v2-gray-light: #b6b6b2;
  --v2-border: #ececea;
  /* The site's one accent color lives in style.css as --accent (loaded
     on every page) and is used directly here, not re-aliased — an
     alias declared on :root would freeze at :root's own --accent and
     never see the body[data-mood="zen"] override in style.css, since
     custom-property resolution happens per declaring element. */

  /* exact card background colors from Figma */
  --v2-remitly: #242620;
  --v2-newsfeed: #cc348d;
  --v2-paylink-bg: #eee9e5;
  --v2-streak: #5f7d8b;
}

body.home-v2 { font-family: 'Inclusive Sans', -apple-system, BlinkMacSystemFont, sans-serif; }

/* ---------- NAV ---------- */
.v2-nav {
  display: flex; align-items: center; justify-content: space-between;
  /* Same max-width + centering + padding recipe as .v2-hero /
     .v2-section-head / .v2-scroll-wrap below — without it, on any
     viewport wider than 1600px + padding, the nav's flat 96px padding
     sits left of where those max-width:1600px boxes actually start
     (they center with extra margin beyond their own padding), so the
     logo reads as misaligned against everything below it. */
  max-width: 1600px; margin: 0 auto; padding: 28px 96px; box-sizing: border-box;
  position: sticky; top: 0; background: var(--white); z-index: 100;
}
/* Logo is an inline SVG (fill="currentColor" on its paths) so it always
   tracks the one accent color via this element's own `color`. */
.v2-logo { display: inline-flex; text-decoration: none; color: var(--accent); }
.v2-logo-img { height: 20px; width: auto; display: block; }
.v2-nav-links { display: flex; gap: 28px; list-style: none; }
.v2-nav-links a { text-decoration: none; }
/* The Zen/Snappy circle-style toggle lives here now, in the nav's old
   Home/About slot — same look (small, bold, letter-spaced, uppercase),
   just buttons instead of links, with the accent marking the active one. */
.v2-nav-links a,
.v2-nav-links .v2-circle-tab {
  font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--v2-black); transition: color 0.15s;
  background: none; border: none; padding: 0; cursor: pointer; font-family: inherit;
}
.v2-nav-links a:hover,
.v2-nav-links .v2-circle-tab:hover { color: var(--accent); }
.v2-nav-links .v2-circle-tab.is-active { color: var(--accent); }
/* Labels the Zen/Snappy pair as a control (a setting to pick), not a
   pair of page destinations like the nav links they replaced. */
.v2-mood-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--v2-gray-light); margin-right: 4px;
}

/* ---------- HERO ---------- */
.v2-hero { text-align: left; padding: 56px 96px 0; max-width: 1600px; margin: 0 auto; box-sizing: border-box; }
.v2-hero h1 {
  font-family: 'Inclusive Sans', sans-serif; font-weight: 400; font-size: clamp(22px, 2.6vw, 30px);
  color: var(--v2-black); margin-bottom: 16px; letter-spacing: -0.01em;
}
.v2-hero p.v2-sub { font-size: 14px; line-height: 1.55; color: #505050; margin-bottom: 6px; max-width: 800px; }
.v2-hero p.v2-detail { font-size: 13px; color: #8c8c8c; margin-top: 10px; }
.v2-accent-divider { color: var(--accent); font-weight: 700; }

/* ---------- CALLOUT CIRCLE(S) ---------- */
.v2-callout {
  /* 142px top/bottom — this and .v2-section-head's margin-top are set to
     the same value so the circle sits centered in the whitespace between
     the hero text and "Some project samples", instead of hugging the
     hero (64px above it, 220px below it, before this fix). */
  max-width: 1600px; margin: 142px auto 0; padding: 0 96px;
  display: flex; justify-content: center; position: relative;
  box-sizing: border-box;
  /* Dragging the dot circle was catching nearby text as a selection,
     which shows a blinking text caret/highlight — this area isn't
     meant to be selectable text anyway. */
  -webkit-user-select: none; user-select: none; cursor: default;
}
/* Both graphics stack in the same spot; only the active one is visible —
   toggled from the Zen/Snappy buttons up in the nav. */
.v2-circle-stage { position: relative; width: 260px; height: 260px; }
.v2-circle-stage .v2-ring3d,
.v2-circle-stage .v2-callout-circle {
  position: absolute; top: 0; left: 0;
  opacity: 0; pointer-events: none;
  transition: opacity 0.4s ease;
}
.v2-circle-stage .v2-ring3d.is-active,
.v2-circle-stage .v2-callout-circle.is-active {
  opacity: 1; pointer-events: auto;
}
.v2-callout-circle {
  /* No fill/gradient behind it on purpose — just the dots themselves.
     `color` isn't used for rendering here — the zen canvas reads it back
     via getComputedStyle so its grains always track --accent, even
     though canvas fillStyle can't reference a CSS variable directly. */
  width: 260px; height: 260px; border-radius: 50%; overflow: hidden;
  background: transparent; color: var(--accent);
  display: block; cursor: pointer;
}

/* --- 3D tilt ring graphic. A cluster of thin circles that spins slowly
   on its own (CSS keyframe on the inner .v2-ring3d-spin layer) while the
   outer .v2-ring3d-stage tilts in 3D toward the cursor (JS-set
   rotateX/rotateY) — two independent transforms on two different
   elements, so they compose instead of fighting each other. */
.v2-ring3d { width: 260px; height: 260px; perspective: 700px; }
.v2-ring3d-stage {
  width: 100%; height: 100%; position: relative;
  transform-style: preserve-3d;
  transition: transform 0.5s var(--liquid-ease, cubic-bezier(.22,1.12,.36,1));
}
.v2-ring3d-spin {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  animation: v2-ring-spin 16s linear infinite;
}
@keyframes v2-ring-spin {
  from { transform: rotateZ(0deg); }
  to { transform: rotateZ(360deg); }
}
.v2-ring {
  position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid var(--accent);
}
.v2-ring-a { transform: translate3d(-4%, -3%, 30px) scale(0.9); opacity: 0.9; }
.v2-ring-b { transform: translate3d(3%, 5%, 0) scale(1); opacity: 0.65; }
.v2-ring-c { transform: translate3d(7%, -6%, -30px) scale(0.78); opacity: 0.45; }

/* ---------- SECTION LABEL ROW ---------- */
/* .v2-section-head and .v2-scroll-wrap share the identical max-width +
   centering + padding recipe below, so their left edges always line up —
   and on screens wider than the max-width, the whole block centers as one
   unit (whitespace grows symmetrically) instead of either one staying
   pinned to the raw viewport edge. */
.v2-section-head { max-width: 1600px; margin: 142px auto 24px; padding: 0 96px; font-size: 17px; box-sizing: border-box; }
.v2-section-head strong { font-weight: 700; color: var(--v2-black); }
.v2-section-head span { color: var(--v2-gray); font-weight: 400; }
/* Prev/next controls for the row — static (no animation), same quiet
   glyph-button treatment as .v2-card-close: no fill/border, just the
   character itself, dimmed until hover. */
.v2-scroll-nav-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; margin-left: 4px;
  background: none; border: none; padding: 0;
  font-size: 20px; line-height: 1; color: var(--v2-black); opacity: 0.5; cursor: pointer;
  transition: opacity 0.2s ease;
}
.v2-scroll-nav-btn:hover { opacity: 1; color: var(--accent); }

/* ---------- WORK SAMPLES: horizontal scroll row ---------- */
.v2-scroll-wrap { max-width: 1600px; margin: 0 auto; padding: 0 0 24px; }
.v2-card-row {
  display: flex; gap: 32px; align-items: flex-start;
  overflow-x: auto;
  /* No scroll-snap: combined with padding on a scroll container, Chrome's
     snap-on-load can set the initial scrollLeft to the padding amount,
     which visually eats the left inset. Dragging works fine without it. */
  padding: 4px 96px 20px;
  -webkit-overflow-scrolling: touch;
  cursor: grab;
  /* No visible scrollbar, ever — this row scrolls by dragging (see home-v2.js)
     or touch/trackpad, never a scrollbar the user drags. */
  scrollbar-width: none;
}
.v2-card-row::-webkit-scrollbar { display: none; }
.v2-card-row.dragging { cursor: grabbing; user-select: none; }
.v2-card-row.dragging .v2-card { pointer-events: none; }

/* Shared "liquid" easing: fast start, long satisfying settle with a
   whisper of overshoot at the end — used everywhere something opens,
   grows, or rises, so the whole card feels like one coherent material. */
:root {
  --liquid-ease: cubic-bezier(.22, 1.12, .36, 1);
  /* Same family, but never exceeds 1 — for the bottom-anchored, masked
     image reveal specifically. The overshoot above is great for width/
     panel motion, but on a clipped bottom-anchored image it means the
     image briefly rises past its resting spot and reveals card
     background beneath it. This curve settles at exactly translateY(0),
     never past it. */
  --liquid-ease-image: cubic-bezier(.16, 1, .3, 1);
  --liquid-duration: 0.7s;
}

.v2-card {
  flex: 0 0 auto; width: 268px; height: 383px;
  border-radius: 15px 15px 0 0; overflow: hidden; position: relative;
  text-decoration: none; color: inherit; cursor: pointer;
  display: flex; flex-direction: row; align-items: stretch;
  transition: width var(--liquid-duration) var(--liquid-ease);
  /* Clicking to toggle expand was starting a text selection on the title/
     description, which some browsers render as a blinking text caret.
     These cards aren't text content to select, so disable it outright. */
  -webkit-user-select: none; user-select: none;
}
.v2-card:focus { outline: none; }
.v2-card:focus-visible { outline: 2px solid rgba(255,255,255,0.6); outline-offset: -2px; }
.v2-card.is-open { width: 688px; }

.v2-card-main {
  flex: 0 0 268px; width: 268px; height: 100%;
  display: flex; flex-direction: column;
  position: relative;
}

.v2-card-title {
  font-weight: 700; font-size: 17px; color: #fff;
  padding: 18px 21px 0;
  position: relative; z-index: 3;
}
.v2-card-desc {
  /* The screenshot sits on top of this at rest and fully hides it — not
     dimmed-through, actually covered — so it doesn't need its own
     position in the flex column; it's overlaid absolutely, starting
     right under the title. On hover the image slides down (see
     .v2-card-shot below) and this simply brightens to full opacity in
     the gap it leaves, rather than moving itself. */
  /* Weight 500, not 400 — plain regular white-on-color was hard to read;
     600 turned out too heavy, especially on the on-light (dark-text)
     cards. 500 needs Inclusive Sans' medium weight loaded in index.html. */
  font-weight: 500; font-size: 13px; line-height: 1.85; color: #fff;
  position: absolute; top: 60px; left: 0; right: 0; z-index: 1;
  padding: 0 23px;
  opacity: 0.4;
  transition: opacity 1s var(--liquid-ease-image);
}
.v2-card.on-light .v2-card-title,
.v2-card.on-light .v2-card-desc { color: var(--v2-black); }

.v2-card:hover .v2-card-desc,
.v2-card.is-open .v2-card-desc {
  opacity: 1;
}

.v2-card-shot {
  /* Full width (auto height, true aspect ratio, never cropped) rather
     than object-fit'd into a box — letterboxing an image to fit a fixed
     box left gaps on the sides that the dimmed text behind it peeked
     through. The reveal is done purely by sliding this whole block down
     on hover, so the image itself never grows or shrinks. */
  position: absolute; left: 8px; right: 8px; top: 58px; z-index: 2;
  padding: 0;
  transform: translateY(0);
  transition: transform 1s var(--liquid-ease-image);
}
.v2-card:hover .v2-card-shot,
.v2-card.is-open .v2-card-shot {
  transform: translateY(120px);
}
.v2-card-shot img {
  width: 100%; height: auto; max-width: none; max-height: none;
  display: block;
  -webkit-user-drag: none; user-select: none;
  /* Uniform rounded top on every card's image — some source screenshots
     (remitly, pay with a link) already have a phone bezel baked in, but
     others (news feed, duocon) don't, which reads as misaligned even
     when the Y position is identical. This makes all five consistent
     regardless of what's in the source file. */
  border-radius: 14px 14px 0 0;
  transform: none; filter: none; transition: none;
}

/* ---------- EXPAND PANEL ---------- */
.v2-card-expand {
  flex: 0 0 0; width: 0; overflow: hidden; position: relative;
  border-left: 1px solid rgba(255,255,255,0.18);
  transition: width var(--liquid-duration) var(--liquid-ease), opacity 0.5s ease;
  opacity: 0; padding: 0; color: #fff;
  display: flex; flex-direction: column; gap: 18px; justify-content: center;
}
.v2-card.is-open .v2-card-expand {
  flex-basis: 420px; width: 420px; opacity: 1; padding: 32px 32px;
}
.v2-card.on-light .v2-card-expand { border-left-color: rgba(0,0,0,0.12); color: var(--v2-black); }
.v2-card.duocon .v2-card-expand { color: var(--v2-black); }

.v2-card-close {
  position: absolute; top: 24px; right: 28px;
  background: none; border: none; padding: 4px; margin: 0;
  font-size: 24px; color: inherit; opacity: 0.6; cursor: pointer; line-height: 1;
  transition: opacity 0.2s ease, transform 0.2s var(--liquid-ease);
}
.v2-card-close:hover { opacity: 1; transform: scale(1.1); }

/* Number + label sit on one row, like the reference — the label given
   generous room (420px panel) and white-space:nowrap so it never wraps
   to a second line. Each stat cascades in with a short stagger once the
   card is open, rather than appearing all at once. */
.v2-stat {
  color: #fff; display: flex; align-items: baseline; gap: 10px; white-space: nowrap;
  opacity: 0; transform: translateY(10px);
  transition: opacity 0.5s ease, transform 0.5s var(--liquid-ease);
  transition-delay: 0s;
}
.v2-card.is-open .v2-stat { opacity: 1; transform: translateY(0); }
.v2-card.is-open .v2-stat:nth-child(2) { transition-delay: 0.06s; }
.v2-card.is-open .v2-stat:nth-child(3) { transition-delay: 0.12s; }
.v2-card.is-open .v2-stat:nth-child(4) { transition-delay: 0.18s; }
.v2-card.is-open .v2-stat:nth-child(5) { transition-delay: 0.24s; }
.v2-card.on-light .v2-stat { color: var(--v2-black); }
.v2-stat-num {
  /* Inclusive Sans throughout — this used to be set to Karla by mistake. */
  font-weight: 700; font-size: 32px; line-height: 1.1;
  flex: 0 0 auto;
}
.v2-stat-label { font-size: 13px; opacity: 0.75; line-height: 1.4; flex: 0 0 auto; }

.v2-card-soon { color: #fff; font-size: 15px; opacity: 0.8; }
.v2-card.on-light .v2-card-soon { color: var(--v2-black); }

/* card 1 — remitly business */
.v2-card.remitly { background: var(--v2-remitly); }

/* Per-card side-inset tuning only — every card shares the same 383px
   height (the base .v2-card rule) so the row stays a clean, even-topped
   line. Each source screenshot still has its own drop-shadow quirks
   (some sit dead-center in their canvas, some are shifted a few px one
   way), so the horizontal inset is nudged per card to keep the phone
   graphic itself visually centered — the taller images just get a
   little more of themselves clipped off the bottom, never a gap. */
.v2-card.remitly .v2-card-shot { left: 6px; right: 10px; }

/* card 2 — duolingo news feed */
.v2-card.newsfeed { background: var(--v2-newsfeed); }
.v2-card.newsfeed .v2-card-shot { left: 2px; right: 14px; }

/* card 3 — pay with a link */
.v2-card.paylink { background: var(--v2-paylink-bg); }

/* card 4 — duocon: frosted dragon (Daenerys/High Valyrian nod) as a
   full-card background — scoping it to just the shot rectangle made it
   crop in too tight and stop reading as a background image, so it spans
   the whole card again. The sharp badge photo sits on top of it inside
   .v2-card-shot, using the exact same alignment/rounding treatment as
   every other card's peek image. */
.v2-card.duocon { background: #f4f2ee; }
.v2-card.duocon::before {
  content: ''; position: absolute; inset: -12px; z-index: 0;
  background-image: url('/assets/images/duocon/07-danydraca.png');
  background-size: cover; background-position: center 48%;
  filter: blur(4px) saturate(0.9) brightness(1.25);
}
.v2-card.duocon::after {
  content: ''; position: absolute; inset: 0; z-index: 0;
  /* #EAEAEA wash, not white — gives it a touch of contrast against the
     page background instead of washing out to pure white. */
  background: rgba(234,234,234,0.55);
  backdrop-filter: blur(1px);
}
.v2-card.duocon .v2-card-title,
.v2-card.duocon .v2-card-desc,
.v2-card.duocon .v2-stat { color: var(--v2-black); }
.v2-card.duocon .v2-card-expand { border-left-color: rgba(0,0,0,0.12); }
/* .v2-card-title/-desc/-shot already carry their own z-index (3/1/2) from
   the shared rules above, which is enough to sit above this card's own
   ::before/::after background layers (z-index 0) — only .v2-card-expand
   needs the explicit bump, since it's otherwise unpositioned. */
.v2-card.duocon .v2-card-expand { position: relative; z-index: 1; }
/* No shadow on the badge photo itself (the source PNG's own baked-in
   border/shadow was cropped off separately); rounded top matches every
   other card's peek image via the shared .v2-card-shot img rule. */
.v2-card.duocon .v2-card-shot img { box-shadow: none; }
/* This photo has no baked-in shadow at all — it's edge to edge already,
   so the side insets stay symmetric (the shared default). */

/* card 5 — duolingo streak society */
.v2-card.streak { background: var(--v2-streak); }
.v2-card.streak .v2-card-shot { left: 1px; right: 15px; }

/* ---------- NUGGETS (placeholder) ---------- */
/* Same max-width + centering + padding recipe as .v2-section-head /
   .v2-scroll-wrap above, so this row's left edge always lines up with the
   "Random nuggets" label. The tiles themselves stay a fixed compact size
   (not stretched full-width) via minmax + justify-content: start. */
.v2-nugget-row {
  display: grid; grid-template-columns: repeat(4, minmax(0, 160px)); justify-content: start; gap: 16px;
  max-width: 1600px; margin: 0 auto; padding: 0 96px; box-sizing: border-box;
}
.v2-nugget { aspect-ratio: 3/4; border-radius: 10px; background: #ececea; }
.v2-nugget.dark { background: #d8d8d4; }

.v2-footer-spacer { height: 40px; }

/* ---------- RESPONSIVE ---------- */
@media (max-width: 640px) {
  .v2-nav, .v2-section-head, .v2-hero { padding-left: 24px; padding-right: 24px; }
  .v2-callout { padding: 0 24px; }
  .v2-card-row { padding-left: 24px; padding-right: 24px; }
  .v2-nugget-row { grid-template-columns: repeat(2, 1fr); padding: 0 24px; }
  .v2-card.is-open { width: 460px; }
  .v2-card.is-open .v2-card-expand { flex-basis: 192px; width: 192px; padding: 28px 18px; }
}
