/* =========================================================================
   filipsalo.se — bold editorial redesign
   Token-driven, responsive, light/dark. The layout is a single "breakout"
   grid (.prose): prose sits in a readable measure, while figures and code
   can widen to .wide / .huge / .full bands or float into the margin (.side).
   ========================================================================= */

/* ---- Self-hosted fonts (variable, latin subset) ------------------------ */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/inter-latin-wght-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/inter-latin-wght-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Cascadia Code";
  font-style: normal;
  font-weight: 200 700;
  font-display: swap;
  src: url("/static/fonts/cascadia-code-latin-wght-normal.woff2") format("woff2");
}

/* ---- Design tokens ----------------------------------------------------- */
:root {
  color-scheme: light dark;

  /* Inter for all text; Cascadia Code reserved for code. */
  --font-display: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Cascadia Code", ui-monospace, "SFMono-Regular", Menlo, monospace;

  /* Fluid type scale (1.25 ratio, clamped between mobile and desktop). */
  --step--1: clamp(0.83rem, 0.80rem + 0.15vw, 0.92rem);
  --step-0:  clamp(1.00rem, 0.95rem + 0.25vw, 1.13rem);
  --step-1:  clamp(1.20rem, 1.10rem + 0.50vw, 1.50rem);
  --step-2:  clamp(1.44rem, 1.25rem + 0.95vw, 2.00rem);
  --step-3:  clamp(1.73rem, 1.40rem + 1.65vw, 2.75rem);
  --step-4:  clamp(2.07rem, 1.55rem + 2.60vw, 3.75rem);

  /* Spacing scale */
  --space-2xs: clamp(0.5rem, 0.45rem + 0.25vw, 0.625rem);
  --space-xs:  clamp(0.75rem, 0.68rem + 0.35vw, 0.94rem);
  --space-s:   clamp(1rem, 0.92rem + 0.4vw, 1.25rem);
  --space-m:   clamp(1.5rem, 1.36rem + 0.7vw, 1.9rem);
  --space-l:   clamp(2.25rem, 2rem + 1.25vw, 3rem);
  --space-xl:  clamp(3.5rem, 3rem + 2.5vw, 5rem);

  /* Layout. The post body (.prose) is a 9-column grid built from --colw
     (one column) and --gut (the gutter between columns). --measure sizes the
     list pages (home / archive). */
  --measure: 60ch;
  --gutter: clamp(1.1rem, 4vw, 2.5rem);
  --colw: clamp(0rem, 8vw, 5.75rem);
  --gut: clamp(0.6rem, 1.7vw, 1.3rem);
  --radius: 12px;
  --radius-s: 8px;

  /* Brand hue drives accents + tag chips so themes recolor in one place. */
  --hue: 210;

  /* Pizzazz gradients: the avatar ring sweeps violet→blue→green→amber and
     the name picks up amber→pink→violet, so the two read as one rainbow. */
  --grad-avatar: linear-gradient(115deg, hsl(268 82% 64%), hsl(210 88% 56%) 35%, hsl(162 70% 48%) 66%, hsl(45 95% 58%));
  --grad-name: linear-gradient(135deg, hsl(28 95% 58%), hsl(330 85% 62%) 55%, hsl(280 80% 64%));
  --glow-color: hsl(210 82% 56% / 0.5);

  /* Semantic colors — light */
  --bg:        hsl(40 30% 98%);
  --bg-tint:   hsl(var(--hue) 40% 97%);
  --surface:   hsl(40 33% 100%);
  --surface-2: hsl(var(--hue) 24% 95%);
  --text:      hsl(225 22% 16%);
  --text-soft: hsl(225 14% 32%);
  --muted:     hsl(225 10% 48%);
  --border:    hsl(225 18% 89%);
  --border-strong: hsl(225 16% 80%);
  --accent:    hsl(var(--hue) 72% 56%);
  --accent-strong: hsl(var(--hue) 78% 46%);
  --accent-soft: hsl(var(--hue) 80% 95%);
  --on-accent: hsl(40 33% 100%);

  /* Callout (note) — warm */
  --note-bg:   hsl(38 92% 95%);
  --note-border: hsl(38 80% 72%);
  --note-text: hsl(30 45% 26%);

  /* Code surface */
  --code-bg:   hsl(var(--hue) 30% 96%);
  --code-text: hsl(225 22% 22%);

  --shadow: 0 1px 2px hsl(225 30% 10% / 0.05), 0 8px 24px hsl(225 30% 10% / 0.06);
  --selection: hsl(var(--hue) 80% 88%);
}

