/* ============================================================================
   OLISEMEKA.DEV — "PAPER & PIXELS" DESIGN SYSTEM
   ----------------------------------------------------------------------------
   A sheet of graph paper on a desk: warm white stock, a faint 24px grid,
   hairline rules, generous whitespace, and hand-made pixel art used as the
   only ornament. No glows, no gradients-as-decoration, no floating shapes.

   SECTIONS
     01. Tokens
     02. Reset & base
     03. Typography primitives
     04. Layout primitives
     05. Pixel-art primitives
     06. Buttons & controls
     07. Site header
     08. Site footer
     09. Hero
     10. Skills index
     11. Cards
     12. Section furniture (embeds, empty states, pagers)
     13. Homepage sections
     14. Blog list controls
     15. Now timeline
     16. Tags
     17. Contact page
     18. Résumé page
     19. 404
     20. Overlays (image modal, reading progress)
     21. Motion & responsive
   ============================================================================ */

/* ============================================================================
   01. TOKENS
   ============================================================================ */
:root {
  /* ---- Paper ------------------------------------------------------------ */
  --paper:          #fbfbf9;
  --paper-raised:   #ffffff;
  --paper-sunken:   #f4f4f0;

  /* ---- Ink -------------------------------------------------------------- */
  --ink:            #16181c;
  --ink-2:          #4d545c;
  --ink-3:          #7d848c;
  --ink-4:          #a9aeb4;

  /* ---- Rules & grid ----------------------------------------------------- */
  --rule:           #e4e5e0;
  --rule-2:         #d3d5cf;
  --rule-3:         #b9bcb4;
  --grid:           rgba(22, 24, 28, 0.05);
  --grid-major:     rgba(22, 24, 28, 0.085);
  --grid-cell:      40px;
  --grid-major-cell: 200px;

  /* ---- Accent (deep teal ink) ------------------------------------------ */
  --accent:         #0f6b5e;
  --accent-deep:    #0a4f45;
  --accent-soft:    rgba(15, 107, 94, 0.07);
  --accent-line:    rgba(15, 107, 94, 0.26);

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

  --step--2: 0.6875rem;   /* 11px */
  --step--1: 0.8125rem;   /* 13px */
  --step-0:  1rem;        /* 16px */
  --step-1:  1.125rem;    /* 18px */
  --step-2:  1.375rem;    /* 22px */
  --step-3:  1.75rem;     /* 28px */
  --step-4:  2.25rem;     /* 36px */
  --step-5:  clamp(2.5rem, 5.5vw, 3.5rem);

  /* ---- Space ------------------------------------------------------------ */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 2.75rem;
  --sp-8: 4rem;
  --sp-9: 6rem;
  --sp-10: 8rem;

  /* ---- Structure -------------------------------------------------------- */
  --measure:      44rem;   /* prose column */
  --wide:         70rem;   /* page container */
  --narrow:       52rem;
  --header-h:     4.5rem;
  --rule-w:       1px;

  /* ---- Pixel shadows (hard edges, never blurred) ------------------------ */
  --px-shadow:      3px 3px 0 var(--rule-2);
  --px-shadow-ink:  4px 4px 0 var(--ink);

  --radius-pill: 999px;    /* the only curve on the page: the nav dock */
}

/* ============================================================================
   02. RESET & BASE
   ============================================================================ */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  background: var(--paper);
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--sp-5));
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--ink);
  background-color: var(--paper);
  /* Graph paper: major 120px cells over a 24px minor grid. */
  background-image:
    linear-gradient(var(--grid-major) var(--rule-w), transparent var(--rule-w)),
    linear-gradient(90deg, var(--grid-major) var(--rule-w), transparent var(--rule-w)),
    linear-gradient(var(--grid) var(--rule-w), transparent var(--rule-w)),
    linear-gradient(90deg, var(--grid) var(--rule-w), transparent var(--rule-w));
  background-size:
    var(--grid-major-cell) var(--grid-major-cell),
    var(--grid-major-cell) var(--grid-major-cell),
    var(--grid-cell) var(--grid-cell),
    var(--grid-cell) var(--grid-cell);
  background-position: -1px -1px;
  background-attachment: scroll;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

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

a {
  color: var(--accent);
  text-decoration: none;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}
a:hover { text-decoration: underline; }

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

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

hr {
  border: 0;
  border-top: var(--rule-w) solid var(--rule);
  margin: var(--sp-7) 0;
}

/* ============================================================================
   03. TYPOGRAPHY PRIMITIVES
   ============================================================================ */
h1, h2, h3, h4, h5, h6 {
  margin: 0 0 var(--sp-4);
  font-weight: 700;
  line-height: 1.18;
  letter-spacing: -0.022em;
  color: var(--ink);
  text-wrap: balance;
}

h1 { font-size: var(--step-5); font-weight: 800; letter-spacing: -0.035em; }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

p { margin: 0 0 var(--sp-4); }
p:last-child { margin-bottom: 0; }

strong { font-weight: 650; color: var(--ink); }

/* Monospace label — used for eyebrows, meta, nav, tags. */
.mono,
.eyebrow,
.meta {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Pixel-font label — the loudest pixel signal, used sparingly. */
.pixel {
  font-family: var(--font-pixel);
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-4);
  color: var(--ink-3);
}
.eyebrow::before {
  content: "";
  width: 8px;
  height: 8px;
  background: var(--accent);
  flex: none;
}

.lede {
  font-size: var(--step-1);
  line-height: 1.6;
  color: var(--ink-2);
}

/* ============================================================================
   04. LAYOUT PRIMITIVES
   ============================================================================ */
.container {
  width: 100%;
  max-width: var(--wide);
  margin-inline: auto;
  padding-inline: var(--sp-5);
}
.container-narrow {
  width: 100%;
  max-width: var(--narrow);
  margin-inline: auto;
  padding-inline: var(--sp-5);
}
.container-prose {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--sp-5);
}

