/* ==========================================================================
   irfanbaht.in — design system
   Built on the modern-web-design skill: fluid type, OKLCH tokens,
   performance-first motion, WCAG AA contrast in both themes.

   Contents
   01. Tokens
   02. Reset
   03. Typography
   04. Layout
   05. Accessibility utilities
   06. Header & navigation
   07. Mega menu
   08. Mobile drawer
   09. Buttons
   10. Hero
   11. Cards
   12. Sections & decoration
   13. Prose / article
   14. Forms
   15. Footer
   16. Motion & cursor
   17. Print
   ========================================================================== */

/* ==========================================================================
   00. FONTS
   Self-hosted. Loading these from Google's CDN cost a third-party connection
   on every page, made the first paint wait on a cross-origin round trip, and
   sat badly with the footer's "no trackers" claim — Google Fonts logs the
   requesting IP. These are the same files, served from the same origin, with
   only the latin and latin-ext subsets kept.

   Both faces are variable, so one file covers every weight the design uses.
   `font-display: swap` keeps text readable while they load; the fallback stack
   in --font-sans is metric-similar enough that the swap is not a jolt.
   ========================================================================== */

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/assets/fonts/jetbrains-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/assets/fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   01. TOKENS
   ========================================================================== */

:root {
  /* ── Palette. Dark is the authored default; light is a full re-map. ────── */
  --bg:              oklch(16% 0.021 265);
  --bg-raised:       oklch(20% 0.024 265);
  --bg-sunken:       oklch(13% 0.020 265);
  --surface:         oklch(23% 0.025 265);
  --surface-hover:   oklch(27% 0.028 265);

  --text:            oklch(96% 0.005 265);
  --text-muted:      oklch(76% 0.014 265);
  --text-subtle:     oklch(62% 0.016 265);

  --border:          oklch(31% 0.026 265);
  --border-strong:   oklch(42% 0.030 265);

  /* Primary reads as a signal colour, not a brand wash. */
  --primary:         oklch(72% 0.155 228);
  --primary-strong:  oklch(80% 0.135 228);
  --primary-dim:     oklch(52% 0.120 228);
  --primary-ink:     oklch(17% 0.040 240);

  --accent:          oklch(78% 0.160 68);
  --accent-strong:   oklch(85% 0.140 68);
  --accent-ink:      oklch(20% 0.050 60);

  --success:         oklch(75% 0.150 155);
  --warning:         oklch(80% 0.150 85);
  --danger:          oklch(70% 0.180 22);

  /* Which cut of the wordmark to paint. A token rather than a selector so that
     anything overriding the palette locally — the light hero band, and the nav
     floating over it — gets the correct cut for free. */
  --brand-logo:      url("/assets/img/logo-dark.png");

  /* The hero's silky wash, as tonal stops rather than fixed colours, so the
     band follows the theme instead of being pinned to one of them. `fold` is
     the highlight that reads as a crease in the fabric. */
  --wash-lo:         oklch(12.5% 0.014 265);
  --wash-mid:        oklch(18% 0.020 265);
  --wash-hi:         oklch(26% 0.026 265);
  --wash-fold:       oklch(88% 0.010 265 / 0.07);
  /* Greyscale particles, following the reference. Light on the dark theme. */
  --hero-particle-far:  oklch(62% 0.006 265);
  --hero-particle-near: oklch(82% 0.005 265);
  --hero-particle-gain: 0.85;
  --hero-particle-blend: add;

  --glass-bg:        oklch(23% 0.025 265 / 0.72);
  --glass-border:    oklch(100% 0 0 / 0.10);
  --glass-blur:      14px;

  /* Tinted shadows read better than neutral black on coloured backgrounds. */
  --shadow-1: 0 1px 2px oklch(8% 0.02 265 / 0.40);
  --shadow-2: 0 4px 12px oklch(8% 0.02 265 / 0.42);
  --shadow-3: 0 12px 32px oklch(8% 0.02 265 / 0.46);
  --shadow-4: 0 24px 64px oklch(8% 0.02 265 / 0.52);
  --glow:     0 0 0 1px oklch(72% 0.155 228 / 0.35), 0 8px 32px oklch(72% 0.155 228 / 0.18);

  /* Hero wash. Kept as tokens because the dark value is far too strong in
     light mode, where a large saturated field fights the text. */

  /* ── Type ─────────────────────────────────────────────────────────────── */
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system,
               "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono",
               Menlo, Consolas, "Liberation Mono", monospace;

  --fs-2xs:  clamp(0.6875rem, 0.66rem + 0.14vw, 0.75rem);
  --fs-xs:   clamp(0.75rem,  0.72rem + 0.16vw, 0.8125rem);
  --fs-sm:   clamp(0.875rem, 0.845rem + 0.15vw, 0.9375rem);
  --fs-base: clamp(1rem,     0.96rem + 0.2vw,   1.0625rem);
  --fs-md:   clamp(1.0625rem,1.01rem + 0.28vw,  1.1875rem);
  --fs-lg:   clamp(1.25rem,  1.15rem + 0.5vw,   1.5rem);
  --fs-xl:   clamp(1.5rem,   1.3rem + 1vw,      2.125rem);
  --fs-2xl:  clamp(1.875rem, 1.55rem + 1.6vw,   3rem);
  --fs-3xl:  clamp(2.375rem, 1.8rem + 2.9vw,    4.25rem);
  --fs-4xl:  clamp(2.75rem,  1.9rem + 4.2vw,    5.75rem);

  --lh-tight: 1.08;
  --lh-snug:  1.25;
  --lh-base:  1.65;
  --lh-loose: 1.78;

  --tracking-tight: -0.022em;
  --tracking-snug:  -0.012em;
  --tracking-wide:  0.06em;
  --tracking-caps:  0.14em;

  /* ── Space ────────────────────────────────────────────────────────────── */
  --space-3xs: clamp(0.25rem, 0.23rem + 0.1vw,  0.3125rem);
  --space-2xs: clamp(0.5rem,  0.46rem + 0.2vw,  0.625rem);
  --space-xs:  clamp(0.75rem, 0.69rem + 0.3vw,  0.9375rem);
  --space-sm:  clamp(1rem,    0.92rem + 0.4vw,  1.25rem);
  --space-md:  clamp(1.5rem,  1.38rem + 0.6vw,  1.875rem);
  --space-lg:  clamp(2rem,    1.8rem + 1vw,     2.75rem);
  --space-xl:  clamp(3rem,    2.6rem + 2vw,     4.5rem);
  --space-2xl: clamp(4rem,    3.2rem + 4vw,     7rem);
  --space-3xl: clamp(5.5rem,  4.2rem + 6.5vw,  10rem);

  /* ── Shape ────────────────────────────────────────────────────────────── */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 18px;
  --radius-xl: 26px;
  --radius-pill: 999px;

  /* ── Motion ───────────────────────────────────────────────────────────── */
  --dur-fast:   150ms;
  --dur-normal: 260ms;
  --dur-slow:   420ms;
  --dur-slower: 680ms;
  --ease:        cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);

  /* ── Layout ───────────────────────────────────────────────────────────── */
  --width-full: 1280px;
  --width-wide: 1120px;
  --width-text: 68ch;
  --gutter: clamp(1.125rem, 4vw, 3rem);
  /* The nav floats, so --header-h is the space it *occupies* — its top offset
     plus its own height. Every scroll offset and sticky sidebar reads from it. */
  --nav-top: clamp(0.75rem, 1.6vw, 1.5rem);
  --nav-h: 2.75rem;
  --header-h: calc(var(--nav-top) * 2 + var(--nav-h));

  color-scheme: dark;
}

