@layer reset, tokens, typography, layout, components, animations, utilities;

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

  html {
    text-size-adjust: 100%;
    -webkit-text-size-adjust: 100%;
    hanging-punctuation: first last;
  }

  body,
  h1,
  h2,
  h3,
  h4,
  h5,
  h6,
  p,
  figure,
  blockquote,
  dl,
  dd {
    margin: 0;
  }

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

  img,
  picture,
  video,
  canvas,
  svg {
    display: block;
    max-inline-size: 100%;
  }

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

  p,
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    overflow-wrap: break-word;
  }

  :focus-visible {
    outline: 0.1875rem solid var(--color-accent);
    outline-offset: 0.25rem;
    border-radius: var(--radius-sm);
  }

  @media (prefers-reduced-motion: no-preference) {
    html {
      scroll-behavior: smooth;
    }
  }
}

@layer tokens {
  /*
    Palette: "Silver Steel"
    —————————————————————————————————————————————————————————
    Evolved from "Workshop at Night." The warm cream backgrounds
    and cool dark-mode slates stay; the accent shifts from amber-
    orange to a muted steel blue inspired by the silver-blue /
    silver-green iridescence in the Apple TV+ branding stills.

    Why the change:
    • The amber-orange accent on near-black dark mode read as
      Pornhub. That's not the vibe for a portfolio/blog.
    • Steel blue is serious-but-relaxed, pairs naturally with
      the warm Fraunces headings, and won't fight beach-photo
      hero images.
    • Enough chroma to feel alive as links/buttons, not so much
      that it screams "tech startup."

    Light mode keeps the warm ivory paper feel — the accent just
    cooled down. Dark mode gets neutral-white text (no more
    cream-on-black) so the whole palette coheres.

    Contrast (WCAG 2.1):
      Light: accent on bg ≈ 5.3:1  (AA normal text ✓)
      Dark:  accent on bg ≈ 7.5:1  (AAA normal text ✓)

    Gamut: all values verified in-gamut for sRGB displays.

    Hex approximations (for reference / Figma):
      Light accent:       #2E6799
      Light accent hover: #175283
      Dark accent:        #6AA3D9
      Dark accent hover:  #82B6E7

    Heading font: Fraunces — quirky optical-size serif with real
    character. Chosen for its warmth and distinctiveness in a
    portfolio context. The "soft" axis gives editorial weight at
    display sizes.
    —————————————————————————————————————————————————————————
  */

  :root {
    /* ── Colors — light mode (default) ── */
    --color-bg:           oklch(96% 0.012 80);    /* warm ivory          #F6F1E8 */
    --color-surface:      oklch(93% 0.014 78);    /* slightly deeper     #EDE6DD */
    --color-text:         oklch(18% 0.02 260);    /* near-black, cool    #0C111A */
    --color-text-muted:   oklch(45% 0.018 260);   /* cool mid-gray       #4F555F */
    --color-accent:       oklch(50% 0.05 248);    /* steelier */
    --color-accent-hover: oklch(43% 0.05 248);    /* steelier */
    --color-border:       oklch(82% 0.016 80);    /* warm hairline       #C9C3B8 */
    --color-code-bg:      oklch(90% 0.018 78);    /* warm tint           #E4DCD1 */

    /*
      On-accent: text/icon color sitting ON TOP of an accent-colored
      background (buttons, badges). Flips per theme because the accent
      lightness flips: dark text on the light-slate dark-mode accent,
      light text on the dark-slate light-mode accent.
    */
    --color-on-accent:    oklch(98% 0.002 260);   /* near-white          #F7F8F9 */

    /* ── Type scale — fluid via clamp(), ~1.25 modular ratio ── */
    --text-xs:   clamp(0.70rem,  0.68rem + 0.10vw, 0.75rem);
    --text-sm:   clamp(0.875rem, 0.84rem + 0.17vw, 0.9375rem);
    --text-base: clamp(1rem,     0.96rem + 0.20vw, 1.0625rem);
    --text-lg:   clamp(1.125rem, 1.06rem + 0.30vw, 1.25rem);
    --text-xl:   clamp(1.25rem,  1.14rem + 0.55vw, 1.5625rem);
    --text-2xl:  clamp(1.5625rem,1.34rem + 1.12vw, 2.0625rem);
    --text-3xl:  clamp(1.9531rem,1.56rem + 1.96vw, 2.8125rem);

    /* ── Font stacks ── */
    --font-heading: 'Fraunces', 'Georgia', serif;
    --font-body:    ui-sans-serif, system-ui, sans-serif;
    --font-mono:    ui-monospace, 'Cascadia Code', 'Fira Code', monospace;

    /* ── Spacing — rem-based, ~1.5 ratio ── */
    --space-2xs: 0.25rem;
    --space-xs:  0.5rem;
    --space-sm:  0.75rem;
    --space-md:  1rem;
    --space-lg:  1.5rem;
    --space-xl:  2.25rem;
    --space-2xl: 3.375rem;
    --space-3xl: 5rem;

    /* ── Border radius ── */
    --radius-sm:   0.25rem;
    --radius-md:   0.5rem;
    --radius-lg:   1rem;
    --radius-full: 9999px;

    /* ── Transitions ── */
    --duration-fast:   150ms;
    --duration-normal: 300ms;
    --duration-slow:   500ms;

    /* ── Container ── */
    --container-max:     75rem;
    --container-padding: clamp(1rem, 5vw, 3rem);
  }

  /* ── Dark mode ──
     Key changes from the old dark palette:
     1. Text shifted from warm cream (hue 80) → neutral cool white (hue 260).
        This kills the orange-and-black problem at the root.
     2. Muted text also cooled and desaturated.
     3. Accent is the same steel-blue family but lighter (70% vs 50%)
        for proper contrast on dark backgrounds.
  */
  [data-theme="dark"] {
    --color-bg:           oklch(14% 0.016 260);   /* deep cool slate     #05090F */
    --color-surface:      oklch(19% 0.018 260);   /* raised panel        #0F131B */
    --color-text:         oklch(92% 0.004 260);   /* neutral white       #E2E4E7 */
    --color-text-muted:   oklch(62% 0.008 260);   /* cool mid-gray       #83868B */
    --color-accent:       oklch(70% 0.05 248);    /* steelier */
    --color-accent-hover: oklch(76% 0.05 248);    /* steelier */
    --color-on-accent:    oklch(14% 0.016 260);   /* near-black on light accent */
    --color-border:       oklch(28% 0.018 260);   /* subtle divider      #232931 */
    --color-code-bg:      oklch(20% 0.020 260);   /* code block fill     #10161F */
  }

  /* ── Light mode (explicit override, mirrors :root) ── */
  [data-theme="light"] {
    --color-bg:           oklch(96% 0.012 80);
    --color-surface:      oklch(93% 0.014 78);
    --color-text:         oklch(18% 0.02 260);
    --color-text-muted:   oklch(45% 0.018 260);
    --color-accent:       oklch(50% 0.05 248);
    --color-accent-hover: oklch(43% 0.05 248);
    --color-on-accent:    oklch(98% 0.002 260);
    --color-border:       oklch(82% 0.016 80);
    --color-code-bg:      oklch(90% 0.018 78);
  }
}

