/* ==========================================================================
   MAIN.CSS -- GENERATED FILE, DO NOT EDIT DIRECTLY
   Built by scripts/build-css.sh from the partials listed in ORDER there.
   Edit the source files under css/base, css/components, css/layout, or
   css/utilities.css, then re-run: bash scripts/build-css.sh
   ========================================================================== */

/* ==========================================================================
   DESIGN TOKENS
   Single source of truth for color, type, spacing, radius, shadow, motion.
   Every other CSS file should reference these vars — no raw hex/px values
   scattered in component files.
   ========================================================================== */

:root {
  /* ---- Color: surfaces ---- */
  --bg-primary: #0B0D12;        /* base background — warm-leaning near-black */
  --bg-secondary: #13161D;      /* card / section surfaces */
  --bg-elevated: #1C2029;       /* hover / raised surfaces */
  --bg-overlay: rgba(11, 13, 18, 0.85);

  /* ---- Color: borders ---- */
  --border-subtle: #262B36;
  --border-strong: #5A6377;      /* WCAG audit: 3.23:1 on bg-primary — meets 3:1 non-text/UI-boundary minimum */

  /* ---- Color: text ---- */
  --text-primary: #F2F1ED;      /* warm off-white, not pure white */
  --text-secondary: #9CA0AC;
  --text-muted: #828796;        /* WCAG audit: 5.42:1 on bg-primary — meets 4.5:1 small-text minimum */
  --text-on-accent: #14100A;

  /* ---- Color: accent (signature) ---- */
  --accent-primary: #E8A33D;    /* amber / marigold — financial + Nigerian warmth. Used for FILLS (buttons, dots) where --text-on-accent sits on top. */
  --accent-primary-hover: #F2B457;
  --accent-primary-muted: rgba(232, 163, 61, 0.14);
  --accent-text: #E8A33D;       /* amber used directly as TEXT/BORDER color against the page background — same as accent-primary in dark mode, darkened in light mode (see [data-theme="light"] override) to keep AA contrast */
  --accent-secondary: #4FD1C5;  /* muted teal — used sparingly, "automation" signal */
  --accent-secondary-muted: rgba(79, 209, 197, 0.14);

  /* ---- Color: semantic ---- */
  --success: #4ADE80;
  --warning: #E8A33D;
  --error: #F87171;

  /* ---- Color: the "flow thread" (signature motif) ---- */
  --thread-stroke: rgba(232, 163, 61, 0.55);
  --thread-stroke-dim: rgba(232, 163, 61, 0.18);

  /* ---- Typography: families ---- */
  --font-display: "Space Grotesk", "Segoe UI", sans-serif;
  --font-body: "IBM Plex Sans", "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", "Courier New", monospace;

  /* ---- Typography: fluid scale (clamp: min, preferred, max) ---- */
  --fs-xs: clamp(0.75rem, 0.72rem + 0.15vw, 0.8125rem);
  --fs-sm: clamp(0.875rem, 0.84rem + 0.15vw, 0.9375rem);
  --fs-base: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  --fs-lg: clamp(1.125rem, 1.07rem + 0.3vw, 1.25rem);
  --fs-xl: clamp(1.375rem, 1.28rem + 0.5vw, 1.625rem);
  --fs-2xl: clamp(1.75rem, 1.6rem + 0.8vw, 2.25rem);
  --fs-3xl: clamp(2.25rem, 2rem + 1.2vw, 3rem);
  --fs-4xl: clamp(2.75rem, 2.3rem + 2.2vw, 4rem);
  --fs-5xl: clamp(3.25rem, 2.6rem + 3.2vw, 5rem);

  --lh-tight: 1.1;
  --lh-snug: 1.3;
  --lh-normal: 1.6;
  --lh-relaxed: 1.75;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* ---- Spacing scale (8px base) ---- */
  --space-1: 0.25rem;   /* 4px  */
  --space-2: 0.5rem;    /* 8px  */
  --space-3: 0.75rem;   /* 12px */
  --space-4: 1rem;      /* 16px */
  --space-5: 1.5rem;    /* 24px */
  --space-6: 2rem;      /* 32px */
  --space-7: 3rem;      /* 48px */
  --space-8: 4rem;      /* 64px */
  --space-9: 6rem;      /* 96px */
  --space-10: 8rem;     /* 128px */

  /* ---- Radius ---- */
  --radius-sm: 8px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-full: 999px;

  /* ---- Shadow ---- */
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.25);
  --shadow-md: 0 8px 30px rgba(0, 0, 0, 0.35);
  --shadow-glow: 0 0 0 1px var(--accent-primary-muted), 0 8px 24px rgba(232, 163, 61, 0.15);

  /* ---- Motion ---- */
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --duration-fast: 150ms;
  --duration-base: 250ms;
  --duration-slow: 450ms;
  --duration-reveal: 700ms;

  /* ---- Layout ---- */
  --container-max: 1200px;
  --container-padding: clamp(1.25rem, 4vw, 3rem);
  --nav-height: 76px;
}