/* Dark — applied when the OS prefers dark (unless forced light)… */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:        hsl(228 20% 9%);
    --bg-tint:   hsl(var(--hue) 22% 12%);
    --surface:   hsl(228 18% 13%);
    --surface-2: hsl(228 16% 17%);
    --text:      hsl(225 24% 92%);
    --text-soft: hsl(225 16% 78%);
    --muted:     hsl(225 12% 60%);
    --border:    hsl(228 14% 22%);
    --border-strong: hsl(228 12% 30%);
    --accent:    hsl(var(--hue) 90% 76%);
    --accent-strong: hsl(var(--hue) 95% 82%);
    --accent-soft: hsl(var(--hue) 40% 20%);
    --on-accent: hsl(228 25% 10%);

    --note-bg:   hsl(38 35% 16%);
    --note-border: hsl(38 45% 38%);
    --note-text: hsl(38 60% 82%);

    --code-bg:   hsl(228 18% 15%);
    --code-text: hsl(225 22% 86%);

    --shadow: 0 1px 2px hsl(0 0% 0% / 0.3), 0 10px 30px hsl(0 0% 0% / 0.35);
    --selection: hsl(var(--hue) 60% 30%);
  }
}

/* …and when the reader explicitly chooses dark via the toggle. */
:root[data-theme="dark"] {
  --bg:        hsl(228 20% 9%);
  --bg-tint:   hsl(var(--hue) 22% 12%);
  --surface:   hsl(228 18% 13%);
  --surface-2: hsl(228 16% 17%);
  --text:      hsl(225 24% 92%);
  --text-soft: hsl(225 16% 78%);
  --muted:     hsl(225 12% 60%);
  --border:    hsl(228 14% 22%);
  --border-strong: hsl(228 12% 30%);
  --accent:    hsl(var(--hue) 90% 76%);
  --accent-strong: hsl(var(--hue) 95% 82%);
  --accent-soft: hsl(var(--hue) 40% 20%);
  --on-accent: hsl(228 25% 10%);
  --note-bg:   hsl(38 35% 16%);
  --note-border: hsl(38 45% 38%);
  --note-text: hsl(38 60% 82%);
  --code-bg:   hsl(228 18% 15%);
  --code-text: hsl(225 22% 86%);
  --shadow: 0 1px 2px hsl(0 0% 0% / 0.3), 0 10px 30px hsl(0 0% 0% / 0.35);
  --selection: hsl(var(--hue) 60% 30%);
}

/* ---- Reset / base ------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

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

body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}

::selection { background: var(--selection); }

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

a {
  color: var(--accent-strong);
  text-decoration-color: color-mix(in oklab, var(--accent) 40%, transparent);
  text-underline-offset: 0.15em;
}
a:hover { text-decoration-color: currentColor; }

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

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

p, ul, ol, blockquote, pre, figure, table { text-wrap: pretty; }

/* ---- The breakout grid ------------------------------------------------- */
/* Default children sit in [content]; opt into wider bands by class. */
/* The post body is a real 9-column grid: 6 content columns with a 2-column
   margin on the left and a 1-column margin on the right, gutters between.
   Mobile collapses to one full-width column. Figures break asymmetrically
   into the margins: large +1 col right, huge +2 cols left, full both. The
   overlay shares the same --colw / --gut so it draws the exact columns. */
.prose {
  display: grid;
  grid-template-columns: [content-start] minmax(0, 1fr) [content-end];
  padding-inline: var(--gutter);
}
.prose > * { grid-column: content; }

@media (min-width: 52rem) {
  .prose {
    padding-inline: 0;
    grid-template-columns:
      [bleed-start] minmax(var(--gutter), 1fr)
      [c1] var(--colw) var(--gut)
      var(--colw) var(--gut)
      [content-start] var(--colw) var(--gut)
      var(--colw) var(--gut)
      var(--colw) var(--gut)
      var(--colw) var(--gut)
      var(--colw) var(--gut)
      var(--colw) [content-end]
      var(--gut) var(--colw) [edge-end bleed-end]
      minmax(var(--gutter), 1fr);
  }
  .prose > .wide,  .prose > figure.large { grid-column: content-start / edge-end; }
  .prose > .huge,  .prose > figure.huge,
  .prose > pre.large { grid-column: c1 / content-end; }
  .prose > .full,  .prose > figure.full { grid-column: c1 / edge-end; }
}

