/* ekibuilds.com — single-screen bento hero */

:root {
  --bg: #000000;
  --card: rgba(14, 14, 15, .58);       /* glass: the black hole reads through it */
  --card-solid: #111111;
  --card-2: rgba(30, 30, 32, .55);
  --line: rgba(255, 255, 255, 0.07);
  --text: #ffffff;
  --muted: #8b8b8b;
  --accent: #f0392b;        /* sampled from the avatar disc */
  --accent-deep: #cf2418;   /* outer edge of the disc gradient */
  --accent-soft: rgba(240, 57, 43, .55);
  --green: #22c55e;
  --r: 26px;
  --gap: 16px;
  --max: min(1200px, 92vw);   /* page width */

  /* Type. --font-display carries the headline and the name; --font-ui carries
     everything else (labels, chips, buttons, body).

     To switch to licensed Tiempos: buy a web licence from klim.co.nz, drop the
     .woff2 files into assets/fonts/, uncomment the @font-face block below and
     change --font-display to 'Tiempos Headline'. Nothing else changes.
     Do NOT ship the "TestTiempos" trial files — their licence forbids web use. */
  /* Wider, Tiempos-adjacent serif. Swap for 'Literata' or 'Lora' by changing
     this line and the family name in the Google Fonts <link> in index.html. */
  --font-display: 'Source Serif 4', 'Tiempos Headline', Georgia, 'Times New Roman', serif;
  --font-ui: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/*
@font-face {
  font-family: 'Tiempos Headline';
  src: url('assets/fonts/TiemposHeadline-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Tiempos Headline';
  src: url('assets/fonts/TiemposHeadline-RegularItalic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
*/

/* Self-hosted so there is no round-trip to fonts.googleapis.com before
   text can render — that round-trip was what made the first load reflow. */
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/outfit-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/outfit-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('assets/fonts/outfit-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('assets/fonts/outfit-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('assets/fonts/outfit-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('assets/fonts/outfit-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/serif-400i-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/serif-400i-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/serif-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/serif-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('assets/fonts/serif-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('assets/fonts/serif-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  min-height: 100vh;
  color: var(--text);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
}

/* One-screen layout: the grid takes the height the nav leaves and centres
   itself in it. When the content is taller than the viewport (mobile) it
   simply grows and the page scrolls as normal. */
body {
  display: flex;
  flex-direction: column;
}

a { text-decoration: none; color: inherit; }
ul { list-style: none; margin: 0; padding: 0; }

/* Background canvas. Fixed and behind everything; the renderer frames the
   hole itself via its `focus` option, so nothing here needs to scale or
   shift the way the video did. */
.bg-canvas {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  inset: 0;
  width: 100vw;
  height: 100vh;
  display: block;
  z-index: 0;
  pointer-events: none;
  opacity: 0.95;
}

/* Film grain. Oversized and fixed so it can jitter without exposing an edge;
   stepped animation gives it the flicker of real film rather than a static
   texture. pointer-events:none keeps it from swallowing clicks. */
body::after {
  content: '';
  position: fixed;
  top: -60%;
  left: -60%;
  width: 220%;
  height: 220%;
  z-index: 9999;
  pointer-events: none;
  opacity: .22;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
  animation: grain 1s steps(8) infinite;
  will-change: transform;
}

@keyframes grain {
  0%   { transform: translate(0, 0); }
  12%  { transform: translate(-4%, -3%); }
  25%  { transform: translate(-8%,  4%); }
  37%  { transform: translate( 5%, -6%); }
  50%  { transform: translate(-3%,  8%); }
  62%  { transform: translate( 7%,  2%); }
  75%  { transform: translate(-6%, -5%); }
  87%  { transform: translate( 3%,  6%); }
  100% { transform: translate(0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  body::after { animation: none; opacity: .14; }
  .bg-canvas  { opacity: .5; }
}

/* ---------------- nav ---------------- */

.nav {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 22px 4px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.logo {
  display: inline-flex;
  align-items: center;
}
.logo-mark {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: block;
  flex: none;
  transition: transform .25s ease;
}
.logo:hover .logo-mark { transform: scale(1.06); }

.nav-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

.nav-link {
  padding: 0 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
  transition: color .2s ease;
}
.nav-link:hover { color: #fff; }

.btn-hire {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 20px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.18);
  /* the nav now sits over the brightest part of the disk; the disk has
     pure-white pixels, so a dark backdrop keeps the label legible in every
     frame rather than only in the average one */
  background: rgba(8, 8, 8, .55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-size: 14px;
  font-weight: 600;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.btn-hire svg { width: 15px; height: 15px; }
.btn-hire .btn-hire-x { width: 14px; height: 14px; }
.btn-hire:hover { background: #fff; color: #000; border-color: #fff; }

/* ---------------- bento grid ---------------- */

.grid {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 0 18px;
  flex: 1;
  display: grid;
  align-content: center;
  gap: var(--gap);
  grid-template-columns: 340px 1fr 290px;
  grid-template-areas:
    "profile intro intro"
    "profile stack contact";
}

.card {
  position: relative;
  overflow: hidden;
  background: var(--card);
  /* Frosted, so the disc behind stays legible as light without its detail
     competing with the text. saturate lifts the colour the blur washes out. */
  backdrop-filter: blur(22px) saturate(135%);
  -webkit-backdrop-filter: blur(22px) saturate(135%);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: var(--r);
  padding: 30px;
  /* warm hairline along the top edge — the lit rim */
  box-shadow: inset 0 1px 0 rgba(255, 176, 140, .17);
}

/* Light spilling down from above, as if cast by the black hole. */
.card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 62%;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(255, 138, 92, .13) 0%,
    rgba(240, 57, 43, .06) 38%,
    transparent 100%
  );
}

/* The bottom row is further from the source, so it catches less. */
.card--stack::before,
.card--contact::before {
  height: 48%;
  background: linear-gradient(
    to bottom,
    rgba(255, 138, 92, .075) 0%,
    rgba(240, 57, 43, .03) 40%,
    transparent 100%
  );
}
.card--stack,
.card--contact {
  box-shadow: inset 0 1px 0 rgba(255, 176, 140, .1);
}

/* content has to sit above the glow layer */
.card > * { position: relative; z-index: 1; }

.card-label {
  margin: 0 0 14px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------------- profile ---------------- */

.card--profile {
  grid-area: profile;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 34px 30px;
}

.avatar {
  width: 100%;
  max-width: 228px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 42% 38%, var(--accent) 0%, var(--accent) 45%, var(--accent-deep) 100%);
  overflow: hidden;
  display: grid;
  place-items: end center;
}
.avatar img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  animation: breathe 9s ease-in-out infinite;
}

@keyframes breathe {
  0%, 100% { transform: translateY(0)     scale(1); }
  50%      { transform: translateY(-5px)  scale(1.015); }
}

.name {
  margin: 22px 0 7px;
  font-family: var(--font-display);
  font-size: 42px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1;
}

.role {
  margin: 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--muted);
  max-width: 24ch;
}

.socials {
  margin-top: 24px;
  display: flex;
  gap: 10px;
}
.socials:empty { display: none; }
.socials a {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, .1);
  background: var(--card-2);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--muted);
  transition: color .2s ease, border-color .2s ease, transform .2s ease;
}
.socials a:hover {
  color: #fff;
  border-color: rgba(255,255,255,.24);
  transform: translateY(-2px);
}
.socials svg { width: 18px; height: 18px; }

/* ---------------- intro ---------------- */

.card--intro {
  grid-area: intro;
  padding: 34px 40px;
  display: flex;
  flex-direction: column;
}

.eyebrow {
  margin: 0 0 14px;
  font-size: 16px;
  color: var(--muted);
}

.headline {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(32px, 3.7vw, 52px);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.015em;
  max-width: 24ch;
}
.headline b { font-weight: 400; }
.headline .hl {
  color: var(--accent);
  font-style: italic;
  font-weight: 400;
}

.status {
  margin: 28px 0 0;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 15px;
  color: var(--muted);
}
.dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--green);
  animation: ping 2.6s cubic-bezier(.4, 0, .2, 1) infinite;
}

@keyframes ping {
  0%   { box-shadow: 0 0 0 0   rgba(34, 197, 94, .5); }
  70%  { box-shadow: 0 0 0 11px rgba(34, 197, 94, 0); }
  100% { box-shadow: 0 0 0 0   rgba(34, 197, 94, 0); }
}

.btn-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 20px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  transition: filter .2s ease, transform .2s ease;
}
.btn-cta svg { width: 15px; height: 15px; }
.btn-cta:hover { filter: brightness(1.1); transform: translateY(-1px); }