/* Light theme. Every token above is redefined — no partial overrides, because
   a half-mapped palette is how contrast bugs get shipped. */
:root[data-theme="light"] {
  --bg:              oklch(99% 0.003 265);
  --bg-raised:       oklch(100% 0 0);
  --bg-sunken:       oklch(96.5% 0.005 265);
  --surface:         oklch(100% 0 0);
  --surface-hover:   oklch(97.5% 0.006 265);

  --text:            oklch(21% 0.022 265);
  --text-muted:      oklch(42% 0.020 265);
  --text-subtle:     oklch(53% 0.018 265);

  --border:          oklch(90% 0.010 265);
  --border-strong:   oklch(80% 0.016 265);

  --primary:         oklch(50% 0.155 240);
  --primary-strong:  oklch(42% 0.160 240);
  --primary-dim:     oklch(88% 0.055 235);
  --primary-ink:     oklch(99% 0.005 240);

  --accent:          oklch(53% 0.150 48);
  --accent-strong:   oklch(45% 0.150 45);
  --accent-ink:      oklch(99% 0.005 60);

  --success:         oklch(46% 0.130 155);
  --warning:         oklch(52% 0.130 75);
  --danger:          oklch(52% 0.190 25);

  --brand-logo:      url("/assets/img/logo-light.png");

  --wash-lo:         oklch(87% 0.003 265);
  --wash-mid:        oklch(93.5% 0.002 265);
  --wash-hi:         oklch(99.2% 0.001 265);
  --wash-fold:       oklch(100% 0 0 / 0.72);
  --hero-particle-far:  oklch(72% 0.004 265);
  --hero-particle-near: oklch(52% 0.005 265);
  --hero-particle-gain: 0.62;
  --hero-particle-blend: normal;

  --glass-bg:        oklch(100% 0 0 / 0.80);
  --glass-border:    oklch(20% 0.02 265 / 0.10);

  --shadow-1: 0 1px 2px oklch(40% 0.03 265 / 0.08);
  --shadow-2: 0 4px 12px oklch(40% 0.03 265 / 0.10);
  --shadow-3: 0 12px 32px oklch(40% 0.03 265 / 0.12);
  --shadow-4: 0 24px 64px oklch(40% 0.03 265 / 0.14);
  --glow:     0 0 0 1px oklch(50% 0.155 240 / 0.30), 0 8px 32px oklch(50% 0.155 240 / 0.14);

  color-scheme: light;
}

/* Follow the OS when the visitor has not chosen explicitly. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg:              oklch(99% 0.003 265);
    --bg-raised:       oklch(100% 0 0);
    --bg-sunken:       oklch(96.5% 0.005 265);
    --surface:         oklch(100% 0 0);
    --surface-hover:   oklch(97.5% 0.006 265);
    --text:            oklch(21% 0.022 265);
    --text-muted:      oklch(42% 0.020 265);
    --text-subtle:     oklch(53% 0.018 265);
    --border:          oklch(90% 0.010 265);
    --border-strong:   oklch(80% 0.016 265);
    --primary:         oklch(50% 0.155 240);
    --primary-strong:  oklch(42% 0.160 240);
    --primary-dim:     oklch(88% 0.055 235);
    --primary-ink:     oklch(99% 0.005 240);
    --accent:          oklch(53% 0.150 48);
    --accent-strong:   oklch(45% 0.150 45);
    --accent-ink:      oklch(99% 0.005 60);
    --success:         oklch(46% 0.130 155);
    --warning:         oklch(52% 0.130 75);
    --danger:          oklch(52% 0.190 25);
    --brand-logo:      url("/assets/img/logo-light.png");
    --wash-lo:         oklch(87% 0.003 265);
    --wash-mid:        oklch(93.5% 0.002 265);
    --wash-hi:         oklch(99.2% 0.001 265);
    --wash-fold:       oklch(100% 0 0 / 0.72);
    --hero-particle-far:  oklch(72% 0.004 265);
    --hero-particle-near: oklch(52% 0.005 265);
    --hero-particle-gain: 0.62;
    --hero-particle-blend: normal;
    --glass-bg:        oklch(100% 0 0 / 0.80);
    --glass-border:    oklch(20% 0.02 265 / 0.10);
    --shadow-1: 0 1px 2px oklch(40% 0.03 265 / 0.08);
    --shadow-2: 0 4px 12px oklch(40% 0.03 265 / 0.10);
    --shadow-3: 0 12px 32px oklch(40% 0.03 265 / 0.12);
    --shadow-4: 0 24px 64px oklch(40% 0.03 265 / 0.14);
    --glow:     0 0 0 1px oklch(50% 0.155 240 / 0.30), 0 8px 32px oklch(50% 0.155 240 / 0.14);
      color-scheme: light;
  }
}

/* ==========================================================================
   02. RESET
   ========================================================================== */

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

/* Components below set `display` on the same elements JS filters with the
   `hidden` property. Without this the UA rule loses and hidden cards stay
   on screen. */
[hidden] { display: none !important; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchor links must not land under the sticky header. This is the single
     source of the offset — per-element scroll-margin would stack on top of it
     and drop the target far below the fold. */
  scroll-padding-top: calc(var(--header-h) + var(--space-sm));
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;
  min-height: 100svh;
  overflow-x: hidden;
}

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

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

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

a { color: var(--primary); text-decoration-thickness: 1px; text-underline-offset: 0.22em; }
a:hover { color: var(--primary-strong); }

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

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

hr { border: 0; border-top: 1px solid var(--border); margin: var(--space-lg) 0; }

::selection { background: var(--primary); color: var(--primary-ink); }

/* One focus treatment everywhere. Never removed, only styled. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-xs);
}
:focus:not(:focus-visible) { outline: none; }

/* ==========================================================================
   03. TYPOGRAPHY
   ========================================================================== */

h1, h2, h3, h4, h5, h6 {
  font-weight: 640;
  line-height: var(--lh-snug);
  letter-spacing: var(--tracking-snug);
  text-wrap: balance;
}

h1 { font-size: var(--fs-3xl); line-height: var(--lh-tight); letter-spacing: var(--tracking-tight); }
h2 { font-size: var(--fs-2xl); letter-spacing: var(--tracking-tight); }
h3 { font-size: var(--fs-xl); }
h4 { font-size: var(--fs-lg); }
h5, h6 { font-size: var(--fs-md); }

p { text-wrap: pretty; }

strong, b { font-weight: 640; color: var(--text); }

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

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--primary);
}
.eyebrow::before {
  content: "";
  inline-size: 1.75rem;
  block-size: 1px;
  background: currentColor;
  opacity: 0.6;
}

.lede {
  font-size: var(--fs-md);
  line-height: var(--lh-loose);
  color: var(--text-muted);
  max-width: 62ch;
}
/* Service and article intros are two paragraphs; without this they merge. */
.lede + .lede { margin-block-start: var(--space-sm); }

.text-muted  { color: var(--text-muted); }
.text-subtle { color: var(--text-subtle); }
.mono { font-family: var(--font-mono); }

