/* =========================================================
   Jad Ayoubi — Portfolio
   Design system: deep navy/near-black base, emerald accent.
   Type: Archivo (grotesque, UI + body) paired on a contrast axis
   with Petrona (serif, editorial display) and JetBrains Mono
   (technical metadata). Three roles, three distinct voices.
   ========================================================= */

/* Metric-matched fallbacks. Archivo arrives via display=swap, so text first
   paints in a fallback and reflows when the real font lands — measured at
   CLS 0.20 on mobile. size-adjust makes each fallback's advance width equal
   Archivo's, so line breaks (and the 56ch measure) survive the swap intact.
   Two faces because the local() source differs by platform. */
@font-face {
  font-family: "Archivo Fallback";
  src: local("Helvetica Neue");
  size-adjust: 98.12%;
}
@font-face {
  font-family: "Archivo Fallback Arial";
  src: local("Arial");
  size-adjust: 99.57%;
}

:root {
  /* --- Surfaces (cool near-black navy) --- */
  --bg:        #070a11;
  --bg-soft:   #0a0e17;
  --surface:   #0e131e;
  --surface-2: #131a28;
  --surface-3: #18212f;

  /* --- Lines --- */
  --line:      rgba(255, 255, 255, 0.07);
  --line-strong: rgba(255, 255, 255, 0.12);

  /* --- Text --- */
  --text:      #eef2f8;
  --text-dim:  #9aa7ba;
  --text-faint:#828ea3;   /* ~5:1 on --bg, meets WCAG AA for small text */

  /* --- Accent (emerald) --- */
  --accent:        #18d99b;
  --accent-bright: #3df0b3;
  --accent-deep:   #0f9d76;
  --accent-glow:   rgba(24, 217, 155, 0.35);
  --accent-tint:   rgba(24, 217, 155, 0.10);
  --accent-line:   rgba(24, 217, 155, 0.28);

  /* --- Type --- */
  --font-sans: "Archivo", "Archivo Fallback", "Archivo Fallback Arial", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-serif: "Petrona", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* --- Layout --- */
  --maxw: 1180px;
  --gutter: clamp(20px, 5vw, 56px);
  --radius: 16px;
  --radius-sm: 10px;
  --radius-lg: 24px;

  --shadow: 0 24px 60px -28px rgba(0, 0, 0, 0.85);
  --shadow-accent: 0 18px 50px -22px var(--accent-glow);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  /* Gentle easing — eased at BOTH ends so hover-in and hover-out
     are equally smooth (no harsh snap on leave). */
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
  /* Decisive "settle" curve for entrance reveals (type setting into place). */
  --ease-entrance: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 92px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.65;
  font-weight: 400;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Ambient background: faint grid + emerald glows fixed behind everything */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    /* emerald — top right (primary) */
    radial-gradient(620px 520px at 82% -4%, rgba(24, 217, 155, 0.14), transparent 60%),
    /* emerald — bottom left (balances the frame) */
    radial-gradient(640px 560px at 2% 96%, rgba(24, 217, 155, 0.13), transparent 62%),
    /* cool blue — top left (subtle variety) */
    radial-gradient(700px 580px at 6% 8%, rgba(24, 120, 217, 0.06), transparent 62%),
    /* emerald — faint mid right */
    radial-gradient(520px 460px at 99% 64%, rgba(24, 217, 155, 0.05), transparent 60%),
    /* emerald — faint lower center */
    radial-gradient(680px 420px at 55% 108%, rgba(24, 217, 155, 0.05), transparent 62%),
    linear-gradient(to bottom, transparent, rgba(0,0,0,0.34) 100%);
}
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.4;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(ellipse 90% 60% at 50% 0%, #000 10%, transparent 75%);
          mask-image: radial-gradient(ellipse 90% 60% at 50% 0%, #000 10%, transparent 75%);
}

main, nav, footer { position: relative; z-index: 1; }

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

::selection { background: var(--accent); color: #04130d; }

:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Skip link — visible only when focused via keyboard */
.skip-link {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 200;
  transform: translateY(-150%);
  background: var(--accent);
  color: #04130d;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  padding: 13px 18px;
  border-radius: 999px;
  box-shadow: var(--shadow-accent);
  transition: transform .25s var(--ease);
}
.skip-link:focus-visible { transform: translateY(0); }

/* ---------------------------------------------------------
   Layout helpers
   --------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: clamp(72px, 11vw, 132px);
  position: relative;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 18px;
  font-weight: 500;
}
.eyebrow::before {
  content: "";
  width: 26px;
  height: 1px;
  background: var(--accent-line);
}

.section-head { max-width: 720px; margin-bottom: clamp(40px, 6vw, 64px); }
.section-title {
  font-size: clamp(28px, 4.6vw, 46px);
  line-height: 1.06;
  letter-spacing: -0.03em;
  font-weight: 700;
  margin: 0 0 16px;
}
.section-sub {
  color: var(--text-dim);
  font-size: clamp(16px, 1.4vw, 18px);
  margin: 0;
  max-width: 60ch;
}

/* ---------------------------------------------------------
   Buttons
   --------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  padding: 13px 22px;
  border-radius: 999px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform .35s var(--ease), background .25s, border-color .25s, box-shadow .35s var(--ease), color .25s;
  white-space: nowrap;
}
.btn svg { width: 17px; height: 17px; transition: transform .35s var(--ease-soft); }
/* Press feedback works on touch (tap), so it stays unscoped */
.btn:active { transform: translateY(0) scale(0.97); transition-duration: .12s; }
@media (hover: hover) {
  .btn:hover { transform: translateY(-2px); }
  /* Arrow motion reinforces meaning: "go" moves right, "download" nudges down */
  .hero-cta .btn-primary:hover svg { transform: translateX(3px); }
  .btn[download]:hover svg { transform: translateY(2px); }
}

.btn-primary {
  background: var(--accent);
  color: #04130d;
  box-shadow: 0 10px 30px -12px var(--accent-glow);
}
@media (hover: hover) {
  .btn-primary:hover {
    background: var(--accent-bright);
    box-shadow: 0 18px 44px -14px var(--accent-glow);
  }
}
.btn-ghost {
  background: rgba(255,255,255,0.03);
  border-color: var(--line-strong);
  color: var(--text);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
}
@media (hover: hover) { .btn-ghost:hover { border-color: var(--accent-line); background: var(--accent-tint); color: var(--text); } }

.btn-sm { padding: 9px 15px; font-size: 13.5px; }

/* ---------------------------------------------------------
   Navbar
   --------------------------------------------------------- */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  transition: background .35s, border-color .35s, backdrop-filter .35s;
  border-bottom: 1px solid transparent;
}
.nav.scrolled {
  background: rgba(7, 10, 17, 0.72);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
          backdrop-filter: blur(16px) saturate(140%);
  border-bottom-color: var(--line);
}
.nav-inner {
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-size: 17px;
  padding-block: 4px;   /* lifts the tap target to 46px */
}
.brand-mark {
  width: 38px; height: 38px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 15px;
  color: #04130d;
  background: linear-gradient(135deg, var(--accent-bright), var(--accent-deep));
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.18), 0 8px 20px -10px var(--accent-glow);
}
.brand-sub { color: var(--text-faint); font-family: var(--font-mono); font-size: 12px; font-weight: 400; display: block; letter-spacing: 0.02em; }

.nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
  list-style: none;
  margin: 0; padding: 0;
}
.nav-links a {
  font-size: 14.5px;
  font-weight: 500;
  color: var(--text-dim);
  padding: 11px 14px;
  border-radius: 999px;
  transition: color .25s var(--ease-soft);
  position: relative;
  display: block;
}
/* Animated underline indicator — faint on hover, solid on active */
.nav-links a::after {
  content: "";
  position: absolute;
  left: 14px; right: 14px; bottom: 3px;
  height: 2px; border-radius: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: center;
  opacity: 0;
  transition: transform .4s var(--ease-soft), opacity .3s var(--ease-soft);
}
@media (hover: hover) {
  .nav-links a:hover { color: var(--text); }
  .nav-links a:hover::after { transform: scaleX(0.55); opacity: 0.4; }
}
.nav-links a.active { color: var(--accent); }
.nav-links a.active::after { transform: scaleX(1); opacity: 1; }
.nav-cta { display: flex; align-items: center; gap: 10px; }

.nav-mobile { display: none; }

/* ---------------------------------------------------------
   Section dot navigation (right rail) — shows current section,
   jumps on click, reveals the section name on hover/focus
   --------------------------------------------------------- */
.dot-nav {
  position: fixed;
  right: clamp(12px, 1.6vw, 26px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.dot {
  position: relative;
  width: 26px; height: 26px;       /* comfortable hit area */
  display: grid; place-items: center;
  border-radius: 50%;
}
.dot::before {                      /* the visible dot */
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--text-faint);
  opacity: 0.5;
  transition: transform .4s var(--ease-soft), background .4s var(--ease-soft),
              opacity .4s var(--ease-soft), box-shadow .4s var(--ease-soft);
}
.dot.is-active::before {
  background: var(--accent);
  opacity: 1;
  transform: scale(1.3);
  box-shadow: 0 0 0 4px var(--accent-tint), 0 0 14px var(--accent-glow);
}
.dot:focus-visible { outline: none; }
.dot:focus-visible::before { box-shadow: 0 0 0 3px var(--accent-bright); }
@media (hover: hover) {
  .dot:hover::before { background: var(--text-dim); opacity: 1; transform: scale(1.25); }
  .dot.is-active:hover::before { background: var(--accent); }
}

/* Section-name label pill (left of the dot) */
.dot-label {
  position: absolute;
  right: calc(100% + 12px);
  top: 50%;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--text);
  background: rgba(10, 14, 23, 0.92);
  border: 1px solid var(--line-strong);
  padding: 6px 11px;
  border-radius: 8px;
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
  box-shadow: var(--shadow);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-50%) translateX(6px);
  transition: opacity .3s var(--ease-soft), transform .3s var(--ease-soft);
}
.dot-label::after {                 /* small arrow pointing at the dot */
  content: "";
  position: absolute;
  left: 100%; top: 50%;
  transform: translateY(-50%);
  border: 5px solid transparent;
  border-left-color: var(--line-strong);
}
.dot:focus-visible .dot-label { opacity: 1; transform: translateY(-50%) translateX(0); }
@media (hover: hover) {
  .dot:hover .dot-label { opacity: 1; transform: translateY(-50%) translateX(0); }
}

/* Hide on smaller screens — the top nav handles wayfinding there */
@media (max-width: 900px) { .dot-nav { display: none; } }

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  border-radius: 12px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--line-strong);
  cursor: pointer;
  padding: 0;
  align-items: center; justify-content: center;
}
.nav-toggle span {
  display: block; width: 18px; height: 2px; background: var(--text);
  position: relative; transition: transform .3s var(--ease), opacity .2s;
}
.nav-toggle span::before, .nav-toggle span::after {
  content: ""; position: absolute; left: 0; width: 18px; height: 2px; background: var(--text);
  transition: transform .3s var(--ease);
}
.nav-toggle span::before { top: -6px; }
.nav-toggle span::after { top: 6px; }
.nav.open .nav-toggle span { background: transparent; }
.nav.open .nav-toggle span::before { transform: translateY(6px) rotate(45deg); }
.nav.open .nav-toggle span::after { transform: translateY(-6px) rotate(-45deg); }

/* ---------------------------------------------------------
   Hero
   --------------------------------------------------------- */
.hero {
  padding-top: clamp(120px, 17vh, 184px);
  padding-bottom: clamp(64px, 9vw, 110px);
}
.hero-grid {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(36px, 5vw, 72px);
  align-items: center;
}
/* Allow grid children to shrink below content size (prevents the code
   card from stretching the shared column and overflowing on mobile). */
.hero-copy, .hero-visual { min-width: 0; }
.hero h1, .hero-lead { overflow-wrap: break-word; }

.hero h1 {
  font-size: clamp(38px, 5.8vw, 68px);
  line-height: 1.04;
  letter-spacing: -0.032em;
  font-weight: 700;
  margin: 0 0 24px;
  text-wrap: balance;
}
/* Solid accent — the emphasis is the colour, not a gradient */
.hero h1 .accent { color: var(--accent); }
.hero-lead {
  font-size: clamp(16.5px, 1.55vw, 18.5px);
  color: var(--text-dim);
  max-width: 56ch;
  margin: 0 0 34px;
  text-wrap: pretty;
}
.hero-lead strong { color: var(--text); font-weight: 600; }

.hero-cta { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 40px; }

/* Three equal columns so the third stat never orphans onto its own row.
   Labels wrap inside their column instead of breaking the grid. */
.hero-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 2.2vw, 26px);
  max-width: 560px;
}
.stat .num {
  font-size: clamp(26px, 2.4vw, 30px); font-weight: 700; letter-spacing: -0.03em;
  display: block; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.stat .num span { color: var(--accent); }
.stat .label {
  font-family: var(--font-mono);
  font-size: 11.5px; color: var(--text-faint);
  text-transform: uppercase; letter-spacing: 0.06em;
  line-height: 1.4;
  margin-top: 8px; display: block;
}

/* Hero visual settles in with a subtle scale (depth) after the copy */
.hero-visual.reveal { transform: translateY(26px) scale(0.985); }
.hero-visual.reveal.in { transform: none; }

/* Hero code card.
   The stage exists so the floating badges can sit outside the card's
   rounded clip — as children of .code-card they were cut off by its
   own `overflow: hidden`. */
.code-stage {
  position: relative;
  /* room for the badges that hang off the corners */
  margin: 26px 12px 16px 18px;
}
.code-card {
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
  position: relative;
  /* smooths the pointer-parallax trailing motion (set via JS) */
  transition: transform .5s var(--ease-soft);
  will-change: transform;
}
.float-badge { transition: transform .6s var(--ease-soft); }
.code-card::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
}
.code-glow {
  position: absolute;
  inset: auto -30% -45% -10%;
  height: 70%;
  background: radial-gradient(60% 100% at 50% 100%, var(--accent-glow), transparent 70%);
  filter: blur(20px);
  z-index: -1;
}
.code-head {
  display: flex; align-items: center; gap: 8px;
  /* Extra top padding keeps the dots + filename clear of the floating
     badge that overlaps the card's top-left corner. */
  padding: 19px 18px 14px;
  border-bottom: 1px solid var(--line);
  background: rgba(255,255,255,0.015);
}
/* Window chrome dots. Named .win-dot so they don't collide with the
   .dot section-nav rail, which they were silently resizing to 11px. */
