/* ============================================================
   Portfolio layer.

   base.css supplies the design tokens (--background, --foreground,
   --border, --destructive, --font-display …), the fonts, the utility
   classes and every @keyframes. Nothing here redefines a token —
   it only composes them.
   ============================================================ */

/* ── legacy-engine safety net ──────────────────────────────────
   base.css defines the whole palette in oklch(). Custom
   properties are not validated when parsed, so on an engine
   without oklch() the tokens survive but every `var(--background)`
   that uses them is invalid at computed-value time and resolves to
   transparent — the page collapses rather than degrading.

   Restating the four tokens as hex costs nothing and turns that
   into a flat-but-legible page. Colours are the oklch values
   converted: Chrome 111+ / Safari 15.4+ never see this block.
   ────────────────────────────────────────────────────────────── */

@supports not (color: oklch(0% 0 0)) {
  :root,
  [data-theme="dark"] {
    --background: #060000;
    --foreground: #fdf6e3;
    --border:     #1a1113;
    --destructive: #ff6467;
  }
}

/* ── light / dark theming ──────────────────────────────────────
   base.css already ships a light palette on :root and dark on
   [data-theme="dark"]; the document defaults to dark. We pin an
   explicit, tuned light palette (base's light --border is near-black,
   far too heavy for hairlines), set color-scheme per theme, and
   re-ink the hero art so the cream plates read on paper. */

:root { color-scheme: dark; }

[data-theme="light"] {
  color-scheme: light;
  --background:  #f4efe3;   /* warm paper          */
  --foreground:  #211a1b;   /* dark ink            */
  --border:      #ddd2c1;   /* soft warm hairline  */
  --destructive: #d23a3d;   /* red tuned for light */
}

/* Ease the switch without transitioning every descendant. */
body { transition: background-color .3s ease, color .3s ease; }

/* Hero art is cream ink on transparency — invert it to dark ink on
   paper so the hands (plates + grain field) stay visible in light. */
[data-theme="light"] .backdrop-layer,
[data-theme="light"] .backdrop-canvas { filter: invert(1) hue-rotate(180deg); }

/* The crosshair HUD is cream too. */
[data-theme="light"] .cursor-hud { --hud: 33 26 27; }

/* ── theme toggle ──────────────────────────────────────────── */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 40px; height: 40px;
  border: 1px solid color-mix(in oklab, var(--foreground) 14%, transparent);
  border-radius: var(--radius-sm);
  background: transparent;
  color: color-mix(in oklab, var(--foreground) 62%, transparent);
  cursor: pointer;
  transition: color .18s, border-color .18s, background .18s;
}
.theme-toggle:hover {
  color: var(--foreground);
  border-color: color-mix(in oklab, var(--foreground) 30%, transparent);
  background: color-mix(in oklab, var(--foreground) 5%, transparent);
}
.theme-toggle svg { display: block; width: 17px; height: 17px; }
.theme-toggle .icon-moon { display: none; }
[data-theme="light"] .theme-toggle .icon-sun  { display: none; }
[data-theme="light"] .theme-toggle .icon-moon { display: block; }

/* ── utilities absent from the base build ─────────────────────
   base.css is a compiled Tailwind bundle and only carries the
   utilities its source markup used. These few are emitted here in
   the same idiom, off the same --spacing / --container scale.
   ────────────────────────────────────────────────────────────── */

.antialiased      { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
.text-destructive { color: var(--destructive); }
.max-w-lg         { max-width: var(--container-lg, 32rem); }

.gap-7   { gap: calc(var(--spacing) * 7); }
.gap-10  { gap: calc(var(--spacing) * 10); }
.gap-x-8 { column-gap: calc(var(--spacing) * 8); }

.pt-32 { padding-top: calc(var(--spacing) * 32); }
.pb-20 { padding-bottom: calc(var(--spacing) * 20); }
.py-20 { padding-block: calc(var(--spacing) * 20); }
.py-9  { padding-block: calc(var(--spacing) * 9); }

@media (min-width: 48rem) {
  .md\:pt-40 { padding-top: calc(var(--spacing) * 40); }
  .md\:pb-28 { padding-bottom: calc(var(--spacing) * 28); }
  .md\:py-28 { padding-block: calc(var(--spacing) * 28); }
}

@media (min-width: 64rem) {
  .lg\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0px, 1fr)); }
}