/* Gradient text used sparingly — one accent per page at most. */
.text-gradient {
  background: linear-gradient(100deg, var(--text) 12%, var(--primary) 58%, var(--accent) 96%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ==========================================================================
   04. LAYOUT
   ========================================================================== */

.container      { width: 100%; max-width: var(--width-full); margin-inline: auto; padding-inline: var(--gutter); }
.container--wide { max-width: var(--width-wide); }
.container--text { max-width: calc(var(--width-text) + var(--gutter) * 2); }

.section       { padding-block: var(--space-2xl); }
.section--tight { padding-block: var(--space-xl); }
.section--flush-top { padding-block-start: 0; }
.section--sunken { background: var(--bg-sunken); }

.section-head { max-width: 62ch; margin-block-end: var(--space-lg); }
.section-head > * + * { margin-block-start: var(--space-sm); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head--center .eyebrow { justify-content: center; }

/* Grid and flex children default to min-width:auto, which lets a long
   unbreakable line inside them inflate the track and push the page sideways.
   Overriding it is what keeps code blocks and tables scrolling internally. */
.grid > *, .split > *, .cluster > * { min-width: 0; }

.grid { display: grid; gap: var(--space-md); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }
/* Four feature cards read best as a 2x2 block rather than 3 + 1 orphan. */
.grid--pillars { grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr)); }

.stack > * + * { margin-block-start: var(--space-sm); }
.stack-lg > * + * { margin-block-start: var(--space-lg); }

.cluster { display: flex; flex-wrap: wrap; gap: var(--space-xs); align-items: center; }

.split {
  display: grid;
  gap: var(--space-xl);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 60rem) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
  .split--sidebar { grid-template-columns: minmax(0, 1fr) minmax(0, 19rem); }
  .split--sticky > :last-child { position: sticky; top: calc(var(--header-h) + var(--space-md)); }
}

/* ==========================================================================
   05. ACCESSIBILITY UTILITIES
   ========================================================================== */

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  inset-block-start: var(--space-2xs);
  inset-inline-start: var(--space-2xs);
  z-index: 200;
  padding: var(--space-2xs) var(--space-sm);
  background: var(--primary);
  color: var(--primary-ink);
  border-radius: var(--radius-sm);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-160%);
  transition: transform var(--dur-fast) var(--ease);
}
.skip-link:focus { transform: translateY(0); }

/* ==========================================================================
   06. HEADER & NAVIGATION

   A floating pill rather than a full-width bar. Two consequences worth naming:

   • The header is `position: fixed`, so it takes no space in the flow. Anything
     that used to sit below a 68px sticky bar now needs its own top clearance —
     `--header-h` below still describes the space the nav *occupies* (its top
     offset plus its height), and every scroll offset and sticky sidebar reads
     from it, so those keep working unchanged.
   • The brand sits outside the pill. Seven nav items plus a CTA already make it
     as wide as it should get.
   ========================================================================== */

.site-header {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--nav-top) var(--gutter);
  pointer-events: none; /* the gap between brand and pill stays click-through */
}
.site-header > * { pointer-events: auto; }

.site-brand { flex-shrink: 0; }

.navbar {
  position: absolute;
  inset-inline-start: 50%;
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: 0.15rem;
  padding: 0.3rem;
  border-radius: var(--radius-pill);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-2);
}
@supports (backdrop-filter: blur(1px)) {
  .navbar { backdrop-filter: blur(var(--glass-blur)) saturate(180%); }
}
/* Below the breakpoint the links live in the drawer, so the pill collapses to
   the two controls and tucks against the right edge. */
@media (max-width: 63.99rem) {
  .navbar { position: static; translate: none; margin-inline-start: auto; }
}

.navbar__list { display: flex; align-items: center; gap: 0.15rem; }
@media (max-width: 63.99rem) { .navbar__list { display: none; } }

.navbar__link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.42rem 0.85rem;
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.navbar__link:hover { color: var(--text); background: var(--surface-hover); }
/* The current page is marked by a filled pill, the way the tab it represents
   would be. No underline or dot — at this size they read as noise. */
.navbar__link.is-current {
  color: var(--text);
  background: var(--surface-hover);
  font-weight: 560;
}

.navbar__cta {
  display: inline-flex;
  align-items: center;
  padding: 0.42rem 0.95rem;
  margin-inline-start: 0.15rem;
  border-radius: var(--radius-pill);
  background: var(--text);
  color: var(--bg);
  font-size: var(--fs-sm);
  font-weight: 560;
  text-decoration: none;
  white-space: nowrap;
  transition: opacity var(--dur-fast) var(--ease);
}
.navbar__cta:hover { color: var(--bg); opacity: 0.84; }
@media (max-width: 63.99rem) { .navbar__cta { display: none; } }

.navbar__rule {
  inline-size: 1px;
  block-size: 1.1rem;
  margin-inline: 0.3rem;
  background: var(--border);
}
@media (max-width: 63.99rem) { .navbar__rule { display: none; } }

.navbar__icon {
  display: grid;
  place-items: center;
  inline-size: 2.15rem;
  block-size: 2.15rem;
  border-radius: 50%;
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.navbar__icon:hover { color: var(--text); background: var(--surface-hover); }

.nav-link__chevron { transition: transform var(--dur-fast) var(--ease); }
[aria-expanded="true"] > .nav-link__chevron { transform: rotate(180deg); }

.nav-toggle { display: none; }
@media (max-width: 63.99rem) { .nav-toggle { display: grid; } }

/* Theme toggle swaps icons purely with CSS so there is no flash on load. */
.theme-toggle__sun, .theme-toggle__moon { grid-area: 1 / 1; }
.theme-toggle__moon { display: none; }
:root[data-theme="light"] .theme-toggle__sun { display: none; }
:root[data-theme="light"] .theme-toggle__moon { display: block; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .theme-toggle__sun { display: none; }
  :root:not([data-theme="dark"]) .theme-toggle__moon { display: block; }
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--text);
  text-decoration: none;
  flex-shrink: 0;
}
.brand:hover { color: var(--text); }
.brand:hover .brand__logo { opacity: 0.82; }

/* The wordmark ships as two cuts, light-on-dark and dark-on-light. Declaring
   them as backgrounds means the engine fetches only the one the current theme
   resolves to — an <img> pair would download both. Aspect ratio is fixed here
   so the header reserves its space before the image arrives (no CLS). */
.brand__logo {
  display: block;
  block-size: 1.9rem;
  aspect-ratio: 720 / 147;
  background: var(--brand-logo) left center / contain no-repeat;
  transition: opacity var(--dur-fast) var(--ease);
}

.brand__role {
  padding-inline-start: 0.7rem;
  border-inline-start: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 0.5625rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-subtle);
  max-inline-size: 9.5rem;
}
@media (max-width: 26rem) { .brand__logo { block-size: 1.6rem; } }

.site-footer .brand__logo { block-size: 2.1rem; }
.drawer__head .brand__logo { block-size: 1.6rem; }

/* ==========================================================================
   07. MEGA MENU
   ========================================================================== */

.has-mega { position: relative; }