.win-dot { width: 11px; height: 11px; border-radius: 50%; flex-shrink: 0; }
.win-dot.r { background: #ff5f57; } .win-dot.y { background: #febc2e; } .win-dot.g { background: #28c840; }
.code-file {
  margin-left: 12px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text-faint);
}
.code-body {
  font-family: var(--font-mono);
  /* Fluid so the snippet fits the card instead of overflowing on phones */
  font-size: clamp(11px, 2.6vw, 13.5px);
  line-height: 1.85;
  padding: 22px 22px 26px;
  margin: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-text-size-adjust: 100%;
}
.code-body .ln { color: var(--text-faint); display: inline-block; width: 22px; user-select: none; opacity: 0.6; }
.tok-key { color: #c98bff; }
.tok-fn  { color: var(--accent-bright); }
.tok-str { color: #e9c891; }
.tok-prop{ color: #7fb3ff; }
.tok-com { color: var(--text-faint); font-style: italic; }
.tok-pun { color: var(--text-dim); }

.float-badge {
  position: absolute;
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono);
  font-size: 12px; font-weight: 500;
  background: rgba(14, 19, 30, 0.9);
  border: 1px solid var(--line-strong);
  padding: 9px 13px;
  border-radius: 12px;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: var(--shadow);
}
.float-badge .fb-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.float-badge.a { top: -24px; left: -18px; }
.float-badge.b { bottom: -16px; right: -12px; }
/* Badges are decorative chrome; below the code card's own breakpoint they
   crowd the card, so they're hidden rather than overlapped (see @600px). */

/* Marquee of tools */
.marquee {
  border-block: 1px solid var(--line);
  background: rgba(255,255,255,0.012);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
/* gap:0 is load-bearing. The loop assumes the track is exactly two identical
   copies, so translateX(-50%) lands on the duplicate. A flex `gap` would add
   one extra space *between* the copies, making the strip jump every cycle.
   All spacing therefore lives on the chip's own separator margins. */
.marquee-track {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  gap: 0;
  align-items: center;
  padding-block: 18px;
  width: max-content;
  animation: scroll-x 60s linear infinite;
}
.marquee-track span {
  font-family: var(--font-mono);
  font-size: 15px; color: var(--text-faint);
  white-space: nowrap; letter-spacing: 0.02em;
  display: inline-flex; align-items: center; gap: 10px;
}
/* Separator carries the inter-chip spacing, centred between the two names */
.marquee-track span::after {
  content: "/";
  margin-inline: 30px;
  color: var(--accent-line);
}
.mq-ico {
  width: 17px; height: 17px;
  flex: none;
  fill: currentColor;
}
@keyframes scroll-x { to { transform: translateX(-50%); } }

/* ---------------------------------------------------------
   Status badges (Live / In Development)
   --------------------------------------------------------- */
.status {
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 500;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: 0.06em;
  white-space: nowrap;
}
.status .status-pulse {
  position: relative;
  width: 7px; height: 7px; border-radius: 50%;
  background: currentColor;
}
.status .status-pulse::after {
  content: "";
  position: absolute; inset: -3px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
  animation: badge-pulse 2.2s var(--ease) infinite;
}
@keyframes badge-pulse {
  0% { transform: scale(0.6); opacity: 0.5; }
  70% { transform: scale(1.8); opacity: 0; }
  100% { transform: scale(0.6); opacity: 0; }
}
.status.live   { color: var(--accent-bright); background: var(--accent-tint); border: 1px solid var(--accent-line); }
.status.dev    { color: #f0c14b; background: rgba(240,193,75,0.12); border: 1px solid rgba(240,193,75,0.30); }

/* ---------------------------------------------------------
   Editorial typography for the Work section
   --------------------------------------------------------- */
.work-header { margin-bottom: clamp(56px, 8vw, 96px); }
.work-tag {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(28px, 4vw, 44px);
}
.work-tag .eyebrow { margin: 0; }
.work-year-range {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text-faint);
  letter-spacing: 0.06em;
}

.work-display {
  font-family: var(--font-serif);
  /* Ceiling held at 96px; Petrona sets wider than the old face, so the
     same optical size needs a lower cap to stay on three lines. */
  font-size: clamp(40px, 7vw, 96px);
  line-height: 1.02;
  letter-spacing: -0.02em;
  font-weight: 500;
  margin: 0 0 clamp(32px, 5vw, 56px);
  color: var(--text);
  max-width: 18ch;
  text-wrap: balance;
}
.work-display em {
  font-style: italic;
  color: var(--accent-bright);
  font-weight: 500;
  position: relative;
}

.work-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 28px;
  align-items: center;
  font-family: var(--font-mono);
}
.ws-item {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
}
.ws-num {
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.ws-lbl {
  font-size: 12.5px;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.ws-divider {
  width: 1px; height: 16px;
  background: var(--line-strong);
  display: inline-block;
}

/* ---------------------------------------------------------
   The Index — vertical ledger of rows
   --------------------------------------------------------- */
.index {
  position: relative;
  /* No `perspective` here: it would make this element the containing block for
     the position:fixed preview, breaking its viewport-based cursor tracking.
     The preview carries its own perspective() instead. */
}

/* Floating cursor-following preview (desktop) */
.index-preview {
  position: fixed;
  top: 0; left: 0;
  width: clamp(280px, 26vw, 420px);
  pointer-events: none;
  z-index: 90;
  opacity: 0;
  visibility: hidden;
  transform: translate3d(var(--px, 0px), var(--py, 0px), 0)
             translate(-50%, -50%)
             perspective(1600px)
             scale(0.92)
             rotateX(var(--rx, 0deg))
             rotateY(var(--ry, 0deg));
  transform-style: preserve-3d;
  transform-origin: center center;
  transition: opacity .35s var(--ease), visibility .35s var(--ease),
              width .5s var(--ease-entrance);
  will-change: transform, opacity;
}
.index.is-active .index-preview {
  opacity: 1;
  visibility: visible;
}
.index-preview-frame {
  position: relative;
  width: 100%;
  aspect-ratio: var(--frame-ratio, 16 / 11);
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--line-strong);
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(24,217,155,0.06), transparent 60%),
    var(--surface-2);
  box-shadow:
    0 40px 80px -28px rgba(0,0,0,0.85),
    0 16px 40px -16px var(--accent-glow),
    inset 0 1px 0 rgba(255,255,255,0.06);
  transform: translateZ(0);
  transition: aspect-ratio .5s var(--ease-entrance),
              padding .5s var(--ease-entrance),
              border-radius .5s var(--ease-entrance),
              background-color .4s var(--ease);
}
/* Clips the artwork so the frame itself is free to carry device chrome
   (bezel padding, a title bar) outside the screen area. */
.index-preview-screen {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  transition: border-radius .5s var(--ease-entrance);
}
.index-preview-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  object-position: center;
  opacity: 0;
  transition: opacity .45s var(--ease);
  will-change: opacity;
}
.index-preview-img.is-current { opacity: 1; }

/* ---- Device frames (per image, driven by "|phone" / "|browser" in data-imgs) ---- */

/* Phone: narrow portrait body with a real bezel, so app screenshots read as
   a handset rather than a cropped landscape card. */
.index-preview.is-phone { width: clamp(188px, 15vw, 248px); }
.index-preview.is-phone .index-preview-frame {
  border-radius: 26px;
  overflow: visible;                 /* lets the progress bar sit above the device */
  border-color: rgba(255, 255, 255, 0.16);
  background: linear-gradient(170deg, #23262f, #10131a 60%, #05070b);
  box-shadow:
    0 44px 90px -30px rgba(0, 0, 0, 0.9),
    0 18px 44px -18px var(--accent-glow),
    inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
/* The bezel is an inset on the screen, not padding on the frame: an absolutely
   positioned child resolves inset:0 against the padding *edge*, so padding here
   would sit under the artwork instead of framing it.
   The radius stays modest on purpose — these are raw device captures whose
   status bar runs to the very edge, and a large radius clips the clock. */
.index-preview.is-phone .index-preview-screen {
  inset: 9px;
  border-radius: 16px;
}
/* The frame ratio includes the bezel, so cover (not contain) keeps the screen full-bleed. */
.index-preview.is-phone .index-preview-img { object-fit: cover; }
/* Side buttons */
.index-preview.is-phone .index-preview-frame::before,
.index-preview.is-phone .index-preview-frame::after {
  content: "";
  position: absolute;
  right: -11px;
  width: 2px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.22);
}
.index-preview.is-phone .index-preview-frame::before { top: 24%; height: 7%; }
.index-preview.is-phone .index-preview-frame::after  { top: 34%; height: 13%; }

/* Browser: the same artwork slot wearing window chrome, for admin/desktop shots. */
.index-preview.is-browser { width: clamp(300px, 30vw, 470px); }
.index-preview.is-browser .index-preview-frame {
  border-radius: 12px;
  background:
    radial-gradient(circle 3.5px at 16px 13px, #ff5f57 96%, transparent),
    radial-gradient(circle 3.5px at 31px 13px, #febc2e 96%, transparent),
    radial-gradient(circle 3.5px at 46px 13px, #28c840 96%, transparent),
    linear-gradient(#1e222c, #1e222c);
  /* Border-box origin puts the dots in the title bar; the default padding-box
     origin would draw them underneath the screenshot. */
  background-origin: border-box;
}
.index-preview.is-browser .index-preview-screen {
  inset: 24px 0 0 0;               /* clears the title bar drawn by the background */
  border-radius: 0 0 11px 11px;
}
.index-preview.is-browser .index-preview-img { object-fit: cover; object-position: top center; }

/* The screenshots bring their own chrome — the technical grid overlay would
   only read as dirt on top of a device screen. */
.index-preview.is-phone .index-preview-grid,
.index-preview.is-browser .index-preview-grid { opacity: 0; }

/* Lift the story bar out of the screen so it never fights the app's own
   status bar — above the handset, and inside the window chrome for browsers. */
.index-preview.is-phone .index-preview-progress {
  top: -19px;
  left: 1px;
  right: 1px;
}
.index-preview.is-browser .index-preview-progress {
  top: 10px;                /* centred in the 24px title bar */
  left: 62px;               /* clears the three window dots */
  right: 10px;
}

/* A 188px-wide handset cannot hold the domain pill and the arrow side by side */
.index-preview.is-phone .index-preview-caption {
  justify-content: center;
  font-size: 10.5px;
  margin-top: 14px;
}
.index-preview.is-phone .ipc-arrow,
.index-preview.is-nolink .ipc-arrow { display: none; }
/* With the arrow gone the pill is the only thing left — centre it rather than
   leaving it pinned to one side by space-between. */
.index-preview.is-nolink .index-preview-caption { justify-content: center; }
.index-preview.is-phone .ipc-domain { padding: 5px 10px; }
.index-preview-grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px);
  background-size: 32px 32px;
  pointer-events: none;
  mix-blend-mode: overlay;
  opacity: 0.4;
}

/* Story-style segmented progress bar (only renders for multi-image projects) */
.index-preview-progress {
  position: absolute;
  top: 12px;
  left: 12px;
  right: 12px;
  display: flex;
  gap: 5px;
  z-index: 4;
  opacity: 0;
  transition: opacity .3s var(--ease);
}
.index-preview-progress.is-on { opacity: 1; }
.ipp-seg {
  flex: 1;
  height: 3px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.18);
  overflow: hidden;
  position: relative;
  -webkit-backdrop-filter: blur(4px);
          backdrop-filter: blur(4px);
}
.ipp-seg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--accent-bright), var(--accent));
  box-shadow: 0 0 10px var(--accent-glow);
  transform: scaleX(0);
  transform-origin: left center;
  will-change: transform;
}
.ipp-seg.is-done::after { transform: scaleX(1); }
.ipp-seg.is-active::after {
  animation: ipp-fill var(--seg-duration, 2800ms) linear forwards;
}
@keyframes ipp-fill {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
.index-preview-caption {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-dim);
  letter-spacing: 0.04em;
}
.ipc-domain {
  background: rgba(7,10,17,0.85);
  border: 1px solid var(--line);
  padding: 6px 12px;
  border-radius: 999px;
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
}
.ipc-arrow {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--accent);
  color: #04130d;
  display: grid; place-items: center;
}
.ipc-arrow svg { width: 14px; height: 14px; }