/* ---------------- stack band ---------------- */

.card--stack { grid-area: stack; padding: 24px 26px; }

/* Six across, two rows — an even block in the right-hand column. */
.tech-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}

.tech {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px 4px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, .1);
  background: var(--card-2);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: border-color .2s ease, transform .2s ease;
}
.tech svg {
  width: 19px;
  height: 19px;
  color: #d2d2d2;
  transition: color .2s ease;
}
.tech span {
  font-size: 9.5px;
  font-weight: 500;
  color: var(--muted);
  text-align: center;
  line-height: 1.2;
}
.tech:hover {
  border-color: var(--accent-soft);
  transform: translateY(-3px);
}
.tech:hover svg { color: var(--accent); }

/* ---------------- contact ---------------- */

.card--contact {
  grid-area: contact;
  padding: 24px 26px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
}
.card--contact .card-label { margin: 0; }

.email {
  display: inline-block;
  font-size: 17px;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: -0.01em;
  word-break: break-all;
}
.email:hover { text-decoration: underline; text-underline-offset: 4px; }

.based {
  margin: 0;
  font-size: 14px;
  color: var(--muted);
}
.handle {
  color: var(--muted);
  transition: color .2s ease;
}
.handle:hover { color: #fff; }

/* ---------------- glitch on hover ---------------- */

/* Two offset copies of the text, sliced into horizontal bands and jittered.
   --glitch-bg must match whatever sits behind the text, so the copies mask the
   original instead of smearing over it. */
.glitch {
  --glitch-bg: var(--card-solid);
  position: relative;
  display: inline-block;
}
.glitch::before,
.glitch::after {
  content: attr(data-text);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  background: var(--glitch-bg);
  opacity: 0;
  pointer-events: none;
  clip-path: inset(0 0 100% 0);
}
.glitch:hover::before {
  opacity: 1;
  color: var(--accent);
  animation: glitch-a .42s steps(2, end) infinite;
}
.glitch:hover::after {
  opacity: 1;
  color: #4de2f0;
  animation: glitch-b .42s steps(2, end) infinite;
}

@keyframes glitch-a {
  0%   { clip-path: inset(6%  0 76% 0); transform: translate(-3px, -1px); }
  25%  { clip-path: inset(28% 0 54% 0); transform: translate( 3px,  1px); }
  50%  { clip-path: inset(46% 0 36% 0); transform: translate(-2px,  0);   }
  75%  { clip-path: inset(14% 0 68% 0); transform: translate( 2px, -1px); }
  100% { clip-path: inset(6%  0 76% 0); transform: translate(-3px,  1px); }
}
@keyframes glitch-b {
  0%   { clip-path: inset(64% 0 12% 0); transform: translate( 3px,  1px); }
  25%  { clip-path: inset(80% 0  4% 0); transform: translate(-3px, -1px); }
  50%  { clip-path: inset(54% 0 28% 0); transform: translate( 2px,  1px); }
  75%  { clip-path: inset(86% 0  2% 0); transform: translate(-2px,  0);   }
  100% { clip-path: inset(64% 0 12% 0); transform: translate( 3px, -1px); }
}

@media (prefers-reduced-motion: reduce) {
  .glitch:hover::before,
  .glitch:hover::after { animation: none; opacity: 0; }
}

/* ---------------- responsive ---------------- */

@media (max-width: 1080px) {
  .grid {
    grid-template-columns: 300px 1fr;
    grid-template-areas:
      "profile  intro"
      "profile  stack"
      "contact  contact";
  }
}

@media (max-width: 900px) {
  .tech-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 520px) {
  .tech-grid { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 780px) {
  :root { --max: 91vw; }          /* a touch more breathing room at the edges */
  .nav { padding: 20px 2px 14px; flex-wrap: wrap; }
  .logo-mark { width: 40px; height: 40px; }
  .grid {
    padding: 0 0 28px;
    grid-template-columns: 1fr;
    grid-template-areas:
      "profile"
      "intro"
      "stack"
      "contact";
  }
  .card { padding: 26px 22px; }
  .card--intro { padding: 30px 22px; }
  .name { font-size: 42px; }
  .socials { margin-top: 26px; padding-top: 0; }
  .btn-cta { flex: 1; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  *,
  .avatar img,
  .dot { animation: none !important; transition: none !important; }
}

/* ==========================================================================
   Blog — index and article pages.
   Shares the shell (nav, glass, grain, black hole) with the home page. The
   background runs dimmer and cheaper here, because a page you read for two
   minutes should not spend the whole time raytracing at full rate.
   ========================================================================== */

body.page {
  display: block;                 /* the home page centres one screen; these scroll */
  min-height: 100vh;
}
/* Dimmer than the home page. Measured: at .34 the disc's brightest point
   dropped the text column to 4.07:1, under the 4.5:1 AA floor. */
body.page .bg-canvas { opacity: .22; }

.page-wrap {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 0 90px;
}

.back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--muted);
  transition: color .2s ease;
}
.back:hover { color: #fff; }
.back svg { width: 15px; height: 15px; }

/* ---------------- blog index ---------------- */

.page-head {
  padding: 54px 0 34px;
  max-width: 46ch;
}
.page-head h1 {
  margin: 14px 0 0;
  font-family: var(--font-display);
  font-size: clamp(34px, 4.2vw, 54px);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.015em;
}
.page-head h1 em { font-style: italic; color: var(--accent); }
.page-head p {
  margin: 18px 0 0;
  font-size: 16px;
  line-height: 1.6;
  color: var(--muted);
}

.posts { display: grid; gap: var(--gap); }

.post-card {
  display: block;
  padding: 28px 30px;
  transition: border-color .2s ease, transform .2s ease;
}
.post-card:hover { border-color: var(--accent-soft); transform: translateY(-2px); }
.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-size: 12.5px;
  color: var(--muted);
}
.post-meta .dot-sep { opacity: .5; }
.post-card h2 {
  margin: 12px 0 0;
  font-family: var(--font-display);
  font-size: clamp(22px, 2.4vw, 30px);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.post-card p {
  margin: 12px 0 0;
  font-size: 15px;
  line-height: 1.6;
  color: var(--muted);
  max-width: 62ch;
}
.post-more {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 16px;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
}
.post-more svg { width: 14px; height: 14px; }

/* ---------------- article ---------------- */

.article {
  max-width: 44rem;
  margin: 0 auto;
  padding: 46px 0 0;
}
.kicker {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--accent);
}
.article h1 {
  margin: 16px 0 0;
  font-family: var(--font-display);
  font-size: clamp(32px, 4.4vw, 52px);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.015em;
}
.article .standfirst {
  margin: 20px 0 0;
  font-family: var(--font-display);
  font-size: clamp(18px, 2vw, 21px);
  line-height: 1.5;
  color: #c9c6c4;
}
.article-meta {
  margin: 26px 0 0;
  padding-bottom: 30px;
  border-bottom: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  font-size: 13px;
  color: var(--muted);
}

.prose { padding-top: 34px; }
.prose p,
.prose li {
  font-family: var(--font-display);
  font-size: 17.5px;
  line-height: 1.72;
  color: #cfcdcb;
}
.prose p { margin: 0 0 22px; }
.prose h2 {
  margin: 44px 0 16px;
  font-family: var(--font-display);
  font-size: clamp(23px, 2.6vw, 30px);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: #fff;
}
.prose strong { color: #fff; font-weight: 600; }
.prose a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.prose a:hover { color: #fff; }
.prose ul { margin: 0 0 22px; padding-left: 1.15em; list-style: disc; }
.prose li { margin-bottom: 9px; }
.prose li::marker { color: var(--accent); }

/* A figure for the numbers, so they are scannable without hunting the prose. */
.figures {
  margin: 30px 0;
  padding: 4px 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
}
.figure {
  padding: 18px 20px;
  border-radius: 16px;
  border: 1px solid rgba(255,255,255,.1);
  background: var(--card-2);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.figure b {
  display: block;
  font-family: var(--font-display);
  font-size: 27px;
  font-weight: 600;
  line-height: 1;
  color: #fff;
}
.figure span {
  display: block;
  margin-top: 8px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--muted);
}

.callout {
  margin: 30px 0;
  padding: 22px 26px;
  border-left: 2px solid var(--accent);
  border-radius: 0 16px 16px 0;
  background: rgba(240, 57, 43, .07);
}
.callout p { margin: 0; font-size: 16.5px; color: #ddd9d7; }

.sources {
  margin-top: 52px;
  padding-top: 28px;
  border-top: 1px solid var(--line);
}
.sources h2 {
  margin: 0 0 14px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
}
.sources ol { margin: 0; padding-left: 1.15em; }
.sources li { margin-bottom: 9px; font-size: 14px; line-height: 1.55; color: var(--muted); }
.sources a { color: var(--muted); text-decoration: underline; text-underline-offset: 3px; word-break: break-word; }
.sources a:hover { color: #fff; }

@media (max-width: 780px) {
  .page-head { padding: 34px 0 26px; }
  .post-card { padding: 24px 22px; }
  .article { padding-top: 30px; }
  .prose p, .prose li { font-size: 16.5px; }
}

/* ---------------- files ----------------
   A list of downloadable single-file experiments, each with a page of its own.
   Deliberately no embeds or thumbnails: each demo is a WebGL/WebGPU scene
   weighing hundreds of KB, and previewing them here would make the index cost
   more than everything else on the site combined. Nothing on these pages loads
   a demo until you download one.
   -------------------------------------- */

.files { display: grid; gap: var(--gap); }

.file-card {
  display: flex;
  gap: 30px;
  align-items: flex-start;
  padding: 28px 30px;
  transition: border-color .2s ease, transform .2s ease;
}
.file-card:hover { border-color: var(--accent-soft); transform: translateY(-2px); }

.file-main { flex: 1; min-width: 0; }
/* `.card > *` positions every child so the text paints above the ::before glow.
   Here the text column must stay static, or the stretched title link below
   only spans the column instead of the card; the glow goes behind instead. */
.file-card { isolation: isolate; }
.file-card::before { z-index: -1; }
.file-card > .file-main { position: static; }

.file-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 12px;
}
.file-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(21px, 2.2vw, 27px);
  font-weight: 600;
  letter-spacing: -0.01em;
}
/* The title link is stretched over the whole card, so the card opens the
   file's page; the actions column sits above it so Download stays one click. */
.file-head h2 a { color: inherit; }
.file-head h2 a::after {
  content: '';
  position: absolute;
  inset: 0;
}
.file-card:hover .file-head h2 a { color: #fff; }
.file-size {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--muted);
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--line);
}

.file-desc {
  margin: 12px 0 0;
  font-size: 15px;
  line-height: 1.62;
  color: var(--muted);
  max-width: 60ch;
}

.file-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin: 16px 0 0;
}
.file-tags li {
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.09);
  background: var(--card-2);
  font-size: 11.5px;
  font-weight: 500;
  color: #c2c0be;
}