/* Vertical rhythm */
.prose > * + * { margin-top: var(--space-s); }
.prose > h2 { margin-top: var(--space-l); }
.prose > h3, .prose > h4 { margin-top: var(--space-m); }
.prose > h2 + *, .prose > h3 + *, .prose > h4 + * { margin-top: var(--space-2xs); }

/* ---- Page frame: header, main, footer ---------------------------------- */
.site-header { padding-inline: var(--gutter); }

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  flex-wrap: wrap;
  max-width: calc(var(--measure) + 4 * var(--colw));
  margin-inline: auto;
  width: 100%;
  padding-block: var(--space-m);
}

/* Home icon (replaces the old wordmark), styled like the nav buttons. */
.home-link {
  display: inline-grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  color: var(--text);
  background: transparent;
  border: 1px solid transparent;
  transition: color 0.2s, background 0.2s, border-color 0.2s;
}
.home-link:hover { color: var(--accent); background: var(--surface); border-color: var(--border); }
.home-link svg { width: 22px; height: 22px; }
body.home .home-link { display: none; }   /* already home — no need for the link */

/* Tight social/nav cluster (matches the filipsalo.se top bar). */
.site-nav {
  display: flex;
  align-items: center;
  gap: 0.15rem;
  margin-left: auto;   /* stay right even when the home link is hidden */
}
.site-nav a,
.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  cursor: pointer;
  transition: color 0.2s, background 0.2s, border-color 0.2s;
}
.site-nav a:hover,
.theme-toggle:hover {
  color: var(--accent);
  background: var(--surface);
  border-color: var(--border);
}
/* Each social icon lights up in its own brand color on hover.
   (GitHub's brand is monochrome, so it goes full-contrast.) */
.site-nav a[aria-label="GitHub"]:hover   { color: var(--text); }
.site-nav a[aria-label="Codeberg"]:hover { color: #4793d8; }
.site-nav a[aria-label="Mastodon"]:hover { color: #6364ff; }
.site-nav a[aria-label="Bluesky"]:hover  { color: #1185fe; }
.site-nav a[aria-label="LinkedIn"]:hover { color: #0a66c2; }
.site-nav a[aria-label="Instagram"]:hover { color: #e1306c; }
.site-nav svg { width: 20px; height: 20px; }

/* The two halves of the sun/moon swap depending on theme */
.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun,
:root:not([data-theme="light"]) .theme-toggle .icon-sun { }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
}
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: none; }

main { flex: 1; padding-block: var(--space-l) var(--space-xl); position: relative; }

/* ---- Layout grid overlay (opt-in via `grid: true` front matter) -------- */
.grid-overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  display: grid;
  grid-template-columns: var(--prose-cols);
  visibility: hidden;
}
body.grid-on .grid-overlay { visibility: visible; }
/* The 9 columns (tinted) with transparent gutters between them, centered to
   match .prose's centered 9-column group. */
.grid-overlay::before {
  content: "";
  display: block;
  height: 100%;
  width: calc(9 * var(--colw) + 8 * var(--gut));
  max-width: calc(100% - 2 * var(--gutter));
  margin-inline: auto;
  background: repeating-linear-gradient(to right,
    hsl(var(--hue) 85% 55% / 0.11) 0, hsl(var(--hue) 85% 55% / 0.11) var(--colw),
    transparent var(--colw), transparent calc(var(--colw) + var(--gut)));
}

.grid-toggle {
  position: fixed;
  bottom: 1rem;
  right: 1rem;
  z-index: 6;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font: 600 var(--step--1) / 1 var(--font-body);
  padding: 0.55rem 0.9rem;
  border-radius: 999px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  cursor: pointer;
}
.grid-toggle[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); border-color: transparent; }
.grid-toggle kbd {
  font: inherit;
  opacity: 0.6;
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 0 0.3em;
}

.site-footer {
  border-top: 1px solid var(--border);
  background: var(--bg-tint);
  color: var(--muted);
  padding-block: var(--space-l);
}
/* Mirror the header frame exactly: full-width bar, with the inner constrained
   and padded just like .site-header — and at the body font-size, so its
   ch-based --measure resolves to the same width as the header's. */
.site-footer .inner {
  max-width: calc(var(--measure) + 4 * var(--colw));
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs);
}
.site-footer p { font-size: var(--step--1); }
.site-footer a { color: var(--text-soft); }