.section { padding-block: var(--sp-9); }
.section--ruled { border-top: var(--rule-w) solid var(--rule); }

/* Two-column label/content split used by every major section. */
.section-grid {
  display: grid;
  grid-template-columns: 12rem minmax(0, 1fr);
  gap: var(--sp-8) var(--sp-7);
  align-items: start;
}
.section-grid > .section-aside {
  position: sticky;
  top: calc(var(--header-h) + var(--sp-5));
}
.aside-title {
  margin: 0 0 var(--sp-3);
  font-size: var(--step-2);
  line-height: 1.2;
}
.aside-note {
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--ink-3);
}
.aside-note a { color: var(--ink-2); text-decoration: underline; text-decoration-color: var(--rule-3); }
.aside-note a:hover { color: var(--accent); text-decoration-color: var(--accent); }
@media (max-width: 60rem) {
  .section-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
  .section-grid > .section-aside { position: static; }
}

.section-head { margin-bottom: var(--sp-6); }
.section-head h2 { margin-bottom: var(--sp-2); }
.section-head p { color: var(--ink-2); max-width: 46rem; }

.stack > * + * { margin-top: var(--sp-4); }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: var(--sp-3) var(--sp-4);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--step--1);
}
.skip-link:focus { left: var(--sp-4); top: var(--sp-4); }

.visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ============================================================================
   05. PIXEL-ART PRIMITIVES
   ============================================================================ */

/* Four L-shaped corner brackets drawn with background gradients — no assets,
   colour controlled by `--bc`, geometry by `--arm` / `--thick`. */
.px-brackets { position: relative; }
.px-brackets::after {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--gap, 6px));
  --arm: 13px;
  --thick: 2px;
  --bc: var(--ink);
  pointer-events: none;
  background:
    linear-gradient(var(--bc), var(--bc)) left top / var(--arm) var(--thick) no-repeat,
    linear-gradient(var(--bc), var(--bc)) left top / var(--thick) var(--arm) no-repeat,
    linear-gradient(var(--bc), var(--bc)) right top / var(--arm) var(--thick) no-repeat,
    linear-gradient(var(--bc), var(--bc)) right top / var(--thick) var(--arm) no-repeat,
    linear-gradient(var(--bc), var(--bc)) left bottom / var(--arm) var(--thick) no-repeat,
    linear-gradient(var(--bc), var(--bc)) left bottom / var(--thick) var(--arm) no-repeat,
    linear-gradient(var(--bc), var(--bc)) right bottom / var(--arm) var(--thick) no-repeat,
    linear-gradient(var(--bc), var(--bc)) right bottom / var(--thick) var(--arm) no-repeat;
}

/* ============================================================================
   06. BUTTONS & CONTROLS
   ============================================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.7rem 1.15rem;
  border: var(--rule-w) solid var(--ink);
  background: var(--paper-raised);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.2;
  cursor: pointer;
  transition: transform 0.08s steps(2), box-shadow 0.08s steps(2),
              background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translate(2px, 2px); box-shadow: none; }

.btn--primary {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.btn--primary:hover {
  background: var(--accent-deep);
  border-color: var(--accent-deep);
  box-shadow: var(--px-shadow);
}

.btn--ghost { background: transparent; border-color: var(--rule-2); color: var(--ink-2); }
.btn--ghost:hover {
  border-color: var(--ink);
  color: var(--ink);
  box-shadow: var(--px-shadow);
}

.btn--small { padding: 0.45rem 0.8rem; font-size: var(--step--2); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  align-items: center;
}

/* Small square icon link (socials, footer actions). */
.icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  color: var(--ink-2);
  font-size: 0.95rem;
  transition: color 0.12s ease, border-color 0.12s ease, background-color 0.12s ease;
}
.icon-link:hover {
  color: var(--ink);
  border-color: var(--ink);
  text-decoration: none;
}
.icon-link svg { inline-size: 1.05rem; block-size: 1.05rem; }

/* --- Header clearance --------------------------------------------------- */
/* The dock floats over the page, so main content is offset below it.
   `main` also grows to fill the viewport so the footer — and with it the
   horizon silhouette — always sits on the bottom edge of short pages. */
#main-content { padding-top: var(--header-h); flex: 1 0 auto; }

/* ============================================================================
   07. SITE HEADER — floating pill dock
   A compact, centred capsule that hovers over the paper. Fixed rather than
   sticky so the grid stays continuous behind it.
   ============================================================================ */
.site-header {
  position: fixed;
  top: var(--sp-3);
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000;
  /* Hug the links rather than sitting at a fixed 34rem: the capsule should read
     as tightly packed, not as a wide pill with slack at both ends. */
  width: max-content;
  max-width: calc(100% - var(--sp-5));
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  padding: 0.3rem 0.4rem;
  background: rgba(255, 255, 255, 0.9);
  border: var(--rule-w) solid var(--rule-2);
  border-radius: var(--radius-pill);
  box-shadow:
    0 1px 0 rgba(22, 24, 28, 0.03),
    0 4px 14px rgba(22, 24, 28, 0.06);
  backdrop-filter: saturate(150%) blur(10px);
  -webkit-backdrop-filter: saturate(150%) blur(10px);
}

.site-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  flex-wrap: nowrap;
  min-width: 0;
}

.nav-link {
  display: block;
  padding: 0.4rem 0.7rem;
  border: var(--rule-w) solid transparent;
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
  transition: color 0.12s ease, background-color 0.12s ease, border-color 0.12s ease;
}
.nav-link:hover {
  color: var(--ink);
  background: var(--paper-sunken);
  text-decoration: none;
}
.nav-link[aria-current="page"] {
  color: var(--accent-deep);
  background: var(--accent-soft);
  border-color: var(--accent-line);
}