/* ── page frame ────────────────────────────────────────────── */

html { scroll-behavior: smooth; scroll-padding-top: 6rem; }
body { line-height: 1.6; }

.shell {
  width: 100%;
  max-width: calc(var(--container-7xl) + 1rem);
  margin-inline: auto;
  padding-inline: 1.25rem;
}
@media (min-width: 48rem) { .shell { padding-inline: 2rem; } }

.font-display { font-family: var(--font-display); font-weight: 400; }

.skip {
  position: fixed;
  top: .5rem; left: .5rem;
  z-index: 200;
  padding: .6rem 1rem;
  background: var(--foreground);
  color: var(--background);
  font-size: 12px;
  transform: translateY(-250%);
}
.skip:focus { transform: none; }

:focus-visible { outline: 2px solid var(--destructive); outline-offset: 3px; }

/* ── ambient texture ───────────────────────────────────────── */

.scanlines, .grain { position: fixed; inset: 0; pointer-events: none; z-index: 1; }
.scanlines {
  opacity: .5;
  background: repeating-linear-gradient(
    to bottom,
    color-mix(in oklab, var(--foreground) 2.2%, transparent) 0 1px,
    transparent 1px 3px);
}
.grain {
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

main, header, footer { position: relative; z-index: 2; }

/* ── nav ───────────────────────────────────────────────────── */

#nav.is-stuck {
  background: color-mix(in oklab, var(--background) 80%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}
.nav-links a.is-active { color: var(--foreground); }

.nav-burger span {
  display: block;
  width: 18px; height: 1.5px;
  background: var(--foreground);
  transition: transform .2s var(--ease-in-out, ease);
}
.nav-burger[aria-expanded="true"] span:first-child { transform: translateY(3.25px) rotate(45deg); }
.nav-burger[aria-expanded="true"] span:last-child  { transform: translateY(-3.25px) rotate(-45deg); }

.drawer {
  display: flex;
  flex-direction: column;
  padding: .25rem 1.25rem 1.25rem;
  background: color-mix(in oklab, var(--background) 96%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}
.drawer[hidden] { display: none; }
.drawer a {
  padding: .85rem 0;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--foreground) 65%, transparent);
}

/* ── atoms ─────────────────────────────────────────────────── */

.eyebrow {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--foreground) 40%, transparent);
}

.head { max-width: 54ch; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .4rem .8rem .4rem .65rem;
  border: 1px solid color-mix(in oklab, var(--foreground) 12%, transparent);
  border-radius: 100px;
  font-size: 12px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--foreground) 68%, transparent);
}
.badge-dot {
  width: 6px; height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--destructive);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 16%, transparent);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: 0 1.3rem;
  height: 40px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background .18s, color .18s, border-color .18s, transform .18s;
}
.btn-solid { background: var(--foreground); color: var(--background); }
.btn-solid:hover { transform: translateY(-1px); }
.btn-ghost {
  border-color: color-mix(in oklab, var(--foreground) 14%, transparent);
  color: color-mix(in oklab, var(--foreground) 75%, transparent);
}
.btn-ghost:hover { border-color: color-mix(in oklab, var(--foreground) 32%, transparent); color: var(--foreground); }

/* Hairline-separated cell grid — one border, no doubling. */
.cellgrid {
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.cellgrid > * { background: var(--background); }

.panel {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background:
    linear-gradient(180deg, color-mix(in oklab, var(--foreground) 2.5%, transparent), transparent 55%),
    var(--background);
}

/* ── hero ──────────────────────────────────────────────────── */

/* Full-bleed parallax field sits behind the hero content: feather
   the sides of every layer, fade the whole stack out toward the
   bottom, and let each layer travel a different distance so the
   field reads as having depth. */
/* Min-height gives the two-hand composition room to resolve —
   the plates are 2.26:1, so a short hero crops the reach. */
.hero-wrap {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  /* Full viewport, so the recon panel below starts past the fold
     instead of peeking in at the bottom of the first screen.
     dvh keeps that true on mobile, where the URL bar shrinks vh. */
  min-height: 100vh;
  min-height: 100dvh;
}
.hero-inner { position: relative; z-index: 1; width: 100%; }

/* The bottom fade has to clear the lower edge of the plate, or it
   slices the fingers into vertical bars that read as a chart. */
.backdrop {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 88%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 88%, transparent 100%);
}