/* Footer icon links (archive, email), styled like the header nav buttons. */
.footer-links { display: flex; align-items: center; gap: 0.15rem; }
.footer-links a {
  display: inline-grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  color: var(--muted);
  border: 1px solid transparent;
  transition: color 0.2s, background 0.2s, border-color 0.2s;
}
.footer-links a:hover { color: var(--accent); background: var(--surface); border-color: var(--border); }
.footer-links svg { width: 18px; height: 18px; }

/* ---- Heading sizes (global; components may override) ------------------- */
h1, .post-title { font-size: var(--step-4); 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); }
h5, h6 { font-size: var(--step-0); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-soft); }

/* Centered single-column container for list pages (home, archive). */
.page {
  max-width: calc(var(--measure) + 2 * var(--colw));
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.page > * + * { margin-top: var(--space-s); }
.page.home { max-width: 56rem; }   /* wider, to give the three promo cards room */
.page.home > .card-group,
.page.home > .home-foot { margin-top: clamp(2rem, 5vw, 3rem); }

/* ---- Lead paragraph ---------------------------------------------------- */
.intro, .prose > .intro {
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.4;
  color: var(--text-soft);
  font-weight: 400;
}

/* ---- Inline elements --------------------------------------------------- */
strong, b { font-weight: 650; }
mark { background: var(--accent-soft); color: inherit; padding: 0 0.2em; border-radius: 3px; }
small { font-size: var(--step--1); }

code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--code-bg);
  padding: 0.15em 0.4em;
  border-radius: 5px;
}

/* ---- Lists ------------------------------------------------------------- */
.prose ul, .prose ol { padding-inline-start: 1.4em; }
.prose li + li { margin-top: 0.35em; }
.prose li::marker { color: var(--accent); }

/* ---- Blockquote -------------------------------------------------------- */
blockquote {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--step-1);
  line-height: 1.45;
  color: var(--text-soft);
  border-inline-start: 3px solid var(--accent);
  padding-inline-start: var(--space-s);
}

/* ---- Code blocks ------------------------------------------------------- */
pre {
  font-family: var(--font-mono);
  background: var(--code-bg);
  color: var(--code-text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-s) var(--space-m);
  overflow-x: auto;
  font-size: var(--step--1);
  line-height: 1.6;
  -webkit-overflow-scrolling: touch;
}
pre code { background: none; padding: 0; font-size: inherit; }

/* ---- Figures & the flexible widths ------------------------------------ */
figure { margin-block: var(--space-s); }
figure img { width: 100%; border-radius: var(--radius-s); }
figcaption {
  margin-top: 0.6em;
  font-size: var(--step--1);
  color: var(--muted);
  text-align: center;
}

/* Divisible figures sit side by side, stacking on small screens. */
figure.divisible { display: flex; flex-wrap: wrap; gap: var(--space-s); }
figure.divisible > figure { flex: 1 1 12rem; margin: 0; }
figure.divisible > figure.two { flex: 2 1 20rem; }

/* Small figures / margin notes: float beside the text on wide screens
   (left by default, right with .right), overhanging into the column margin.
   Stack inline on narrow screens. Only .small / .side opt in, so full-width
   callouts (.note) are unaffected. */
.prose > .small,
.prose > .side { grid-column: content; margin-block: var(--space-s); }
@media (min-width: 52rem) {
  .prose > .small,
  .prose > .side {
    width: calc(2 * var(--colw) + var(--gut));   /* 2 columns wide */
    justify-self: start;
    float: left;
    margin-inline: calc(-2 * var(--colw) - 2 * var(--gut)) var(--gut);   /* into the 2-col left margin */
    clear: left;
  }
  .prose > .small.right,
  .prose > .side.right {
    justify-self: end;   /* floats are ignored on grid items, so align to the content edge */
    float: right;
    margin-inline: var(--gut) calc(-2 * var(--colw) - 2 * var(--gut));   /* into the 2-col right margin */
    clear: right;
  }
}
aside {
  font-size: var(--step--1);
  color: var(--text-soft);
}
aside blockquote {
  font-size: var(--step-0);
  border-inline-start-width: 2px;
}