.nav-group {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-left: 0.35rem;
  /* 0.85rem, not 0.4rem: the divider is a full 13.6px from the last nav
     label and from the Contact pill, so it sits centred between them rather
     than crowding the button. */
  padding-left: 0.85rem;
  border-left: var(--rule-w) solid var(--rule);
}
.nav-group .icon-link {
  inline-size: 2rem;
  block-size: 2rem;
  border-radius: var(--radius-pill);
  border-color: transparent;
  background: transparent;
  font-size: 0.95rem;
}
.nav-group .icon-link:hover {
  color: var(--accent-deep);
  background: var(--accent-soft);
  border-color: var(--accent-line);
}
.nav-group .icon-link svg { inline-size: 1rem; block-size: 1rem; }

/* The dock's one call to action: pure black on white, and it stays that way.
   Following the link must not repaint it, so :link, :visited and :hover are
   all pinned — the only change on hover is the inversion. */
.nav-cta,
.nav-cta:link,
.nav-cta:visited,
.nav-cta:active {
  display: inline-flex;
  align-items: center;
  padding: 0.42rem 0.9rem;
  border: var(--rule-w) solid var(--ink);
  border-radius: var(--radius-pill);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.04em;
  line-height: 1.2;
  white-space: nowrap;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.nav-cta:hover,
.nav-cta:focus-visible {
  background: var(--paper-raised);
  border-color: var(--ink);
  color: var(--ink);
  text-decoration: none;
}

@media (max-width: 30rem) {
  .nav-link { padding: 0.38rem 0.5rem; font-size: var(--step--2); }
  .nav-group { margin-left: 0.2rem; padding-left: 0.7rem; }
  .nav-group .icon-link { inline-size: 1.75rem; block-size: 1.75rem; }
  .nav-cta { padding: 0.36rem 0.6rem; letter-spacing: 0.02em; }
}

/* ============================================================================
   08. SITE FOOTER — links over the landscape
   Two things only: one quiet row (links left, colophon over a back-to-top
   link on the right), then the pixel horizon at the very bottom of the page.
   ============================================================================ */
.site-footer {
  border-top: var(--rule-w) solid var(--rule);
  background: transparent;   /* the paper grid continues to the very bottom */
}

.footer-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-6);
  padding-block: var(--sp-7) var(--sp-6);
}

/* --- links -------------------------------------------------------------- */
.footer-links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.85rem;
}
.footer-link {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  color: var(--ink-2);
  transition: color 0.12s ease;
}
.footer-link:hover { color: var(--accent-deep); text-decoration: none; }

/* Pixel bullet — a square, not a round chip, so it reads as pixel art
   rather than as an icon font. */
.footer-dot {
  inline-size: 5px;
  block-size: 5px;
  background: var(--rule-3);
  flex: none;
  transform: translateY(-2px);
  transition: background-color 0.12s ease;
}
.footer-link:hover .footer-dot { background: var(--accent); }

/* --- colophon + back to top --------------------------------------------- */
.footer-aside {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
}
.footer-aside > * + * { margin-top: 0.5rem; }
.footer-note {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.footer-note a { color: var(--ink-3); }
.footer-note a:hover { color: var(--accent-deep); text-decoration: none; }

.footer-top {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.footer-top:hover { color: var(--accent-deep); text-decoration: none; }
.footer-top__arrow { font-size: 1.05em; line-height: 0; transform: translateY(-1px); }

/* Pixel horizon: the SVG tile is 480x24, drawn at exactly 2x so every pixel
   lands on a whole device pixel. The silhouette is the page's end mark and
   the last thing in the document. */
.footer-horizon {
  height: 52px;
  background-image: url("/assets/pixel/horizon.svg");
  background-repeat: repeat-x;
  background-position: left bottom;
  background-size: 960px 48px;
  image-rendering: pixelated;
}

@media (max-width: 48rem) {
  /* The row cannot hold links plus colophon: stack them, centred, so it reads
     as a deliberate signature instead of a squeeze. */
  .footer-row {
    flex-direction: column;
    align-items: center;
    padding-block: var(--sp-6) var(--sp-5);
    text-align: center;
  }
  /* margin, not gap: keeps the spacing if `gap` inside a column flex
     container is unsupported (older Safari). */
  .footer-row > * + * { margin-top: var(--sp-5); }
  .footer-links { justify-content: center; }
  .footer-aside { align-items: center; text-align: center; }
  .footer-horizon { height: 42px; background-size: 800px 40px; }
}

@media (max-width: 32rem) {
  .footer-links { gap: 0.3rem 0.6rem; }
  .footer-link,
  .footer-note,
  .footer-top { font-size: 0.625rem; }
  .footer-link { gap: 0.35rem; }
  .footer-note { letter-spacing: 0.04em; }
}

/* ============================================================================
   09. HERO
   ============================================================================ */
.hero { padding-block: var(--sp-8) var(--sp-8); }

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 13rem;
  gap: var(--sp-8);
  align-items: start;
}
@media (max-width: 56rem) {
  .hero-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); }
}

/* --- ASCII wordmark ----------------------------------------------------- */
/* Three stacked copies of the same block art, offset by whole pixels, read as
   a letterpress extrusion. Paper tones only — no glow, no blur.

   The art is 71 monospace cells wide, so the font size is capped by the space
   actually available beside (or above) the portrait — the wordmark can never
   clip, at any viewport. Below 34rem it gives way to set type. */
.ascii-name {
  --ascii-cols: 42.6;               /* 71 cells x 0.6em advance */
  --ascii-size: min(0.85rem, (min(70rem, 100vw) - 20rem) / var(--ascii-cols));
  margin: 0 0 var(--sp-5);
  line-height: 0;
}