/* Respect user motion preference globally — components should also check this
   in JS before running IntersectionObserver-based reveals. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0ms;
    --duration-base: 0ms;
    --duration-slow: 0ms;
    --duration-reveal: 0ms;
  }
}

/* ==========================================================================
   LIGHT THEME
   Activated by data-theme="light" on <html> (see js/modules/theme.js).
   Every value below was checked against the same WCAG contrast formula
   used for the dark theme audit (see README) before being chosen — this
   is not just "dark colors, but paler."
   ========================================================================== */
[data-theme="light"] {
  --bg-primary: #F7F5F0;
  --bg-secondary: #FFFFFF;
  --bg-elevated: #EFEBE1;
  --bg-overlay: rgba(247, 245, 240, 0.85);

  --border-subtle: #E2DDCF;
  --border-strong: #847F71;      /* 3.67:1 on bg-primary — clears the 3:1 UI-boundary minimum */

  --text-primary: #1A1712;       /* 16.4:1 on bg-primary */
  --text-secondary: #4B4740;     /* 8.47:1 on bg-primary */
  --text-muted: #6B665C;         /* 5.24:1 on bg-primary — clears the 4.5:1 small-text minimum */
  --text-on-accent: #14100A;     /* unchanged — still checked against accent-primary below */

  /* accent-primary/-hover/-muted stay the same amber in both themes (the
     button fill + text-on-accent pairing was already validated and doesn't
     depend on page background). accent-text is what changes: a darker
     amber so it's legible as TEXT/BORDER color on a light background. */
  --accent-text: #8A5613;        /* 5.63:1 on bg-primary, 6.14:1 on bg-secondary */

  --thread-stroke: rgba(138, 86, 19, 0.55);
  --thread-stroke-dim: rgba(138, 86, 19, 0.18);

  --shadow-sm: 0 2px 8px rgba(20, 16, 10, 0.08);
  --shadow-md: 0 8px 30px rgba(20, 16, 10, 0.12);
  --shadow-glow: 0 0 0 1px var(--accent-primary-muted), 0 8px 24px rgba(232, 163, 61, 0.2);
}

/* ==========================================================================
   RESET
   Deliberately minimal — only what this project needs, not a full
   normalize.css. Box-sizing, margin removal, sane media defaults.
   ========================================================================== */

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

* {
  margin: 0;
}

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

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

body {
  min-height: 100dvh;
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
}

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

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: none;
}

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

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

table {
  border-collapse: collapse;
  width: 100%;
}

/* Keep default, visible focus rings — never remove focus outlines.
   Component files may restyle this, but must not delete it. */
:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
}

/* ==========================================================================
   TYPOGRAPHY
   Base element styles. Utility-level type classes live in utilities.css.
   ========================================================================== */

body {
  font-family: var(--font-body);
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  color: var(--text-primary);
  background-color: var(--bg-primary);
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
  color: var(--text-primary);
}

h1 { font-size: var(--fs-5xl); }
h2 { font-size: var(--fs-3xl); }
h3 { font-size: var(--fs-2xl); }
h4 { font-size: var(--fs-xl); }

p {
  color: var(--text-secondary);
  line-height: var(--lh-relaxed);
}