/* ---- Rows ---- */
.index-row {
  --row-pad-y: clamp(22px, 3.4vw, 38px);
  --indent: 0px;
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) auto 56px;
  align-items: center;
  gap: clamp(18px, 3vw, 44px);
  padding: var(--row-pad-y) 0;
  border-top: 1px solid var(--line);
  position: relative;
  color: var(--text);
  text-decoration: none;
  transition:
    background-color .4s var(--ease),
    border-color .4s var(--ease),
    opacity .45s var(--ease-soft);
}
/* The hover indent rides on the independent `translate` property rather
   than padding-left: it composites instead of triggering layout, and it
   stacks with the JS scroll-parallax that writes to `transform` without
   either one clobbering the other. */
.index-row > * { translate: var(--indent) 0; transition: translate .55s var(--ease); }
.index-row::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--accent-tint) 0%, transparent 35%);
  opacity: 0;
  transition: opacity .5s var(--ease);
  pointer-events: none;
}
@media (hover: hover) {
  .index-row:hover::before { opacity: 1; }
  .index-row:hover {
    --indent: clamp(8px, 2vw, 28px);
    border-top-color: var(--accent-line);
  }
  /* Focus: hovering one project quietly recedes the others (Linear-style list focus).
     :has scopes it so it only fires while a row is actually hovered. */
  .index:has(.index-row:hover) .index-row:not(:hover) { opacity: 0.45; }
}