.mega {
  position: fixed;
  inset-block-start: var(--header-h);
  inset-inline: 0;
  z-index: 90;
  display: flex;
  justify-content: center;
  pointer-events: none;
  background: none;
  border: 0;
  box-shadow: none;
  /* 22 links do not fit a 650px-tall laptop window. Cap the panel to what is
     left below the header and let it scroll rather than running off-screen. */
  padding: 0 var(--gutter);
  opacity: 0;
  transform: translateY(-0.5rem);
  /* `visibility` keeps the closed panel out of the tab order and the a11y tree.
     It is transitioned with a *delay* rather than a duration: hiding waits for
     the fade to finish, but showing flips on frame one — so a link is focusable
     the instant `.is-open` lands. Transitioning its duration instead is what
     made the panel unreachable by keyboard. */
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--dur-normal) var(--ease),
              transform var(--dur-normal) var(--ease-out),
              visibility 0s linear var(--dur-normal);
}
/* The card, rather than the positioning wrapper, is what carries the surface.
   It is capped to the viewport and scrolls internally: 22 links do not fit a
   650px-tall laptop window, and a fixed panel with no scroll simply hides the
   last few. */
.mega__card {
  inline-size: min(64rem, 100%);
  /* At four links a column the panel no longer approaches the viewport height,
     but the cap stays: a short laptop window with the browser chrome open is
     still shorter than people expect. */
  max-block-size: calc(100vh - var(--header-h) - var(--space-md));
  max-block-size: calc(100dvh - var(--header-h) - var(--space-md));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-md) var(--space-lg);
  border-radius: var(--radius-xl);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-4);
}
@supports (backdrop-filter: blur(1px)) {
  .mega__card { backdrop-filter: blur(20px) saturate(180%); }
}
.mega.is-open {
  opacity: 1;
  transform: translateY(0);
  visibility: visible;
  pointer-events: none;
  transition: opacity var(--dur-normal) var(--ease),
              transform var(--dur-normal) var(--ease-out),
              visibility 0s linear 0s;
}

.mega.is-open .mega__card { pointer-events: auto; }

.mega__grid {
  display: grid;
  gap: var(--space-md) var(--space-lg);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
/* Four fixed columns rather than auto-fit: with auto-fit the fourth group fell
   to a second row the moment the labels grew, which reads as a layout bug
   rather than as a choice. The panel only ever opens above 64rem. */
@media (min-width: 64rem) {
  .mega__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.mega__col-head {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  padding-block-end: var(--space-2xs);
  margin-block-end: var(--space-2xs);
  border-block-end: 1px solid var(--border);
}
.mega__col-title {
  font-size: var(--fs-2xs);
  font-weight: 640;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-subtle);
  text-wrap: balance;
}
.mega__icon { color: var(--primary); flex-shrink: 0; }

/* One line per service, no description. Four short labels are scanned at a
   glance; four labels each with a sentence under them is a page to be read,
   which is what the dropdown had become. */
.mega__link {
  display: block;
  padding: 0.42rem 0.6rem;
  margin-inline: -0.6rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease);
}
.mega__link:hover { background: var(--surface-hover); }
.mega__link-label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 520;
  color: var(--text-muted);
}
.mega__link:hover .mega__link-label { color: var(--text); }

.mega__more {
  display: inline-block;
  padding: 0.42rem 0;
  font-size: var(--fs-2xs);
  font-family: var(--font-mono);
  letter-spacing: 0.03em;
  color: var(--text-subtle);
  text-decoration: none;
}
.mega__more:hover { color: var(--primary); }

.mega__all {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--fs-sm);
  font-weight: 560;
  color: var(--text);
  text-decoration: none;
}
.mega__all:hover { color: var(--primary); }

.mega__footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-block-start: var(--space-md);
  padding-block-start: var(--space-md);
  border-block-start: 1px solid var(--border);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* ==========================================================================
   08. MOBILE DRAWER
   ========================================================================== */

.drawer {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: grid;
  grid-template-rows: auto 1fr;
  background: var(--bg);
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  /* Same pattern as the mega panel, and for the same reason: a `visibility`
     transitioned by duration made the first `.focus()` after opening a silent
     no-op, which left the focus trap disengaged and Tab walking the page
     behind the overlay. */
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--dur-normal) var(--ease),
              visibility 0s linear var(--dur-normal);
}
.drawer.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity var(--dur-normal) var(--ease), visibility 0s linear 0s;
}

.drawer__head {
  position: sticky;
  inset-block-start: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  block-size: var(--header-h);
  padding-inline: var(--gutter);
  background: var(--bg);
  border-block-end: 1px solid var(--border);
}
.drawer__body { padding: var(--space-md) var(--gutter) var(--space-2xl); }

.drawer__link {
  display: block;
  padding: 0.75rem 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  border-block-end: 1px solid var(--border);
}
.drawer__link[aria-current="page"] { color: var(--primary); }

.drawer__group { border-block-end: 1px solid var(--border); }
.drawer__group-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  width: 100%;
  padding: 0.75rem 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--text);
  text-align: start;
}
.drawer__group-btn[aria-expanded="true"] .nav-link__chevron { transform: rotate(180deg); }
.drawer__panel { display: none; padding-block-end: var(--space-sm); }
.drawer__panel.is-open { display: block; }
.drawer__sub-title {
  margin-block: var(--space-sm) var(--space-3xs);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--primary);
}
.drawer__sub-link {
  display: block;
  padding: 0.4rem 0;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  text-decoration: none;
}
.drawer__sub-link:hover { color: var(--text); }

/* ==========================================================================
   09. BUTTONS
   ========================================================================== */

.btn {
  --btn-bg: var(--surface);
  --btn-fg: var(--text);
  --btn-border: var(--border-strong);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-block-size: 2.75rem;
  padding: 0.7rem 1.25rem;
  border: 1px solid var(--btn-border);
  /* Rounded rectangle, not a pill. The nav pill stays fully round, and the
     contrast between the two is what stops the page reading as all-capsule. */
  border-radius: var(--radius-md);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: -0.005em;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-spring),
              box-shadow var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); color: var(--btn-fg); }
.btn:active { transform: translateY(0) scale(0.985); }

/* Solid ink rather than the brand blue — the reference's primary button is the
   foreground colour itself, which is what makes it read as the one decisive
   action on the page rather than one more coloured element. */
.btn--primary {
  --btn-bg: var(--text);
  --btn-fg: var(--bg);
  --btn-border: transparent;
}
.btn--primary:hover { --btn-bg: var(--text); --btn-fg: var(--bg); opacity: 0.86; box-shadow: var(--shadow-3); }

.btn--accent { --btn-bg: var(--accent); --btn-fg: var(--accent-ink); --btn-border: transparent; }
.btn--accent:hover { --btn-bg: var(--accent-strong); }

.btn--ghost { --btn-bg: transparent; --btn-border: var(--border-strong); }
.btn--ghost:hover { --btn-bg: var(--surface-hover); --btn-border: var(--primary); }

.btn--quiet { --btn-bg: transparent; --btn-border: transparent; --btn-fg: var(--text-muted); padding-inline: 0.6rem; }
.btn--quiet:hover { --btn-fg: var(--primary); transform: none; box-shadow: none; }

.btn--lg { min-block-size: 3.25rem; padding: 0.9rem 1.85rem; font-size: var(--fs-base); }
.btn--sm { min-block-size: 2.25rem; padding: 0.45rem 0.95rem; font-size: var(--fs-xs); }
.btn--block { width: 100%; }

.btn__arrow { transition: transform var(--dur-normal) var(--ease-out); }
.btn:hover .btn__arrow { transform: translateX(3px); }