/* Sits between the plates and the copy: darkens the middle just
   enough to hold the headline, while leaving the reach at the
   edges untouched. */
.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(
    46% 34% at 50% 47%,
    color-mix(in oklab, var(--background) 62%, transparent) 0%,
    color-mix(in oklab, var(--background) 30%, transparent) 52%,
    transparent 78%);
}

/* Grain field. Sits above the plates — in canvas mode the plates
   are held at opacity 0 and this carries the image instead. */
.backdrop-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  will-change: transform;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
}

/* ── HUD cursor ────────────────────────────────────────────────
   Page-wide, fixed to the viewport, above content (z-40) but under
   the nav (z-50) so the bar stays crisp. The class on <html> is
   added by JS, so the native cursor is only hidden once the overlay
   actually exists.

   Colours are literal rgb rather than color-mix() — an unsupported
   color-mix invalidates a whole gradient, which would leave the
   glow invisible rather than degraded.
   ────────────────────────────────────────────────────────────── */

.cursor-hud {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  opacity: 0;
  transition: opacity .35s ease-out;
  --hud: 253 246 227;
}
.cursor-hud.is-live  { opacity: 1; }
.cursor-hud.is-active { --hud: 255 100 103; }

.cursor-hud > * {
  position: absolute;
  top: 0; left: 0;
  will-change: transform;
}

/* Full-viewport rules crossing at the fingertip. */
.cursor-line--h {
  width: 100vw; height: 1px;
  background: linear-gradient(to right,
    transparent, rgb(var(--hud) / .18) 18%, rgb(var(--hud) / .18) 82%, transparent);
}
.cursor-line--v {
  width: 1px; height: 100vh;
  background: linear-gradient(to bottom,
    transparent, rgb(var(--hud) / .18) 18%, rgb(var(--hud) / .18) 82%, transparent);
}

.cursor-glow {
  width: 260px; height: 260px;
  margin: -130px 0 0 -130px;
  border-radius: 50%;
  mix-blend-mode: screen;
  background: radial-gradient(circle,
    rgb(var(--hud) / .17) 0%, rgb(var(--hud) / .06) 40%, transparent 70%);
}

.cursor-read {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 14px 0 0 18px;
  font-size: 9px;
  line-height: 1.3;
  letter-spacing: .16em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: rgb(var(--hud) / .55);
}
.cursor-read__ang { color: rgb(var(--hud) / .9); }

/* Coarse pointers never build the overlay, but belt and braces. */
@media (pointer: coarse) {
  .cursor-hud { display: none; }
}

.hero-center { text-align: center; }
.hero-center .badge { margin-inline: auto; }

/* Ambient glyph speckle — deliberately near-invisible. */
.noise-strip {
  display: block;
  overflow: hidden;
  font-size: 11px;
  line-height: 1.35;
  letter-spacing: .18em;
  word-break: break-all;
  color: color-mix(in oklab, var(--foreground) 14%, transparent);
  user-select: none;
}

/* Each plate is contain-fitted and feathered at its own left and
   right edges, so the layers dissolve into the page rather than
   ending on a hard rectangle. */
.backdrop-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background-position: center;
  background-repeat: no-repeat;
  background-size: contain;
  will-change: transform;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
}

.hero-line { letter-spacing: -.035em; }
.hero-role { font-size: 13px; letter-spacing: .2em; text-transform: uppercase; }

.hero-link {
  padding: .55rem .9rem;
  border: 1px solid color-mix(in oklab, var(--foreground) 12%, transparent);
  border-radius: var(--radius-sm);
  font-size: 12px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--foreground) 60%, transparent);
  transition: border-color .18s, color .18s;
}
.hero-link:hover { border-color: var(--destructive); color: var(--destructive); }