/* Lead project carries a persistent, quiet accent so the eye lands there first */
.index-row.is-featured .index-num { color: var(--accent); }
/* The rail hangs in the page gutter, not at the row's left edge — at left:0 it
   sat directly under the N of N°01, and the hover indent only cleared it while
   hovered. Scaling the pull-out off --gutter keeps it off-canvas at every width. */
.index-row.is-featured::after {
  content: "";
  position: absolute;
  left: calc(var(--gutter) * -0.4); top: 50%;
  width: 3px; height: 40%;
  transform: translateY(-50%);
  background: linear-gradient(var(--accent-bright), var(--accent));
  border-radius: 2px;
  opacity: 0.7;
  box-shadow: 0 0 12px var(--accent-glow);
}
@media (hover: hover) { .index-row:hover + .index-row { border-top-color: var(--accent-line); } }
.index-row:last-child {
  border-bottom: 1px solid var(--line);
}
.index-row > * { position: relative; z-index: 1; }

.index-num {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  color: var(--text-faint);
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  transition: color .4s var(--ease);
}
@media (hover: hover) { .index-row:hover .index-num { color: var(--accent); } }

.index-body { min-width: 0; }
.index-title {
  font-family: var(--font-serif);
  font-size: clamp(28px, 4.6vw, 62px);
  letter-spacing: -0.022em;
  line-height: 1.06;
  margin: 0;
  font-weight: 500;
  color: var(--text);
  transition: color .4s var(--ease), transform .6s var(--ease);
  will-change: transform;
}
@media (hover: hover) {
  .index-row:hover .index-title {
    color: var(--accent-bright);
    font-style: italic;
  }
}
.index-meta {
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-faint);
  transition: color .4s var(--ease);
}
@media (hover: hover) { .index-row:hover .index-meta { color: var(--text-dim); } }
.index-meta .meta-sep {
  color: var(--text-faint);
  margin: 0 6px;
  opacity: 0.6;
}

.index-status-col {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  text-align: right;
  white-space: nowrap;
}
.index-domain {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-faint);
  letter-spacing: 0.02em;
}
@media (hover: hover) { .index-row:hover .index-domain { color: var(--text-dim); } }

.index-arrow {
  width: 48px; height: 48px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  display: grid; place-items: center;
  color: var(--text-dim);
  transition:
    background .4s var(--ease),
    border-color .4s var(--ease),
    color .4s var(--ease),
    transform .55s var(--ease);
  flex-shrink: 0;
}
.index-arrow svg { width: 16px; height: 16px; transition: transform .5s var(--ease); }
@media (hover: hover) {
  .index-row:hover .index-arrow {
    background: var(--accent);
    border-color: var(--accent);
    color: #04130d;
    transform: rotate(-45deg);
    box-shadow: 0 12px 30px -8px var(--accent-glow);
  }
  .index-row:hover .index-arrow svg { transform: rotate(45deg); }
}

/* ---- No-link rows (private / NDA projects) ---- */
.index-row.is-nolink { cursor: default; }
/* Keep the row interactive enough to trigger the preview, but signal
   it isn't a link: muted lock glyph, no accent/rotate on hover. */
.index-row.is-nolink .index-arrow.is-lock {
  color: var(--text-faint);
  cursor: default;
}
@media (hover: hover) {
  .index-row.is-nolink:hover .index-arrow.is-lock {
    background: transparent;
    border-color: var(--line-strong);
    color: var(--text-dim);
    transform: none;
    box-shadow: none;
  }
  .index-row.is-nolink:hover .index-arrow.is-lock svg { transform: none; }
}
.index-row.is-nolink .index-domain {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.8;
}

.index-thumb-mobile {
  display: none;
}

/* ---- Extras (hidden until expanded) ---- */
.index-row.is-extra {
  display: grid;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  border-top-width: 0;
  height: 0;
  padding-block: 0;
  overflow: hidden;
  transform: translateY(8px);
  transition:
    opacity .55s var(--ease),
    transform .55s var(--ease),
    height .55s var(--ease),
    padding-block .55s var(--ease),
    border-top-width .25s var(--ease);
}
.index.is-expanded .index-row.is-extra {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  border-top-width: 1px;
  height: auto;
  padding-block: var(--row-pad-y);
  transform: none;
}
/* Staggered reveal — nth-child (type-agnostic, since rows are a mix of
   <a> linked and <div> no-link elements). The .index-preview is child 1 and
   7 rows show by default, so the 9 extra rows are children 9–17. */
.index.is-expanded .index-row.is-extra            { transition-delay: 0ms; }
.index.is-expanded .index-row.is-extra:nth-child(10) { transition-delay: 40ms; }
.index.is-expanded .index-row.is-extra:nth-child(11) { transition-delay: 80ms; }
.index.is-expanded .index-row.is-extra:nth-child(12) { transition-delay: 120ms; }
.index.is-expanded .index-row.is-extra:nth-child(13) { transition-delay: 160ms; }
.index.is-expanded .index-row.is-extra:nth-child(14) { transition-delay: 200ms; }
.index.is-expanded .index-row.is-extra:nth-child(15) { transition-delay: 240ms; }
.index.is-expanded .index-row.is-extra:nth-child(16) { transition-delay: 280ms; }
.index.is-expanded .index-row.is-extra:nth-child(17) { transition-delay: 320ms; }

/* ---- Show-more button ---- */
.index-foot {
  margin-top: clamp(48px, 6vw, 72px);
  display: flex;
  justify-content: center;
}
.index-more {
  display: inline-flex;
  align-items: center;
  gap: clamp(16px, 2.5vw, 28px);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--text);
  font-family: var(--font-mono);
  width: 100%;
  max-width: 720px;
}
.im-rule {
  flex: 1;
  height: 1px;
  background: var(--line-strong);
  transition: background .4s var(--ease);
}
.im-text {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 14px 24px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  transition: all .35s var(--ease);
  white-space: nowrap;
}
.im-label {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.02em;
}
.im-count {
  font-size: 12px;
  color: var(--text-faint);
  background: rgba(255,255,255,0.04);
  padding: 3px 9px;
  border-radius: 999px;
  letter-spacing: 0.04em;
}
@media (hover: hover) {
  .index-more:hover .im-text {
    background: var(--accent);
    border-color: var(--accent);
    color: #04130d;
    transform: translateY(-2px);
    box-shadow: 0 14px 36px -10px var(--accent-glow);
  }
  .index-more:hover .im-count {
    background: rgba(4,19,13,0.18);
    color: #04130d;
  }
  .index-more:hover .im-rule { background: var(--accent-line); }
}