/* Section eyebrow label — used above section headings ("Projects",
   "Learning & Growth") to add wayfinding, set in mono per the design system */
.eyebrow {
  position: relative;
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: var(--space-3);
  padding-bottom: var(--space-3);
}

.eyebrow::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 32px;
  height: 2px;
  background: var(--accent-primary);
  border-radius: var(--radius-full);
}

/* Data / label text — tech badges, timeline dates, AI tools table.
   This is where --font-mono earns its place: real tabular/label data,
   not decorative "code window" styling. */
.data-text {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: 0.01em;
}

code {
  font-family: var(--font-mono);
}

/* ==========================================================================
   LAYOUT PRIMITIVES
   Shared structural rules every section builds on top of.
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-padding);
}

/* Every top-level <section> uses this for consistent vertical rhythm.
   Individual layout/*.css files add their own internal layout on top. */
.section {
  padding-block: var(--space-9);
  scroll-margin-top: var(--nav-height); /* so anchor-jumps clear the fixed nav */
}

.section-header {
  max-width: 640px;
  margin-bottom: var(--space-7);
}

/* Generic responsive grid — components opt into column count via
   --grid-cols, set per breakpoint in the component's own file. */
.grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(var(--grid-cols, 1), 1fr);
}

@media (max-width: 900px) {
  .grid {
    grid-template-columns: repeat(var(--grid-cols-tablet, 2), 1fr);
  }
}

@media (max-width: 600px) {
  .grid {
    grid-template-columns: 1fr;
  }
}

/* Staggered reveal: direct grid children fade in with a slight cascade
   instead of all at once. Only affects timing (transition-delay), not
   whether/how they animate -- .reveal-armed + .is-visible still control
   that, so this stays inert until scrollReveal.js arms an element. */
.grid > .reveal:nth-child(1) { transition-delay: 0ms; }
.grid > .reveal:nth-child(2) { transition-delay: 60ms; }
.grid > .reveal:nth-child(3) { transition-delay: 120ms; }
.grid > .reveal:nth-child(4) { transition-delay: 180ms; }
.grid > .reveal:nth-child(5) { transition-delay: 240ms; }
.grid > .reveal:nth-child(6) { transition-delay: 300ms; }
.grid > .reveal:nth-child(7) { transition-delay: 360ms; }
.grid > .reveal:nth-child(8) { transition-delay: 420ms; }
.grid > .reveal:nth-child(n+9) { transition-delay: 480ms; }

@media (prefers-reduced-motion: reduce) {
  .grid > .reveal {
    transition-delay: 0ms !important;
  }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Skip-to-content link — accessibility requirement, visually hidden until focused */
.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-4);
  z-index: 200;
  padding: var(--space-3) var(--space-5);
  background: var(--accent-primary);
  color: var(--text-on-accent);
  border-radius: var(--radius-sm);
  transition: top var(--duration-fast) var(--ease-out);
}

.skip-link:focus {
  top: var(--space-4);
}

/* ==========================================================================
   UTILITIES
   Small, single-purpose helper classes. Reach for a component class first —
   these are for the genuine one-off cases, not a substitute for structure.
   ========================================================================== */

.text-center { text-align: center; }
.text-muted { color: var(--text-muted); }
.text-secondary { color: var(--text-secondary); }
.text-accent { color: var(--accent-text); }

.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }

.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }

/* Reveal-on-scroll target state. IMPORTANT: elements are visible by
   default. JS (scrollReveal.js) adds .reveal-armed right before it starts
   observing an element -- only then does it go opacity:0 and wait to be
   faded in via .is-visible. This means if JS fails to load or is
   disabled, .reveal content simply stays visible instead of being
   permanently hidden. Do not set opacity:0 on the bare .reveal selector. */
.reveal.reveal-armed {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--duration-reveal) var(--ease-out),
    transform var(--duration-reveal) var(--ease-out);
}

.reveal.reveal-armed.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* Image fade-in-on-load. Same principle as .reveal: images are visible
   by default. JS (pagePolish.js) only adds .js-fade-armed if it
   successfully attaches a load listener before the image finishes
   loading -- so a cached/instant image is never needlessly hidden, and
   an image never stays hidden if JS fails. */