.file-note {
  margin: 14px 0 0;
  font-size: 13px;
  line-height: 1.55;
  color: #7d7a78;
  max-width: 58ch;
}

.file-actions {
  position: relative;       /* above the stretched title link */
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  flex: none;
  padding-top: 4px;
}
.file-more {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  transition: color .2s ease;
}
.file-more svg { width: 13px; height: 13px; }
.file-more:hover { color: #fff; }

.btn-download {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  height: 46px;
  padding: 0 22px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  transition: filter .2s ease, transform .2s ease;
}
.btn-download svg { width: 16px; height: 16px; }
.btn-download:hover { filter: brightness(1.1); transform: translateY(-1px); }

.files-foot {
  margin: 30px 0 0;
  font-size: 13px;
  line-height: 1.6;
  color: #6f6c6a;
  max-width: 62ch;
}

/* ---- one file's own page: article layout plus a download panel ---- */

.file-hero {
  margin: 32px 0 0;
  padding: 22px 24px;
  border-radius: 20px;
  border: 1px solid rgba(255,255,255,.1);
  background: var(--card-2);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px 24px;
}
.file-hero p {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--muted);
  max-width: 36ch;
}
.file-hero .btn-download { height: 50px; padding: 0 26px; font-size: 15px; }

.prose kbd,
.prose code {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 6px;
  border: 1px solid rgba(255,255,255,.14);
  background: var(--card-2);
  font-family: var(--font-ui);
  font-size: 13.5px;
  color: #e8e6e4;
}
.prose code { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 14px; }

.others {
  margin-top: 52px;
  padding-top: 28px;
  border-top: 1px solid var(--line);
}
.others h2 {
  margin: 0 0 14px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
}
.others ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.others li { font-size: 14.5px; line-height: 1.55; color: var(--muted); }
.others a { color: #fff; font-weight: 500; text-decoration: underline; text-underline-offset: 3px; }
.others a:hover { color: var(--accent); }

@media (max-width: 780px) {
  .file-card { flex-direction: column; gap: 20px; padding: 24px 22px; }
  .file-actions { width: 100%; }
  .btn-download { flex: 1; width: 100%; }
  .file-hero { padding: 20px; }
  .file-hero .btn-download { width: 100%; }
}