/* Hide-on-small helper used in display heading */
.hide-sm { display: inline; }

/* ---------------------------------------------------------
   Mobile adjustments for the Index
   --------------------------------------------------------- */
@media (max-width: 880px) {
  .index-preview { display: none; }
  .index-row {
    grid-template-columns: 56px 1fr auto;
    grid-template-areas:
      "num title status"
      "num meta  meta"
      "thumb thumb thumb";
    gap: 14px;
    align-items: start;
  }
  .index-num { grid-area: num; padding-top: 8px; }
  .index-body { grid-area: title; min-width: 0; }
  .index-meta { grid-area: meta; margin-top: 8px; }
  .index-status-col { grid-area: status; align-items: flex-end; }
  .index-status-col .index-domain { display: none; }
  /* With the domain hidden here, a column holding no status pill has nothing
     left to render — collapse it so it stops reserving a row on small phones. */
  .index-status-col:not(:has(.status)) { display: none; }
  .index-arrow { display: none; }
  .index-title {
    font-size: clamp(28px, 9vw, 44px);
  }
  .index-thumb-mobile {
    display: block;
    grid-area: thumb;
    width: 100%;
    height: auto;                /* override the img height attribute so aspect-ratio governs */
    aspect-ratio: 16 / 10;       /* reserve space → no layout shift on load */
    object-fit: cover;
    object-position: top center;
    background: var(--surface-2);
    border-radius: var(--radius-sm);
    border: 1px solid var(--line);
    margin-top: 14px;
  }
  .index-row:hover { --indent: 0px; }
  .index-row:hover .index-title { font-style: normal; }
  .hide-sm { display: none; }
  .work-display { font-size: clamp(38px, 11vw, 64px); }
}


/* ---------------------------------------------------------
   Timeline
   --------------------------------------------------------- */
.timeline { position: relative; max-width: 820px; }
.timeline::before {
  content: ""; position: absolute; left: 7px; top: 6px; bottom: 6px;
  width: 1px; background: linear-gradient(var(--accent-line), var(--line) 70%);
}
.tl-item {
  position: relative;
  --tl-shift: 0px;
  padding-left: 42px;
  padding-bottom: 44px;
  cursor: pointer;
}
.tl-item:last-child { padding-bottom: 0; }
/* Composited nudge (was an animated padding-left) */
.tl-item > * {
  position: relative; z-index: 1;
  translate: var(--tl-shift) 0;
  transition: translate .6s var(--ease-soft);
}

/* Hover highlight panel — sits to the right of the timeline rail.
   Soft, slow fade-in so it feels gentle rather than snappy. */
.tl-item::after {
  content: "";
  position: absolute;
  left: 24px; right: -20px; top: -12px; bottom: 24px;
  border-radius: 16px;
  background: linear-gradient(100deg, var(--accent-tint), rgba(255,255,255,0.012) 55%, transparent);
  border: 1px solid transparent;
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity .6s var(--ease-soft), transform .6s var(--ease-soft), border-color .6s var(--ease-soft);
  pointer-events: none;
  z-index: 0;
}
.tl-item:last-child::after { bottom: -12px; }
@media (hover: hover) {
  .tl-item:hover::after { opacity: 1; transform: translateX(0); border-color: var(--accent-line); }
  .tl-item:hover { --tl-shift: 8px; }
}

/* Timeline node */
.tl-item::before {
  content: ""; position: absolute; left: 0; top: 6px;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--bg); border: 2px solid var(--accent);
  box-shadow: 0 0 0 4px rgba(24,217,155,0.08);
  z-index: 2;
  transition: background .6s var(--ease-soft), box-shadow .6s var(--ease-soft), transform .6s var(--ease-soft);
}
@media (hover: hover) {
  .tl-item:hover::before {
    background: var(--accent);
    transform: scale(1.16);
    box-shadow: 0 0 0 6px rgba(24,217,155,0.10), 0 0 26px var(--accent-glow);
  }
}

.tl-date { font-family: var(--font-mono); font-size: 13px; color: var(--accent); margin-bottom: 8px; letter-spacing: 0.02em; transition: color .5s var(--ease-soft), letter-spacing .5s var(--ease-soft); }
.tl-item h3 { font-size: 20px; letter-spacing: -0.02em; margin: 0 0 4px; transition: color .5s var(--ease-soft); }
.tl-org { color: var(--text-dim); font-size: 15px; margin: 0 0 12px; transition: color .5s var(--ease-soft); }
@media (hover: hover) {
  .tl-item:hover .tl-date { color: var(--accent-bright); letter-spacing: 0.045em; }
  .tl-item:hover h3 { color: var(--accent-bright); }
  .tl-item:hover .tl-org { color: var(--text); }
}
.tl-item p { color: var(--text-dim); font-size: 15px; margin: 0; max-width: 60ch; }

/* ---------------------------------------------------------
   Skills
   --------------------------------------------------------- */
.skills-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
.skill-group {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 24px;
  cursor: pointer;
  transition:
    border-color .6s var(--ease-soft),
    transform .6s var(--ease-soft),
    box-shadow .6s var(--ease-soft),
    background .6s var(--ease-soft);
}
/* Soft emerald halo that fades in from the icon corner on hover */
.skill-group::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(120% 90% at 0% 0%, var(--accent-tint), transparent 55%);
  opacity: 0;
  transition: opacity .6s var(--ease-soft);
  pointer-events: none;
}
.skill-group > * { position: relative; z-index: 1; }
@media (hover: hover) {
  .skill-group:hover {
    transform: translateY(-5px);
    border-color: var(--accent-line);
    background: var(--surface-2);
    box-shadow:
      0 0 0 1px var(--accent-line),
      0 22px 54px -26px var(--accent-glow),
      0 0 42px -12px var(--accent-glow);
  }
  .skill-group:hover::before { opacity: 1; }
}
.skill-group h3 {
  font-family: var(--font-mono); font-size: 13px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--accent); margin: 0 0 18px;
  display: flex; align-items: center; gap: 10px;
  transition: color .6s var(--ease-soft), letter-spacing .6s var(--ease-soft);
}
@media (hover: hover) { .skill-group:hover h3 { color: var(--accent-bright); letter-spacing: 0.1em; } }
.skill-list { display: flex; flex-wrap: wrap; gap: 9px; list-style: none; margin: 0; padding: 0; }
.skill-list li {
  font-size: 14px; font-weight: 500;
  background: rgba(255,255,255,0.035);
  border: 1px solid var(--line);
  padding: 7px 13px; border-radius: 10px;
  color: var(--text);
  transition: border-color .25s, background .25s, color .25s;
}
@media (hover: hover) { .skill-list li:hover { border-color: var(--accent-line); background: var(--accent-tint); color: var(--accent-bright); } }