img.js-fade-armed {
  opacity: 0;
  transition: opacity var(--duration-slow) var(--ease-out);
}

img.js-fade-armed.is-loaded {
  opacity: 1;
}

/* ==========================================================================
   NAV
   ========================================================================== */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: var(--nav-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-inline: var(--container-padding);
  background: var(--bg-overlay);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border-subtle);
}

.nav-brand {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-lg);
  letter-spacing: -0.01em;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-6);
}

.nav-link {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
  position: relative;
  padding-block: var(--space-1);
  transition: color var(--duration-fast) var(--ease-out);
}

.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 2px;
  background: var(--accent-primary);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-base) var(--ease-out);
}

.nav-link:hover,
.nav-link.is-active {
  color: var(--text-primary);
}

.nav-link.is-active::after {
  transform: scaleX(1);
}

.nav-toggle {
  display: none;
  width: 40px;
  height: 40px;
  position: relative;
}

.nav-toggle::before,
.nav-toggle::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  height: 2px;
  background: var(--text-primary);
  transition: transform var(--duration-fast) var(--ease-out);
}

.nav-toggle::before { top: 15px; }
.nav-toggle::after { bottom: 15px; }

.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  flex-shrink: 0;
  transition: border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

.theme-toggle:hover {
  border-color: var(--accent-text);
  color: var(--accent-text);
}

.scroll-progress {
  position: fixed;
  top: var(--nav-height);
  left: 0;
  right: 0;
  height: 2px;
  z-index: 99;
  background: transparent;
  pointer-events: none;
}

.scroll-progress__bar {
  height: 100%;
  width: 0%;
  background: var(--accent-primary);
  transform-origin: left;
}

.theme-toggle__icon {
  display: none;
  align-items: center;
  justify-content: center;
}

/* Dark theme (default, no data-theme attribute): show the moon -- it
   represents the mode currently active. Clicking switches to light. */
:root:not([data-theme="light"]) .theme-toggle__icon--moon {
  display: flex;
}

/* Light theme active: show the sun instead. */
[data-theme="light"] .theme-toggle__icon--sun {
  display: flex;
}

@media (max-width: 768px) {
  .nav-toggle {
    display: block;
  }

  .nav-links {
    position: fixed;
    top: var(--nav-height);
    right: 0;
    bottom: 0;
    width: min(80vw, 320px);
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-5);
    padding: var(--space-6);
    background: var(--bg-secondary);
    border-left: 1px solid var(--border-subtle);
    transform: translateX(100%);
    transition: transform var(--duration-base) var(--ease-out);
  }

  .nav-links.is-open {
    transform: translateX(0);
  }
}

/* Extra-narrow phones: the brand name, six nav links (hidden into the
   hamburger, but still contribute to this row's width via nav-controls'
   siblings), theme toggle, and hamburger all compete for space. Shrink
   the non-critical bits rather than letting anything wrap or overflow. */
@media (max-width: 380px) {
  .nav-brand {
    font-size: var(--fs-base);
  }

  .theme-toggle,
  .nav-toggle {
    width: 34px;
    height: 34px;
  }

  .nav-controls {
    gap: var(--space-2);
  }
}

/* ==========================================================================
   BUTTONS
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-full);
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  transition: transform var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

.btn-primary {
  background: var(--accent-primary);
  color: var(--text-on-accent);
}

.btn-primary:hover {
  background: var(--accent-primary-hover);
  box-shadow: var(--shadow-glow);
  transform: translateY(-2px);
}

.btn-secondary {
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border-strong);
}

.btn-secondary:hover {
  border-color: var(--accent-text);
  color: var(--accent-text);
  transform: translateY(-2px);
}

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
  padding-inline: var(--space-2);
}

.btn-ghost:hover {
  color: var(--accent-text);
}

/* ==========================================================================
   BADGES / PILLS
   ========================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  white-space: nowrap;
  transition: border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

.badge:hover {
  border-color: var(--accent-text);
  color: var(--text-primary);
}

.badge-list {
  list-style: none;
}

/* ==========================================================================
   CARDS
   Shared base + modifiers for about/expertise/project cards.
   ========================================================================== */