@layer typography {
  /*
    Fraunces: loaded from Google Fonts CDN via @font-face.
    Variable axes: wght 100-900, SOFT 0-100, WONK 0-1.
    We target wght 400 + 700 only; the variable font handles interpolation.
    format("woff2-variations") is the modern descriptor for variable fonts.
  */
  @font-face {
    font-family: 'Fraunces';
    src: url('https://fonts.gstatic.com/s/fraunces/v31/6NUh8FyLNQOQZAnv9bYEvDiIdE9Ea92uemj4B5ary_0mgd0.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-036F, U+0370-037F, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }

  @font-face {
    font-family: 'Fraunces';
    src: url('https://fonts.gstatic.com/s/fraunces/v31/6NUh8FyLNQOQZAnv9bYEvDiIdE9Ea92uemj4B5ary_0mgd0.woff2') format('woff2');
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-036F, U+0370-037F, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }

  body {
    font-family: var(--font-body);
    font-size: var(--text-base);
    line-height: 1.6;
    color: var(--color-text);
    background-color: var(--color-bg);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  h1,
  h2,
  h3,
  h4 {
    font-family: var(--font-heading);
    line-height: 1.15;
    font-weight: 700;
    color: var(--color-text);
  }

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

  a {
    color: var(--color-accent);
    text-decoration-thickness: 0.08em;
    text-underline-offset: 0.25em;
    transition: color var(--duration-fast) ease;

    &:hover {
      color: var(--color-accent-hover);
    }
  }

  code,
  kbd,
  samp {
    font-family: var(--font-mono);
    font-size: 0.875em;
  }

  small {
    font-size: var(--text-sm);
  }

  strong {
    font-weight: 600;
  }

  /* Prose: article/long-form content rhythm */
  .prose {
    max-inline-size: 65ch;
    line-height: 1.75;

    & p,
    & li {
      margin-block: var(--space-sm);
    }

    & h2 {
      margin-block-start: var(--space-2xl);
      margin-block-end: var(--space-sm);
    }

    & h3 {
      margin-block-start: var(--space-xl);
      margin-block-end: var(--space-xs);
    }

    & h4 {
      margin-block-start: var(--space-lg);
      margin-block-end: var(--space-xs);
    }

    & a {
      color: var(--color-accent);
      text-decoration-thickness: 0.08em;
      text-underline-offset: 0.25em;
      transition: color var(--duration-fast) ease;

      &:hover {
        color: var(--color-accent-hover);
      }
    }

    & blockquote {
      border-inline-start: 0.25rem solid var(--color-accent);
      padding-inline-start: var(--space-lg);
      padding-block: var(--space-xs);
      margin-inline: 0;
      margin-block: var(--space-lg);
      font-style: italic;
      color: var(--color-text-muted);
    }

    & pre {
      background-color: var(--color-code-bg);
      padding: var(--space-md);
      border-radius: var(--radius-md);
      overflow-x: auto;
      margin-block: var(--space-lg);
      border: 0.0625rem solid var(--color-border);

      /* Custom scrollbar — webkit only, progressive */
      &::-webkit-scrollbar {
        block-size: 0.375rem;
      }

      &::-webkit-scrollbar-track {
        background: transparent;
      }

      &::-webkit-scrollbar-thumb {
        background-color: var(--color-border);
        border-radius: var(--radius-full);
      }

      & code {
        background: none;
        padding: 0;
        font-size: var(--text-sm);
        border-radius: 0;
      }
    }

    & code {
      background-color: var(--color-code-bg);
      padding-inline: 0.3em;
      padding-block: 0.1em;
      border-radius: var(--radius-sm);
      font-size: 0.875em;
    }

    & img {
      border-radius: var(--radius-md);
      margin-block: var(--space-lg);
      inline-size: 100%;
    }

    & ul,
    & ol {
      padding-inline-start: var(--space-lg);
      margin-block: var(--space-sm);
    }

    & ul {
      list-style: disc;
    }

    & ol {
      list-style: decimal;
    }

    & hr {
      border: none;
      border-block-start: 0.0625rem solid color-mix(in oklch, var(--color-border) 80%, transparent);
      margin-block: var(--space-2xl);
    }

    & table {
      /* Markdown pipeline emits bare <table> with no wrapper div.
         display: block turns the table into a scrollable island without
         sacrificing internal table layout (inline-size: max-content preserves it). */
      display: block;
      overflow-x: auto;
      inline-size: max-content;
      max-inline-size: 100%;
      margin-block: var(--space-lg);
      border-collapse: collapse;
      font-size: var(--text-sm);

      &::-webkit-scrollbar {
        block-size: 0.375rem;
      }

      &::-webkit-scrollbar-track {
        background: transparent;
      }

      &::-webkit-scrollbar-thumb {
        background-color: var(--color-border);
        border-radius: var(--radius-full);
      }
    }

    & th,
    & td {
      padding-inline: var(--space-sm);
      padding-block: var(--space-xs);
      border: 0.0625rem solid var(--color-border);
      text-align: start;
      vertical-align: top;
    }

    & th {
      background-color: var(--color-code-bg);
      font-weight: 600;
      color: var(--color-text);
    }

    & tr:nth-child(even) td {
      background-color: color-mix(in oklch, var(--color-surface) 60%, transparent);
    }
  }
}

@layer layout {
  body {
    min-block-size: 100dvh;
    display: grid;
    grid-template-rows: auto 1fr auto;
    /* Without an explicit column, the implicit track is minmax(auto, auto) which
       expands to fit children — wide <pre>/<table> inside main blow out the page.
       minmax(0, 1fr) caps the track at available viewport width. */
    grid-template-columns: minmax(0, 1fr);
  }

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

  main {
    padding-block: var(--space-md);
  }

  /* Page-level section spacing */
  .section {
    padding-block: var(--space-xl);
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);

    /* Consecutive sections would double-stack outer padding — pull the top
       of the following section back in so the gap stays visually even. */
    & + & {
      padding-block-start: var(--space-md);
    }

    /* Kill default paragraph margin — flex gap handles rhythm */
    & > p:last-child {
      margin: 0;
      font-size: var(--text-sm);
      font-weight: 500;

      & a {
        color: var(--color-accent);
        text-decoration: none;
        display: inline-flex;
        align-items: center;
        gap: var(--space-2xs);
        padding-block: var(--space-2xs);
        border-block-end: 0.0625rem solid transparent;
        transition:
          color var(--duration-fast) ease,
          border-color var(--duration-fast) ease;

        &:hover {
          color: var(--color-accent-hover);
          border-block-end-color: var(--color-accent);
        }

        &:focus-visible {
          outline: 0.125rem solid var(--color-accent);
          outline-offset: 0.25rem;
          border-radius: var(--radius-sm);
        }
      }
    }
  }

  /* Two-column grid that collapses to single on narrow viewports */
  .grid-auto {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
    gap: var(--space-lg);
  }

  /* Hero section */
  .hero {
    /* top: md at mobile (pulls block closer to header), lg at wide; bottom: md at mobile, lg at wide */
    padding-block: var(--space-md) var(--space-md);

    @media (min-width: 48rem) {
      padding-block: var(--space-lg);
    }

    & .hero__eyebrow {
      font-size: var(--text-sm);
      font-weight: 600;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--color-accent);
      margin-block-end: var(--space-sm);
    }

    & .hero__heading {
      margin-block-end: var(--space-sm);

      @media (min-width: 48rem) {
        margin-block-end: var(--space-md);
      }
    }

    & .hero__lead {
      font-size: var(--text-lg);
      color: var(--color-text-muted);
      max-inline-size: 50ch;
      margin-block-end: var(--space-md);

      @media (min-width: 48rem) {
        margin-block-end: var(--space-lg);
      }
    }

    /* When two leads stack, tighten the inner gap — xl is reserved for the last lead → actions gap */
    & .hero__lead:has(+ .hero__lead) {
      margin-block-end: var(--space-sm);
    }

    & .hero__actions {
      display: flex;
      flex-wrap: wrap;
      gap: var(--space-sm);
      align-items: center;
    }
  }

  /* Stacked block between .hero and first .section — photo above, bio below. */
  .about {
    padding-block: 0;

    @media (min-width: 48rem) {
      padding-block: var(--space-sm);
    }

    display: flex;
    flex-direction: column;
    gap: var(--space-lg);

    @media (min-width: 48rem) {
      gap: var(--space-md);
    }

    & .about__photo {
      inline-size: 100%;
      block-size: auto;
      border-radius: var(--radius-lg);
      display: block;

      &[hidden] {
        display: none;
      }
    }

    & .about__text {
      display: flex;
      flex-direction: column;
      gap: var(--space-sm);

      & p {
        margin: 0;
      }
    }
  }

  /* Site header */
  .site-header {
    position: sticky;
    inset-block-start: 0;
    z-index: 100;
    background-color: var(--color-bg);
    border-block-end: 0.0625rem solid var(--color-border);
    -webkit-backdrop-filter: blur(0.5rem);
    backdrop-filter: blur(0.5rem);

    & .container {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding-block: var(--space-sm);

      @media (min-width: 48rem) {
        display: grid;
        grid-template-columns: 1fr auto 1fr;

        & .nav__logo { justify-self: start; }
        & .nav__controls { justify-self: end; }
      }
    }
  }

  /* Site footer */
  .site-footer {
    border-block-start: 0.0625rem solid var(--color-border);
    padding-block: var(--space-xl);
    color: var(--color-text-muted);
    font-size: var(--text-sm);

    & .container {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: var(--space-md);
      text-align: center;
    }

    & a {
      color: var(--color-text-muted);
      text-decoration: none;

      &:hover {
        color: var(--color-accent);
      }
    }
  }
}

@layer components {
  /* ── Site logo / wordmark ─────────────────────────────────────────── */
  .nav__logo {
    font-family: var(--font-heading);
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--color-text);
    text-decoration: none;
    letter-spacing: -0.02em;

    & span {
      color: var(--color-accent);
    }

    &:hover {
      color: var(--color-text);
    }
  }

  /* ── Nav shell ────────────────────────────────────────────────────── */
  .nav {
    /* Scroll-hide: JS adds .nav--hidden which translates the header up */
    transition: transform var(--duration-normal) ease;

    &.nav--hidden {
      transform: translateY(-110%);
    }

    /* Hidden checkbox — the pure-CSS toggle mechanism */
    & #nav-toggle {
      display: none;
      position: absolute;
      inset-inline-start: -9999px;
    }
  }

  /* ── Nav links — desktop base ─────────────────────────────────────── */
  .nav__links {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    list-style: none;
    margin: 0;
    padding: 0;

    & a {
      font-size: var(--text-sm);
      font-weight: 500;
      color: var(--color-text-muted);
      text-decoration: none;
      padding-block: var(--space-2xs);
      border-block-end: 0.125rem solid transparent;
      transition:
        color var(--duration-fast) ease,
        border-color var(--duration-fast) ease;

      &:hover,
      &[aria-current="page"] {
        color: var(--color-text);
        border-block-end-color: var(--color-accent);
      }
    }
  }

  /* ── Hamburger label — hidden on desktop ──────────────────────────── */
  .nav__toggle-label {
    display: none;
    flex-direction: column;
    justify-content: center;
    gap: 0.3125rem;
    block-size: 2.5rem;
    inline-size: 2.5rem;
    cursor: pointer;
    padding: var(--space-xs);
    border-radius: var(--radius-sm);
    transition: background-color var(--duration-fast) ease;

    &:hover {
      background-color: var(--color-surface);
    }

    & span {
      display: block;
      block-size: 0.125rem;
      inline-size: 100%;
      background-color: var(--color-text);
      border-radius: var(--radius-full);
      transition:
        transform var(--duration-normal) ease,
        opacity var(--duration-fast) ease;
      transform-origin: center;
    }
  }

  /* ── Mobile layout — below 48rem (768px) ─────────────────────────── */
  @media (max-width: 48rem) {
    .nav__toggle-label {
      display: flex;
    }

    .nav .nav__links {
      position: absolute;
      inset-block-start: 100%;
      inset-inline: 0;
      flex-direction: column;
      align-items: stretch;
      gap: 0;
      background-color: var(--color-bg);
      border-block-end: 0.0625rem solid var(--color-border);
      padding-block: var(--space-sm);
      opacity: 0;
      pointer-events: none;
      transform: translateY(-0.5rem);
      transition:
        opacity var(--duration-normal) ease,
        transform var(--duration-normal) ease;

      & a {
        padding-inline: var(--container-padding);
        padding-block: var(--space-sm);
        border-block-end: none;
        font-size: var(--text-base);

        &:hover,
        &[aria-current="page"] {
          border-block-end: none;
          color: var(--color-accent);
        }
      }
    }

    /* Open state — :has() on the nav reads the hidden checkbox */
    .nav:has(#nav-toggle:checked) {
      & .nav__links {
        opacity: 1;
        pointer-events: auto;
        transform: translateY(0);
      }

      /* Animate hamburger → X */
      & .nav__toggle-label span:nth-child(1) {
        transform: translateY(0.4375rem) rotate(45deg);
      }

      & .nav__toggle-label span:nth-child(2) {
        opacity: 0;
      }

      & .nav__toggle-label span:nth-child(3) {
        transform: translateY(-0.4375rem) rotate(-45deg);
      }
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .nav,
    .nav__links,
    .nav__toggle-label span {
      transition: none;
    }
  }
}