/* ---- Note callout ------------------------------------------------------ */
.note {
  background: var(--note-bg);
  border: 1px solid var(--note-border);
  color: var(--note-text);
  border-radius: var(--radius);
  padding: var(--space-s) var(--space-m);
}
.note h4 {
  font-family: var(--font-body);
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 0.3em;
}
.note p { margin: 0; }

/* ---- Tables ------------------------------------------------------------ */
.prose table { border-collapse: collapse; width: 100%; font-size: var(--step--1); }
.prose th, .prose td { text-align: left; padding: 0.5em 0.75em; border-bottom: 1px solid var(--border); }
.prose th { font-weight: 650; }

/* ---- Post header / metadata ------------------------------------------- */
.post-title { margin-bottom: var(--space-s); }
/* Keep the date tucked under the title on post pages: drop the title's
   bottom margin and the breakout-grid rhythm margin the meta would inherit. */
.post .post-title { margin-bottom: 0; }
/* Date + reading time (the byline lives at the end now). */
.post-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.3rem;
  color: var(--muted);
  font-size: var(--step--1);
  margin-top: var(--space-2xs);
  margin-bottom: var(--space-2xs);
}
.post-meta .post-when { color: var(--text-soft); display: inline-flex; align-items: center; }
.post-meta time { color: var(--muted); font-weight: 650; }
.post-meta .reading { margin-left: 0.7em; display: inline-flex; align-items: center; }   /* a little space before the clock icon */
/* Dim calendar / clock icon, rendered inline before each line. */
.post-meta .meta-icon {
  display: inline-block;
  width: 15px;
  height: 15px;
  color: var(--muted);
}
.post-meta .post-when .meta-icon { margin-right: 0.4em; }

/* End-of-article author byline — a snazzy card that echoes the home hero:
   gradient avatar ring + gradient name. */
.post-byline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-s);
  margin-top: var(--space-xl);
  padding: var(--space-s) var(--space-m);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow);
}
/* On the grid layout, push the box out by its own horizontal padding so its
   contents line up with the body text and it reads as a frame, not a nested
   card. (Only above the breakpoint, where .prose has margin columns to spare.) */