/* ---------------------------------------------------------
   Education + Languages
   --------------------------------------------------------- */
/* The languages aside is a short companion to a tall card. Rather than
   stretch it (which just spreads the gaps out inside), it keeps its
   natural height and tracks alongside as the long card scrolls past. */
.edu-grid {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: 20px;
  align-items: start;
}
.edu-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(24px, 3vw, 36px);
  transition: border-color .35s, transform .35s var(--ease);
}
@media (hover: hover) { .edu-card:hover { border-color: var(--line-strong); transform: translateY(-3px); } }
.edu-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 16px; margin-bottom: 16px;
}
.edu-degree { font-size: clamp(20px, 2.4vw, 27px); letter-spacing: -0.02em; margin: 0 0 6px; }
.edu-org { color: var(--text-dim); font-size: 14.5px; margin: 0; }
.edu-org .sep { color: var(--text-faint); margin: 0 8px; }
.edu-date {
  font-family: var(--font-mono); font-size: 12.5px; color: var(--accent);
  white-space: nowrap; letter-spacing: 0.02em; flex-shrink: 0; padding-top: 4px;
}
.edu-desc { color: var(--text-dim); font-size: 15px; margin: 0 0 20px; max-width: 62ch; }
.edu-points { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.edu-points li { position: relative; padding-left: 22px; color: var(--text-dim); font-size: 14.5px; line-height: 1.5; }
.edu-points li::before {
  content: ""; position: absolute; left: 0; top: 8px;
  width: 7px; height: 7px; border-radius: 2px;
  background: var(--accent); transform: rotate(45deg);
}
.edu-k { display: block; color: var(--text); font-weight: 600; font-size: 13px; letter-spacing: -0.01em; margin-bottom: 2px; }

.lang-card {
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(24px, 3vw, 32px);
  position: sticky;
  top: 96px;
}
.lang-title {
  font-family: var(--font-mono); font-size: 13px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--accent);
  margin: 0 0 24px; display: flex; align-items: center; gap: 10px;
}
.lang-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 24px; }
.lang-list li { display: grid; grid-template-columns: 1fr auto; gap: 8px 12px; align-items: baseline; }
.lang-name { font-size: 16px; font-weight: 600; }
.lang-level { font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; }
.lang-bar { grid-column: 1 / -1; height: 5px; border-radius: 999px; background: rgba(255,255,255,0.06); overflow: hidden; }
.lang-bar > span {
  display: block; height: 100%; width: 100%; border-radius: inherit;
  background: linear-gradient(90deg, var(--accent-bright), var(--accent));
  box-shadow: 0 0 10px var(--accent-glow);
  /* scaleX instead of width — composites, no layout on each frame */
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.3s var(--ease-soft);
}
/* Fill the bars over time once the card scrolls into view */
.lang-card.is-filled .lang-bar > span { transform: scaleX(var(--fill, 0)); }
.lang-card.is-filled .lang-list li:nth-child(2) .lang-bar > span { transition-delay: .18s; }

/* ---------------------------------------------------------
   Certifications
   --------------------------------------------------------- */
.cert-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}
.cert-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  transition: border-color .6s var(--ease-soft), transform .6s var(--ease-soft), background .6s var(--ease-soft), box-shadow .6s var(--ease-soft);
}
@media (hover: hover) {
  .cert-card:hover {
    border-color: var(--accent-line);
    transform: translateY(-5px);
    background: var(--surface-2);
    box-shadow: 0 0 0 1px var(--accent-line), 0 20px 48px -26px var(--accent-glow), 0 0 36px -14px var(--accent-glow);
  }
}
.cert-top { display: flex; align-items: center; gap: 10px; }
.cert-ico {
  width: 34px; height: 34px; border-radius: 10px; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--accent-tint); color: var(--accent-bright);
  border: 1px solid var(--accent-line);
}
.cert-ico svg { width: 18px; height: 18px; }
.cert-issuer { font-family: var(--font-mono); font-size: 12.5px; font-weight: 500; color: var(--text); }
.cert-date { margin-left: auto; font-family: var(--font-mono); font-size: 11.5px; color: var(--text-faint); white-space: nowrap; }
.cert-title { font-size: 16px; line-height: 1.32; letter-spacing: -0.01em; margin: 0; font-weight: 600; flex: 1; }
.cert-skills { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.cert-skills li {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.02em;
  color: var(--text-dim); background: rgba(255,255,255,0.035);
  border: 1px solid var(--line); padding: 4px 8px; border-radius: 7px;
}
.cert-cred { font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); letter-spacing: 0.02em; }

/* ---------------------------------------------------------
   Resume CTA
   --------------------------------------------------------- */
.resume {
  background: linear-gradient(135deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: clamp(32px, 5vw, 56px);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 32px;
  align-items: center;
  position: relative;
  overflow: hidden;
}
.resume::before {
  content: ""; position: absolute; inset: auto -10% -60% auto; width: 420px; height: 420px;
  background: radial-gradient(circle, var(--accent-glow), transparent 65%);
  filter: blur(30px); opacity: 0.6;
}
.resume-text { position: relative; z-index: 1; }
.resume-text h2 { font-size: clamp(24px, 3vw, 36px); letter-spacing: -0.03em; margin: 0 0 12px; }
.resume-text p { color: var(--text-dim); margin: 0; max-width: 48ch; }
.resume-actions { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 12px; }

/* ---------------------------------------------------------
   Contact
   --------------------------------------------------------- */
.contact-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 4vw, 56px); align-items: start; }
.contact-lead h2 { font-size: clamp(30px, 4.4vw, 50px); letter-spacing: -0.035em; line-height: 1.05; margin: 0 0 18px; }
.contact-lead h2 .accent { color: var(--accent); }
.contact-lead p { color: var(--text-dim); max-width: 42ch; margin: 0 0 28px; }
.contact-email {
  font-family: var(--font-mono); font-size: clamp(15px, 1.8vw, 19px);
  color: var(--text); display: inline-flex; align-items: center; gap: 10px;
  border-bottom: 1px solid var(--accent-line);
  padding: 10px 0;   /* clears the 44px tap target */
  transition: color .25s, border-color .25s;
}
@media (hover: hover) { .contact-email:hover { color: var(--accent-bright); } }