/* Text link with an animated underline. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  min-block-size: 24px;
  gap: 0.35rem;
  font-weight: 560;
  font-size: var(--fs-sm);
  text-decoration: none;
  color: var(--primary);
}
.link-arrow::after {
  content: "";
  position: absolute;
  inset-block-end: -2px;
  inset-inline: 0;
  block-size: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-normal) var(--ease-out);
}
.link-arrow { position: relative; }
.link-arrow:hover::after { transform: scaleX(1); transform-origin: left; }
.link-arrow svg { transition: transform var(--dur-normal) var(--ease-out); }
.link-arrow:hover svg { transform: translateX(3px); }

/* ==========================================================================
   10. HERO

   Modelled on the reference: a light, near-monochrome band with a silky
   gradient wash, the copy on the left and a framed portrait on the right.

   The light ground is deliberate in BOTH themes — the tokens are redefined
   on `.hero` itself rather than the hero being painted a fixed colour. Every
   child (buttons, borders, the particle field, the muted text) reads the same
   token names it always did and follows automatically, so nothing inside the
   hero needs a dark-theme exception of its own.
   ========================================================================== */

.hero {
  position: relative;
  display: grid;
  align-items: center;
  /* No min-height on small screens. A 38rem floor meant a phone got a 608px
     band before any content was measured, and the stacked copy-plus-portrait
     then pushed it past 1000px — most of a second screen of scrolling before
     anything else appeared. Here the content sets the height. */
  padding-block: calc(var(--header-h) + var(--space-md)) var(--space-xl);
  overflow: hidden;
  isolation: isolate;
  background: var(--bg);
}
/* Only once the layout is side by side is a full-height band worth having. */
@media (min-width: 48rem) {
  .hero {
    min-block-size: min(92svh, 52rem);
    padding-block: calc(var(--header-h) + var(--space-lg)) var(--space-2xl);
  }
}

/* ── The wash ──────────────────────────────────────────────────────────────
   The reference uses a photograph of silk run through `grayscale(1)`. This is
   the same effect built from gradients instead: four soft radial pools for the
   broad tonal drift, and three long angled bands for the fold highlights.
   Reproducing it in CSS rather than shipping the image keeps the page at zero
   third-party requests and costs nothing to download. */
.hero__wash {
  position: absolute;
  inset: 0;
  z-index: -3;
  background:
    /* Fold highlights — the long angled streaks that read as creases. */
    linear-gradient(107deg, transparent 12%, var(--wash-fold) 20%, transparent 30%),
    linear-gradient(102deg, transparent 38%, var(--wash-fold) 46%, transparent 56%),
    linear-gradient(112deg, transparent 60%, var(--wash-fold) 69%, transparent 80%),
    /* Tonal pools — the broad drift underneath them. */
    radial-gradient(70% 55% at 18% 8%, var(--wash-lo), transparent 70%),
    radial-gradient(60% 50% at 82% 4%, var(--wash-mid), transparent 68%),
    radial-gradient(80% 60% at 62% 34%, var(--wash-hi), transparent 72%),
    radial-gradient(90% 70% at 30% 88%, var(--wash-hi), transparent 76%),
    linear-gradient(180deg, var(--wash-lo) 0%, var(--wash-mid) 46%, var(--bg) 82%);
}

/* The band has to end somewhere. A fade to the page background is what stops
   the light hero reading as a pasted-in panel on the dark theme. */
.hero::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: clamp(4rem, 12vh, 9rem);
  z-index: -1;
  background: linear-gradient(180deg, transparent, var(--bg));
  pointer-events: none;
}

/* WebGL canvas covers the whole hero band and sits behind the text. */
.hero__canvas {
  position: absolute;
  inset: 0;
  z-index: -2;
  inline-size: 100%;
  block-size: 100%;
  opacity: 0;
  transition: opacity 1.2s var(--ease);
}
.hero__canvas.is-ready { opacity: 1; }

/* ── Layout ────────────────────────────────────────────────────────────── */
.hero__layout {
  display: grid;
  gap: var(--space-md);
  align-items: center;
}
/* Side by side from 48rem rather than 62rem. Between those two there is ample
   room for both columns, and the stacked layout was the single biggest reason
   the hero ran to 1000px+ on tablets. */
@media (min-width: 48rem) {
  .hero__layout {
    grid-template-columns: minmax(0, 1fr) minmax(0, 15rem);
    gap: var(--space-lg);
  }
}
@media (min-width: 64rem) {
  .hero__layout {
    grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
    gap: var(--space-xl);
  }
}
@media (min-width: 80rem) {
  .hero__layout { grid-template-columns: minmax(0, 1fr) minmax(0, 26rem); gap: var(--space-2xl); }
}
.hero__inner { max-width: 34rem; min-width: 0; }

.hero__greeting {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--text);
  margin-block-end: var(--space-sm);
}
.hero__wave {
  display: inline-block;
  font-size: 1.05em;
  transform-origin: 70% 80%;
  animation: wave 2.8s var(--ease) infinite;
}
@keyframes wave {
  0%, 62%, 100% { transform: rotate(0deg); }
  68% { transform: rotate(14deg); }
  74% { transform: rotate(-8deg); }
  80% { transform: rotate(12deg); }
  86% { transform: rotate(-4deg); }
}

.hero__title {
  /* Capped against the *column*, not the viewport: at 900px wide the old
     viewport-only clamp had already reached 58px while the copy still had the
     full width, which is why the headline looked oversized on tablets. */
  font-size: clamp(2.1rem, 1.35rem + 2.6vw, 3.65rem);
  /* 500, not 700. The reference's headline is large but not heavy, and that is
     most of why it reads as calm rather than shouted. */
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.025em;
  margin-block: 0 var(--space-sm);
}
.hero__title .line { display: block; }

.hero__lede {
  font-size: var(--fs-md);
  max-width: 34ch;
  color: var(--text-muted);
  line-height: 1.55;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin-block-start: var(--space-md);
}

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-sm);
  margin-block-start: var(--space-xl);
  padding-block-start: var(--space-sm);
  border-block-start: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.03em;
  color: var(--text-subtle);
}
.hero__meta-item { display: inline-flex; align-items: center; gap: 0.4rem; }
.hero__meta-dot {
  inline-size: 6px; block-size: 6px;
  border-radius: 50%;
  background: var(--success);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--success) 20%, transparent);
}

/* ── Portrait ──────────────────────────────────────────────────────────────
   A rounded square in a surface-coloured frame, as the reference has it. The
   frame is padding on the figure rather than a border on the image, so the
   inner and outer radii stay concentric at any size. */
.hero__portrait {
  position: relative;
  margin: 0;
  justify-self: center;
  inline-size: min(100%, 26rem);
  aspect-ratio: 1;
  padding: 0.5rem;
  border-radius: clamp(1.5rem, 3vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-4);
}
@media (min-width: 62rem) { .hero__portrait { justify-self: end; } }

.hero__portrait img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  border-radius: calc(clamp(1.5rem, 3vw, 2rem) - 0.5rem);
  /* No greyscale filter. The reference greyscales a flat studio shot; this
     photograph is already almost monochrome and its one colour is the warm rim
     light, which is the thing worth keeping. A slight lift on hover instead. */
  transition: transform var(--dur-slow) var(--ease-out);
}
.hero__portrait:hover img { transform: scale(1.015); }

/* Shown until a photo exists at assets/img/irfan-bhat.jpg. A visible, labelled
   gap is more useful than a silently missing element — it says what to do. */
