/* Fabio XM Semibold (licensed), self-hosted */
@font-face {
  font-family: "Fabio XM";
  src: url("assets/fonts/FabioXM-Semibold.woff2") format("woff2"),
       url("assets/fonts/FabioXM-Semibold.woff") format("woff");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* ------------------------------------------------------------------
   Tokens — the Figma frame is 1728px wide; --u is one design pixel.
------------------------------------------------------------------ */
:root {
  --ink: #332d2b;
  --bg: #f2f1eb;
  --white: #ffffff;
  --tint: #dcd8d2; /* #c1b8b5 @ 40% over --bg */
  --lime: #ccf718;
  --tile: #d9d9d9;
  --link: #000000;
  --line: color-mix(in srgb, var(--ink) 10%, transparent);
  --line-strong: color-mix(in srgb, var(--ink) 15%, transparent);

  --u: calc(100vw / 1728);
  --pad: calc(30 * var(--u));      /* page gutter */
  --edge: calc(8 * var(--u));      /* card inset */
  --gap: calc(33 * var(--u));      /* grid gap */
  --radius: 8px;
  --peek: 64px;                    /* how much of "What I do" shows under the hero */

  --fs-s: max(13px, calc(15 * var(--u)));
  --fs-m: max(15px, calc(20 * var(--u)));
  --fs-l: max(28px, calc(48 * var(--u)));
  --fs-xl: max(36px, calc(64 * var(--u)));
  --fs-xxl: max(88px, calc(188 * var(--u)));
  --fs-mono: calc(264 * var(--u)); /* a touch under Figma's 276.76 so Tomás clears Louro */

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* Inverted palette — toggled by the dot in the footer */
:root[data-theme="inverted"] {
  --ink: #f2f1eb;
  --bg: #332d2b;
  --white: #272221;
  --tint: #423b38;
  --tile: #4d4542;
  --link: #ffffff;
}

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

html { -webkit-text-size-adjust: 100%; background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "Fabio XM", system-ui, sans-serif;
  font-weight: 600;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; padding: 0; font: inherit; }
ul, ol { list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; text-align: inherit; }
img { display: block; max-width: 100%; }
:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; border-radius: 2px; }

::selection { background: var(--lime); color: #332d2b; }

/* Full-page circular wipe when the palette flips */
::view-transition-old(root),
::view-transition-new(root) { animation: none; mix-blend-mode: normal; }

/* Type scale (Fabio XM Semibold everywhere) */
/* Letter-spacing per size. Fabio XM sets ~9% wider than Inter Tight did,
   so the tracking tightens more as the size grows (see README table). */
.s  { font-size: var(--fs-s);  line-height: 1.3; letter-spacing: 0; }
.m  { font-size: var(--fs-m);  line-height: 1.2; letter-spacing: -0.01em; }
.l  { font-size: var(--fs-l);  line-height: 1.1; letter-spacing: -0.035em; }
.xl { font-size: var(--fs-xl); line-height: 1.1; letter-spacing: -0.04em; }
.xxl { font-size: var(--fs-xxl); line-height: 1.1; letter-spacing: -0.03em; }
.s, .m, .l, .xl, .xxl { text-box: trim-both cap alphabetic; }
/* Text split into lines for the reveal: trim the first and last line
   themselves. Trimming the parent across the line blocks spaced the lines
   unevenly in Safari. */
:has(> .split-line) { text-box: none; }
.split-line:first-child { text-box: trim-start cap alphabetic; }
.split-line:last-child { text-box: trim-end cap alphabetic; }
.split-line:only-child { text-box: trim-both cap alphabetic; }
.dim { opacity: 0.5; }
.faint { opacity: 0.4; }

/* Underlined links inside running copy */
.hero-sub a,
.bio a {
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: 0.15em;
  transition: opacity 0.2s;
}
.hero-sub a { color: var(--link); }
/* Bio text is half-strength via colour (not opacity), so its links can go
   to full ink on hover */
.bio-inner { color: color-mix(in srgb, var(--ink) 50%, transparent); }
.bio a { transition: color 0.25s var(--ease); }
.bio a:hover { color: var(--ink); opacity: 1; }
.hero-sub { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 0.95em; row-gap: 0.6em; }
.hero-sub .sep { opacity: 0.2; }
.hero-sub a:hover, .bio a:hover { opacity: 0.6; }

/* Hover underline for nav-ish links */
.nav a, .brand, .footer ul a {
  background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition: background-size 0.4s var(--ease);
  padding-bottom: 2px;
}
.nav a:hover, .brand:hover, .footer ul a:hover { background-size: 100% 1px; }
/* Nav links are cap-trimmed blocks, so their box ends at the baseline; extend it
   by the font's descender (0.25em) to put the line where the footer links' is */
.nav a, .brand { padding-bottom: calc(0.25em + 2px); margin-bottom: calc(-0.25em - 2px); }

/* Round photo that pops out beside the name on hover */
.brand { position: relative; }
.brand-avatar {
  position: absolute;
  top: 50%;
  left: calc(100% + 14px);
  width: 60px;
  height: 60px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--white);
  box-shadow: 0 4px 18px rgba(51, 45, 43, 0.18);
  pointer-events: none;
  transform: translateY(-50%) scale(0) rotate(-12deg);
  transition: transform 0.45s var(--ease);
}
.brand-avatar img { width: 100%; height: 100%; object-fit: cover; transform: scale(1.3); transition: transform 0.6s var(--ease); }
@media (hover: hover) {
  .brand:hover .brand-avatar { transform: translateY(-50%) scale(1) rotate(0deg); }
  .brand:hover .brand-avatar img { transform: scale(1); }
}

/* ------------------------------------------------------------------
   Layout primitives
------------------------------------------------------------------ */
.grid {
  display: grid;
  grid-template-columns: repeat(9, minmax(0, 1fr));
  column-gap: var(--gap);
}

.section { position: relative; padding-inline: var(--pad); }
.card {
  position: relative;
  margin-inline: var(--edge);
  padding-inline: calc(var(--pad) - var(--edge));
  border-radius: var(--radius);
}
.card--white { background: var(--white); }
.card--tint { background: var(--tint); }
.card--lime { background: var(--lime); }

.rule {
  height: 1px;
  margin: 0;
  border: 0;
  background: var(--line);
  transform-origin: left center;
}

.section-head .label { grid-column: 1 / 3; }
.count { grid-column: 9 / 10; text-align: right; }

.tile { position: relative; overflow: hidden; background: var(--tile); border-radius: 6px; }
.tile img,
.tile video,
.portrait img {
  position: absolute;
  left: var(--l, 0);
  top: var(--t, 0);
  width: var(--w, 100%);
  height: var(--h, 100%);
  max-width: none;
  object-fit: cover;
}

/* ------------------------------------------------------------------
   Hero + sketch
------------------------------------------------------------------ */
.hero {
  position: relative;
  height: calc(100vh - var(--peek));
  height: calc(100svh - var(--peek));
  min-height: 520px;
  padding-inline: var(--pad);
  user-select: none;
  -webkit-user-select: none;
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22'%3E%3Ccircle cx='11' cy='11' r='9' fill='%23CCF718' stroke='%23332D2B' stroke-opacity='.25'/%3E%3C/svg%3E") 11 11, crosshair;
}
.hero a, .hero button { cursor: pointer; }

/* Strokes are clipped to the beige hero so they sit behind "What I do" */
.sketch {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
}
/* Drawing surface for fingers: the open space between the header and the headline */
.sketch-pad { display: none; position: absolute; left: 0; right: 0; }
@media (pointer: coarse) {
  .sketch-pad { display: block; touch-action: none; }
}
/* Opening line: a filled brush shape from Figma, uncovered by the mask below */
.sketch .brush {
  fill: var(--lime);
  stroke: var(--lime);
  stroke-width: var(--brush-grow, 0);
  stroke-linejoin: round;
  stroke-linecap: round;
}
.sketch .scribble {
  fill: none;
  stroke: #fff;
  stroke-width: var(--mask-stroke, 44);
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Visitors' own strokes */
.sketch .strokes path {
  fill: none;
  stroke: var(--lime);
  stroke-width: var(--stroke, 21);
  stroke-linecap: round;
  stroke-linejoin: round;
}

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  padding-inline: var(--pad);
  padding-top: calc(30 * var(--u));
  transition: background-color 0.4s var(--ease);
}
.site-header.is-scrolled { background: var(--bg); }

/* Overall page progress along the very top */
.progress { position: absolute; top: 0; left: 0; right: 0; height: 3px; }
.progress-bar {
  display: block;
  height: 100%;
  background: var(--lime);
  transform: scaleX(0);
  transform-origin: left center;
}
.header-row { align-items: start; }
.brand { grid-column: 1 / 3; justify-self: start; }
.nav {
  grid-column: 6 / 9;
  display: flex;
  gap: calc(40 * var(--u));
  white-space: nowrap;
}
.header-meta {
  grid-column: 9 / 10;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: max(10px, calc(14 * var(--u)));
}
.clock { opacity: 0.3; }
/* Flex children don't inherit the cap-height trim, so apply it per link */
.nav a { text-box: trim-both cap alphabetic; }
.menu-btn { display: none; }
.site-header .rule { margin-top: calc(30 * var(--u)); }

.hero-body {
  position: absolute;
  z-index: 2;
  left: var(--pad);
  right: var(--pad);
  bottom: 0;
  padding-bottom: calc(79 * var(--u));
  pointer-events: none;
}
.hero-copy {
  grid-column: 6 / 10;
  display: flex;
  flex-direction: column;
  gap: calc(44 * var(--u));
}
.hero-copy a { pointer-events: auto; }
/* Extra room inside each mask so ascenders and the dots on the i's aren't clipped */
.hero h1 .line { display: block; overflow: hidden; padding-block: 0.2em 0.08em; margin-block: -0.2em -0.08em; }
.hero h1 .line > span { display: inline-block; }

.sketch-hint {
  position: absolute;
  left: 0;
  bottom: calc(22 * var(--u));
  pointer-events: none;
  opacity: 0.5;
}
.sketch-hint .hint-reset { display: none; }
.hero.has-sketch .sketch-hint { pointer-events: auto; }
.hero.has-sketch .hint-draw { display: none; }
.hero.has-sketch .hint-reset { display: inline; }
.sketch-hint:hover { opacity: 1; }

/* Pill that replaces the cursor: "Scroll to view more", "Projects coming soon", "Send an email" */
.cursor-label {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  height: max(30px, calc(32 * var(--u)));
  padding: 0 max(16px, calc(20 * var(--u)));
  border: 1px solid rgba(51, 45, 43, 0.1);
  border-radius: 999px;
  background: var(--lime);
  color: #332d2b;
  filter: drop-shadow(0 4px 2px rgba(0, 0, 0, 0.25));
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
}

/* Website screenshot that follows the cursor over Contrast / Swap Club */
.site-preview {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 55;
  width: max(180px, calc(216 * var(--u)));
  aspect-ratio: 216 / 130;
  border-radius: 6px;
  overflow: hidden;
  background: var(--white);
  box-shadow: 0 1px 24px rgba(51, 45, 43, 0.3);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
}
.site-preview img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.cursor-label.is-cream { background: var(--cream, #f2f1eb); }
/* Drawn arrow used in the email pill and button */
.icon-arrow {
  width: 0.8em;
  height: 0.8em;
  flex: none;
  fill: currentColor;
  transform: rotate(-45deg);
}
.cursor-label { gap: 0.4em; }
.email-btn .icon-arrow { margin-left: 0.3em; vertical-align: -0.05em; }
html.cursor-label-on,
html.cursor-label-on * { cursor: none !important; }

/* ------------------------------------------------------------------
   Menu overlay (tablet + mobile)
------------------------------------------------------------------ */
.menu {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  padding: 20px var(--pad) 24px;
  background: var(--ink);
  color: var(--bg);
  visibility: hidden;
  clip-path: inset(0 0 100% 0);
}
.menu-top { display: flex; justify-content: space-between; }
.menu-links { margin-top: auto; display: flex; flex-direction: column; }
.menu-links a {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: 20px 0;
  border-top: 1px solid color-mix(in srgb, var(--bg) 18%, transparent);
}
.menu-links a .s { opacity: 0.5; width: 2ch; }
.menu-foot { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-top: 28px; }
.menu-foot a { text-decoration: underline; text-decoration-thickness: from-font; text-underline-offset: 0.2em; }

/* Breathing room under What I do (inside its white card), Selected work,
   About and Process (Process's sits on top of Stats, outside the pinned card) */
:root { --section-gap: max(64px, calc(140 * var(--u))); }
#work, #about { margin-bottom: var(--section-gap); }
#stats { margin-top: var(--section-gap); }

/* ------------------------------------------------------------------
   What I do
------------------------------------------------------------------ */
#what { padding-top: calc(18 * var(--u)); padding-bottom: var(--section-gap); }
/* Card stays blank white until the visitor starts scrolling */
#what > * { transition: opacity 0.9s var(--ease); }
.js #what.is-veiled > * { opacity: 0; }
#what .section-head { margin-top: calc(23 * var(--u)); }

.services {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin-top: calc(244 * var(--u));
}
.service {
  display: flex;
  flex-direction: column;
  padding-left: calc(20 * var(--u));
  border-left: 1px solid var(--line);
}
.service-text { display: flex; flex-direction: column; }
.service .l { margin-top: calc(36 * var(--u)); }
/* 19.5em keeps every description on exactly three balanced lines (measured:
   any width from 17.5em to 21.5em works), whatever the screen size */
.service .m { margin-top: calc(130 * var(--u)); max-width: 19.5em; text-wrap: balance; }
.service-img {
  margin-top: calc(34 * var(--u));
  width: calc(438 * var(--u));
  aspect-ratio: 438 / 300;
}
.service-img--brand { background: #070707; }
.service-img--web { background: #dedad5; }
/* Screen area of the MacBook mockup (Figma: 606×381 at 135,105 in 876×600);
   the recording fills its width and crops from the bottom */
.laptop-screen { position: absolute; left: 15.445%; top: 17.533%; width: 69.2%; height: 63.48%; overflow: hidden; background: #fff; }
.laptop-screen video { object-position: top; }
.service-img--product { background: #3f22ff; }

/* ------------------------------------------------------------------
   Selected work
------------------------------------------------------------------ */
#work { padding-top: calc(25 * var(--u)); }
#work .section-head { margin-top: calc(25 * var(--u)); }
.work-intro { grid-column: 6 / 9; }
.work-grid {
  margin-top: calc(72 * var(--u));
  grid-template-rows: calc(422 * var(--u)) calc(138 * var(--u)) calc(301 * var(--u));
  row-gap: calc(28 * var(--u));
}
.work-grid .tile > :not(.is-current) { clip-path: inset(100% 0 0 0); }
/* A layer that stacks more than one piece, e.g. a screen recording on a poster */
.tile .layer { position: absolute; inset: 0; }
.layer--screen > img { filter: blur(2px); }
.layer--screen > video {
  left: 50%; top: 50%;
  width: 76.01%; height: 63.95%;
  translate: -50% -50%;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: max(4px, calc(10 * var(--u)));
  box-shadow: 0 4px 17.1px #000;
}

/* Shuffle pill: sticks to the bottom of the screen while the work is in view.
   The ring fills up until the next set appears. */
.work-controls {
  position: sticky;
  bottom: max(16px, calc(24 * var(--u)));
  z-index: 5;
  display: flex;
  justify-content: center;
  margin-top: calc(28 * var(--u));
  pointer-events: none;
}
.shuffle {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 40px;
  padding: 0 18px 0 12px;
  border: 1px solid rgba(51, 45, 43, 0.1);
  border-radius: 999px;
  background: var(--lime);
  color: #332d2b;
  filter: drop-shadow(0 4px 2px rgba(0, 0, 0, 0.25));
  transition: transform 0.3s var(--ease);
}
.shuffle:hover { transform: scale(1.04); }
/* With a mouse, the pill replaces the cursor over the images instead */
.work-controls.is-cursor {
  position: fixed;
  top: 0;
  left: 0;
  bottom: auto;
  z-index: 60;
  margin: 0;
  opacity: 0;
}
.work-controls.is-cursor .shuffle { pointer-events: none; }
.work-grid.is-shuffle-target { cursor: none; }
.work-grid.is-shuffle-target * { cursor: none; }
.shuffle:active { transform: scale(0.97); }
.shuffle-timer { width: 20px; height: 20px; transform: rotate(-90deg); }
.shuffle-timer circle { fill: none; stroke: #332d2b; stroke-width: 2.5; }
.shuffle-timer .track { opacity: 0.15; }
.shuffle-timer .ring { stroke-dasharray: 100; stroke-dashoffset: 100; stroke-linecap: round; }
.shuffle-count { opacity: 0.5; font-variant-numeric: tabular-nums; }
/* ---------- Aeris product page, live inside the laptop photo ----------
   The photo keeps its own aspect and is centred in the tile; the screen
   sits at 421,204 / 1059×665 of the 1910×1071 photo. The page is the
   1440×930 Figma frame, scaled to the screen width by JS (--s). */
.tile .mock {
  --l: 0%; --t: 0%; --w: 100%; --h: 100%; /* children fill the mock */
  position: absolute;
  left: var(--ml);
  width: var(--mw);
  top: 50%;
  translate: 0 -50%;
  aspect-ratio: 1910 / 1071;
}
.mock-screen { position: absolute; left: 22.042%; top: 19.048%; width: 55.445%; height: 62.091%; overflow: hidden; background: #fff; }
.aeris {
  position: absolute;
  left: 0;
  top: 0;
  width: 1440px;
  height: 930px;
  transform-origin: 0 0;
  scale: var(--s, 0.3);
  overflow: hidden;
  background: #fff;
  color: #000;
  font: 400 20px/1.2 "Figtree", "Circular Std", system-ui, sans-serif;
  letter-spacing: 0;
  text-box: normal;
}
.aeris p { margin: 0; text-box: normal; }
.aeris img { position: static; inset: auto; width: auto; height: auto; max-width: none; object-fit: fill; display: block; }
.aeris-left { position: absolute; left: 0; top: 0; width: 720px; height: 930px; overflow: hidden; }
.aeris-photos { position: absolute; left: 0; top: 0; display: flex; width: 1440px; height: 930px; }
.aeris-photo { position: relative; flex: none; width: 720px; height: 930px; }
.aeris-photo img { width: 100%; height: 100%; object-fit: cover; }
.aeris-photo::after { content: ""; position: absolute; inset: 0; }
.aeris-photo--a::after { background: linear-gradient(90deg, rgba(0, 0, 0, 0.3), transparent 50%); }
.aeris-photo--b::after { background: rgba(0, 0, 0, 0.2); }
.aeris-titles { position: absolute; left: 24px; bottom: 156px; width: 128px; height: 535px; overflow: hidden; }
.aeris-titles-track { display: flex; width: 256px; }
.aeris-titles-track p { display: flex; flex: none; align-items: center; justify-content: center; width: 128px; height: 535px; }
.aeris-titles-track span { flex: none; width: 535px; rotate: -90deg; font-size: 64px; line-height: 1; color: #fff; }
.aeris-prodnav { position: absolute; left: 40px; bottom: 27px; width: 640px; display: flex; color: #fff; line-height: 28px; }
.aeris-prodnav > span { flex: 1 0 0; display: flex; align-items: center; gap: 4px; padding: 10px 0; }
.aeris-prodnav > span:nth-child(2) { justify-content: center; }
.aeris-prodnav > span:nth-child(3) { justify-content: flex-end; }
.aeris-prev { opacity: 0.4; }
.aeris-prodnav img { width: 16px; height: 16px; }
.aeris-prodnav img.flip { scale: -1 1; }
.aeris-right { position: absolute; left: 720px; top: 0; width: 720px; height: 930px; background: #f5f5f5; }
.aeris-state { position: absolute; inset: 0; }
.aeris-state--b { opacity: 0; }
.aeris-copy { position: absolute; left: 41px; top: 113px; width: 366px; }
.aeris .aeris-chair { position: absolute; scale: -1 1; }
.aeris .aeris-chair--a { left: 128px; top: 317px; width: 452px; height: 452px; }
.aeris .aeris-chair--b { left: 165px; top: 264px; width: 402px; height: 476px; object-fit: contain; }
.aeris-btn { position: absolute; bottom: 37px; display: flex; align-items: center; gap: 14px; height: 31px; font-size: 26px; white-space: nowrap; }
.aeris-btn::before { content: ""; width: 15px; height: 15px; border-radius: 50%; background: #000; }
.aeris-btn--1 { left: 48px; }
.aeris-btn--2 { left: 407px; }
.aeris-specs { position: absolute; left: 41px; top: 263px; display: flex; align-items: flex-end; gap: 10px; font-size: 16px; }
.aeris-specs img { width: 16px; height: 16.5px; rotate: 90deg; scale: 1 -1; }
.aeris-3d { position: absolute; left: 48px; top: 757px; display: flex; align-items: center; gap: 29px; font-size: 16px; }
.aeris-3d img { width: 54px; height: 40px; }
.aeris-nav { position: absolute; left: 0; top: 0; width: 1440px; height: 80px; }
.aeris .aeris-logo { position: absolute; left: 30px; top: 21px; width: 139px; height: 34px; }
.aeris-pages { position: absolute; left: 720px; top: 40px; translate: -50% -50%; display: flex; gap: 42px; line-height: 1.3; white-space: nowrap; }
.aeris-tools { position: absolute; right: 30px; top: 30px; display: flex; gap: 20px; align-items: flex-start; font: 700 13px/normal "DM Sans", system-ui, sans-serif; letter-spacing: 2px; }
.aeris-tools img { width: 20px; height: 20px; }

.work-grid .w1 { grid-column: 1 / 6; grid-row: 1 / 3; }
.work-grid .w2 { grid-column: 6 / 8; grid-row: 1 / 2; }
.work-grid .w3 { grid-column: 8 / 10; grid-row: 1 / 2; }
.work-grid .w4 { grid-column: 1 / 3; grid-row: 3 / 4; }
.work-grid .w5 { grid-column: 3 / 6; grid-row: 3 / 4; }
.work-grid .w6 { grid-column: 6 / 10; grid-row: 2 / 4; }

/* ------------------------------------------------------------------
   About
------------------------------------------------------------------ */
#about { padding-top: calc(28 * var(--u)); padding-bottom: calc(17 * var(--u)); }
.about-grid { margin-top: calc(25 * var(--u)); align-items: start; }
.about-grid .label { grid-column: 1 / 3; }
.about-title { grid-column: 3 / 7; max-width: 13.4em; }
.about-body { grid-column: 5 / 9; margin-top: calc(134 * var(--u)); }
.about-body > .m { max-width: calc(535 * var(--u)); min-width: min(100%, 30ch); }
.about-body .rule { margin-top: calc(23 * var(--u)); }
.more { margin-top: calc(25 * var(--u)); display: inline-flex; gap: 0.25em; }
.more-icon { display: inline-block; transition: transform 0.4s var(--ease); }
.more[aria-expanded="true"] .more-icon { transform: rotate(45deg); }

.bio { grid-column: 5 / 9; height: 0; overflow: hidden; }
.bio-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: var(--gap);
  padding-top: calc(66 * var(--u));
}
.bio p + p { margin-top: 1.3em; }

/* Experience and clients: columns 3–4, next to the portrait, top in line
   with it, in the small text size */
.about-facts {
  grid-column: 3 / 5;
  align-self: start;
  margin-top: calc(80 * var(--u));
}
.facts-label {
  font-size: var(--fs-s);
  line-height: 1.3;
  letter-spacing: 0;
  margin-top: calc(28 * var(--u));
  color: color-mix(in srgb, var(--ink) 50%, transparent);
}
/* Below ~1400px the small text stops shrinking (13px floor) while the
   columns keep narrowing, so borrow column 5 to keep each role on one line */
@media (min-width: 1024px) and (max-width: 1399px) {
  .about-facts { grid-column: 3 / 6; }
}
.facts-label + .facts-list { margin-top: 0.4em; }
.facts-list + .facts-label { margin-top: calc(40 * var(--u)); }
.facts-list {
  font-size: var(--fs-s);
  line-height: 1.3;
  letter-spacing: 0;
  text-wrap: balance;
}

/* Portrait with two cards tucked behind it that fan out on hover */
.portrait-stack {
  position: relative;
  grid-column: 1 / 3;
  width: calc(248 * var(--u));
  min-width: 140px;
  margin-top: calc(80 * var(--u));
}
.portrait-card {
  position: absolute;
  inset: 0;
  border-radius: 6px;
  transition: transform 0.7s var(--ease);
}
.portrait-card--sand { background: #dedad5; }
.portrait-card--lime { background: var(--lime); }
.portrait {
  position: relative;
  z-index: 1;
  display: block;
  cursor: pointer;
  aspect-ratio: 1;
  width: 100%;
  border-radius: 6px;
  overflow: hidden;
  background: var(--white);
  transition: transform 0.7s var(--ease);
}
.portrait img:not(.is-current) { clip-path: inset(100% 0 0 0); }
/* Angles and offsets from the Figma frame */
.portrait-stack:hover .portrait-card--sand { transform: translate(9.7%, -0.4%) rotate(8.35deg); }
.portrait-stack:hover .portrait-card--lime { transform: translate(3.7%, 0) rotate(4.09deg) scale(1.016); }
.portrait-stack:hover .portrait { transform: rotate(-0.53deg); }



/* ------------------------------------------------------------------
   Process — steps light up one by one while the card is pinned
------------------------------------------------------------------ */
#process {
  padding-top: calc(25 * var(--u));
  padding-bottom: calc(53 * var(--u));
}
#process .section-head { margin-top: calc(25 * var(--u)); }
.process-intro { grid-column: 3 / 6; max-width: calc(400 * var(--u)); min-width: min(100%, 22ch); }
.process-side { grid-column: 7 / 9; }

.steps { position: relative; margin-top: calc(125 * var(--u)); }
.step {
  cursor: pointer;
  padding-bottom: max(28px, calc(44 * var(--u)));
  align-content: start;
}
.step-rule {
  grid-column: 3 / 10;
  grid-row: 1;
  position: relative;
  height: 1px;
  margin-bottom: calc(25 * var(--u));
  background: var(--line-strong);
}
.step-fill {
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
}
.step .num { grid-column: 3 / 4; grid-row: 2; opacity: 0.5; transition: opacity 0.5s var(--ease); }
.step-title {
  grid-column: 3 / 7;
  grid-row: 2;
  padding-left: calc(30 * var(--u));
}
.step-title > span { display: inline-block; transition: transform 0.6s var(--ease); }
/* Height is animated in JS; starts closed */
.step-desc { grid-column: 7 / 9; grid-row: 2; height: 0; overflow: hidden; }
.step-desc p { padding-bottom: 0.3em; opacity: 0.5; }
.step.is-open .num { opacity: 1; }
.step:hover .step-title > span { transform: translateX(calc(10 * var(--u))); }

/* Arrow in a circle: points up-right when closed, turns to point across when open */
.step-toggle {
  grid-column: 9 / 10;
  grid-row: 2;
  justify-self: end;
  display: grid;
  place-items: center;
  width: max(34px, calc(46 * var(--u)));
  aspect-ratio: 1;
  margin-top: calc(-6 * var(--u));
  border-radius: 50%;
  background: var(--bg);
  color: var(--ink);
}
/* Arrow sits at ↗ and turns to → on hover; stays → while the step is open */
.arrow-spin {
  position: relative;
  width: 36%;
  aspect-ratio: 16 / 15;
  transform: rotate(-45deg);
  transition: transform 0.7s var(--ease);
}
.arrow-spin svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: currentColor;
}
.step.is-open .arrow-spin,
.step:hover .arrow-spin { transform: rotate(0deg); }

/* ------------------------------------------------------------------
   Side quests — personal projects, the last card before the footer
------------------------------------------------------------------ */
#side {
  margin-top: var(--section-gap);
  padding-top: calc(25 * var(--u));
  padding-bottom: calc(260 * var(--u));
  margin-bottom: max(64px, calc(140 * var(--u))); /* room before the footer slides over */
  transform-origin: 50% 0;
}
#side .section-head { margin-top: calc(25 * var(--u)); }
.sq-intro { grid-column: 4 / 9; margin-left: calc(-12 * var(--u)); max-width: calc(872 * var(--u)); }
.sq-grid { margin-top: calc(161 * var(--u)); }
.sq { display: block; width: calc(706 * var(--u)); color: inherit; text-decoration: none; }
.sq--contrast { grid-column: 1 / 5; justify-self: start; margin-left: calc(20 * var(--u)); }
.sq--swap { grid-column: 6 / 10; justify-self: start; }
.sq-frame { position: relative; display: block; aspect-ratio: 706 / 458; border-radius: 6px; overflow: hidden; }
.sq--contrast .sq-frame { background: #c1bef1; }
.sq--swap .sq-frame { background: #da481c; }
/* The screen-like rectangle (581×326 in 706×458); it zooms a touch on hover */
.sq-media {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 82.29%;
  height: 71.18%;
  translate: -50% -50%;
  border-radius: 8px;
  overflow: hidden;
  background: #f2f1eb;
  transition: scale 0.9s var(--ease);
}
.sq-media video { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; }
/* Swap Club recording includes the browser frame; Figma crops it out */
.sq--swap .sq-media video { left: -10.5%; top: -11.96%; width: 118.24%; height: 141.1%; }
.sq:hover .sq-media { scale: 1.04; }
.sq-arrow {
  position: absolute;
  right: calc(20 * var(--u));
  bottom: calc(20 * var(--u));
  display: grid;
  place-items: center;
  width: max(34px, calc(42 * var(--u)));
  aspect-ratio: 1;
  border-radius: 50%;
  background: #f2f1eb;
  color: #332d2b;
  transition: background-color 0.4s var(--ease);
}
.sq:hover .sq-arrow { background: #fff; }
.sq-arrow svg { width: 36%; fill: currentColor; transition: rotate 0.7s var(--ease); }
.sq:hover .sq-arrow svg { rotate: -45deg; }
.sq-info { display: flex; justify-content: space-between; align-items: flex-start; gap: 24px; margin-top: calc(25 * var(--u)); }
.sq-text { display: flex; flex-direction: column; gap: calc(10 * var(--u)); }
.sq-desc { max-width: calc(467 * var(--u)); min-width: min(100%, 24ch); opacity: 0.5; }
.sq-tags { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; flex: none; }
.sq-tags > span {
  padding: 10px 16px;
  border: 1px solid rgba(51, 45, 43, 0.2);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.8);
  color: #332d2b;
  font-size: max(12px, calc(14 * var(--u)));
  white-space: nowrap;
}

/* ------------------------------------------------------------------
   Stats
------------------------------------------------------------------ */
/* Fills the viewport so the numbers are fully seen before the footer covers them */
#stats { padding-top: calc(25 * var(--u)); padding-bottom: calc(220 * var(--u)); }
.stats-grid {
  margin-top: calc(25 * var(--u));
  row-gap: calc(76 * var(--u));
}
.stats-grid .label { grid-column: 1 / 3; grid-row: 1; }
.stats-grid .count { grid-row: 1; }
.stat { display: flex; flex-direction: column; gap: calc(40 * var(--u)); }
.stat .no { font-size: 0.645em; }
.stat:nth-of-type(3n + 1) { grid-column: 3 / 5; }
.stat:nth-of-type(3n + 2) { grid-column: 5 / 7; }
.stat:nth-of-type(3n)     { grid-column: 7 / 9; }
.stat:nth-of-type(-n + 3) { grid-row: 1; }
.stat:nth-of-type(n + 4)  { grid-row: 2; }

/* ------------------------------------------------------------------
   Footer — slides up over the page; always lime with dark ink
------------------------------------------------------------------ */
.footer {
  --ink: #332d2b;
  --line: rgba(51, 45, 43, 0.12);
  z-index: 2;
  color: var(--ink);
  margin-bottom: var(--edge);
  padding-top: calc(24 * var(--u));
  padding-bottom: calc(34 * var(--u));
  min-height: calc(718 * var(--u));
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.f-col { display: flex; flex-direction: column; }
.f-col > .faint { opacity: 0.5; } /* Menu / Social / Contact */
.f-col .rule { margin-bottom: calc(17 * var(--u)); }
.f-menu { grid-column: 1 / 3; }
.f-social { grid-column: 3 / 6; }
.f-contact { grid-column: 6 / 10; }
.f-col ul { margin-top: calc(57 * var(--u)); display: flex; flex-direction: column; gap: calc(22 * var(--u)); }
.f-col li { text-box: trim-both cap alphabetic; }
.f-cta { margin-top: calc(60 * var(--u)); align-self: start; }

/* Touch screens have no hover pill, so they get a real button instead */
.email-btn {
  display: none;
  align-self: start;
  margin-top: 24px;
  padding: 12px 18px 11px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--lime);
}
@media (hover: none), (pointer: coarse) {
  .email-btn { display: inline-block; }
}

.dot {
  flex: none;
  width: 17px;
  height: 17px;
  margin-block: -6px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--ink);
  transition: transform 0.4s var(--ease), background-color 0.3s;
}
.dot:hover { transform: scale(1.35); }
.dot--nav { width: 0.72em; height: 0.72em; margin: 0; font-size: var(--fs-m); }
[data-theme="inverted"] .dot { background: transparent; }

/* Jonas sits where the big name was: the pinwheel's left edge lines up with
   "Contact" and its base sits just above the bottom rule. The offsets are
   fractions of his box (the pinwheel spans x 46–189, bottom 191 of 241). */
.footer-jonas { margin-top: auto; align-items: end; }
.jonas {
  --jw: max(170px, calc(270 * var(--u)));
  grid-column: 6 / 10;
  justify-self: start;
  width: var(--jw);
  aspect-ratio: 1;
  margin-left: calc(var(--jw) * -0.191);
  margin-bottom: calc(var(--jw) * -0.18);
}
.mono {
  display: flex;
  overflow: hidden;
  font-size: var(--fs-mono);
  letter-spacing: -0.055em; /* -15px at the design's 276.76px (was -5px with Inter Tight) */
  /* A full line box keeps the á accent and the last letter's edge inside the
     reveal mask; the negative bottom margin removes the descender space so the
     letters still sit on the rule below */
  line-height: 1;
  padding-right: 0.06em;
  margin-bottom: -0.137em;
  white-space: nowrap;
  cursor: default;
}
.mono:focus-visible { outline-offset: -2px; }
.mono-first, .mono-rest > span { display: inline-block; }
.mono-rest { display: inline-flex; }
.mono-rest > span { transform: translateY(105%); }
/* Pull each word left by its first letter's built-in side space (measured in
   Fabio XM), so the ink lines up with "Menu" and "Contact" above */
.mono-t { grid-column: 1 / 6; justify-self: start; margin-left: -0.013em; }
.mono-l { grid-column: 6 / 10; justify-self: start; margin-left: -0.08em; }
.footer > .rule { margin-top: calc(17 * var(--u)); }
.footer-bottom { margin-top: calc(17 * var(--u)); }
.f-copy { grid-column: 1 / 4; }
.f-tag { grid-column: 6 / 10; grid-row: 1; }
/* Credit for the typeface, on the same line, pushed to the far right */
.f-colophon { grid-column: 6 / 10; grid-row: 1; justify-self: end; }
.f-colophon a {
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: 0.15em;
}

/* ==================================================================
   Tablet (≤1023px) — 6-column grid, menu overlay
================================================================== */
@media (max-width: 1023px) {
  :root {
    --pad: 24px;
    --edge: 8px;
    --gap: 16px;
    --fs-s: 14px;
    --fs-m: 17px;
    --fs-l: 34px;
    --fs-xl: 48px;
    --fs-xxl: 120px;
    --fs-mono: 13.8vw;
  }
  .grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }

  /* Section heads: label + count on row one, copy underneath */
  .section-head .label, .about-grid .label, .stats-grid .label { grid-column: 1 / 5; grid-row: 1; }
  .count { grid-column: 5 / -1; grid-row: 1; }

  /* Header */
  .header-row { display: flex; align-items: center; gap: 24px; }
  .nav { display: none; }
  .header-meta { margin-left: auto; }
  .menu-btn { display: block; }
  .site-header { padding-top: 22px; }
  .site-header .rule { margin-top: 20px; }

  /* Hero */
  .hero { min-height: 540px; }
  .hero-body { padding-bottom: 36px; align-items: end; }
  .hero-copy { grid-column: 1 / -1; grid-row: 1; gap: 28px; }
  .sketch-hint { position: static; grid-column: 1 / -1; grid-row: 2; margin-top: 32px; justify-self: start; }

  /* What I do — each service becomes a row: copy left, image right */
  #what { padding-top: 12px; }
  #what .section-head { margin-top: 20px; }
  .services { grid-template-columns: 1fr; margin-top: 56px; }
  .service {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: var(--gap);
    padding: 20px 0 28px;
    border-left: 0;
    border-top: 1px solid var(--line);
  }
  .service .l { margin-top: 20px; }
  .service .m { margin-top: 20px; }
  .service-img { margin-top: 0; width: 100%; }

  /* Work */
  #work, #about, #stats { padding-top: 24px; }
  #work .section-head, .about-grid, #process .section-head, .stats-grid { margin-top: 20px; }
  .work-intro { grid-column: 3 / -1; grid-row: 2; margin-top: 40px; }
  .work-grid { margin-top: 40px; grid-template-rows: none; row-gap: var(--gap); }
  .work-grid .tile { grid-row: auto; }
  .work-grid .w1, .work-grid .w6 { grid-column: 1 / -1; aspect-ratio: 16 / 10; }
  .work-grid .w2, .work-grid .w4 { grid-column: 1 / 4; aspect-ratio: 1; }
  .work-grid .w3, .work-grid .w5 { grid-column: 4 / -1; aspect-ratio: 1; }

  /* About */
  #about { padding-bottom: 24px; }
  .about-title { grid-column: 1 / -1; grid-row: 2; margin-top: 40px; max-width: 14em; }
  .about-body { grid-column: 3 / -1; margin-top: 48px; }
  .about-body > .m { max-width: none; min-width: 0; }
  .about-body .rule { margin-top: 22px; }
  .more { margin-top: 22px; }
  .bio { grid-column: 1 / -1; }
  .bio-inner { padding-top: 40px; }
  .portrait-stack { grid-column: 1 / 3; width: 100%; min-width: 0; margin-top: 48px; }
  .about-facts { grid-column: 3 / -1; margin-top: 48px; }
  .facts-label { margin-top: 20px; }
  .facts-list + .facts-label { margin-top: 36px; }

  /* Process */
  #process { padding-top: 12px; padding-bottom: 32px; }
  .process-intro { grid-column: 1 / 5; grid-row: 2; margin-top: 36px; max-width: none; min-width: 0; }
  .process-side { grid-column: 1 / 5; grid-row: 3; margin-top: 18px; }
  .steps { margin-top: 48px; }
  .step { padding-bottom: 30px; }
  .step-toggle { grid-column: -2 / -1; }
  .step-rule { grid-column: 1 / -1; margin-bottom: 20px; }
  .step .num { grid-column: 1 / 2; }
  .step-title { grid-column: 1 / 4; padding-left: 40px; }
  .step-desc { grid-column: 4 / -1; }

  /* Stats — three across */
  #stats { padding-bottom: 120px; }
  .stats-grid { row-gap: 56px; }
  .stat { gap: 24px; }
  .stat:nth-of-type(n) { grid-column: auto / span 2; grid-row: auto; }
  .stat:nth-of-type(1) { grid-column: 1 / 3; }
  .stat:nth-of-type(-n + 3) { grid-row: 2; margin-top: 40px; }

  /* Footer */
  .footer { min-height: 0; padding-top: 16px; padding-bottom: 20px; }
  .f-menu { grid-column: 1 / 3; }
  .f-social { grid-column: 3 / 5; }
  .f-contact { grid-column: 1 / -1; grid-row: 2; margin-top: 56px; }
  .f-col .rule { margin-bottom: 14px; }
  .f-col ul { margin-top: 32px; gap: 16px; }
  .f-cta { margin-top: 36px; }
  .footer-jonas { margin-top: 72px; }
  .jonas { grid-column: 4 / -1; }
  .footer > .rule { margin-top: 20px; }
  .footer-bottom { margin-top: 14px; }
  .mono-t { grid-column: 1 / 4; }
  .mono-l { grid-column: 4 / -1; }
  .f-copy { grid-column: 1 / 4; }
  .f-tag { grid-column: 4 / -1; }
  .f-colophon { grid-column: 4 / -1; }
}

/* ==================================================================
   Mobile (≤639px) — 4-column grid, stacked sections
================================================================== */
@media (max-width: 639px) {
  :root {
    --pad: 16px;
    --edge: 6px;
    --gap: 12px;
    --fs-s: 14px;
    --fs-m: 16px;
    --fs-l: 30px;
    --fs-xl: 40px;
    --fs-xxl: 96px;
    --fs-mono: 40vw;
  }
  .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .section-head .label, .about-grid .label, .stats-grid .label { grid-column: 1 / 4; }
  .count { grid-column: 4 / -1; }

  .header-row { gap: 18px; }
  .site-header { padding-top: 18px; }
  .site-header .rule { margin-top: 18px; }
  .hero { min-height: 500px; }
  .hero-body { padding-bottom: 28px; }
  .hero-copy { gap: 22px; }
  /* Keep the headline to three lines on narrow phones */
  .hero h1 { font-size: min(var(--fs-xl), calc((100vw - 2 * var(--pad)) / 9.4)); }
  .hero-sub { flex-direction: column; row-gap: 8px; }
  .hero-sub .sep { display: none; }

  .services { margin-top: 40px; }
  .service { grid-template-columns: 1fr; padding-bottom: 32px; }
  .service-img { margin-top: 24px; }

  .work-intro { grid-column: 1 / -1; margin-top: 28px; }
  .work-grid { margin-top: 32px; }
  .work-grid .w2, .work-grid .w4 { grid-column: 1 / 3; }
  .work-grid .w3, .work-grid .w5 { grid-column: 3 / -1; }

  .about-title { margin-top: 28px; }
  .about-facts { grid-column: 1 / -1; margin-top: 40px; }
  .about-body { grid-column: 1 / -1; margin-top: 36px; }
  .bio-inner { grid-template-columns: 1fr; padding-top: 28px; }
  .bio-inner > div + div { margin-top: 1.3em; }

  .process-intro, .process-side { grid-column: 1 / -1; }
  .process-intro { margin-top: 24px; }
  .process-side { margin-top: 14px; }
  .steps { margin-top: 32px; }
  .step { padding-bottom: 18px; }
  .step-rule { margin-bottom: 16px; }
  .step-title { grid-column: 1 / -1; padding-left: 36px; }
  .step-desc { grid-column: 1 / -1; grid-row: 3; }
  .step-desc p { padding-top: 14px; }

  #stats { padding-bottom: 96px; }
  .stats-grid { row-gap: 40px; }
  .stat:nth-of-type(n) { grid-column: auto / span 2; grid-row: auto; margin-top: 0; }
  .stat:nth-of-type(1) { grid-column: 1 / 3; }
  .stat:nth-of-type(-n + 2) { grid-row: 2; margin-top: 32px; }
  .stat { gap: 18px; }

  .footer { padding-bottom: 16px; }
  .f-contact { margin-top: 44px; }
  .f-cta { font-size: 36px; }
  /* Just the initials: T bottom-left, L bottom-right, no name reveal */
  .footer-jonas { margin-top: 56px; }
  .jonas { grid-column: 3 / -1; }
  .mono-rest { display: none; }
  .mono { cursor: default; }
  .mono-t { grid-column: 1 / 3; justify-self: start; margin-left: -0.013em; }
  .mono-l { grid-column: 3 / -1; justify-self: start; margin-left: -0.08em; }
  .f-copy { grid-column: 1 / 3; }
  .f-tag { grid-column: 3 / -1; }
  /* No room for the type credit on phones */
  .f-colophon { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; }
}


/* Side quests on tablet and phone: intro under the label, cards stacked */
@media (max-width: 1023px) {
  #side { padding-top: 12px; padding-bottom: 48px; margin-bottom: 48px; }
  #side .section-head { margin-top: 20px; }
  .sq-intro { grid-column: 1 / -1; grid-row: 2; margin: 36px 0 0; max-width: 14em; }
  .sq-grid { margin-top: 48px; row-gap: 48px; }
  .sq--contrast, .sq--swap { grid-column: 1 / -1; justify-self: stretch; width: auto; margin-left: 0; }
  .sq-arrow { right: 14px; bottom: 14px; }
  .sq-info { margin-top: 18px; }
  .sq-text { gap: 8px; }
  .sq-desc { max-width: 30em; }
}
@media (max-width: 639px) {
  .sq-intro { margin-top: 24px; }
  .sq-grid { margin-top: 32px; row-gap: 40px; }
  .sq-info { flex-direction: column; gap: 16px; }
  .sq-tags { flex-direction: row; flex-wrap: wrap; align-items: flex-start; }
}

.nowrap { white-space: nowrap; }