.card {
  display: block;
  padding: var(--space-6);
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  transition: transform var(--duration-base) var(--ease-out),
    border-color var(--duration-base) var(--ease-out),
    box-shadow var(--duration-base) var(--ease-out);
}

.card:hover {
  transform: translateY(-4px);
  border-color: var(--accent-text);
  box-shadow: var(--shadow-md);
}

.card h3,
.card h4 {
  margin-bottom: var(--space-3);
}

.card p {
  font-size: var(--fs-sm);
}

/* Shared reset for any non-interactive card (About, NextGen topic cards,
   AI Concepts cards) so section files don't each redeclare this. */
.card--static {
  cursor: default;
}

.card--static:hover {
  transform: none;
  border-color: var(--border-subtle);
  box-shadow: var(--shadow-sm);
}

.card--expertise {
  border-top: 2px solid transparent;
}

.card--expertise:hover {
  border-top-color: var(--accent-text);
}

.card--expertise__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-bottom: var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--accent-primary-muted);
  color: var(--accent-text);
}

.card--project {
  text-decoration: none;
  color: inherit;
  position: relative;
  overflow: hidden;
}

.card--project__visual {
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-4);
  overflow: hidden;
  background: linear-gradient(135deg, var(--bg-elevated), var(--bg-secondary));
  border: 1px solid var(--border-subtle);
}

.card--project__visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  transition: transform var(--duration-slow) var(--ease-out);
}

.card--project:hover .card--project__visual img {
  transform: scale(1.05);
}

.card--project h3 {
  margin-bottom: var(--space-2);
}

.card--project .badge-list {
  margin-block: var(--space-4);
}

.card--project__cta {
  display: inline-block;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--accent-text);
  transition: transform var(--duration-fast) var(--ease-out);
}

.card--project:hover .card--project__cta {
  transform: translateX(4px);
}


/* ==========================================================================
   CASE STUDY BLOCK
   Reused 4x. Generous vertical rhythm — this is the visual centerpiece.
   ========================================================================== */

.case-study {
  padding-block: var(--space-9);
  border-top: 1px solid var(--border-subtle);
}

.case-study__visual {
  display: flex;
  justify-content: center;
  padding: var(--space-7) var(--space-6);
  margin-bottom: var(--space-6);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: linear-gradient(135deg, var(--bg-elevated), var(--bg-secondary));
  border: 1px solid var(--border-subtle);
}

.case-study__visual img {
  width: auto;
  max-width: 100%;
  max-height: 560px;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  transition: transform var(--duration-slow) var(--ease-out);
}

.case-study__visual:hover img {
  transform: scale(1.02);
}

.case-study h3 {
  margin-bottom: var(--space-2);
  max-width: 720px;
}

.case-study__tagline {
  color: var(--text-secondary);
  font-size: var(--fs-lg);
  margin-bottom: var(--space-6);
  max-width: 640px;
}

.case-study__story {
  max-width: 720px;
  margin-bottom: var(--space-7);
}

.case-study__story p {
  margin-bottom: var(--space-4);
}

.case-study__meta {
  margin-bottom: var(--space-6);
}

.case-study__meta h4 {
  margin-bottom: var(--space-3);
  font-size: var(--fs-lg);
}

.case-study__list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2) var(--space-5);
}

.case-study__list li {
  position: relative;
  padding-left: var(--space-4);
  color: var(--text-secondary);
  font-size: var(--fs-sm);
}

.case-study__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent-primary);
}

.case-study__links {
  margin-top: var(--space-7);
}

@media (max-width: 600px) {
  .case-study__list {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   TIMELINE
   Learning & Growth chronological entries. Reuses the thread color
   language (dot + line) but as its own left-rail layout distinct from
   .thread-flow, since entries here carry much more content per item.
   ========================================================================== */

.timeline {
  position: relative;
  margin-block: var(--space-8);
  padding-left: var(--space-7);
}

.timeline::before {
  content: "";
  position: absolute;
  left: calc(var(--space-7) / 2 - 1px);
  top: 8px;
  bottom: 8px;
  width: 2px;
  background: var(--border-strong);
}

.timeline-item {
  position: relative;
  padding-bottom: var(--space-7);
}

.timeline-item:last-child {
  padding-bottom: 0;
}

.timeline-item::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--space-7) / 2 - 6px);
  top: 6px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--bg-primary);
  border: 2px solid var(--accent-text);
}