#hero-certs li {
  padding: .38rem .7rem;
  border: 1px solid color-mix(in oklab, var(--foreground) 12%, transparent);
  border-radius: var(--radius-sm);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .13em;
  color: color-mix(in oklab, var(--foreground) 55%, transparent);
}

/* ── recon panel ───────────────────────────────────────────── */

/* A little air above the panel so it doesn't sit flush against the
   fold once you scroll past the hero. */
.recon-section { padding-top: clamp(1.25rem, 4vw, 3rem); }

/* Full-width strip below the hero, so the field list flows into
   as many columns as the viewport allows. */
.recon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: .3rem 1.75rem;
  margin: 0;
}

.recon-row { display: flex; justify-content: space-between; gap: .6rem; min-width: 0; }
.recon-row dt {
  letter-spacing: .07em;
  white-space: nowrap;
  color: color-mix(in oklab, var(--foreground) 34%, transparent);
}
.recon-row dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: color-mix(in oklab, var(--foreground) 62%, transparent);
}
.recon-row dd.is-warn { color: var(--destructive); }

/* ── stats ─────────────────────────────────────────────────── */

.stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 48rem) { .stats-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.stat { padding: 1.5rem 1.75rem; }
.stat-value { font-family: var(--font-display); font-size: clamp(1.4rem, 3vw, 1.9rem); letter-spacing: -.03em; }
.stat-label {
  margin-top: .55rem;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--foreground) 35%, transparent);
}

/* ── about ─────────────────────────────────────────────────── */

.bio { display: grid; gap: 1.1rem; max-width: 68ch; }
.bio-p { font-size: 16px; line-height: 1.75; color: color-mix(in oklab, var(--foreground) 62%, transparent); }

.op-points { margin: 1rem 0 0; padding: 0; list-style: none; display: grid; gap: .45rem; }
.op-points li {
  position: relative;
  padding-left: 1rem;
  font-size: 14px;
  line-height: 1.6;
  color: color-mix(in oklab, var(--foreground) 48%, transparent);
}
.op-points li::before {
  content: "";
  position: absolute;
  left: 0; top: .55em;
  width: 4px; height: 4px;
  background: var(--destructive);
}

/* ── experience ────────────────────────────────────────────── */

.job {
  display: grid;
  gap: 1rem;
  padding: clamp(1.5rem, 3vw, 2rem) 0;
  border-top: 1px solid var(--border);
}
.job:last-child { border-bottom: 1px solid var(--border); }

/* Date sits above the role rather than in a left rail. The rail
   version left a ~240px column empty for the whole height of every
   entry, since nothing below the header ever filled it. */
.job-head { display: grid; gap: .55rem; }

.job-when {
  display: flex;
  align-items: center;
  gap: .6rem;
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--foreground) 38%, transparent);
}
.job-now {
  padding: .15rem .4rem;
  border: 1px solid var(--destructive);
  border-radius: 2px;
  font-size: 8.5px;
  letter-spacing: .14em;
  color: var(--destructive);
}

.job-title { min-width: 0; }
.job-role { font-size: 18px; font-weight: 500; letter-spacing: -.01em; }
.job-org  { margin-top: .3rem; font-size: 14.5px; color: var(--destructive); }
.job-meta {
  font-size: 12px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--foreground) 32%, transparent);
}

.job-summary { font-size: 15px; line-height: 1.7; color: color-mix(in oklab, var(--foreground) 58%, transparent); }

.job-points { margin: 0; padding: 0; list-style: none; display: grid; gap: .5rem; }
.job-points li {
  position: relative;
  padding-left: 1.1rem;
  font-size: 15px;
  line-height: 1.65;
  color: color-mix(in oklab, var(--foreground) 48%, transparent);
}
.job-points li::before {
  content: "";
  position: absolute;
  left: 0; top: .6em;
  width: 5px; height: 1px;
  background: color-mix(in oklab, var(--foreground) 35%, transparent);
}

/* ── certification timeline ────────────────────────────────────
   The full path as a vertical progress spine: a continuous hairline
   (drawn per-item so it survives any content height), category-
   coloured dots as milestones, and year markers. Newest sits at the
   top with a pulsing dot. Each cert carries its category tone in
   --tone, which colours its dot, tag, and hover states. */