.ascii-name__stack {
  position: relative;
  display: block;
  font-size: var(--ascii-size);
  line-height: 1;
}

.ascii-name__layer {
  margin: 0;
  font-family: var(--font-mono);
  font-size: inherit;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0;
  white-space: pre;
  background: none;
  border: 0;
  padding: 0;
  overflow: visible;
}

.ascii-name__layer--back,
.ascii-name__layer--mid {
  position: absolute;
  inset: 0;
  user-select: none;
  pointer-events: none;
}
.ascii-name__layer--back  { color: var(--rule-2); transform: translate(3px, 3px); }
.ascii-name__layer--mid   { color: var(--rule-3); transform: translate(1.5px, 1.5px); }
.ascii-name__layer--front { position: relative; color: var(--ink); z-index: 1; }

@media (max-width: 56rem) {
  /* Single-column hero: the wordmark owns the full measure. */
  .ascii-name { --ascii-size: min(0.78rem, (min(70rem, 100vw) - 3.5rem) / var(--ascii-cols)); }
  .ascii-name__layer--back { display: none; }
}
@media (max-width: 40rem) {
  /* Tighten the gutter so the 71-cell wordmark keeps as much size as possible. */
  .ascii-name { --ascii-size: min(0.7rem, (100vw - 2.5rem) / var(--ascii-cols)); }
}

.hero-role {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  margin: 0 0 var(--sp-5);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--ink-2);
}
.hero-role .at { color: var(--ink-4); }

/* Role badge — the original pill treatment, in paper tones. */
.role-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.28rem 0.65rem;
  border: var(--rule-w) solid var(--accent-line);
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent-deep);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.company-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.25rem 0.6rem 0.25rem 0.3rem;
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  color: var(--ink);
  font-weight: 500;
}
.company-pill:hover { border-color: var(--ink); text-decoration: none; }
/* The Codegig mark is yellow-on-transparent, so it needs a dark chip to read
   against paper. */
.company-pill img {
  inline-size: 1.15rem;
  block-size: 1.15rem;
  padding: 2px;
  background: var(--ink);
  border-radius: 2px;
}

.hero-bio {
  max-width: 38rem;
  margin: 0 0 var(--sp-6);
  font-size: var(--step-1);
  line-height: 1.62;
  color: var(--ink-2);
}
.hero-bio strong { color: var(--ink); font-weight: 650; }
/* Frosted "glass" chip for the live location + weather, as on the old site —
   re-cut for paper: a bright top highlight, a soft cast shadow, no neon. */
.weather-display {
  display: inline-flex;
  align-items: center;
  padding: 0.05em 0.5em;
  margin: 0 1px;
  border: var(--rule-w) solid var(--rule-2);
  border-radius: 6px;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(243, 244, 240, 0.88));
  -webkit-backdrop-filter: blur(10px) saturate(160%);
  backdrop-filter: blur(10px) saturate(160%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.95),
    inset 0 -1px 0 rgba(22, 24, 28, 0.04),
    0 1px 2px rgba(22, 24, 28, 0.06);
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  vertical-align: baseline;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.weather-display:hover {
  border-color: var(--accent-line);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.95),
    0 2px 10px rgba(15, 107, 94, 0.16);
}
.weather-display a {
  display: inline-flex;
  align-items: center;
  color: inherit;
  text-decoration: none;
}

.hero-actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* ---- Pixel portrait ---------------------------------------------------- */
.hero-portrait { justify-self: end; }
@media (max-width: 56rem) { .hero-portrait { justify-self: start; order: -1; } }

.avatar-frame {
  --gap: 7px;
  position: relative;
  display: block;
  inline-size: 13rem;
  padding: var(--sp-2);
  background: var(--paper-raised);
  border: var(--rule-w) solid var(--ink);
  box-shadow: var(--px-shadow-ink);
}
.avatar-frame img {
  inline-size: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  image-rendering: pixelated;
  -ms-interpolation-mode: nearest-neighbor;
}
.avatar-caption {
  position: absolute;
  left: 0;
  bottom: calc(-1 * var(--sp-6));
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-3);
  white-space: nowrap;
}
@media (max-width: 56rem) {
  .avatar-frame { inline-size: 9rem; }
  .avatar-caption { display: none; }
}

/* ============================================================================
   09b. EXPERIENCE
   ============================================================================ */
.exp-list {
  display: grid;
  gap: var(--sp-5);
}

.exp {
  padding: var(--sp-5) var(--sp-6);
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
}

.exp-head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  padding-bottom: var(--sp-4);
  border-bottom: var(--rule-w) solid var(--rule);
}

.exp-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.6rem;
  block-size: 2.6rem;
  flex: none;
  border: var(--rule-w) solid var(--rule);
  background: var(--paper-sunken);
}
.exp-mark img { inline-size: 1.6rem; block-size: 1.6rem; object-fit: contain; }
/* Marks that are light-on-transparent need a dark tile to read on paper. */
.exp-mark--dark { background: var(--ink); border-color: var(--ink); }
.exp-initial {
  font-family: var(--font-pixel);
  font-size: 1.05rem;
  line-height: 1;
  color: var(--ink-3);
}

.exp-id { flex: 1; min-width: 0; }
.exp-role {
  margin: 0 0 0.15rem;
  font-size: var(--step-2);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
.exp-role a { color: var(--ink); }
.exp-role a:hover { color: var(--accent); text-decoration: none; }

.exp-company {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.exp-company a { color: var(--ink-2); }
.exp-company a:hover { color: var(--accent); }
.exp-company .sep { inline-size: 3px; block-size: 3px; background: var(--rule-3); }

.exp-period {
  flex: none;
  margin: 0;
  padding-top: 0.2rem;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.04em;
  color: var(--ink-3);
  text-align: right;
  white-space: nowrap;
}

.exp-summary {
  margin: var(--sp-4) 0 0;
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--ink-2);
}

.exp-points {
  margin: var(--sp-4) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--sp-3);
}
.exp-points li {
  position: relative;
  padding-left: 1.15rem;
  font-size: var(--step--1);
  line-height: 1.65;
  color: var(--ink-2);
}
.exp-points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  inline-size: 5px;
  block-size: 5px;
  background: var(--accent);
}