.timeline-item h3 {
  margin-block: var(--space-1) var(--space-2);
}

.timeline-item h4 {
  margin-top: var(--space-4);
  font-size: var(--fs-base);
  color: var(--text-secondary);
}

.timeline-item .case-study__list {
  margin-top: var(--space-3);
  grid-template-columns: 1fr;
}

/* ==========================================================================
   ACCORDION
   Prompt Engineering Portfolio. Height animates via grid-template-rows
   (1fr <-> 0fr) toggled by accordion.js adding/removing a data attribute
   -- no JS height calculation needed, and it works with dynamic content.
   ========================================================================== */

.accordion-item {
  border-bottom: 1px solid var(--border-subtle);
}

.accordion-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: var(--space-5);
  text-align: left;
  font-family: var(--font-display);
  font-weight: var(--fw-medium);
  font-size: var(--fs-lg);
  color: var(--text-primary);
}

.accordion-trigger::after {
  content: "+";
  font-family: var(--font-mono);
  font-size: var(--fs-xl);
  color: var(--accent-text);
  transition: transform var(--duration-base) var(--ease-out);
  flex-shrink: 0;
  margin-left: var(--space-4);
}

.accordion-trigger[aria-expanded="true"]::after {
  transform: rotate(45deg);
}

.accordion-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--duration-base) var(--ease-out);
}

.accordion-trigger[aria-expanded="true"] + .accordion-panel {
  grid-template-rows: 1fr;
}

.accordion-panel > * {
  overflow: hidden;
}

.accordion-panel p,
.accordion-panel ul {
  padding-bottom: var(--space-5);
}

.accordion-panel .case-study__list {
  grid-template-columns: repeat(2, 1fr);
}

@media (max-width: 600px) {
  .accordion-panel .case-study__list {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   TABLE
   AI Tools table. Real semantic table, mono type for data cells.
   ========================================================================== */

table {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-top: var(--space-6);
}

th {
  text-align: left;
  padding: var(--space-4) var(--space-5);
  background: var(--bg-secondary);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--accent-text);
  border-bottom: 1px solid var(--border-subtle);
}

td {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

td:first-child {
  color: var(--text-primary);
}

tbody tr:last-child td {
  border-bottom: none;
}

tbody tr:hover td {
  background: var(--bg-elevated);
}

@media (max-width: 700px) {
  table, thead, tbody, th, td, tr {
    display: block;
  }

  thead {
    display: none;
  }

  tbody tr {
    padding: var(--space-4) var(--space-5);
  }

  td {
    border: none;
    padding: var(--space-1) 0;
  }

  td:first-child {
    font-family: var(--font-display);
    font-weight: var(--fw-semibold);
  }
}

/* ==========================================================================
   CONTACT CARD
   ========================================================================== */

.contact-card {
  display: block;
  padding: var(--space-6);
  text-align: center;
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  color: inherit;
  transition: transform var(--duration-base) var(--ease-out),
    border-color var(--duration-base) var(--ease-out);
}

a.contact-card:hover {
  transform: translateY(-4px);
  border-color: var(--accent-text);
}

.contact-card h3 {
  font-size: var(--fs-base);
  margin-bottom: var(--space-2);
  color: var(--text-secondary);
}

.contact-card__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: 0 auto var(--space-4);
  border-radius: var(--radius-full);
  background: var(--accent-primary-muted);
  color: var(--accent-text);
}

.contact-card p a {
  color: var(--text-primary);
}

.contact-card p a:hover {
  color: var(--accent-text);
}

.pull-quote {
  max-width: 680px;
  margin-inline: auto;
  text-align: center;
  padding-left: var(--space-4);
  border-left: 2px solid var(--accent-text);
  text-align: left;
}

.pull-quote p {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-style: normal;
  color: var(--text-primary);
  line-height: var(--lh-snug);
}

.pull-quote--closing {
  margin-top: var(--space-9);
  text-align: center;
  border-left: none;
  padding-left: 0;
}

.pull-quote--closing p {
  font-size: var(--fs-2xl);
}

/* ==========================================================================
   THREAD (signature motif)
   Static CSS presentation here; draw-on animation lives in threadDraw.js
   (Phase 5), which will render an actual SVG line and animate its
   stroke-dashoffset. This file styles the three manifestations:
   1. .thread-bg      -- Hero background wash
   2. .thread-flow     -- ordered "flow" lists (engineering journey,
                          AI automation workflow) styled as a connected
                          vertical sequence with a running line
   ========================================================================== */

.thread-bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(circle at 15% 20%, var(--accent-primary-muted), transparent 45%),
    radial-gradient(circle at 85% 60%, var(--accent-secondary-muted), transparent 50%);
  pointer-events: none;
  opacity: 1; /* visible by default -- decorative, must not depend on JS */
}