@layer components {
  /* ── Skip link ────────────────────────────────────────────────────── */
  #skip-link {
    position: absolute;
    inset-block-start: var(--space-sm);
    inset-inline-start: var(--space-sm);
    padding: var(--space-xs) var(--space-md);
    background-color: var(--color-accent);
    color: var(--color-bg);
    font-weight: 600;
    font-size: var(--text-sm);
    border-radius: var(--radius-md);
    text-decoration: none;
    z-index: 9999;
    transform: translateY(-200%);
    transition: transform var(--duration-fast) ease;

    &:focus-visible {
      transform: translateY(0);
      outline: none;
    }
  }

  /* ── Tag / tech pill ─────────────────────────────────────────────── */
  .tag,
  .tech {
    display: inline-flex;
    align-items: center;
    padding-inline: var(--space-sm);
    padding-block: var(--space-2xs);
    font-size: var(--text-xs);
    font-weight: 500;
    line-height: 1;
    border-radius: var(--radius-full);
    background-color: color-mix(in oklch, var(--color-accent) 15%, transparent);
    color: var(--color-accent);
    border: 0.0625rem solid color-mix(in oklch, var(--color-accent) 30%, transparent);
    white-space: nowrap;
  }

  /* ── Cards (article + project) ────────────────────────────────────── */
  .card {
    /* Anchor for the title-link ::after overlay that makes the whole card clickable */
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    background-color: var(--color-surface);
    border: 0.0625rem solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    text-decoration: none;
    color: inherit;
    transition:
      transform var(--duration-normal) ease,
      box-shadow var(--duration-normal) ease,
      border-color var(--duration-normal) ease;

    &:hover {
      transform: translateY(-0.125rem);
      box-shadow: 0 0.5rem 2rem color-mix(in oklch, var(--color-text) 10%, transparent);
      border-color: var(--color-accent);
    }

    & h2,
    & h3 {
      font-family: var(--font-heading);
      font-size: var(--text-xl);
      font-weight: 700;
      line-height: 1.2;
      margin: 0;

      & a {
        color: inherit;
        text-decoration: none;
        transition: color var(--duration-fast) ease;

        /* Stretched overlay: whole card becomes a click target for the title link. */
        &::after {
          content: "";
          position: absolute;
          inset: 0;
          border-radius: inherit;
        }
      }
    }

    &:hover h2 a,
    &:hover h3 a {
      color: var(--color-accent);
    }

    & header {
      display: flex;
      flex-wrap: wrap;
      align-items: baseline;
      gap: var(--space-sm) var(--space-xs);

      & h2,
      & h3 {
        inline-size: 100%;
      }

      & time {
        font-size: var(--text-xs);
        color: var(--color-text-muted);
        font-variant-numeric: tabular-nums;
      }
    }

    & p {
      font-size: var(--text-sm);
      color: var(--color-text-muted);
      line-height: 1.6;
      margin: 0;
      /* pushes tags/links cluster to the bottom of the card */
      flex: 1;
    }

    & .tags {
      display: flex;
      flex-wrap: wrap;
      gap: var(--space-xs);
      margin-block-start: auto;
    }

    & .tech-stack {
      display: flex;
      flex-wrap: wrap;
      gap: var(--space-xs);
      margin-block-start: auto;
    }

    & .links {
      display: flex;
      flex-wrap: wrap;
      gap: var(--space-sm);
      /* Sits above the title-link overlay so Live/GitHub stay independently clickable. */
      position: relative;
      z-index: 1;

      & a {
        display: inline-flex;
        align-items: center;
        gap: var(--space-2xs);
        font-size: var(--text-sm);
        font-weight: 500;
        color: var(--color-accent);
        text-decoration: none;
        padding-block: var(--space-2xs);
        padding-inline: var(--space-sm);
        border: 0.0625rem solid color-mix(in oklch, var(--color-accent) 35%, transparent);
        border-radius: var(--radius-md);
        transition:
          background-color var(--duration-fast) ease,
          border-color var(--duration-fast) ease;

        &:hover {
          background-color: color-mix(in oklch, var(--color-accent) 10%, transparent);
          border-color: var(--color-accent);
        }

        &:focus-visible {
          outline: 0.125rem solid var(--color-accent);
          outline-offset: 0.125rem;
        }
      }
    }
  }

  /* ── Button ───────────────────────────────────────────────────────── */
  .btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding-inline: var(--space-lg);
    padding-block: var(--space-sm);
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1;
    border-radius: var(--radius-md);
    border: 0.125rem solid transparent;
    background-color: var(--color-accent);
    color: var(--color-on-accent);
    text-decoration: none;
    cursor: pointer;
    transition:
      background-color var(--duration-fast) ease,
      transform var(--duration-fast) ease,
      box-shadow var(--duration-fast) ease;

    &:hover {
      background-color: var(--color-accent-hover);
      transform: translateY(-0.0625rem);
      box-shadow: 0 0.25rem 0.75rem color-mix(in oklch, var(--color-accent) 35%, transparent);
    }

    &:active {
      transform: translateY(0);
    }

    &.btn--outline {
      background-color: transparent;
      border-color: var(--color-border);
      color: var(--color-text);

      &:hover {
        border-color: var(--color-accent);
        color: var(--color-accent);
        background-color: color-mix(in oklch, var(--color-accent) 8%, transparent);
        box-shadow: none;
      }
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .card,
    .btn {
      transition: none;
    }
  }

  /* ── Carousel ─────────────────────────────────────────────────────── */
  .carousel-wrapper {
    container-type: inline-size;
    container-name: carousel;
    position: relative;
  }

  .carousel-track {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;

    &::-webkit-scrollbar {
      display: none;
    }
  }

  .carousel-slide {
    flex: 0 0 100%;
    scroll-snap-align: start;
  }

  .carousel-prev,
  .carousel-next {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 2.5rem;
    block-size: 2.5rem;
    border-radius: var(--radius-full);
    border: 0.0625rem solid var(--color-border);
    background-color: var(--color-surface);
    color: var(--color-text);
    cursor: pointer;
    font-size: var(--text-base);
    line-height: 1;
    padding: 0;
    transition:
      background-color var(--duration-fast) ease,
      border-color var(--duration-fast) ease,
      color var(--duration-fast) ease,
      transform var(--duration-fast) ease;

    &:hover {
      background-color: var(--color-accent);
      border-color: var(--color-accent);
      color: var(--color-on-accent);
      transform: scale(1.08);
    }

    &:focus-visible {
      outline: 0.125rem solid var(--color-accent);
      outline-offset: 0.125rem;
    }

    &:active {
      transform: scale(0.96);
    }
  }

  .carousel-dots {
    display: flex;
    justify-content: center;
    gap: var(--space-xs);
    margin-block-start: var(--space-sm);
  }

  .carousel-dot {
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: var(--radius-full);
    border: none;
    background-color: var(--color-border);
    cursor: pointer;
    padding: 0;
    transition:
      background-color var(--duration-fast) ease,
      transform var(--duration-fast) ease;

    &[aria-current="true"] {
      background-color: var(--color-accent);
      transform: scale(1.3);
    }

    &:focus-visible {
      outline: 0.125rem solid var(--color-accent);
      outline-offset: 0.125rem;
    }
  }

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

    .carousel-dot,
    .carousel-prev,
    .carousel-next {
      transition: none;
    }

    .carousel-prev:hover,
    .carousel-next:hover {
      transform: none;
    }

    .carousel-dot[aria-current="true"] {
      transform: none;
    }
  }

  /* ── Page header (list pages: /articles/, /projects/) ────────────── */
  .page-header {
    padding-block: var(--space-2xl) var(--space-xl);
    border-block-end: 0.0625rem solid var(--color-border);
    margin-block-end: var(--space-2xl);

    & h1 {
      margin-block-end: var(--space-sm);
    }
  }

  .page-header__lead {
    font-size: var(--text-lg);
    color: var(--color-text-muted);
    max-inline-size: 55ch;
    margin: 0;
  }

  /* ── Article header (article detail page) ────────────────────────── */
  /* Lives in layout — it's the top region of a one-off page, not a reusable widget */
  .article-header {
    padding-block-end: var(--space-xl);
    border-block-end: 0.0625rem solid var(--color-border);
    margin-block-end: var(--space-xl);

    & h1 {
      margin-block-end: var(--space-md);
    }

    & .tags {
      display: flex;
      flex-wrap: wrap;
      gap: var(--space-xs);
      margin-block-start: var(--space-sm);
    }
  }

  /* ── Article meta row (date + reading time) ──────────────────────── */
  .article-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-sm);
    font-size: var(--text-sm);
    color: var(--color-text-muted);

    & time {
      font-variant-numeric: tabular-nums;
    }
  }

  /* ── Reading time atom ───────────────────────────────────────────── */
  .reading-time {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
  }

  /* Dot only when reading-time is preceded by a time element */
  time + .reading-time::before {
    content: "·";
    display: inline-block;
  }

  /* ── Article footer ──────────────────────────────────────────────── */
  .article-footer {
    margin-block-start: var(--space-2xl);
  }

  /* ── Project header ──────────────────────────────────────────────── */
  .project-header {
    padding-block-end: var(--space-xl);
    border-block-end: 0.0625rem solid var(--color-border);
    margin-block-end: var(--space-xl);

    & h1 {
      margin-block-end: var(--space-md);
    }
  }

  /* ── Tech stack — row of tag pills ──────────────────────────────── */
  .tech-stack {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
  }

  /* margin only needed on the project detail page, not inside cards */
  .project-header .tech-stack {
    margin-block-end: var(--space-md);
  }

  /* ── Project links — live / github row ──────────────────────────── */
  .project-links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin-block-start: var(--space-md);

    & a {
      display: inline-flex;
      align-items: center;
      gap: var(--space-2xs);
      font-size: var(--text-sm);
      font-weight: 500;
      color: var(--color-accent);
      text-decoration: none;
      padding-block: var(--space-2xs);
      padding-inline: var(--space-sm);
      border: 0.0625rem solid color-mix(in oklch, var(--color-accent) 35%, transparent);
      border-radius: var(--radius-md);
      transition:
        background-color var(--duration-fast) ease,
        border-color var(--duration-fast) ease;

      &:hover {
        background-color: color-mix(in oklch, var(--color-accent) 10%, transparent);
        border-color: var(--color-accent);
      }

      &:focus-visible {
        outline: 0.125rem solid var(--color-accent);
        outline-offset: 0.125rem;
      }
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .project-links a {
      transition: none;
    }
  }

  /* ── Project footer ──────────────────────────────────────────────── */
  .project-footer {
    margin-block-start: var(--space-2xl);
    padding-block-start: var(--space-xl);
    border-block-start: 0.0625rem solid var(--color-border);
  }

  /* ── Back link ───────────────────────────────────────────────────── */
  .back-link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-muted);
    text-decoration: none;
    transition: color var(--duration-fast) ease;

    &:hover {
      color: var(--color-accent);
    }

    &:focus-visible {
      outline: 0.125rem solid var(--color-accent);
      outline-offset: 0.125rem;
      border-radius: var(--radius-sm);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .back-link {
      transition: none;
    }
  }

  /* ── Nav controls (theme toggle + hamburger cluster) ─────────────── */
  .nav__controls {
    display: flex;
    align-items: center;
    gap: var(--space-xs);

    & button {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      inline-size: 2.5rem;
      block-size: 2.5rem;
      border-radius: var(--radius-sm);
      border: none;
      background-color: transparent;
      color: var(--color-text-muted);
      cursor: pointer;
      transition:
        background-color var(--duration-fast) ease,
        color var(--duration-fast) ease;

      &:hover {
        background-color: var(--color-surface);
        color: var(--color-text);
      }

      &:focus-visible {
        outline: 0.125rem solid var(--color-accent);
        outline-offset: 0.125rem;
      }
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .nav__controls button {
      transition: none;
    }
  }

  /* ── Empty state — shown when a project/article list is empty ────────── */
  .empty-state {
    grid-column: 1 / -1;
    text-align: center;
    color: var(--color-text-muted);
    padding-block: var(--space-xl);
    margin: 0;
  }
}