.exp-stack {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-5) 0 0;
  padding: var(--sp-4) 0 0;
  border-top: var(--rule-w) solid var(--rule);
  list-style: none;
}
.stack-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  border: var(--rule-w) solid var(--rule);
  background: var(--paper-sunken);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-2);
}
.stack-tag img { inline-size: 0.9rem; block-size: 0.9rem; flex: none; }
.stack-tag i { font-size: 0.8rem; color: var(--ink-3); flex: none; }

@media (max-width: 40rem) {
  .exp { padding: var(--sp-5); }
  .exp-head { flex-wrap: wrap; }
  .exp-period { text-align: left; padding-top: 0; width: 100%; }
}

/* ============================================================================
   10. SKILLS INDEX
   Two columns at desktop width, so an opened entry gets a readable measure
   instead of a narrow ribbon of text.
   ============================================================================ */
.skill-groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: var(--sp-7) var(--sp-6);
  align-items: start;
}

.skill-group-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-2);
  padding-bottom: var(--sp-2);
  border-bottom: var(--rule-w) solid var(--ink);
  font-family: var(--font-pixel);
  font-size: 0.72rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.skill-group-title .count {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-4);
  letter-spacing: 0;
}
.skill-group-desc {
  margin: 0 0 var(--sp-4);
  font-size: var(--step--1);
  color: var(--ink-3);
  line-height: 1.55;
}

.skill-list { list-style: none; margin: 0; padding: 0; }

.skill {
  border-bottom: var(--rule-w) solid var(--rule);
}
.skill > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0.4rem 0;
  cursor: pointer;
  list-style: none;
  color: var(--ink-2);
  transition: color 0.12s ease;
}
.skill > summary::-webkit-details-marker { display: none; }
.skill > summary:hover { color: var(--ink); }
.skill > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.skill-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 1.4rem;
  block-size: 1.4rem;
  flex: none;
  border: var(--rule-w) solid var(--rule);
  background: var(--paper-raised);
}
.skill-mark img { inline-size: 0.9rem; block-size: 0.9rem; }

.skill-name { flex: 1; font-size: var(--step--1); font-weight: 500; }

.skill-toggle {
  flex: none;
  font-size: 0.75rem;
  color: var(--ink-4);
  transition: color 0.12s ease, transform 0.12s ease;
}
.skill[open] > summary .skill-toggle { color: var(--accent); transform: rotate(90deg); }
.skill[open] > summary { color: var(--ink); font-weight: 600; }

.skill-detail {
  padding: 0 0 var(--sp-4) 2.25rem;
  font-size: var(--step--1);
  line-height: 1.65;
  color: var(--ink-2);
}
.skill-detail p { margin: 0 0 var(--sp-3); }
.skill-projects {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-3);
}
.skill-projects a {
  padding: 0.15rem 0.45rem;
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  color: var(--ink-2);
}
.skill-projects a:hover { border-color: var(--ink); color: var(--ink); text-decoration: none; }

/* ============================================================================
   11. CARDS
   ----------------------------------------------------------------------------
   One component for every project and every post: a gallery print. A clipped
   mount holds the figure, with the caption on a smaller plate hung below and
   to the right. The grid is salon-hung, so the second column sits lower.

   The wireframe window (`.three-container`) and the tilt live in depth.css.
   `.card-tags` and `.card-badge` are also used by the project detail header,
   so they stay here even though the card itself no longer renders them.
   ============================================================================ */
.card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 3rem 2.5rem;                 /* mockup: 48 / 40 */
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The wrapper is a grid child on the blog list; keep the 3D context flowing
   through it so the tilt still gets the grid's perspective. */
.card-grid > * { min-width: 0; transform-style: preserve-3d; }
.card-grid > *:nth-child(2n) { margin-top: 2.25rem; }

@media (max-width: 48rem) {
  .card-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-8); }
  .card-grid > *:nth-child(2n) { margin-top: 0; }
}

/* ---- The print ---------------------------------------------------------- */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
}

/* Bulldog clip holding the print to the wall. */
.card-clip {
  position: absolute;
  top: -0.7rem;
  left: 50%;
  margin-left: -0.7rem;
  inline-size: 1.4rem;
  block-size: 1rem;
  color: var(--ink);
  pointer-events: none;
  transform: translateZ(34px);
}
.card-clip svg { display: block; inline-size: 100%; block-size: 100%; }
.card-clip::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 0.95rem;
  inline-size: 1px;
  block-size: 0.6rem;
  margin-left: -0.5px;
  background: var(--rule-3);
}

/* ---- Mount: the matted figure ------------------------------------------- */
.card-mount {
  position: relative;
  padding: var(--sp-4);
  background: var(--paper-raised);
  border: var(--rule-w) solid var(--ink);
  box-shadow: var(--px-shadow-ink);
  /* No preserve-3d here on purpose: it would project the wireframe window's
     translateZ and drag it off the corner it is meant to lap over. */
}