.thread-flow {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding-left: var(--space-6);
}

.thread-flow::before {
  content: "";
  position: absolute;
  left: calc(var(--space-6) / 2 - 1px);
  top: 10px;
  bottom: 10px;
  width: 2px;
  background: linear-gradient(
    to bottom,
    var(--thread-stroke),
    var(--thread-stroke-dim)
  );
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--duration-reveal) var(--ease-out);
}

.thread-flow.is-drawn::before {
  transform: scaleY(1);
}

.thread-flow li {
  position: relative;
  padding-block: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-primary);
}

.thread-flow li::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--space-6) / 2 - 5px);
  top: calc(var(--space-3) + 0.5em);
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--accent-primary);
  box-shadow: 0 0 0 4px var(--accent-primary-muted);
}

.thread-flow li span {
  display: block;
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-family: var(--font-body);
}

@media (min-width: 900px) {
  /* Engineering journey + workflow diagram feel less cramped as a
     horizontal sequence on wide screens */
  .journey-flow .thread-flow {
    flex-direction: row;
    flex-wrap: wrap;
    padding-left: 0;
    gap: var(--space-2) 0;
  }

  .journey-flow .thread-flow::before {
    display: none;
  }

  .journey-flow .thread-flow li {
    padding-inline: var(--space-3);
  }

  .journey-flow .thread-flow li::before {
    display: none;
  }

  .journey-flow .thread-flow li:not(:last-child)::after {
    content: "→";
    position: absolute;
    right: calc(-1 * var(--space-3) + 2px);
    color: var(--thread-stroke);
  }
}

/* ==========================================================================
   SECTION: hero
   ========================================================================== */

.hero {
  position: relative;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding-top: var(--nav-height);
  overflow: hidden;
}

.hero__content {
  max-width: 820px;
}

.hero__avatar {
  width: 112px;
  height: 112px;
  border-radius: 50%;
  object-fit: cover;
  margin-bottom: var(--space-5);
  border: 3px solid var(--bg-secondary);
  box-shadow: 0 0 0 1px var(--border-subtle), var(--shadow-md);
}

.hero h1 {
  margin-block: var(--space-4) var(--space-5);
}

.hero__statement {
  font-size: var(--fs-xl);
  color: var(--text-secondary);
  max-width: 620px;
  margin-bottom: var(--space-7);
}

.hero__actions {
  margin-bottom: var(--space-5);
}

.hero__links {
  font-size: var(--fs-sm);
}

.hero__scroll-cue {
  position: absolute;
  left: 50%;
  bottom: var(--space-6);
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-subtle);
  color: var(--text-muted);
  animation: hero-scroll-cue-bounce 2.2s ease-in-out infinite;
  transition: color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

/* Hero entrance sequence: hidden until pagePolish.js flips .is-in on
   each [data-hero-in] element (staggered via inline transition-delay).
   Elements start visible by default -- same "don't depend on JS for
   visibility" principle as .reveal -- this only ever makes something
   MORE hidden via JS, never permanently hidden if JS fails. */