@media (min-width: 52rem) {
  .post-byline { margin-inline: calc(-1 * var(--space-m)); }
}
/* Smaller version of the home .avatar ring; tame the glow inside the card. */
.byline-avatar { padding: 3px; }
.byline-avatar::before { inset: -9px; filter: blur(8px); }
.post-byline .byline-photo {
  position: relative;
  z-index: 1;
  width: 72px; height: 72px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid var(--surface);   /* gap between ring and photo */
}
.post-byline .byline { display: flex; flex-direction: column; gap: 0.1em; min-width: 0; }
.post-byline .author {
  width: fit-content;
  font-weight: 700;
  font-size: var(--step-1);
  letter-spacing: -0.02em;
  color: var(--text);
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .post-byline .author {
    background: var(--grad-name);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
.post-byline .byline-role { color: var(--accent-strong); font-weight: 600; font-size: var(--step--1); }
.post-byline .byline-city { color: var(--muted); font-size: var(--step--1); }
/* Right-side cluster: contact icons next to the More button. */
.byline-actions { display: flex; align-items: center; gap: var(--space-s); margin-left: auto; flex: none; }
.byline-socials { display: flex; gap: 0.75rem; }
.byline-socials a { display: inline-flex; color: var(--muted); transition: color 0.15s; }
.byline-socials a:hover { color: var(--accent-strong); }
.byline-socials svg { width: 21px; height: 21px; display: block; }
.post-byline .byline-more {
  flex: none;
  font-weight: 650;
  color: var(--accent-strong);
  text-decoration: none;
  padding: 0.4em 0.95em;
  border-radius: 9px;
  border: 1px solid var(--border);
  transition: color 0.15s, border-color 0.15s, transform 0.15s;
}
.post-byline .byline-more:hover {
  color: var(--accent);
  border-color: var(--accent);
  transform: translateY(-1px);
}
@media (max-width: 36rem) {
  /* Keep the name/role beside the avatar; let "More" wrap to its own row. */
  .post-byline .byline { flex: 1 1 60%; }
}

/* ---- Home: hero --------------------------------------------------------- */
.hero {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--space-l);
  align-items: start;
  margin-bottom: var(--space-l);
}
/* Avatar in column 1; name, role, lead, history stack in column 2, so the
   text below the name/role lines up with them. */
.hero > .avatar { grid-column: 1; grid-row: 1 / span 4; }
.hero-name     { grid-column: 2; grid-row: 1; }
.hero .role    { grid-column: 2; grid-row: 2; }
.hero .lead    { grid-column: 2; grid-row: 3; }
.hero .history { grid-column: 2; grid-row: 4; }
.avatar {
  position: relative;
  flex: none;
  border-radius: 50%;
  padding: 4px;                 /* gradient ring thickness */
  background: var(--grad-avatar);
  line-height: 0;
}
.avatar::before {               /* soft glow behind the photo */
  content: "";
  position: absolute;
  inset: -16px;
  z-index: 0;
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--glow-color), transparent 72%);
  filter: blur(10px);
}
.hero-photo {
  position: relative;
  z-index: 1;
  display: block;
  width: clamp(112px, 26vw, 200px);
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 50%;
  border: 3px solid var(--surface);   /* gap between ring and photo */
}
.hero-name { font-size: var(--step-4); letter-spacing: -0.035em; width: fit-content; max-width: 100%; }
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero-name {
    background: var(--grad-name);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
.role {
  margin-top: 0.35rem;
  color: var(--accent-strong);
  font-weight: 600;
  font-size: var(--step-1);
}
.history {
  margin-top: var(--space-s);   /* match the space above the lead */
  max-width: 40rem;
  color: var(--muted);
  font-size: var(--step--1);
  line-height: 1.5;
}
.history b { color: var(--text-soft); font-weight: 650; }
@media (max-width: 36rem) {
  /* Smaller avatar with name + role beside it; lead + history drop to full
     width underneath, left-aligned under the avatar. */
  .hero { column-gap: var(--space-s); }
  .hero-photo { width: clamp(80px, 24vw, 104px); }
  .hero > .avatar { grid-row: 1 / span 2; }
  .hero .lead,
  .hero .history { grid-column: 1 / -1; }
}

/* Lead paragraph under the home hero. */
.lead {
  margin-top: var(--space-s);
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--text-soft);
  max-width: 42rem;
}
/* Highlighter mark on the emphasized lead text. */
.lead strong {
  color: var(--text);
  font-weight: 650;
  background: var(--selection);
  padding: 0.05em 0.25em;
  border-radius: 0.2em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Promo cards, grouped under a shared heading instead of a per-card kind. */
.card-group { margin-top: clamp(2rem, 5vw, 3rem); }
.cards-heading {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--accent-strong);
  margin-bottom: var(--space-xs);
  margin-left: 1.4rem;   /* align with the text inside the cards (matches .card padding-inline) */
}
.cards {
  display: grid;
  grid-template-columns: 1fr;          /* stacked on phones / small tablets */
  gap: clamp(0.85rem, 1.5vw, 1.25rem);
  align-items: start;                  /* don't stretch shorter cards to the tall apparel one */
}
@media (min-width: 48rem) {
  /* Reach past the text column toward the page margins (heading + cards
     together) so the three cards keep gaining width as the window grows.
     Collapses to 0 where there's no spare margin. */
  .card-group {
    --reach: clamp(0rem, (100vw - 56rem) / 2 - 1.5rem, 7rem);
    margin-inline: calc(-1 * var(--reach));
  }
  .cards { grid-template-columns: repeat(3, 1fr); }
  .cards.cards-pair { grid-template-columns: repeat(2, 1fr); }   /* two tees, half-width each */
}
.card {
  position: relative;
  overflow: hidden;
  display: block;
  /* fill (padding box) + edge (hover border). Gradients so the multi-layer
     hover background below stays valid even with no language tint. */
  --card-fill: linear-gradient(var(--surface), var(--surface));
  --card-edge: var(--grad-avatar);
  background: var(--card-fill);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.25rem 1.4rem;
  text-decoration: none;
  color: inherit;
  transition: transform .15s, border-color .15s, box-shadow .15s;
}
/* Faint glow in the card + a matching hover border, in the language's colour. */
.card:has(.lang-go)     { --card-fill: radial-gradient(135% 125% at 100% 0%, color-mix(in oklab, #00add8 24%, var(--surface)), var(--surface) 64%); --card-edge: linear-gradient(135deg, hsl(192 85% 55%), hsl(193 92% 38%)); }
.card:has(.lang-swift)  { --card-fill: radial-gradient(135% 125% at 100% 0%, color-mix(in oklab, #f05138 20%, var(--surface)), var(--surface) 64%); --card-edge: linear-gradient(135deg, hsl(11 95% 66%), hsl(6 82% 52%)); }
.card:has(.lang-python) { --card-fill: radial-gradient(135% 125% at 100% 0%, color-mix(in oklab, #3776ab 24%, var(--surface)), var(--surface) 64%); --card-edge: linear-gradient(135deg, hsl(207 78% 62%), hsl(207 58% 42%)); }
.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  border-color: transparent;
  /* gradient border: the card fill stays in the padding box, the edge gradient
     shows through the (transparent) border, respecting the rounded corners */
  background:
    var(--card-fill) padding-box,
    var(--card-edge) border-box;
}
/* Faint watermark icon peeking from the top-right corner. */
.card-icon {
  position: absolute;
  top: -0.5rem;
  right: -0.5rem;
  width: 4.5rem;
  height: 4.5rem;
  color: var(--text);
  opacity: 0.07;
  pointer-events: none;
}
.card h3 { font-size: var(--step-1); font-weight: 700; }
/* Language badge in the top-right corner, in each language's brand colors. */
.card .lang {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  font-size: 0.68rem;
  font-weight: 650;
  letter-spacing: 0.02em;
  line-height: 1.4;
  padding: 0.3em 0.9em;
  border-radius: 0 0 0 0.7rem;   /* flush to the corner; round only the inner (bottom-left) corner */
}
.lang-go     { background: linear-gradient(135deg, hsl(192 92% 31%), hsl(194 97% 23%)); color: #fff; }
.lang-swift  { background: linear-gradient(135deg, hsl(11 92% 64%), hsl(6 82% 51%)); color: #fff; }
.lang-python { background: linear-gradient(135deg, hsl(207 52% 53%), hsl(207 54% 37%)); color: #fff; }
.card p { margin-top: .4rem; color: var(--text-soft); font-size: var(--step--1); line-height: 1.5; }
/* Code/Docs links: equal-width columns filling the card, icon + left-aligned text. */
/* Equal-width columns sized to the widest link (not stretched across the card),
   flowing as a compact inline-ish block. */
.card-links {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  width: max-content;
  max-width: 100%;
  gap: 0.5rem;
  margin-top: 0.5rem;
  font-size: var(--step--1);
}
.card-links a { display: flex; align-items: center; gap: 0.4em; }
.card-links .link-icon { width: 14px; height: 14px; flex: none; }

/* Apparel: each tee is its own card; the image is cropped to its top half. */
.card.tee { padding: 0; }
.card.tee img {
  width: 100%;
  display: block;
  aspect-ratio: 2 / 1;          /* top half of the square 480x480 source */
  object-fit: cover;
  object-position: top;
}

/* ---- Home: recent posts (toned-down, secondary list) ------------------- */
.section-label {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  font-weight: 600;
  padding-bottom: var(--space-2xs);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-2xs);
}
/* "Latest posts" heading: title left, feed icon right-aligned. */
.recent-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.feed-link {
  display: inline-flex;
  color: var(--muted);
  transition: color 0.2s;
}
.feed-link:hover { color: var(--accent-strong); }
.feed-link svg { width: 16px; height: 16px; display: block; }
/* No dividers — spacing comes from the gap between entries. */
.entries { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--space-s); }
.entry-row { line-height: 1.35; }
.entry-title {
  font-weight: 600;
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--border-strong);
  text-underline-offset: 0.15em;
}
.entry-title:hover { color: var(--accent-strong); text-decoration-color: currentColor; }
/* Date sits inline, right after the title. */
.entry-date { margin-left: 0.55em; color: var(--muted); font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.entry-summary { margin-top: 0.3rem; color: var(--text-soft); font-size: var(--step--1); line-height: 1.5; max-width: 62ch; }

.more { margin-top: var(--space-m); font-size: var(--step-0); font-weight: 600; }
.more a { color: var(--accent-strong); text-decoration: none; }
.more a:hover { text-decoration: underline; }

/* Home bottom: apparel boxes stacked in a column beside the latest-posts list. */
.home-foot { display: grid; gap: var(--space-l); }
@media (min-width: 44rem) {
  .home-foot {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
  }
}
.home-foot .recent { margin-top: 0; }
.apparel-stack {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(0.85rem, 1.5vw, 1.25rem);
}

/* ---- Archive ----------------------------------------------------------- */
.archive-month {
  font-size: var(--step-1);
  color: var(--muted);
  font-weight: 600;
  margin-top: var(--space-l);
  margin-bottom: var(--space-xs);
  padding-bottom: 0.3em;
  border-bottom: 1px solid var(--border);
}
.archive-list { list-style: none; padding: 0; }
.archive-list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-s);
  padding: 0.3rem 0;
}
.archive-entry { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4em 0.6em; min-width: 0; }
.archive-list a { color: var(--text); text-decoration: none; }
.archive-list a:hover { color: var(--accent-strong); text-decoration: underline; }
.archive-date { flex: none; font-size: var(--step--1); color: var(--muted); font-variant-numeric: tabular-nums; }

/* ---- Experience timeline ----------------------------------------------- */
.experience { max-width: 52rem; }
.timeline {
  position: relative;
  list-style: none;
  margin-top: var(--space-l);
  padding: 0;
}
/* The thread running through the markers — a vertical take on the brand rainbow. */
.timeline::before {
  content: "";
  position: absolute;
  left: 6px;
  top: 0.55rem;
  bottom: 0.55rem;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(to bottom,
    hsl(268 82% 64%), hsl(210 88% 56%) 33%, hsl(162 70% 48%) 66%, hsl(45 95% 58%));
}
.tl-item {
  position: relative;
  padding-left: 2.1rem;
  padding-bottom: var(--space-xl);
  display: grid;
  gap: var(--space-s) var(--space-xl);
}
.tl-item:last-child { padding-bottom: var(--space-2xs); }
/* The node sitting on the line. */
.tl-item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.4rem;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--bg);
  border: 3px solid var(--accent);
  box-shadow: 0 0 0 3px var(--bg);   /* mask the line cleanly behind the node */
  z-index: 1;
}
@media (min-width: 46rem) {
  .tl-item { grid-template-columns: minmax(0, 1fr) minmax(11rem, 15rem); align-items: start; }
}
.tl-date {
  font-size: var(--step--1);
  font-weight: 650;
  letter-spacing: 0.02em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.tl-role { font-size: var(--step-1); margin: 0.15em 0 0.4em; }
.tl-role .tl-org { color: var(--accent-strong); }
.tl-main > p { color: var(--text-soft); max-width: 46ch; }
.tl-aside { font-size: var(--step--1); color: var(--text-soft); line-height: 1.5; }
.tl-aside-label {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent-strong);
  margin-bottom: 0.55em;
}
.tl-aside ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.45em; }
.tl-aside li { position: relative; padding-left: 1.05em; }
.tl-aside li::before { content: "\2192"; position: absolute; left: 0; color: var(--accent); }

/* ---- Syntax highlighting (highlight.js tokens, theme-aware) ----------- */
.hljs-comment, .hljs-quote { color: var(--muted); font-style: italic; }
.hljs-keyword, .hljs-selector-tag, .hljs-meta .hljs-keyword, .hljs-doctag, .hljs-section {
  color: hsl(var(--hue) 70% 60%);
}
.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta .hljs-string {
  color: hsl(150 55% 42%);
}
.hljs-number, .hljs-literal, .hljs-variable, .hljs-template-variable, .hljs-tag .hljs-attr {
  color: hsl(28 85% 52%);
}
.hljs-title, .hljs-title.function_, .hljs-name, .hljs-selector-id, .hljs-selector-class {
  color: hsl(210 80% 56%);
}
.hljs-built_in, .hljs-class .hljs-title, .hljs-type { color: hsl(190 70% 45%); }
.hljs-symbol, .hljs-bullet, .hljs-link { color: hsl(330 70% 58%); }
.hljs-emphasis { font-style: italic; }
.hljs-strong { font-weight: 700; }
.hljs-deletion { color: hsl(0 70% 55%); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hljs-string { color: hsl(150 50% 65%); }
  :root:not([data-theme="light"]) .hljs-number { color: hsl(28 85% 68%); }
  :root:not([data-theme="light"]) .hljs-title { color: hsl(210 85% 72%); }
  :root:not([data-theme="light"]) .hljs-built_in { color: hsl(190 70% 65%); }
}
:root[data-theme="dark"] .hljs-string { color: hsl(150 50% 65%); }
:root[data-theme="dark"] .hljs-number { color: hsl(28 85% 68%); }
:root[data-theme="dark"] .hljs-title { color: hsl(210 85% 72%); }
:root[data-theme="dark"] .hljs-built_in { color: hsl(190 70% 65%); }

/* ---- Motion ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}