.card-art {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
}
.card-art img {
  inline-size: 100%;
  block-size: 100%;
  /* contain, never cover: a screenshot or a plot is evidence, don't crop it */
  object-fit: contain;
  filter: saturate(0.94);
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.card:hover .card-art img { transform: scale(1.015); }

/* No screenshot: ruled paper, and the wireframe takes the frame. */
.card-art--blank {
  background-color: var(--paper-sunken);
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 14px 14px;
}
.card-blank-tag {
  position: absolute;
  left: var(--sp-3);
  bottom: var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* ---- Caption plate: narrower than the print, hung off-centre ------------- */
.card-plate {
  align-self: flex-start;
  max-inline-size: min(100%, 22rem);
  margin: 1.1rem 0 0 1.9rem;
  padding: 0.7rem 0.9rem 0.75rem;
  background: var(--paper-raised);
  border: var(--rule-w) solid var(--ink);
  box-shadow: 2px 2px 0 var(--ink);
  transform: translateZ(14px);
}
@media (max-width: 30rem) {
  .card-plate { margin-left: var(--sp-4); max-inline-size: 100%; }
}

.card-kicker {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.35rem;
  font-family: var(--font-pixel);
  font-size: 0.6rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.card-dot { inline-size: 0.5rem; block-size: 0.5rem; background: var(--rule-3); flex: none; }
.card--featured .card-dot { background: var(--accent); }

.card-title {
  margin: 0 0 0.3rem;
  font-size: 1.0625rem;
  font-weight: 650;
  letter-spacing: -0.015em;
  line-height: 1.3;
}
.card-title a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.18em;
  transition: color 0.12s ease, text-decoration-color 0.12s ease;
}
.card:hover .card-title a { color: var(--accent); text-decoration-color: var(--accent-line); }

/* Class name kept as `card-excerpt`: static/js/blog-list.js searches it. */
.card-excerpt {
  margin: 0 0 0.55rem;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 0.45rem;
  margin: 0;
  padding: 0.45rem 0 0;
  border-top: var(--rule-w) solid var(--rule);
  list-style: none;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.card-meta li + li::before { content: "·"; margin-right: 0.45rem; color: var(--rule-3); }
/* The trailing field sits hard right; suppress its separator. */
.card-meta-end { margin-left: auto; }
.card-meta-end::before { content: none !important; margin: 0 !important; }
.card-meta a { color: var(--ink-3); }
.card-meta a:hover { color: var(--accent); }

.card-status {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--ink-2);
  white-space: nowrap;
}
.card-status::before { content: ""; inline-size: 6px; block-size: 6px; background: var(--accent); flex: none; }
.card-status--wip { color: var(--ink-4); }
.card-status--wip::before { background: var(--rule-2); }

/* ---- Also used by the project detail header ------------------------------ */
.card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.card-tag {
  padding: 0.1rem 0.45rem;
  border: var(--rule-w) solid var(--rule);
  background: var(--paper-sunken);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-3);
}
.card-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ============================================================================
   12. SECTION FURNITURE
   ============================================================================ */
.section-actions {
  display: flex;
  justify-content: center;
  margin-top: var(--sp-6);
}

/* Framed live embed (the Paokinator game). */
.embed-panel {
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  padding: var(--sp-3);
}
.embed-panel-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: 0 var(--sp-1) var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.embed-panel-bar .lights { display: inline-flex; gap: 5px; }
.embed-panel-bar .lights i {
  inline-size: 8px;
  block-size: 8px;
  background: var(--rule-2);
}
.embed-panel-bar .lights i:first-child { background: var(--rule-3); }
.embed-panel-frame {
  position: relative;
  border: var(--rule-w) solid var(--rule);
  background: var(--paper-sunken);
}
.embed-panel-frame iframe {
  display: block;
  inline-size: 100%;
  block-size: 34rem;
  border: 0;
}
@media (max-width: 48rem) { .embed-panel-frame iframe { block-size: 26rem; } }

.empty-state {
  padding: var(--sp-8) var(--sp-5);
  border: var(--rule-w) dashed var(--rule-3);
  background: var(--paper-raised);
  text-align: center;
}
.empty-state .empty-glyph { font-size: 1.6rem; color: var(--ink-4); margin-bottom: var(--sp-4); display: block; }
.icon-lg { font-size: 1.5em; line-height: 1; }
.empty-title { margin: 0 0 var(--sp-2); font-size: var(--step-2); }
.empty-message { margin: 0 auto var(--sp-5); max-width: 34rem; color: var(--ink-2); }
.empty-cta { display: flex; justify-content: center; }

/* Prev / next navigation between sibling pages. */
.pager {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--sp-4);
  margin-top: var(--sp-8);
  padding-top: var(--sp-6);
  border-top: var(--rule-w) solid var(--rule);
}
.pager-link {
  display: block;
  padding: var(--sp-4);
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  color: var(--ink);
  transition: border-color 0.12s ease, box-shadow 0.12s steps(2);
}
.pager-link:hover { border-color: var(--ink); box-shadow: var(--px-shadow); text-decoration: none; }
.pager-link--next { text-align: right; }
.pager-direction {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: var(--sp-2);
}
.pager-link--next .pager-direction { justify-content: flex-end; }
.pager-title { font-weight: 600; line-height: 1.35; }

.back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-5);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.back-link:hover { color: var(--ink); text-decoration: none; }

/* ============================================================================
   13. HOMEPAGE SECTIONS
   ============================================================================ */
.page-head { padding-block: var(--sp-8) var(--sp-6); }
.page-head h1 { margin-bottom: var(--sp-3); }
.page-head .lede { max-width: 40rem; }
.page-head-extra { margin: var(--sp-5) 0 0; color: var(--ink-3); }
.page-head-extra .back-link { margin-bottom: 0; }

/* ============================================================================
   14. BLOG LIST CONTROLS
   ============================================================================ */
.list-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-bottom: var(--sp-6);
  padding-bottom: var(--sp-5);
  border-bottom: var(--rule-w) solid var(--rule);
}