.cert-timeline { position: relative; max-width: 52rem; }

.cert-path-caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .45rem 1rem;
  margin-bottom: 1.6rem;
  padding-left: 1.9rem;
}
.cert-path-span {
  font-family: var(--font-display);
  font-size: 16px;
  letter-spacing: .02em;
  color: color-mix(in oklab, var(--foreground) 60%, transparent);
}
.cert-path-count {
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--foreground) 32%, transparent);
}

/* The spine — one segment per item, so they abut into a solid line. */
.cert-year::before,
.cert-node::before {
  content: "";
  position: absolute;
  left: 5px; top: 0; bottom: 0;
  width: 1px;
  background: color-mix(in oklab, var(--foreground) 10%, transparent);
}

/* Year milestone — a diamond notch riding the spine. */
.cert-year { position: relative; padding: 1.5rem 0 .55rem 1.9rem; }
.cert-year::after {
  content: "";
  position: absolute;
  left: 1.5px; top: 1.6rem;
  width: 8px; height: 8px;
  transform: rotate(45deg);
  background: color-mix(in oklab, var(--foreground) 42%, transparent);
}
.cert-year-num {
  font-family: var(--font-display);
  font-size: 15px;
  letter-spacing: .12em;
  color: color-mix(in oklab, var(--foreground) 42%, transparent);
}

/* One credential. */
.cert-node {
  position: relative;
  padding: 1.15rem 0 1.2rem 1.9rem;
  border-top: 1px solid color-mix(in oklab, var(--foreground) 6%, transparent);
}
.cert-year + .cert-node { border-top: 0; }

.cert-dot {
  position: absolute;
  left: 0; top: 1.4rem;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--background);
  border: 2px solid var(--tone, var(--destructive));
  transition: box-shadow .2s;
}
.cert-node:hover .cert-dot { box-shadow: 0 0 0 4px color-mix(in oklab, var(--tone) 16%, transparent); }
.cert-node.is-latest .cert-dot {
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--tone) 20%, transparent);
  animation: pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;
}

.cert-node-top { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem .7rem; }
.cert-node-date {
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: color-mix(in oklab, var(--foreground) 42%, transparent);
}
.cert-latest {
  padding: .14rem .45rem;
  border: 1px solid var(--tone);
  border-radius: 2px;
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--tone);
}
.cert-node-cat {
  margin-left: auto;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--tone);
}

.cert-node-name { margin-top: .55rem; font-size: 18px; font-weight: 500; line-height: 1.4; }
.cert-node-name a { transition: color .18s; }
.cert-node-name a:hover { color: var(--tone); }

.cert-node-issuer { margin-top: .4rem; font-size: 15px; color: color-mix(in oklab, var(--foreground) 48%, transparent); }
.cert-node-note { margin-top: .6rem; font-size: 15px; line-height: 1.6; color: color-mix(in oklab, var(--foreground) 42%, transparent); }

.cert-node-children {
  margin: .7rem 0 0;
  padding: .1rem 0 .1rem .9rem;
  list-style: none;
  display: grid;
  gap: .35rem;
  border-left: 1px solid color-mix(in oklab, var(--foreground) 10%, transparent);
}
.cert-node-children li { font-size: 15px; letter-spacing: .01em; color: color-mix(in oklab, var(--foreground) 48%, transparent); }
.cert-node-children a { transition: color .18s; }
.cert-node-children a:hover { color: var(--tone); }

.cert-node-skills { margin-top: .7rem; display: flex; flex-wrap: wrap; gap: .35rem; }
.cert-node-skills span {
  padding: .2rem .5rem;
  border: 1px solid color-mix(in oklab, var(--foreground) 10%, transparent);
  border-radius: var(--radius-sm);
  font-size: 13px;
  letter-spacing: .03em;
  color: color-mix(in oklab, var(--foreground) 46%, transparent);
  transition: border-color .18s, color .18s;
}
.cert-node-skills span:hover {
  border-color: color-mix(in oklab, var(--tone) 40%, transparent);
  color: color-mix(in oklab, var(--foreground) 72%, transparent);
}