.hero__portrait-empty {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-2xs);
  block-size: 100%;
  border-radius: calc(clamp(1.5rem, 3vw, 2rem) - 0.5rem);
  border: 1px dashed var(--border-strong);
  background: var(--surface-hover);
  color: var(--text-subtle);
  font-size: var(--fs-sm);
  text-align: center;
  padding: var(--space-md);
}
.hero__portrait-empty em {
  display: block;
  margin-block-start: 0.35rem;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-style: normal;
  color: var(--text-subtle);
  opacity: 0.75;
}

@media (max-width: 47.99rem) {
  /* Copy first on a phone: the headline is what the page is for. */
  .hero__portrait { order: 2; inline-size: min(100%, 15rem); }
  .hero__inner { order: 1; }
  /* The status line is reference material, not a headline. Below the fold it
     competes with the portrait for the little space there is. */
  .hero__meta { margin-block-start: var(--space-md); }
}

/* Compact hero for interior pages. */
.page-hero {
  position: relative;
  /* The nav no longer occupies layout space, so the first section on every
     interior page has to clear it itself. */
  padding-block: calc(var(--header-h) + var(--space-lg)) var(--space-lg);
  border-block-end: 1px solid var(--border);
  overflow: hidden;
  isolation: isolate;
}
.page-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(46rem 26rem at 18% -10%, oklch(72% 0.155 228 / 0.13), transparent 62%);
}
.page-hero__inner { max-width: 56rem; }
.page-hero h1 { margin-block: var(--space-xs) var(--space-sm); }

/* ==========================================================================
   11. CARDS
   ========================================================================== */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding: var(--space-md);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  transition: transform var(--dur-normal) var(--ease-out),
              border-color var(--dur-normal) var(--ease),
              box-shadow var(--dur-normal) var(--ease);
  overflow: hidden;
  isolation: isolate;
}
.card:hover { transform: translateY(-3px); border-color: var(--border-strong); box-shadow: var(--shadow-3); }

/* A pointer-tracked highlight. --mx/--my are set by JS; the fallback keeps it
   centred and invisible when JS is off. */
.card--interactive::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: inherit;
  background: radial-gradient(
    16rem 16rem at var(--mx, 50%) var(--my, 50%),
    oklch(72% 0.155 228 / 0.14),
    transparent 68%
  );
  opacity: 0;
  transition: opacity var(--dur-normal) var(--ease);
}
.card--interactive:hover::before { opacity: 1; }

.card__icon {
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  margin-block-end: var(--space-2xs);
  border-radius: var(--radius-md);
  background: var(--primary-dim);
  color: var(--primary-strong);
  flex-shrink: 0;
}
:root[data-theme="light"] .card__icon { color: var(--primary); }

.card__title { font-size: var(--fs-lg); font-weight: 620; }
.card__title a { color: var(--text); text-decoration: none; }
.card__title a:hover { color: var(--primary); }
.card__body { font-size: var(--fs-sm); color: var(--text-muted); line-height: var(--lh-base); }
.card__foot { margin-block-start: auto; padding-block-start: var(--space-sm); }

/* Whole-card click target, keyboard-accessible because the anchor is real. */
.card__link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.card:has(.card__link:focus-visible) { outline: 3px solid var(--accent); outline-offset: 3px; }

.card--feature { padding: var(--space-lg); }
.card--flat { background: transparent; border-color: var(--border); }

/* Service card with a numeric index. */
.service-card__index {
  position: absolute;
  inset-block-start: var(--space-sm);
  inset-inline-end: var(--space-md);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-subtle);
  opacity: 0.55;
}

/* ── Pills & tags ──────────────────────────────────────────────────────── */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-raised);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.02em;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
}
a.pill:hover { border-color: var(--primary); color: var(--primary); }
/* Long-form pills (legends, definitions) must wrap rather than run off screen. */
.pill--wrap { white-space: normal; text-align: start; align-items: flex-start; max-inline-size: 100%; }
.pill--primary { background: var(--primary-dim); border-color: transparent; color: var(--primary-strong); }
:root[data-theme="light"] .pill--primary { color: var(--primary-strong); }
.pill--accent  { background: oklch(78% 0.16 68 / 0.16); border-color: transparent; color: var(--accent); }
.pill--core     { border-color: var(--primary); color: var(--primary); }
.pill--working  { border-color: var(--border-strong); color: var(--text-muted); }
.pill--familiar { border-color: var(--border); color: var(--text-subtle); }

.dot-sep::before { content: "·"; margin-inline: 0.45rem; color: var(--text-subtle); }

/* ── Post card ─────────────────────────────────────────────────────────── */
.post-card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-subtle);
}
.post-card__title { font-size: var(--fs-lg); font-weight: 620; line-height: var(--lh-snug); }
.post-card__title a { color: var(--text); text-decoration: none; }
.post-card__title a:hover { color: var(--primary); }

/* ── Skill entries ─────────────────────────────────────────────────────── */
.skill-item {
  display: grid;
  gap: 0.2rem;
  padding: var(--space-xs) 0;
  border-block-end: 1px solid var(--border);
}
.skill-item:last-child { border-block-end: 0; }
.skill-item__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2xs); }
.skill-item__name { font-weight: 600; font-size: var(--fs-sm); }
.skill-item__blurb { font-size: var(--fs-xs); color: var(--text-muted); line-height: 1.55; }

/* A–Z jump bar. */
.az-bar {
  position: sticky;
  inset-block-start: calc(var(--header-h) + 0.5rem);
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem;
  padding: var(--space-2xs);
  margin-block-end: var(--space-lg);
  background: var(--glass-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
@supports (backdrop-filter: blur(1px)) { .az-bar { backdrop-filter: blur(12px); } }
.az-bar__link {
  display: grid;
  place-items: center;
  min-inline-size: 1.9rem;
  min-block-size: 1.9rem;
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
}
.az-bar__link:hover { background: var(--primary); color: var(--primary-ink); }
.az-bar__link[aria-disabled="true"] { color: var(--text-subtle); opacity: 0.35; pointer-events: none; }

.az-group__letter {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-block: var(--space-lg) var(--space-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-xl);
  font-weight: 700;
  color: var(--primary);
  /* Offset comes from html { scroll-padding-top }; see 02. RESET. */
}
.az-group__letter::after { content: ""; flex: 1; block-size: 1px; background: var(--border); }

/* ── Stats ─────────────────────────────────────────────────────────────── */
.stat { display: grid; gap: 0.15rem; }
.stat__value {
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  font-variant-numeric: tabular-nums;
  color: var(--primary);
}
.stat__label { font-size: var(--fs-xs); color: var(--text-muted); }

/* ── Numbered process list ─────────────────────────────────────────────── */
.steps { counter-reset: step; display: grid; gap: var(--space-md); }
.step { position: relative; padding-inline-start: 3.25rem; counter-increment: step; }
.step::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: -0.1rem;
  display: grid;
  place-items: center;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--primary);
}
.step__title { font-size: var(--fs-md); font-weight: 620; margin-block-end: 0.2rem; }
.step__body { font-size: var(--fs-sm); color: var(--text-muted); }