[data-hero-in] {
  opacity: 1;
  transform: none;
}

.js-hero-armed [data-hero-in] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--duration-slow) var(--ease-out),
    transform var(--duration-slow) var(--ease-out);
}

.js-hero-armed [data-hero-in].is-in {
  opacity: 1;
  transform: translateY(0);
}

.hero__scroll-cue:hover {
  color: var(--accent-text);
  border-color: var(--accent-text);
}

@keyframes hero-scroll-cue-bounce {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(6px); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__scroll-cue {
    animation: none;
  }
}

@media (max-width: 600px) {
  .hero__scroll-cue {
    display: none;
  }
}

/* ==========================================================================
   SECTION: about
   ========================================================================== */

.about__grid {
  margin-bottom: 0;
}

/* ==========================================================================
   SECTION: expertise
   ========================================================================== */

/* Grid + card styling handled by base/layout.css and components/cards.css.
   No section-specific overrides needed at this stage. */

/* ==========================================================================
   SECTION: stack
   ========================================================================== */

.stack__groups {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.stack__group h3,
.stack__group h4 {
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: var(--space-3);
}

.stack__group-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.stack__group-header h3 {
  margin-bottom: 0;
}

.stack__group-icon {
  display: flex;
  color: var(--accent-text);
}

/* ==========================================================================
   SECTION: projects
   ========================================================================== */

.project-preview-grid {
  margin-bottom: var(--space-9);
}

/* ==========================================================================
   SECTION: growth
   ========================================================================== */

.journey-flow {
  margin-block: var(--space-8) var(--space-9);
}

.nextgen {
  margin-bottom: var(--space-9);
}

.prompts {
  margin-bottom: var(--space-9);
}

.prompts__featured {
  max-width: 760px;
  margin-block: var(--space-7);
  padding: var(--space-6);
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

.prompts__featured h4 {
  margin-bottom: var(--space-3);
}

.prompts__featured p {
  margin-bottom: var(--space-4);
}

.prompts__featured-label {
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  margin-bottom: var(--space-3) !important;
}

.prompts__library {
  margin-block: var(--space-8);
}

.prompts__library h4 {
  margin-block: var(--space-2) var(--space-5);
}

.prompts__process {
  max-width: 620px;
  margin-bottom: var(--space-8);
}

.prompts__process h4 {
  margin-block: var(--space-2) var(--space-3);
}

.prompts__process > p {
  margin-bottom: var(--space-5);
}

.process-list {
  counter-reset: process-step;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.process-list li {
  position: relative;
  padding-left: var(--space-8);
  color: var(--text-secondary);
}

.process-list li::before {
  counter-increment: process-step;
  content: counter(process-step);
  position: absolute;
  left: 0;
  top: -0.1em;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent-primary-muted);
  color: var(--accent-text);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
}

.prompts__why {
  max-width: 700px;
}

.prompts__why p {
  margin-bottom: var(--space-4);
}

.ai-concepts {
  margin-bottom: var(--space-9);
}

.ai-tools {
  margin-bottom: var(--space-9);
}

.skills h3 {
  margin-bottom: var(--space-5);
}

.skills .stack__group {
  margin-bottom: var(--space-5);
}

/* ==========================================================================
   SECTION: contact
   ========================================================================== */

.contact__grid {
  margin-block: var(--space-7) var(--space-8);
}

.footer {
  padding-block: var(--space-8) var(--space-6);
  border-top: 1px solid var(--border-subtle);
  font-size: var(--fs-sm);
}

.footer__top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-6);
  padding-bottom: var(--space-6);
}

.footer__name {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  margin-bottom: var(--space-1);
}

.footer__nav,
.footer__contact {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.footer__nav a,
.footer__contact a {
  color: var(--text-secondary);
  transition: color var(--duration-fast) var(--ease-out);
}

.footer__nav a:hover,
.footer__contact a:hover {
  color: var(--accent-text);
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-subtle);
}

.footer__top-link {
  color: var(--text-secondary);
  transition: color var(--duration-fast) var(--ease-out);
}

.footer__top-link:hover {
  color: var(--accent-text);
}