/* ── writing ───────────────────────────────────────────────── */

.post { display: block; padding: clamp(1.4rem, 2.6vw, 1.9rem); transition: background .22s; }
.post:hover { background: color-mix(in oklab, var(--foreground) 3%, var(--background)); }
.post:hover .post-title { color: var(--destructive); }

.post-top { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.post-tag {
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--destructive);
}
.post-date {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: color-mix(in oklab, var(--foreground) 30%, transparent);
}
.post-title {
  margin-top: .9rem;
  font-size: 17px;
  font-weight: 500;
  line-height: 1.4;
  transition: color .18s;
}
.post-excerpt {
  margin-top: .7rem;
  font-size: 15px;
  line-height: 1.7;
  color: color-mix(in oklab, var(--foreground) 48%, transparent);
}

/* ── noise strips ──────────────────────────────────────────── */

.hero-noise {
  position: absolute;
  right: 0; bottom: 1.25rem; left: 0;
  z-index: 1;
  padding-inline: 1.25rem;
  max-height: 2.7em;
  text-align: center;
  opacity: .6;
}
.foot-noise { padding: .9rem 1.25rem 0; max-height: 2.7em; opacity: .5; }

/* ── operations ────────────────────────────────────────────── */

.op { padding: 1.75rem; transition: background .22s; }
.op:hover { background: color-mix(in oklab, var(--foreground) 2.5%, var(--background)); }
.op-key { font-size: 9.5px; letter-spacing: .16em; color: var(--destructive); }
.op-title { margin-block: .85rem .7rem; font-size: 16.5px; font-weight: 500; }
.op-body { font-size: 15px; line-height: 1.7; color: color-mix(in oklab, var(--foreground) 48%, transparent); }

/* ── arsenal ───────────────────────────────────────────────── */

.kit {
  display: grid;
  gap: .8rem;
  padding: 1.5rem;
}
@media (min-width: 48rem) {
  .kit { grid-template-columns: minmax(0, 13rem) minmax(0, 1fr); gap: 1rem 2rem; align-items: baseline; }
}
.kit-label { font-size: 10px; letter-spacing: .15em; text-transform: uppercase;
             color: color-mix(in oklab, var(--foreground) 35%, transparent); }
.kit-tags { display: flex; flex-wrap: wrap; gap: .45rem; }
.kit-tags span {
  padding: .35rem .7rem;
  border: 1px solid color-mix(in oklab, var(--foreground) 12%, transparent);
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: color-mix(in oklab, var(--foreground) 62%, transparent);
  transition: border-color .18s, color .18s;
}
.kit-tags span:hover { border-color: color-mix(in oklab, var(--foreground) 32%, transparent); color: var(--foreground); }

/* ── contact ───────────────────────────────────────────────── */

.cta-panel {
  max-width: 66ch;
  background:
    radial-gradient(120% 100% at 0% 0%, color-mix(in oklab, var(--destructive) 8%, transparent), transparent 60%),
    var(--background);
}

#foot-links a { color: color-mix(in oklab, var(--foreground) 45%, transparent); transition: color .18s; }
#foot-links a:hover { color: var(--destructive); }

/* ── scroll reveal ─────────────────────────────────────────── */

.reveal { opacity: 0; transform: translateY(14px); }
.reveal.is-in { opacity: 1; transform: none; transition: opacity .6s ease-out, transform .6s ease-out; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .reveal.is-in { opacity: 1; transform: none; transition: none; }
}

/* ── narrow screens ────────────────────────────────────────── */

@media (max-width: 47.99rem) {
  /* No hands on phones, so the wash that held the headline over them is
     just a dark smudge — and the hero can size to its content. */
  .hero-scrim { display: none; }
  .hero-noise { display: none; }
  /* min-height stays at 100dvh so the recon panel keeps clear of the fold. */

  .hero-role { font-size: 12.5px; letter-spacing: .12em; }
}

@media (max-width: 560px) {
  #recon-grid { grid-template-columns: minmax(0, 1fr); }
}

/* Content type is sized in fixed px tuned to read well on both PC and
   phones, so there is no separate small-screen scale to maintain. */