/* ── Accordion (FAQ) ───────────────────────────────────────────────────── */
.faq { border-block-end: 1px solid var(--border); }
.faq:first-child { border-block-start: 1px solid var(--border); }
.faq__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-sm);
  width: 100%;
  padding: var(--space-sm) 0;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  text-align: start;
  line-height: var(--lh-snug);
}
.faq__q:hover { color: var(--primary); }
.faq__icon { flex-shrink: 0; margin-block-start: 0.2rem; transition: transform var(--dur-normal) var(--ease); }
.faq__q[aria-expanded="true"] .faq__icon { transform: rotate(45deg); color: var(--primary); }
.faq__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-normal) var(--ease-out);
}
.faq__a > div { overflow: hidden; }
.faq__a.is-open { grid-template-rows: 1fr; }
.faq__a p { padding-block-end: var(--space-sm); font-size: var(--fs-sm); color: var(--text-muted); max-width: 68ch; }

/* ── Breadcrumbs ───────────────────────────────────────────────────────── */
.breadcrumbs { font-size: var(--fs-2xs); font-family: var(--font-mono); color: var(--text-subtle); }
.breadcrumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; }
.breadcrumbs a { color: var(--text-muted); text-decoration: none; }
.breadcrumbs a:hover { color: var(--primary); }
.breadcrumbs li:not(:last-child)::after { content: "/"; margin-inline-start: 0.35rem; opacity: 0.45; }
.breadcrumbs [aria-current="page"] { color: var(--text); }

/* ── Callout / note ────────────────────────────────────────────────────── */
.note {
  display: grid;
  gap: var(--space-3xs);
  padding: var(--space-sm) var(--space-md);
  border-inline-start: 3px solid var(--primary);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  background: var(--bg-raised);
}
.note__title {
  font-size: var(--fs-xs);
  font-weight: 680;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--primary);
}
.note p { font-size: var(--fs-sm); color: var(--text-muted); }
.note--warn { border-inline-start-color: var(--warning); }
.note--warn .note__title { color: var(--warning); }

/* ── CTA banner ────────────────────────────────────────────────────────── */
.cta-banner {
  position: relative;
  display: grid;
  gap: var(--space-md);
  padding: var(--space-xl);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background:
    radial-gradient(38rem 22rem at 8% 0%, oklch(72% 0.155 228 / 0.16), transparent 62%),
    radial-gradient(32rem 20rem at 96% 100%, oklch(78% 0.16 68 / 0.13), transparent 60%),
    var(--bg-raised);
  overflow: hidden;
}
@media (min-width: 48rem) {
  .cta-banner { grid-template-columns: 1fr auto; align-items: center; gap: var(--space-lg); }
}
.cta-banner__title { font-size: var(--fs-xl); font-weight: 660; }
.cta-banner__body { font-size: var(--fs-sm); color: var(--text-muted); max-width: 52ch; margin-block-start: var(--space-2xs); }

/* ── Placeholder marker for unfinished portfolio entries ───────────────── */
.placeholder-note {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--warning);
}

/* ==========================================================================
   12. SECTIONS & DECORATION
   ========================================================================== */

.rule {
  block-size: 1px;
  background: linear-gradient(90deg, transparent, var(--border) 12%, var(--border) 88%, transparent);
  border: 0;
  margin: 0;
}

.marquee-strip {
  display: flex;
  gap: var(--space-md);
  padding-block: var(--space-sm);
  border-block: 1px solid var(--border);
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee-strip__track {
  display: flex;
  gap: var(--space-md);
  flex-shrink: 0;
  animation: marquee 48s linear infinite;
}
.marquee-strip:hover .marquee-strip__track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(calc(-100% - var(--space-md))); } }
.marquee-strip__item {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.05em;
  color: var(--text-subtle);
  white-space: nowrap;
}

/* ==========================================================================
   13. PROSE / ARTICLE
   ========================================================================== */

.prose { max-width: min(var(--width-text), 100%); font-size: var(--fs-md); line-height: var(--lh-loose); }
.prose > * { max-width: 100%; }
.prose > * + * { margin-block-start: var(--space-sm); }
.prose > h2 {
  margin-block-start: var(--space-xl);
  font-size: var(--fs-xl);
}
.prose > h3 { margin-block-start: var(--space-lg); font-size: var(--fs-lg); }
.prose p { color: var(--text-muted); }
.prose strong { color: var(--text); }
.prose a { color: var(--primary); text-decoration: underline; text-decoration-thickness: 1px; }
.prose a:hover { color: var(--primary-strong); }

.prose ul, .prose ol { display: grid; gap: var(--space-2xs); padding-inline-start: 1.35rem; color: var(--text-muted); }
.prose ul { list-style: none; }
.prose ul > li { position: relative; }
.prose ul > li::before {
  content: "";
  position: absolute;
  inset-inline-start: -1.05rem;
  inset-block-start: 0.72em;
  inline-size: 5px; block-size: 5px;
  border-radius: 50%;
  background: var(--primary);
}
.prose ol { list-style: decimal; }
.prose ol > li::marker { color: var(--primary); font-family: var(--font-mono); font-size: 0.85em; }

.prose :not(pre) > code {
  padding: 0.15em 0.4em;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--bg-raised);
  color: var(--accent);
  font-size: 0.86em;
  word-break: break-word;
}
:root[data-theme="light"] .prose :not(pre) > code { color: var(--accent-strong); }

/* Code blocks scroll inside their own container — the page never scrolls
   sideways. tabindex on the <pre> makes that reachable without a mouse. */
.code-block {
  margin-block-start: var(--space-md);
  max-inline-size: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-sunken);
  overflow: hidden;
}
.code-block__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: 0.4rem 0.75rem;
  border-block-end: 1px solid var(--border);
  background: var(--bg-raised);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-subtle);
}
.code-block pre {
  margin: 0;
  padding: var(--space-sm) var(--space-md);
  overflow-x: auto;
  font-size: var(--fs-xs);
  line-height: 1.72;
  tab-size: 2;
}
.code-block pre:focus-visible { outline-offset: -3px; }
.code-block code { color: var(--text); background: none; border: 0; padding: 0; }
.copy-btn { font-family: inherit; font-size: inherit; letter-spacing: inherit; color: var(--text-subtle); padding: 0.15rem 0.4rem; border-radius: var(--radius-xs); }
.copy-btn:hover { color: var(--primary); background: var(--surface-hover); }

.table-wrap { margin-block-start: var(--space-md); max-inline-size: 100%; overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-md); }
.table-wrap table { font-size: var(--fs-sm); min-inline-size: 34rem; }
.table-wrap th, .table-wrap td { padding: var(--space-2xs) var(--space-sm); text-align: start; border-block-end: 1px solid var(--border); vertical-align: top; }
.table-wrap thead th { background: var(--bg-raised); font-weight: 620; font-size: var(--fs-xs); letter-spacing: 0.02em; }
.table-wrap tbody tr:last-child td { border-block-end: 0; }
.table-wrap td { color: var(--text-muted); }

.prose blockquote {
  padding-inline-start: var(--space-md);
  border-inline-start: 3px solid var(--primary);
  font-size: var(--fs-lg);
  font-style: italic;
  color: var(--text);
}

/* ── Article furniture ─────────────────────────────────────────────────── */
.article-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-subtle);
}

.toc { font-size: var(--fs-sm); }
.toc__title {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-subtle);
  margin-block-end: var(--space-2xs);
}
.toc__link {
  display: block;
  padding: 0.32rem 0 0.32rem var(--space-2xs);
  border-inline-start: 2px solid var(--border);
  color: var(--text-muted);
  text-decoration: none;
  line-height: 1.4;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.toc__link:hover { color: var(--text); border-inline-start-color: var(--border-strong); }
.toc__link.is-active { color: var(--primary); border-inline-start-color: var(--primary); }

.read-progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 120;
  block-size: 2px;
  background: linear-gradient(90deg, var(--primary), var(--accent));
  transform: scaleX(0);
  transform-origin: left;
}