@layer animations {
  @keyframes fade-in {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }

  @keyframes slide-up {
    from {
      opacity: 0;
      transform: translateY(1.5rem);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  @keyframes scale-in {
    from {
      opacity: 0;
      transform: scale(0.94);
    }
    to {
      opacity: 1;
      transform: scale(1);
    }
  }

  /* Page-load entrance animations */
  @media (prefers-reduced-motion: no-preference) {
    [data-animate] {
      animation: slide-up var(--duration-slow) ease both;
    }

    .stagger-1 { animation-delay: 0ms; }
    .stagger-2 { animation-delay: 80ms; }
    .stagger-3 { animation-delay: 160ms; }
    .stagger-4 { animation-delay: 240ms; }
  }

  /* Scroll-driven reveal — progressive enhancement */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      [data-reveal] {
        animation: fade-in linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 40%;
      }

      /* Explicit declaration — default [data-reveal] already uses fade-in, but
         this selector survives if the default rule's animation-name ever changes. */
      [data-reveal="fade-in"] {
        animation-name: fade-in;
      }

      [data-reveal="fade-up"] {
        animation-name: slide-up;
      }

      [data-reveal="scale-in"] {
        animation-name: scale-in;
      }
    }
  }

  /* JS-driven reveal fallback — only active when scroll-driven animations are unsupported.
     Gated so these rules never compete with the [data-reveal] native path above. */
  @supports not (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      [data-reveal].reveal-pending {
        opacity: 0;
      }

      [data-reveal="fade-up"].reveal-pending {
        transform: translateY(1.5rem);
      }

      [data-reveal="scale-in"].reveal-pending {
        transform: scale(0.94);
      }

      [data-reveal].revealed {
        opacity: 1;
        transform: none;
        transition:
          opacity var(--duration-slow) ease,
          transform var(--duration-slow) ease;
      }

      [data-reveal].no-transition {
        transition: none;
      }
    }

    @media (prefers-reduced-motion: reduce) {
      [data-reveal].reveal-pending {
        opacity: 1;
        transform: none;
      }
    }
  }

  /* Reduced motion: kill everything */
  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }

    [data-reveal],
    [data-animate] {
      animation: none;
      opacity: 1;
      transform: none;
    }
  }
}