.search-field {
  position: relative;
  flex: 1 1 16rem;
  display: flex;
  align-items: center;
}
.search-field > i {
  position: absolute;
  left: 0.8rem;
  font-size: 0.85rem;
  color: var(--ink-4);
  pointer-events: none;
}
.search-field input {
  inline-size: 100%;
  padding: 0.6rem 0.8rem 0.6rem 2.2rem;
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--ink);
}
.search-field input::placeholder { color: var(--ink-4); }
.search-field input:focus { outline: none; border-color: var(--ink); box-shadow: var(--px-shadow); }

.filter-wrap { position: relative; }
.filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.6rem 0.9rem;
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  cursor: pointer;
}
.filter-toggle:hover { border-color: var(--ink); color: var(--ink); }

.filter-dropdown {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 30;
  display: none;
  min-width: 13rem;
  max-height: 20rem;
  overflow-y: auto;
  padding: var(--sp-2);
  border: var(--rule-w) solid var(--ink);
  background: var(--paper-raised);
  box-shadow: var(--px-shadow);
}
.filter-dropdown.active { display: block; }
.tag-filter {
  display: block;
  inline-size: 100%;
  padding: 0.4rem 0.6rem;
  border: 0;
  background: transparent;
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  text-align: left;
  cursor: pointer;
}
.tag-filter:hover { background: var(--paper-sunken); color: var(--ink); }
.tag-filter.active { background: var(--accent-soft); color: var(--accent-deep); font-weight: 500; }

/* ============================================================================
   15. NOW TIMELINE
   ============================================================================ */
/* The spine is two stacked 2px rules: a static track and an accent fill that
   is scaled from the top as the reader scrolls (see js/timeline.js). */
.timeline {
  position: relative;
  margin: 0;
  padding: 0 0 0 var(--sp-6);
  list-style: none;
}
.timeline::before,
.timeline::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  inline-size: 2px;
}
.timeline::before { background: var(--rule-2); }
.timeline::after {
  background: var(--accent);
  transform: scaleY(var(--timeline-progress, 0));
  transform-origin: top center;
}

.entry { position: relative; padding-bottom: var(--sp-7); }
.entry:last-child { padding-bottom: 0; }
.entry::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--sp-6) - 2.5px);
  top: 0.45rem;
  inline-size: 7px;
  block-size: 7px;
  background: var(--accent);
}

/* Reveal-on-scroll is opt-in: js/timeline.js adds `.is-animated`, so the page
   is fully readable with JavaScript off. */
.timeline.is-animated .entry > * {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22, 0.8, 0.3, 1);
}
.timeline.is-animated .entry::before {
  transform: scale(0);
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.timeline.is-animated .entry.is-visible > * { opacity: 1; transform: none; }
.timeline.is-animated .entry.is-visible::before { transform: scale(1); }
.timeline.is-animated .entry > *:nth-child(2) { transition-delay: 0.06s; }
.timeline.is-animated .entry > *:nth-child(3) { transition-delay: 0.12s; }
.timeline.is-animated .entry > *:nth-child(n+4) { transition-delay: 0.18s; }

@media (prefers-reduced-motion: reduce) {
  .timeline.is-animated .entry > *,
  .timeline.is-animated .entry::before { opacity: 1; transform: none; }
}

.entry-date {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.entry-mood {
  display: inline-block;
  margin-left: var(--sp-3);
  padding: 0.05rem 0.4rem;
  border: var(--rule-w) solid var(--rule);
  background: var(--paper-raised);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-3);
}
.entry-title { margin: 0 0 var(--sp-3); font-size: var(--step-2); }
.entry-body { color: var(--ink-2); }
.entry-image {
  margin-top: var(--sp-4);
  border: var(--rule-w) solid var(--rule);
  background: var(--paper-raised);
  padding: var(--sp-2);
}
.entry-tags { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
.entry-tag {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-3);
}
.timeline-footer {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: var(--rule-w) solid var(--rule);
  color: var(--ink-3);
  font-size: var(--step--1);
}

/* ============================================================================
   16. TAGS
   ============================================================================ */
.tag-cloud {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--sp-3);
}
.tag-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  color: var(--ink);
  transition: border-color 0.12s ease, box-shadow 0.12s steps(2);
}
.tag-item:hover { border-color: var(--ink); box-shadow: var(--px-shadow); text-decoration: none; }
.tag-name { font-family: var(--font-mono); font-size: var(--step--1); font-weight: 500; }
.tag-count { font-family: var(--font-mono); font-size: var(--step--2); color: var(--ink-4); }

/* ============================================================================
   17. CONTACT PAGE
   ============================================================================ */
.contact-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.contact-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  /* Matches .contact-card so the bar reads as the card's running head. */
  max-width: 40rem;
  width: 100%;
  margin-inline: auto;
  padding: var(--sp-5) var(--sp-5) var(--sp-3);
}
/* --- Back link ----------------------------------------------------------- */
/* One control, shared by the contact top bar and the project detail pages:
   step back through history when there is history, otherwise fall through to
   the href, which is always the sensible parent. */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.back-link:hover { color: var(--ink); text-decoration: none; }
.back-link i { font-size: 0.72rem; }

.contact-main {
  flex: 1;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: var(--sp-6) var(--sp-5) var(--sp-9);
}
.contact-card {
  width: 100%;
  max-width: 40rem;
}
.contact-card h1 { margin-bottom: var(--sp-3); }
.contact-card .lede { margin-bottom: var(--sp-6); }

.cooldown-text {
  margin: var(--sp-3) 0 0;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-3);
}

/* Hugging Face brand mark inside the "elsewhere" list. */
.hf-mark { display: inline-flex; }
.hf-mark svg { inline-size: 0.95rem; block-size: 0.95rem; }

.contact-form {
  display: grid;
  gap: var(--sp-5);
  padding: var(--sp-6);
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
}