/* ==========================================================================
   14. FORMS
   ========================================================================== */

.field { display: grid; gap: 0.35rem; }

.field__label { font-size: var(--fs-sm); font-weight: 560; color: var(--text); }
.field__label .req { color: var(--accent); margin-inline-start: 0.15rem; }
.field__hint { font-size: var(--fs-xs); color: var(--text-subtle); }

.input, .textarea, .select {
  inline-size: 100%;
  min-block-size: 2.75rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
  color: var(--text);
  font-size: var(--fs-sm);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--text-subtle); }
.input:hover, .textarea:hover, .select:hover { border-color: var(--text-subtle); }
.input:focus, .textarea:focus, .select:focus {
  /* A transparent outline instead of `none`: invisible in normal rendering, but
     forced-colours mode repaints it, so the ring survives High Contrast — which
     strips box-shadow entirely. */
  outline: 2px solid transparent;
  outline-offset: 2px;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px oklch(72% 0.155 228 / 0.22);
}
.input:focus-visible, .textarea:focus-visible, .select:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.textarea { min-block-size: 9rem; resize: vertical; line-height: var(--lh-base); }

.select {
  appearance: none;
  padding-inline-end: 2.5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%23888' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.9rem center;
}

.field--invalid .input,
.field--invalid .textarea,
.field--invalid .select { border-color: var(--danger); }

.field__error { font-size: var(--fs-xs); color: var(--danger); }
.field__error:empty { display: none; }

/* Honeypot — a bot-only field. Hidden from sight and from assistive tech,
   never with display:none, which some bots detect. */
.hp-field {
  position: absolute !important;
  left: -9999px;
  opacity: 0;
  height: 0;
  width: 0;
  overflow: hidden;
  pointer-events: none;
}

.form-status {
  padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-size: var(--fs-sm);
}
.form-status:empty { display: none; }
.form-status[data-state="ok"]   { border-color: var(--success); color: var(--success); background: oklch(75% 0.15 155 / 0.10); }
.form-status[data-state="err"]  { border-color: var(--danger);  color: var(--danger);  background: oklch(70% 0.18 22 / 0.10); }
.form-status[data-state="busy"] { border-color: var(--border-strong); color: var(--text-muted); }

/* ==========================================================================
   15. FOOTER
   ========================================================================== */

.site-footer {
  margin-block-start: var(--space-2xl);
  padding-block: var(--space-xl) var(--space-md);
  border-block-start: 1px solid var(--border);
  background: var(--bg-sunken);
}
.footer-grid {
  display: grid;
  gap: var(--space-lg);
  grid-template-columns: 1fr;
}
@media (min-width: 44rem) { .footer-grid { grid-template-columns: 1.4fr repeat(3, 1fr); } }

.footer-about { max-width: 34ch; }
.footer-about p { font-size: var(--fs-sm); color: var(--text-muted); margin-block-start: var(--space-2xs); }

.footer-col__title {
  font-size: var(--fs-2xs);
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-subtle);
  margin-block-end: var(--space-2xs);
}
.footer-col li + li { margin-block-start: 0.35rem; }
.footer-col a { font-size: var(--fs-sm); color: var(--text-muted); text-decoration: none; }
.footer-col a:hover { color: var(--primary); }

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-block-start: var(--space-xl);
  padding-block-start: var(--space-sm);
  border-block-start: 1px solid var(--border);
  font-size: var(--fs-xs);
  color: var(--text-subtle);
}
.footer-social { display: flex; gap: var(--space-2xs); }
.footer-social a {
  display: grid;
  place-items: center;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
}
.footer-social a:hover { border-color: var(--primary); color: var(--primary); }

/* ==========================================================================
   16. MOTION & CURSOR
   ========================================================================== */

/* Scroll reveal. `.reveal` starts hidden ONLY when JS has claimed the page —
   without the .js class the content is visible, so no-JS users see everything. */
.js .reveal {
  opacity: 0;
  transform: translateY(1.25rem);
  transition: opacity var(--dur-slower) var(--ease-out),
              transform var(--dur-slower) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* Hero headline lines, animated in on load. */
.js .hero__title .line { overflow: hidden; }
.js .hero__title .line > span {
  display: block;
  transform: translateY(105%);
  transition: transform 0.9s var(--ease-out);
  transition-delay: var(--line-delay, 0ms);
}
.js .hero.is-loaded .hero__title .line > span { transform: none; }

/* Custom cursor. Pointer-fine only — never on touch. */
.cursor-dot, .cursor-ring {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 300;
  pointer-events: none;
  border-radius: 50%;
  will-change: transform;
  opacity: 0;
  transition: opacity var(--dur-normal) var(--ease);
}
.cursor-dot  { inline-size: 6px;  block-size: 6px;  background: var(--primary); }
.cursor-ring {
  inline-size: 32px; block-size: 32px;
  border: 1px solid var(--primary);
  transition: opacity var(--dur-normal) var(--ease),
              width var(--dur-normal) var(--ease-out),
              height var(--dur-normal) var(--ease-out),
              background-color var(--dur-normal) var(--ease);
}
.cursor-ring.is-hover { inline-size: 52px; block-size: 52px; background: oklch(72% 0.155 228 / 0.10); }
.has-cursor .cursor-dot, .has-cursor .cursor-ring { opacity: 1; }
@media (hover: none), (pointer: coarse) { .cursor-dot, .cursor-ring { display: none; } }

/* Reduced motion. Everything decorative stops; nothing becomes unusable. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .js .reveal { opacity: 1; transform: none; }
  .js .hero__title .line > span { transform: none; }
  .hero__canvas { display: none; }
  .cursor-dot, .cursor-ring { display: none; }
  .marquee-strip__track { animation: none; }
  .hero__wave { animation: none; }
}

/* Forced colours (Windows High Contrast). The system palette replaces ours;
   everything that carried meaning through colour or shadow alone needs a border
   or an outline to survive. */
@media (forced-colors: active) {
  :focus-visible { outline: 3px solid Highlight; outline-offset: 3px; }
  .input:focus, .textarea:focus, .select:focus { outline: 3px solid Highlight; }
  .btn, .card, .site-header.is-scrolled, .mega, .drawer { border: 1px solid CanvasText; }
  .cursor-dot, .cursor-ring { display: none; }
  .hero__canvas { display: none; }
  .read-progress { background: Highlight; }
  .faq__q[aria-expanded="true"] .faq__icon { forced-color-adjust: none; }
}

/* ==========================================================================
   17. PRINT
   ========================================================================== */

@media print {
  /* Print is always on white — force the dark-on-light cut whatever the
     on-screen theme was. */
  .brand__logo { background-image: url("/assets/img/logo-light.png") !important; }
  .site-header, .site-footer, .mega, .drawer,
  .hero__canvas, .hero__wash, .cursor-dot, .cursor-ring, .read-progress,
  .az-bar, .cta-banner, .toc { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .prose a::after { content: " (" attr(href) ")"; font-size: 0.85em; color: #555; }
  .code-block { border: 1px solid #ccc; page-break-inside: avoid; }
  h2, h3 { page-break-after: avoid; }
}