.contact-links { display: grid; gap: 12px; }
.contact-link {
  display: flex; align-items: center; gap: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px 20px;
  transition: border-color .3s, transform .3s var(--ease), background .3s;
}
@media (hover: hover) { .contact-link:hover { border-color: var(--accent-line); transform: translateX(4px); background: var(--surface-2); } }
.contact-ico {
  width: 44px; height: 44px; border-radius: 12px; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--accent-tint); color: var(--accent-bright);
  border: 1px solid var(--accent-line);
}
.contact-ico svg { width: 20px; height: 20px; }
.contact-link .cl-label { font-size: 12px; font-family: var(--font-mono); color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.06em; }
.contact-link .cl-value { font-size: 15.5px; font-weight: 500; color: var(--text); }
.contact-link .cl-arrow { margin-left: auto; color: var(--text-faint); transition: transform .3s var(--ease), color .3s; }
@media (hover: hover) { .contact-link:hover .cl-arrow { color: var(--accent); transform: translate(3px, -3px); } }

/* ---------------------------------------------------------
   Footer
   --------------------------------------------------------- */
.footer {
  border-top: 1px solid var(--line);
  padding-block: 40px;
  margin-top: clamp(40px, 6vw, 80px);
}
.footer-inner { display: flex; align-items: center; justify-content: space-between; gap: 20px 8px; flex-wrap: wrap; }
.footer p { margin: 0; color: var(--text-faint); font-size: 13.5px; font-family: var(--font-mono); }
.footer-links { display: flex; gap: 4px; flex-wrap: wrap; margin-inline: -10px; }
/* Padded to a comfortable tap target (was a 23px-tall hit area) */
.footer-links a { color: var(--text-dim); font-size: 14px; transition: color .2s; padding: 11px 10px; }
@media (hover: hover) { .footer-links a:hover { color: var(--accent); } }

/* ---------------------------------------------------------
   Scroll reveal — content settles into place (not a long slide)
   --------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s var(--ease-entrance), transform .8s var(--ease-entrance);
  transition-delay: var(--rd, 0s);   /* content-driven stagger (set per group in JS) */
}
.reveal.in { opacity: 1; transform: none; }
/* Explicit cascade buckets (hero) still win over the auto stagger */
.reveal[data-d="1"] { transition-delay: .06s; }
.reveal[data-d="2"] { transition-delay: .14s; }
.reveal[data-d="3"] { transition-delay: .22s; }
.reveal[data-d="4"] { transition-delay: .30s; }

/* Section eyebrow rule "draws" in when its header reveals — a chapter cue */
.section-head .eyebrow::before,
.work-tag .eyebrow::before {
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform .7s var(--ease-entrance) .15s;
}
.section-head.in .eyebrow::before,
.work-tag.in .eyebrow::before { transform: scaleX(1); }

/* ---------------------------------------------------------
   Responsive
   --------------------------------------------------------- */
@media (max-width: 940px) {
  .hero-grid { grid-template-columns: 1fr; }
  /* Copy first on mobile, visual below and centered */
  .hero-copy { order: 0; }
  .hero-visual { order: 1; max-width: 520px; margin-inline: auto; width: 100%; }
  .skills-grid { grid-template-columns: repeat(2, 1fr); }
  .cert-grid { grid-template-columns: repeat(2, 1fr); }
  .edu-grid { grid-template-columns: 1fr; }
  .contact-grid { grid-template-columns: 1fr; }
  .resume { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .nav-links, .nav-cta .btn-desktop { display: none; }
  .nav-toggle { display: flex; }
  .nav-mobile {
    position: fixed; inset: 72px 0 auto 0;
    background: rgba(7,10,17,0.96);
    -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
    border-bottom: 1px solid var(--line);
    padding: 20px var(--gutter) 28px;
    display: flex; flex-direction: column; gap: 4px;
    transform: translateY(-12px); opacity: 0; pointer-events: none;
    transition: transform .35s var(--ease), opacity .3s;
    z-index: 99;
    max-height: calc(100dvh - 72px);
    overflow-y: auto;
  }
  .nav.open .nav-mobile { transform: none; opacity: 1; pointer-events: auto; }
  .nav-mobile a { padding: 14px 4px; font-size: 17px; font-weight: 500; border-bottom: 1px solid var(--line); color: var(--text); }
  .nav-mobile .btn { margin-top: 14px; }
}

@media (max-width: 600px) {
  body { font-size: 16px; }
  .skills-grid { grid-template-columns: 1fr; }
  .cert-grid { grid-template-columns: 1fr; }
  .edu-head { flex-direction: column; gap: 6px; }
  .edu-date { padding-top: 0; }
  .hero { padding-top: clamp(104px, 22vh, 140px); }
  .hero-cta { gap: 10px; }
  .hero-cta .btn { flex: 1 1 100%; }
  .hero-stats { gap: 16px 14px; max-width: none; }
  .stat .label { font-size: 10.5px; letter-spacing: 0.04em; }
  .float-badge { display: none; }
  .code-stage { margin: 0; }
  /* Index rows: tighter, status badge above meta, comfortable taps */
  .index-row { gap: 12px; }
  .index-num { font-size: 11.5px; }
  .index-meta { font-size: 11px; letter-spacing: 0.02em; }
  .status { font-size: 10.5px; padding: 4px 9px; }
  .work-stats { gap: 10px 18px; }
  .ws-num { font-size: 19px; }
  .timeline { max-width: 100%; }
  .resume { padding: 26px 22px; text-align: left; }
  .resume-actions .btn { width: 100%; }
  .contact-email { font-size: 15px; word-break: break-all; }
}

/* Very small phones — keep everything readable, no overflow */
@media (max-width: 400px) {
  :root { --gutter: 16px; }
  .brand-sub { display: none; }
  .index-row {
    grid-template-columns: 38px 1fr;
    grid-template-areas:
      "num   title"
      "meta  meta"
      "status status"
      "thumb thumb";
    gap: 8px 10px;
  }
  .index-num { padding-top: 6px; }
  .index-status-col { grid-area: status; align-items: flex-start; margin-top: 4px; }
  .index-title { font-size: clamp(26px, 11vw, 36px); }
  /* Never reintroduce a track `gap` here — it desyncs the -50% loop.
     Tighten the separator margin instead. */
  .marquee-track span { font-size: 13px; gap: 8px; }
  .marquee-track span::after { margin-inline: 20px; }
  .mq-ico { width: 15px; height: 15px; }
  /* The show-more pill is 323px of nowrap content in a 288px column here;
     let it wrap and tighten it so it stops pushing the page wider. */
  .index-more { gap: 10px; }
  .im-text {
    white-space: normal;
    flex-wrap: wrap;
    justify-content: center;
    padding: 12px 16px;
    gap: 8px;
  }
  .im-label { font-size: 13px; }
  .im-count { font-size: 11px; padding: 3px 8px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
  .reveal, .hero-visual.reveal { opacity: 1; transform: none; }
  /* Make sure decorative reveal cues never leave content hidden */
  .section-head .eyebrow::before,
  .work-tag .eyebrow::before { transform: scaleX(1); }
  .code-card, .float-badge { transform: none !important; }
  /* Freeze the ticker at the start of the first copy rather than relying on
     a near-zero duration resolving to the right frame. */
  .marquee-track { animation: none !important; transform: none !important; }
}

/* Direct-edit overrides */