.field { display: grid; gap: var(--sp-2); }
.field label {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.field input,
.field textarea {
  inline-size: 100%;
  padding: 0.7rem 0.85rem;
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  color: var(--ink);
  transition: border-color 0.12s ease, box-shadow 0.12s steps(2);
}
.field textarea { resize: vertical; min-height: 9rem; line-height: 1.6; }
.field input::placeholder,
.field textarea::placeholder { color: var(--ink-4); }
.field input:focus,
.field textarea:focus { outline: none; border-color: var(--ink); box-shadow: var(--px-shadow); }

.form-actions { display: flex; justify-content: flex-start; }
.form-submit {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.7rem 1.25rem;
  border: var(--rule-w) solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  cursor: pointer;
  transition: transform 0.08s steps(2), box-shadow 0.08s steps(2), background-color 0.12s ease;
}
.form-submit:hover { background: var(--accent-deep); border-color: var(--accent-deep); box-shadow: var(--px-shadow); }
.form-submit:active { transform: translate(2px, 2px); box-shadow: none; }
.form-submit[disabled] { opacity: 0.55; cursor: not-allowed; box-shadow: none; }

.form-status {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--accent-deep);
}
.form-status--error { color: #b91c1c; }

.thank-you {
  padding: var(--sp-7) var(--sp-6);
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  text-align: center;
}
.thank-you .thank-you-glyph { font-size: 1.9rem; color: var(--accent); margin-bottom: var(--sp-4); display: block; }
.thank-you h2 { margin-bottom: var(--sp-3); }
.thank-you p { color: var(--ink-2); }
.thank-you.hidden { display: none; }

.contact-elsewhere {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: var(--rule-w) solid var(--rule);
}
/* Leading position: the profiles come before the form, so the rule moves to
   the underside and the block introduces the page instead of closing it. */
.contact-elsewhere--lead {
  margin-top: 0;
  margin-bottom: var(--sp-6);
  padding-top: 0;
  padding-bottom: var(--sp-5);
  border-top: 0;
  border-bottom: var(--rule-w) solid var(--rule);
}
.contact-elsewhere--lead .contact-elsewhere-label { margin-bottom: var(--sp-4); }
.contact-elsewhere-label {
  margin: 0 0 var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.contact-elsewhere-links { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.contact-elsewhere-links a {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.4rem 0.7rem;
  border: var(--rule-w) solid var(--rule-2);
  background: var(--paper-raised);
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: var(--step--2);
}
.contact-elsewhere-links a:hover { border-color: var(--ink); color: var(--ink); text-decoration: none; }
.contact-elsewhere-links svg { inline-size: 0.95rem; block-size: 0.95rem; }

/* ============================================================================
   18. RÉSUMÉ PAGE
   ============================================================================ */
/* The document viewer is the framed embed from section 12 with a portrait
   opening: a letter page needs for height what the game embed spends on width. */
.resume-viewer .embed-panel-frame iframe {
  block-size: min(78vh, 56rem);
  min-block-size: 30rem;
}
@media (max-width: 48rem) {
  .resume-viewer .embed-panel-frame iframe { block-size: 62vh; min-block-size: 24rem; }
}

/* Caption under the panel: what the file is, then the escape hatch for the
   browsers (mostly mobile Safari) that will not render a PDF inline. */
.resume-note {
  margin: var(--sp-4) 0 0;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  line-height: 1.7;
  color: var(--ink-3);
}

/* ============================================================================
   19. 404
   ============================================================================ */
.not-found {
  display: grid;
  place-items: center;
  min-height: 60vh;
  padding: var(--sp-9) var(--sp-5);
  text-align: center;
}
.not-found-code {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
  font-family: var(--font-pixel);
  font-size: clamp(3rem, 12vw, 6rem);
  line-height: 1;
  color: var(--ink);
}
.not-found-code i { font-size: clamp(1.75rem, 6vw, 3rem); color: var(--accent); }
.not-found h1 { font-size: var(--step-3); margin-bottom: var(--sp-3); }
.not-found p { color: var(--ink-2); max-width: 32rem; margin-inline: auto; }
.not-found .btn-row { justify-content: center; margin-top: var(--sp-6); }

/* ============================================================================
   20. OVERLAYS
   ============================================================================ */
.reading-progress-container {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  height: 2px;
  background: transparent;
  pointer-events: none;
}
.reading-progress-bar {
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width 0.1s linear;
}

.image-modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
  background: rgba(22, 24, 28, 0.82);
}
.image-modal__figure {
  max-width: min(92vw, 72rem);
  max-height: 90vh;
  margin: 0;
  border: var(--rule-w) solid rgba(255, 255, 255, 0.18);
  background: var(--paper-raised);
  padding: var(--sp-2);
}
.image-modal__figure img { max-height: 78vh; object-fit: contain; margin-inline: auto; }
.image-modal__caption {
  margin: var(--sp-3) 0 var(--sp-1);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--ink-3);
  text-align: center;
}
.image-modal__close {
  position: absolute;
  top: var(--sp-5);
  right: var(--sp-5);
  inline-size: 2.5rem;
  block-size: 2.5rem;
  display: grid;
  place-items: center;
  border: var(--rule-w) solid rgba(255, 255, 255, 0.3);
  background: transparent;
  color: #fff;
  font-size: 1.1rem;
  cursor: pointer;
}
.image-modal__close:hover { background: rgba(255, 255, 255, 0.12); }

/* ============================================================================
   21. MOTION & RESPONSIVE
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

@media (max-width: 48rem) {
  :root { --sp-9: 4rem; --sp-10: 5rem; }
  .hero { padding-block: var(--sp-7) var(--sp-6); }
  .contact-form { padding: var(--sp-5); }
}

@media print {
  .site-header, .site-footer, .reading-progress-container, .image-modal { display: none; }
  body { background: #fff; }
  a { color: var(--ink); }
}
