/* =========================================================
   Tokens
   ========================================================= */
:root {
  color-scheme: light;
  --bg: #f8f8f8;
  --black: #000;          /* strongest text (logo, name) — near-white in dark */
  --dark-2: #414141;      /* primary text / active */
  --grey: #808080;        /* secondary text */
  --line: rgba(0, 0, 0, 0.05);
  --separator: #c2c2c2;
  --fill: rgba(0, 0, 0, 0.05);          /* email pill */
  --fill-hover: rgba(0, 0, 0, 0.08);
  --fill-ring: rgba(0, 0, 0, 0.08);
  --inverse-fg: #fff;                   /* text on a var(--black) surface */
  --photo-bg: #ececec;
  --photo-border: rgba(0, 0, 0, 0.025); /* half the grid-line strength */
  --card-bg: #fff;                      /* Work cards */
  --label: #666;                        /* phone section labels */
  --figma-blue: #0091ff;
  --figma-label: #33aaff;
  /* Shadows on page surfaces (stronger in dark, or they'd vanish) */
  --shadow-inset: inset 0 0 6px rgba(0, 0, 0, 0.25);                                  /* Work card media */
  --shadow-photo: 0 6px 16px -6px rgba(0, 0, 0, 0.2), 0 1px 3px rgba(0, 0, 0, 0.06);  /* Photos strip */
  --shadow-pop: 0 10px 30px -12px rgba(0, 0, 0, 0.25);                                /* team cards */
  --shadow-shot: 0 6px 18px -8px rgba(0, 0, 0, 0.35);                                 /* stacked screens */

  --font: "SF Pro Display", -apple-system, BlinkMacSystemFont, "Inter", system-ui, "Segoe UI", Roboto, sans-serif;

  --shell-max: 1240px;
  --gutter: 32px;
  --shell: min(var(--shell-max), 100% - var(--gutter) * 2);
  --header-h: 80px;
  --body-lh: 1.5;   /* line height of all body text in the project pages' sections */
  /* 1 Framer px outside the container-query stages */
  --px: min(1px, (100vw - 2 * var(--gutter)) / 1240);

  /* 6-column grid measured from the original: 212 | 204 ×4 | 212 */
  --cols: 212fr 204fr 204fr 204fr 204fr 212fr;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Dark theme: data-theme="dark" on <html>. The inline script in <head>
   sets it before first paint, only if the visitor picked dark in the header
   switch: light otherwise, whatever the device is set to. main.js switches it. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0f0f0f;
  --black: #f5f5f5;
  --dark-2: #c4c4c4;
  --grey: #b7b7b7;
  --active: #ececec;   /* current section link: almost white */
  --line: rgba(255, 255, 255, 0.07);
  --separator: #3a3a3a;
  --fill: rgba(255, 255, 255, 0.06);
  --fill-hover: rgba(255, 255, 255, 0.1);
  --fill-ring: rgba(255, 255, 255, 0.1);
  --inverse-fg: #0f0f0f;
  --photo-bg: #1c1c1c;
  --photo-border: rgba(255, 255, 255, 0.06);
  --card-bg: #161616;
  --label: #ababab;
  --shadow-inset: inset 0 0 6px rgba(0, 0, 0, 0.5);
  --shadow-photo: 0 6px 16px -6px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.35);
  --shadow-pop: 0 10px 30px -12px rgba(0, 0, 0, 0.7);
  --shadow-shot: 0 6px 18px -8px rgba(0, 0, 0, 0.7);
}

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

/* The page scrolls as usual, but without a visible scrollbar */
html { scrollbar-width: none; -ms-overflow-style: none; }
html::-webkit-scrollbar,
body::-webkit-scrollbar { display: none; width: 0; height: 0; }

html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;   /* no grey/blue flash on tap (iOS/Android) */
  scroll-behavior: smooth;
  scroll-padding-top: var(--header-h);
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--black);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

p, h1, figure, ul { margin: 0; padding: 0; }
ul { list-style: none; }
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }

:focus-visible {
  outline: 2px solid var(--figma-blue);
  outline-offset: 3px;
  border-radius: 4px;
}
/* The focus ring is for keyboard users: after a tap or click (main.js
   sets .using-pointer until a key is pressed) it never shows */
.using-pointer :focus-visible,
.using-pointer *:focus-visible { outline: none !important; }

.shell {
  width: var(--shell);
  margin-inline: auto;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.skip-link {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 100;
  padding: 10px 14px;
  border-radius: 6px;
  background: var(--black);
  color: var(--inverse-fg);
  font-size: 14px;
  transform: translateY(-200%);
  transition: transform 0.2s var(--ease-out);
}
.skip-link:focus { transform: none; }

/* Shared arrow icon (source points left) */
.arrow {
  width: 11px;
  height: 9px;
  flex: none;
  color: var(--dark-2);
  transition: opacity 0.25s var(--ease-out), transform 0.35s var(--ease-out);
}
.arrow--out { transform: rotate(135deg); }

/* =========================================================
   Background grid
   ========================================================= */
.grid-bg {
  position: fixed;
  /* As tall as the screen can get: when a phone's address bar slides away
     while scrolling, the lines still reach the bottom edge */
  inset: 0 0 auto;
  height: 100vh;
  height: 100lvh;
  z-index: -1;
  pointer-events: none;
}
.grid-bg__cols {
  position: relative;
  height: 100%;
  display: grid;
  grid-template-columns: var(--cols);
}
.grid-bg__cols span { position: relative; }
/* Each line is its own element so it can be drawn in during the intro:
   every column's left edge, plus the container's right edge.
   --l is the line's order (left → right). */
.grid-bg__cols span::before,
.grid-bg__cols::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line);
  transform-origin: top;
}
.grid-bg__cols span::before { left: 0; }
.grid-bg__cols::after { right: 0; --l: 6; }
/* The outer edges use the header separator's colour. On desktop the header's
   side borders match so the edge lines run unbroken to the top (on mobile
   the header is full-width with no side borders). */
.grid-bg__cols span:first-child::before,
.grid-bg__cols::after { background: var(--separator); }
@media (min-width: 1000px) {
  .site-header .site-header__inner { border-inline-color: var(--separator); }
}

/* Project pages, desktop: no sidebar column. The dash nav sits in the
   margin left of the grid instead, and the content uses all 6 columns
   (the layout overrides are under "Project pages: 6 columns"). */
@media (min-width: 1000px) {
  .page-case {
    --gutter: 56px;   /* room for the dash nav outside the grid */
    --vis: min(var(--shell-max), 100vw - 2 * var(--gutter));   /* the grid's width */
    --px: calc(var(--vis) / 1240);
    --shell: min(var(--shell-max), 100% - var(--gutter) * 2);   /* re-read with this gutter */
  }
}
.grid-bg__cols span:nth-child(2) { --l: 1; }
.grid-bg__cols span:nth-child(3) { --l: 2; }
.grid-bg__cols span:nth-child(4) { --l: 3; }
.grid-bg__cols span:nth-child(5) { --l: 4; }
.grid-bg__cols span:nth-child(6) { --l: 5; }

/* =========================================================
   Header
   ========================================================= */
.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 20;
  pointer-events: none;
}
.site-header__inner {
  position: relative;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 33px 0 20px;
  background: var(--bg);
  border-bottom: 1px solid var(--separator);
  border-inline: 1px solid var(--line);
  pointer-events: auto;
}

.logo {
  font-size: 42px;
  line-height: 1;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--black);
  transition: opacity 0.2s;
}
.logo:hover { opacity: 0.7; }

/* Project pages: "← Back" (to all work) fills the first grid column of the
   header, its line on the right. It's a solid block, line included:
   arriving, it slides up from under the header and pushes the logo out of
   the top. Clicking it opens the lobby, which plays the reverse
   (.head-return, set in its <head>): the block drops out and the logo comes
   back down. */
.head-back { display: none; }
:root { --head-swap: 0.48s cubic-bezier(0.7, 0, 0.2, 1); }
:is(.page-case, .head-return) .head-back {
  position: absolute;
  inset: 0 auto 0 0;
  /* % is the header's inside (its 1px side borders excluded): add them back
     so the line lands exactly on the grid line below */
  width: calc((100% + 2px) * 212 / 1240);
  display: block;
  overflow: hidden;   /* the block slides in and out of its own cell */
  font-size: 18px;
  line-height: 1.2;
  color: var(--grey);
  transition: color 0.2s;
}
:is(.page-case, .head-return) .head-back__face {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-right: 1px solid var(--line);
  background: var(--bg);
}
.head-back .arrow { color: currentColor; transition: transform 0.3s var(--ease-out); }
@media (hover: hover) {
  .page-case .head-back:is(:hover, :focus-visible) { color: var(--black); }
  .page-case .head-back:is(:hover, :focus-visible) .arrow { transform: translateX(-3px); }
}

.page-case .logo { animation: head-logo-up var(--head-swap) 0.4s forwards; }
.page-case .head-back__face { animation: head-face-up var(--head-swap) 0.4s backwards; }
.head-return .head-back { pointer-events: none; }
.head-return .logo { animation: head-logo-down var(--head-swap) 0.24s backwards; }
.head-return .head-back__face { animation: head-face-down var(--head-swap) 0.24s forwards; }
/* Phones and tablets: the header runs edge to edge, so the block reaches
   from the screen edge to the 2nd grid line (gutter + the first of the
   four columns), its label centred between the screen edge and its
   line; text sized like
   the header links. Its line is a short divider like the ones between
   the header buttons, not a full-height grid line */
@media (max-width: 999px) {
  :is(.page-case, .head-return) .head-back {
    width: calc(var(--gutter) + (100vw - 2 * var(--gutter)) * 127 / 543 + 1px);   /* + the line itself */
    font-size: clamp(15px, calc(17 * var(--f)), 24px);
  }
  :is(.page-case, .head-return) .head-back__face { gap: 6px; border-right: 0; }
  :is(.page-case, .head-return) .head-back__face::after {
    content: "";
    position: absolute;
    top: 50%;
    right: 0;
    width: 1px;
    height: clamp(22px, calc(34 * var(--f)), 52px);
    background: var(--separator);
    opacity: 0.5;
    transform: translateY(-50%);
  }
}
@keyframes head-face-up   { from { transform: translateY(100%); } }
@keyframes head-face-down { to   { transform: translateY(100%); visibility: hidden; } }
@keyframes head-logo-up   { to   { transform: translateY(calc(-1 * var(--header-h))); visibility: hidden; } }
@keyframes head-logo-down { from { transform: translateY(calc(-1 * var(--header-h))); } }

.top-nav {
  display: flex;
  align-items: center;
  gap: 24px;
}

.top-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 40px;
  font-size: 18px;
  line-height: 1.2;
  color: var(--dark-2);
  white-space: nowrap;
  transition: color 0.2s;
}
.top-link .arrow { opacity: 0; }
.top-link .arrow--out { transform: rotate(135deg) translateX(4px); }
.top-link:hover .arrow,
.top-link:focus-visible .arrow { opacity: 1; }
.top-link:hover .arrow--out,
.top-link:focus-visible .arrow--out { transform: rotate(135deg) translateX(0); }

/* Desktop CV: the hover arrow doesn't reserve space, so the word sits
   centred between its two separators; the arrow appears in the gap */
.top-nav > .top-link.desktop-only {
  position: relative;
  transition: color 0.2s, transform 0.35s var(--ease-out);
}
/* On hover the visible group becomes "CV ↗" (~18px wider on the right),
   so slide left by half of that to keep the pair centred */
.top-nav > .top-link.desktop-only:hover,
.top-nav > .top-link.desktop-only:focus-visible { transform: translateX(-9px); }
.top-nav > .top-link.desktop-only .arrow {
  position: absolute;
  left: calc(100% + 6px);
  top: 50%;
  margin-top: -4.5px;
}

.divider {
  width: 1px;
  height: 40px;
  background: var(--separator);
  opacity: 0.5;
  flex: none;
}

/* Desktop: 30px from the separator to "Contacts", matching the 30px between
   its arrow and the header's edge (nav gap is 24px, so add 6px) */
.contacts-toggle { margin-left: 6px; }

/* Contacts toggle: "←" hints the panel opens leftwards, "→" closes it */
.contacts-toggle .arrow--toggle { transform: translateX(3px); }
.contacts-toggle:hover .arrow--toggle { transform: none; }
.contacts-toggle[aria-expanded="true"] .arrow--toggle { opacity: 1; transform: rotate(180deg); }

/* Expanding contacts panel */
.contacts {
  display: flex;
  align-items: center;
}
.contacts[hidden] { display: none; }
/* Desktop reveal: main.js animates this row's width from 0. Its right edge
   is the separator next to "Contacts" (kept outside the row, so it never
   moves or clips), and the links are anchored to the row's left edge — so
   as the width grows they travel left out from behind the separator,
   pushing CV ahead of them. */
.contacts__inner {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 20px;
  overflow: hidden;
}
.contacts__inner > * { flex-shrink: 0; }
.contacts__inner > :last-child { margin-right: 20px; }   /* space before the separator */
.contacts__socials { display: flex; gap: 20px; }
/* Desktop: the revealed social links also get wider targets (half their
   20px gap each side; the row's height already matches the email pill) */
@media (min-width: 1000px) {
  .contacts__socials .top-link { position: relative; }
  .contacts__socials .top-link::after {
    content: "";
    position: absolute;
    inset: 0 -10px;
  }
}

.email-pill {
  position: relative;
  display: inline-grid;
  /* Centre the content explicitly: Safari sizes a grid inside a <button> to
     its content and pins it to the top instead of stretching it */
  place-content: center;
  place-items: center;
  height: 40px;
  padding: 0 20px;
  border-radius: 6px;
  background: var(--fill);
  box-shadow: inset 0 0 0 1px var(--fill-ring);
  font-size: 16px;
  color: var(--black);
  /* Safari will otherwise break the address at "." / "@" inside a grid button */
  white-space: nowrap;
  transition: background-color 0.25s, color 0.25s, box-shadow 0.25s;
}
.email-pill:hover { background: var(--fill-hover); }
.email-pill > span {
  grid-area: 1 / 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: opacity 0.25s var(--ease-out), transform 0.35s var(--ease-spring);
}
.email-pill svg { width: 14px; height: 14px; flex-shrink: 0; fill: currentColor; }
.email-pill__copied svg { fill: none; }
.email-pill__copied { opacity: 0; transform: scale(0.6); }

.email-pill.is-copied { background: var(--black); color: var(--inverse-fg); box-shadow: none; }
.email-pill.is-copied .email-pill__default { opacity: 0; transform: scale(0.8); }
.email-pill.is-copied .email-pill__copied { opacity: 1; transform: none; }

/* Hamburger + menu sheet + CV inside Contacts: mobile/tablet only
   (see Responsive) */
.menu-only,
.menu-only-item,
.menu-sheet { display: none; }

.menu-toggle {
  flex-direction: column;
  justify-content: center;
  /* Line to line: a whole number of pixels, so all three lines land on
     the same fraction of a screen pixel and render equally thick */
  --burger-pitch: calc(var(--burger-gap, 8px) + var(--burger-stroke));
  gap: calc(var(--burger-pitch) - var(--burger-stroke));
  width: var(--burger-w, 32px);
  height: 40px;
}
@supports (width: round(1.5px, 1px)) {
  .menu-toggle { --burger-pitch: round(calc(var(--burger-gap, 8px) + var(--burger-stroke)), 1px); }
}
.menu-toggle span {
  display: block;
  width: 100%;          /* Safari ≤ 18 doesn't stretch children inside a flex <button> */
  height: var(--burger-stroke);
  background: var(--dark-2);
  border-radius: 1px;
  transition: transform 0.35s var(--ease-out), opacity 0.2s;
}
/* Morph into an × when open */
.menu-toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(var(--burger-pitch)) rotate(45deg);
}
.menu-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.menu-toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(calc(-1 * var(--burger-pitch))) rotate(-45deg);
}
/* Project pages: the burger folds into its bottom line with the scroll %
   above it (main.js adds .is-pct 0.4s in, as "← Back" pushes the logo
   out, and removes it on the lobby as the logo returns; the lobby adds it
   again from the middle of the Work section on). The top two lines
   drop onto the bottom one and fade; the % rises into place. Opening the
   menu unfolds it into the × as usual. */
.menu-toggle__pct { display: none; }
.menu-toggle .menu-toggle__pct {
  position: absolute;
  left: 50%;
  bottom: calc(50% - var(--burger-pitch) + var(--burger-stroke) / 2 + 3px);   /* 3px above the bottom line */
  display: block;
  width: auto;
  height: auto;
  background: none;
  border-radius: 0;
  translate: -50% 4px;
  opacity: 0;
  font-size: 11px;
  font-weight: 500;
  line-height: 1;
  color: var(--dark-2);
  font-variant-numeric: tabular-nums;   /* steady width while it changes */
  white-space: nowrap;
  pointer-events: none;
}
.menu-toggle:has(.menu-toggle__pct) span {
  transition: transform 0.35s var(--ease-out), translate var(--head-swap), opacity var(--head-swap), width var(--head-swap);
}
.menu-toggle:has(.menu-toggle__pct) span:nth-child(3) { align-self: center; }   /* widens from its centre */
.menu-toggle.is-pct:not([aria-expanded="true"]) span:nth-child(3) { width: 22px; }   /* under the % at any value */
.menu-toggle.is-pct:not([aria-expanded="true"]) span:nth-child(1) { translate: 0 calc(2 * var(--burger-pitch)); opacity: 0; }
.menu-toggle.is-pct:not([aria-expanded="true"]) span:nth-child(2) { translate: 0 var(--burger-pitch); opacity: 0; }
.menu-toggle.is-pct:not([aria-expanded="true"]) .menu-toggle__pct { translate: -50% 0; opacity: 1; }
.menu-toggle.is-instant span { transition: none; }
/* One stroke width for every header icon, whatever size each is drawn at:
   the moon/sun, the burger's lines and the arrows (filled shapes, thickened
   by an outline to the same weight) */
:root {
  --icon-stroke: 1.5px;
  --burger-stroke: 1.5px;
}
.theme-toggle__icon svg path,
.theme-toggle__static,
.theme-toggle__static * {
  stroke-width: var(--icon-stroke);
  vector-effect: non-scaling-stroke;
}
.site-header .arrow {
  stroke: currentColor;
  stroke-width: calc(var(--icon-stroke) - 1.29px);   /* the arrow's own bar is 1.29px */
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
}
.contacts-toggle .arrow { stroke-width: 0.13px; }   /* 1.42px: a touch lighter next to the text */

/* Larger click/tap targets: an invisible ::after stretches each header item
   into the space around it — sideways up to the neighbouring separator (every
   pair of items has one between them, so targets never overlap) and most of
   the header's height — without changing the visible layout. */
:root {
  --hit-x: 23px;   /* the 24px desktop gap, stopping just short of the separator */
  --hit-h: 64px;   /* of the 80px desktop header */
}
.site-header__inner > .logo,
.top-nav > .top-link,
.top-nav > .theme-toggle,
.top-nav > .menu-toggle { position: relative; }
.site-header__inner > .logo::after,
.top-nav > .top-link::after,
.top-nav > .theme-toggle::after,
.top-nav > .menu-toggle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: calc(-1 * var(--hit-x));
  right: calc(-1 * var(--hit-x));
  height: var(--hit-h);
  transform: translateY(-50%);
}

/* Theme switch: moon in light (→ go dark), sun in dark (→ go light) */
.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  color: var(--dark-2);
  transition: color 0.2s;
}
/* Mouse only: on phones a tap would leave the icon stuck in its hover
   colour, out of step with the burger */
@media (hover: hover) { .theme-toggle:hover { color: var(--black); } }
.theme-toggle__icon {
  grid-area: 1 / 1;
  width: 26px;
  height: 26px;
  display: none;
}
:root:not([data-theme="dark"]) .theme-toggle__moon,
:root[data-theme="dark"] .theme-toggle__sun { display: block; }
/* Lottie draws black strokes; follow the text colour in both themes */
.theme-toggle__icon svg path { stroke: currentColor; }
.theme-toggle__static {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.theme-toggle.has-lottie .theme-toggle__static { display: none; }

/* Theme switch: instant (main.js). Colour transitions are off for that
   moment, so every element changes in the same frame */
html.theme-switching *,
html.theme-switching *::before,
html.theme-switching *::after { transition: none !important; }



/* Phones/tablets: "scroll" hint at the bottom right of the hero (shown in
   the Responsive section); the chevrons nudge down every 2s */
.scroll-hint { display: none; }
.scroll-hint__text {
  writing-mode: vertical-rl;
  /* reads top → bottom; the capitals centre on the pill as they are
     (measured on the rendered pixels) */
  font-size: 9px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  white-space: nowrap;
  /* the trailing letter-space after the last letter would push the word
     away from the pill, so pull it back */
  margin-bottom: -0.12em;
}
/* Chevrons sit in a vertical pill outlined at the same weight as their
   strokes; nudged up 2px so their 4px dip stays centred in it */
.scroll-hint__pill {
  display: grid;
  place-items: center;
  width: 16px;
  height: 32px;
  /* a step softer than the chevrons, so the outline doesn't compete */
  border: 1.5px solid color-mix(in srgb, currentColor 55%, transparent);
  border-radius: 999px;
}
.scroll-hint__chevrons {
  translate: 0 -1.5px;
  width: 8px;
  height: 10px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
}
/* Going down, the upper chevron follows the lower one 0.12s (6%) behind;
   the lower one waits at the bottom, then both rise back together.
   Sine-like in/out ease on every segment for soft turnarounds */
.scroll-hint__chevrons path:nth-child(2) {
  animation: scroll-nudge-lead 2s cubic-bezier(.45, 0, .55, 1) infinite;
}
.scroll-hint__chevrons path:nth-child(1) {
  animation: scroll-nudge-follow 2s cubic-bezier(.45, 0, .55, 1) infinite;
}
@keyframes scroll-nudge-lead {
  0%, 40% { transform: translateY(0); }
  62%, 68% { transform: translateY(4px); }
  100% { transform: translateY(0); }
}
@keyframes scroll-nudge-follow {
  0%, 46% { transform: translateY(0); }
  68% { transform: translateY(4px); }
  100% { transform: translateY(0); }
}


/* =========================================================
   Sidebar
   ========================================================= */
.sidebar {
  position: fixed;
  inset: 0;
  z-index: 10;
  pointer-events: none;
}
.sidebar__inner {
  position: relative;
  height: 100%;
}

.section-nav {
  position: absolute;
  top: calc(50% - 6px);
  left: 33px;
  transform: translateY(-50%);
  pointer-events: auto;
}
.section-nav ul {
  display: grid;
  gap: 15px;
}
.section-nav a {
  display: block;
  font-size: 16px;
  line-height: 1;
  color: var(--grey);
  transition: color 0.25s, font-weight 0.25s;
}
/* Hover looks exactly like the current section */
.section-nav a:hover,
.section-nav a[aria-current="true"] {
  color: var(--active, var(--dark-2));
  font-weight: 700;
}
/* Secondary items (e.g. the products under Core products): a dropdown of
   smaller, indented links. main.js opens it while that section is on
   screen; the chevron opens / closes it by hand */
.section-nav__row {
  display: flex;
  align-items: center;
}
/* The chevron sits at the start of its (larger) click area. Turned 45°, it
   is wider than its box by 1.24px a side, so 5.24px of padding puts its tip
   4px after the text */
.section-nav__toggle {
  display: grid;
  place-items: center start;
  width: 22px;
  height: 22px;
  margin: -3px 0;
  padding: 0 0 0 5.24px;
  border: 0;
  background: none;
  color: var(--grey);
  cursor: pointer;
}
.section-nav__toggle::before {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.25s;
}
.section-nav__toggle[aria-expanded="true"]::before { transform: translateY(2px) rotate(225deg); }
.section-nav__toggle:hover { color: var(--active, var(--dark-2)); }
.section-nav__drop {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.3s ease;
}
.section-nav__drop.is-open { grid-template-rows: 1fr; }
.section-nav .section-nav__sub {
  min-height: 0;
  overflow: hidden;
  gap: 12px;
  padding-left: 14px;
}
.section-nav__sub > li:first-child { margin-top: 12px; }
.section-nav__sub a { font-size: 15px; }
/* Closed: its links can't be reached by Tab */
.section-nav__drop:not(.is-open) .section-nav__sub { visibility: hidden; transition: visibility 0s 0.3s; }
/* Product headings jumped to from the nav: a little room above */
.fr-p[id] { scroll-margin-top: 48px; }

.based {
  position: absolute;
  left: 21px;   /* in line with the logo and footer text (they sit 1px in from a border) */
  /* --footer-lift (main.js) raises it above the footer at the page end */
  bottom: calc(22px + var(--footer-lift, 0px));
  display: grid;
  gap: 8px;
  pointer-events: auto;
}

/* Project pages, desktop: the sidebar is a hidden nav in the margin left of the grid.
   Closed, each link is a short dash (the current one darker); hovering it
   (or tabbing into it) opens a card with the names. The card's width grows
   from the dash column to fit the names, uncovering them as it goes. */
@media (min-width: 1000px) {
  .page-case { interpolate-size: allow-keywords; }   /* lets width ease to max-content */
  .page-case .sidebar__inner { overflow: visible; }
  .page-case .sidebar .based { display: none; }   /* "Based in" lives in the mobile menu */
  /* Scroll percentage under the closed dashes (main.js places it) */
  .page-case .scroll-pct {
    position: absolute;
    translate: -50% 0;
    margin: 0;
    font-size: 12px;
    line-height: 1;
    color: var(--grey);
    font-variant-numeric: tabular-nums;   /* steady width while it changes */
    white-space: nowrap;
    pointer-events: none;
    transition: opacity 0.25s;
  }
  .page-case .section-nav:is(:hover, :focus-within) ~ .scroll-pct { opacity: 0; }

  .page-case .sidebar .section-nav {
    --dash: 14px;
    --pad: 16px;
    /* the dashes end 30px before the grid's left line, or closer, centred
       in the margin, when the margin is narrower than that allows */
    --gap: min(30px, ((100vw - var(--vis)) / 2 - var(--dash)) / 2);
    left: calc(-1 * var(--gap) - var(--dash) - var(--pad) - 1px);
    width: calc(var(--dash) + 2 * var(--pad) + 2px);
    padding: 20px var(--pad);
    overflow: clip;
    border: 1px solid transparent;
    border-radius: 16px;
    transition: width 0.35s var(--ease-out), background-color 0.25s, border-color 0.25s, box-shadow 0.25s;
  }
  .page-case .sidebar .section-nav:is(:hover, :focus-within) {
    width: max-content;
    background: var(--bg);
    border-color: var(--separator);
    box-shadow: var(--shadow-pop);
  }
  .page-case .sidebar .section-nav :is(ul, .section-nav__sub) { gap: 4px; transition: gap 0.35s var(--ease-out); }
  .page-case .sidebar .section-nav:is(:hover, :focus-within) ul { gap: 15px; }
  .page-case .sidebar .section-nav:is(:hover, :focus-within) .section-nav__sub { gap: 12px; }

  .page-case .sidebar .section-nav a {
    display: flex;
    align-items: center;
    height: 10px;
    white-space: nowrap;
    transition: color 0.25s, height 0.35s var(--ease-out);
  }
  .page-case .sidebar .section-nav:is(:hover, :focus-within) a { height: 17px; }
  .page-case .sidebar .section-nav:is(:hover, :focus-within) .section-nav__sub a { height: 15px; }
  .page-case .sidebar .section-nav:not(:hover, :focus-within) a { color: transparent; }
  .page-case .sidebar .section-nav ul a::before {
    content: "";
    flex: none;
    width: var(--dash);
    height: 1.5px;
    margin-right: 12px;
    border-radius: 1px;
    background: var(--grey);
    opacity: 0.6;
    transition: width 0.35s var(--ease-out), margin 0.35s var(--ease-out), opacity 0.25s, background-color 0.25s;
  }
  .page-case .sidebar .section-nav ul a[aria-current="true"]::before { background: var(--active, var(--dark-2)); opacity: 1; }
  .page-case .sidebar .section-nav:is(:hover, :focus-within) ul a::before { width: 0; margin-right: 0; opacity: 0; }

  /* Secondary items: shorter, indented dashes */
  .page-case .sidebar .section-nav .section-nav__sub { padding-left: 5px; transition: gap 0.35s var(--ease-out), padding 0.35s var(--ease-out); }
  .page-case .sidebar .section-nav .section-nav__sub a::before { width: calc(var(--dash) - 5px); }
  .page-case .sidebar .section-nav .section-nav__sub > li:first-child { margin-top: 4px; transition: margin 0.35s var(--ease-out); }
  .page-case .sidebar .section-nav:is(:hover, :focus-within) .section-nav__sub { padding-left: 14px; }
  .page-case .sidebar .section-nav:is(:hover, :focus-within) .section-nav__sub > li:first-child { margin-top: 12px; }
  .page-case .sidebar .section-nav:not(:hover, :focus-within) .section-nav__toggle { visibility: hidden; }

}
.based__label { font-size: 13px; line-height: 1; color: var(--grey); margin-bottom: 3px; }
.based__city { font-size: 14px; line-height: 1; font-weight: 500; color: var(--dark-2); }
.based__time { font-size: 13px; line-height: 1; color: var(--grey); font-variant-numeric: tabular-nums; }

/* =========================================================
   Hero
   Positions are expressed in container units so the composition
   scales exactly like the 1240px Framer frame.
   ========================================================= */
.hero__shell { container-type: inline-size; }

.hero {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: var(--header-h) 0 26px;
}

.hero__stage {
  position: relative;
  height: calc(356 / 1240 * 100cqw);
  --u: calc(100cqw / 1240);   /* 1 Framer px at the current scale */
}

.hero__title {
  position: absolute;
  top: 0;
  left: calc(213 * var(--u));
  font-weight: 700;
  white-space: nowrap;
}
.hero__title > span { display: block; }
.hero__hi {
  font-size: calc(86 * var(--u));
  line-height: 1.1;
  letter-spacing: -0.009em;
  color: var(--grey);
}
.hero__name {
  font-size: calc(120 * var(--u));
  line-height: 1.1;
  letter-spacing: -0.009em;
  color: var(--black);
}

.hero__extra {
  position: absolute;
  top: calc(271 * var(--u));
  left: calc(418 * var(--u));
  /* Column ends 32px before the photo (photo starts at 924) so longer lines
     wrap instead of running underneath it */
  max-width: calc((924 - 32 - 418) * var(--u));
  display: grid;
  gap: 10px;
  font-size: clamp(16px, calc(19 * var(--u)), 19px);
  line-height: 1.2;
  color: var(--grey);
}
.hero__extra p:first-child { letter-spacing: 0.005em; }
.hero__extra p:last-child { letter-spacing: -0.005em; }
.hero__extra strong { font-weight: 500; color: var(--active, var(--dark-2)); }
.inline-link {
  display: inline-flex;
  align-items: flex-start;
  gap: 2px;
}
.inline-link strong {
  background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition: background-size 0.35s var(--ease-out), color 0.2s;
}
.inline-link .arrow { width: 9px; height: 8px; margin-top: 2px; }
.inline-link:hover strong { background-size: 100% 1px; color: var(--black); }
.inline-link:hover .arrow { transform: rotate(135deg) translateX(-2px); }

.hero__photo {
  position: absolute;
  top: calc(57 * var(--u));
  left: calc(924 * var(--u));
  width: calc(230 * var(--u));
  aspect-ratio: 230 / 299;
  border-radius: 12px;
  overflow: hidden;
  background: var(--photo-bg);
  border: 1px solid var(--photo-border);
}
.hero__photo picture { display: contents; }
.hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.8s var(--ease-out);
}
.hero__photo:hover img { transform: scale(1.03); }

/* Figma-style multiplayer cursor */
.figma-cursor {
  position: absolute;
  top: calc(-46 * var(--u));
  left: calc(835 * var(--u));
  z-index: 2;
  pointer-events: none;
  transform: translate(var(--cx, 0px), var(--cy, 0px));
  will-change: transform;
}
.figma-cursor__icon {
  display: block;
  width: 12px;
  height: 12px;
  fill: var(--figma-blue);
  stroke: rgba(255, 255, 255, 0.35);
  stroke-width: 1;
}
.figma-cursor__label {
  position: absolute;
  top: 11px;
  left: 14px;
  padding: 5px 8px 6px;
  border-radius: 4px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: var(--figma-label);
  color: #f8f8f8;   /* stays light on the blue label in both themes */
  font-size: 12px;
  line-height: 1.1;
  white-space: nowrap;
  transform-origin: 0 0;
}

/* =========================================================
   Work
   Four project cards spanning columns 2–6. Sizes are Framer px of the
   1240px frame (--u), so the cards scale exactly like the hero.
   ========================================================= */
.work__shell {
  container-type: inline-size;
  --u: calc(100cqw / 1240);
}
.work {
  --u: var(--px);   /* same scale as the shell */
  /* 260 Framer px below the hero in total; the part inside the section
     is what's left under the header when "Work" is clicked in the nav */
  margin-top: calc(180 * var(--u));
  padding: calc(80 * var(--u)) 0 calc(120 * var(--u));
}
/* Section label: on desktop it's for screen readers only (the sidebar
   names the sections); on phones it opens each section as a cell in the
   first grid column (see the phone styles) */
.section-label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  margin: 0;
}

.work__list {
  display: grid;
  gap: calc(80 * var(--u));
  /* Columns 2–6, 1px clear of the grid lines on either side */
  margin-left: calc(212 * var(--u) + 1px);
  margin-right: 1px;
}

.work-card {
  display: grid;
  align-items: stretch;
  /* Hairlines above and below, in the inner grid lines' colour */
  border-block: 1px solid var(--line);
  gap: calc(30 * var(--u));
  padding: calc(30 * var(--u));
  background: var(--card-bg);
}
/* Column widths and image shapes per card, from the original */
.work-card--platform { grid-template-columns: 332fr 609fr; column-gap: calc(25 * var(--u)); }
.work-card--platform .work-card__media { aspect-ratio: 609 / 400; }
.work-card--betslip  { grid-template-columns: 455fr 481fr; }
.work-card--betslip .work-card__media { aspect-ratio: 455 / 442; }
.work-card--bonus    { grid-template-columns: 458fr 478fr; }
.work-card--bonus .work-card__media { aspect-ratio: 478 / 440; }
.work-card--archive  { grid-template-columns: 301fr 635fr; }
.work-card--archive .work-card__media { aspect-ratio: 635 / 440; }
/* The image comes first in the markup (it leads on phones); on desktop
   it sits on the right, except for the betslip card */
.work-card:not(.work-card--betslip) .work-card__media { order: 2; }

.work-card__media {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
  background: var(--photo-bg);
}
.work-card__media picture { display: contents; }
.work-card__media img,
.work-card__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.8s var(--ease-out);
}
.work-card:hover .work-card__media img,
.work-card:hover .work-card__video { transform: scale(1.03); }
/* Soft inner edge on every project image */
.work-card__media::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: var(--shadow-inset);
  pointer-events: none;
}
/* The video covers its still once it is actually playing. It starts a
   screen ahead of the card (main.js), so the swap is never seen; no fade,
   a crossfade between the two different frames reads as a blink */
.work-card__video { visibility: hidden; }
.work-card__video.is-playing { visibility: visible; }

.work-card__body {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 24px;
  min-width: 0;
}
.work-card__title {
  margin: 0;
  font-size: clamp(30px, calc(44 * var(--u)), 44px);
  line-height: 1.2;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--black);
}
.work-card__desc {
  margin-top: 16px;
  font-size: clamp(15px, calc(18 * var(--u)), 18px);
  line-height: 1.2;
  color: var(--grey);
  text-wrap: pretty;
}

.work-card__foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}
/* Betslip and bonus cards: list on the left, button bottom-right */
.work-card--betslip .work-card__foot,
.work-card--bonus .work-card__foot {
  flex-direction: row;
  flex-wrap: wrap;   /* button drops under the list on narrow screens */
  align-items: flex-end;
  justify-content: space-between;
}
.work-card--archive .work-card__foot { gap: 19px; }
.work-card__facts { display: grid; gap: 10px; }
.work-card__facts ul { display: grid; gap: 8px; }
.work-card__label {
  font-size: clamp(13px, calc(15 * var(--u)), 15px);
  line-height: 1;
  color: var(--grey);
}
.work-card__facts li {
  font-size: clamp(14px, calc(16 * var(--u)), 16px);
  line-height: 1.1;
  color: var(--dark-2);
}

/* "View Project": black pill; on hover it turns light and the arrow
   slides out to the right while a fresh one slides in from the left */
.btn-project {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding: 0 26px 0 32px;
  border-radius: 6px;
  background: var(--black);
  color: var(--inverse-fg);
  font-size: 18px;
  line-height: 1;
  white-space: nowrap;
  transition: background-color 0.3s var(--ease-out), color 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out);
}
.btn-project__arrows {
  position: relative;
  width: 24px;
  height: 9px;
  margin-left: 2px;
  overflow: hidden;
}
.btn-project .arrow {
  position: absolute;
  top: 0;
  left: 6px;
  color: currentColor;
  transform: rotate(180deg);   /* source points left */
  transition: translate 0.45s var(--ease-out);
}
.btn-project .arrow:last-child { translate: -30px 0; }
.btn-project:hover {
  background: var(--card-bg);
  color: var(--black);
  box-shadow: inset 0 0 0 1px var(--black);
}
.btn-project:hover .arrow { translate: 30px 0; }
.btn-project:hover .arrow:last-child { translate: 0 0; }

/* Cards slide up (fully opaque, no fade) as they scroll into view
   (class set by main.js, so without JavaScript they simply sit in place).
   A longer rise with a gentle ease so the movement is actually seen. */
.has-reveal .work-card {
  transition: transform 1.2s cubic-bezier(0.25, 0.8, 0.3, 1);
}
.has-reveal .work-card:not(.is-in) {
  transform: translateY(90px);
}

/* =========================================================
   Values
   A stage on the 1240px frame like the hero: big words on the left,
   the Values | Motivation switch and its text on the right, social
   links bottom-left. Positions are Framer px (--u).
   ========================================================= */
.values__shell {
  container-type: inline-size;
  --u: calc(100cqw / 1240);
}
.values {
  --u: var(--px);   /* for the margin below */
  margin-top: calc(452 * var(--u));   /* ~600 Framer px after the last card, as on the original */
}
.values__stage {
  position: relative;
  height: calc(896 * var(--u));
  /* How far each line travels when the sets swap: they move together
     but over different distances, so they read as a staggered wave */
  --shift-0: calc(550 * var(--u));
  --shift-1: calc(860 * var(--u));
  --shift-2: calc(1170 * var(--u));
  --swap: 1.3s cubic-bezier(0.32, 0.12, 0.12, 1);
}

/* A window from the 2nd grid line to just before the text column (as on
   the original): lines slide out under its left edge and in from its
   right edge, and the set that's waiting stays out of sight */
.values__words {
  position: absolute;
  top: calc(30 * var(--u));
  left: calc(212 * var(--u));
  width: calc(410 * var(--u));
  height: calc(320 * var(--u));
  overflow: hidden;
}
.values__set { margin: 0; }
.values__line {
  position: absolute;
  top: 0;
  left: calc(1 * var(--u));   /* just clear of the 2nd grid line, like the hero title */
  font-size: calc(80 * var(--u));
  line-height: 1.2;
  font-weight: 700;
  white-space: nowrap;
  color: var(--black);
  transition: transform var(--swap);
}
.values__line:nth-child(2) { top: calc(112 * var(--u)); }
.values__line:nth-child(3) { top: calc(224 * var(--u)); }
.values__line:nth-child(1) { --shift: var(--shift-0); }
.values__line:nth-child(2) { --shift: var(--shift-1); }
.values__line:nth-child(3) { --shift: var(--shift-2); }
/* First set (Motivation) shows by default; the second (Values) waits off
   to the right. Choosing the second tab slides the first out to the left
   and the second in; going back reverses it. */
.values__set--second .values__line { transform: translateX(var(--shift)); }
.values.is-second .values__set--first .values__line { transform: translateX(calc(-1 * var(--shift))); }
.values.is-second .values__set--second .values__line { transform: none; }

.values__about {
  position: absolute;
  top: calc(440 * var(--u));
  left: calc(623 * var(--u));
  width: calc(542 * var(--u));
}
.values__tabs {
  display: flex;
  gap: calc(30 * var(--u));
}
.values__tab {
  padding: 0;
  font-size: clamp(16px, calc(18 * var(--u)), 18px);
  line-height: 1.2;
  color: var(--dark-2);
  opacity: 0.5;
  transition: opacity 0.3s var(--ease-out);
}
.values__tab:hover { opacity: 0.8; }
.values__tab[aria-selected="true"] { opacity: 1; font-weight: 600; }
/* Both texts share one grid cell, so the block keeps the height of the
   longer one and the swap is a crossfade with no jump */
.values__panels {
  display: grid;
  margin-top: 20px;
}
.values__panel {
  grid-area: 1 / 1;
  font-size: clamp(16px, calc(18 * var(--u)), 18px);
  line-height: 1.8;
  color: var(--grey);
  text-wrap: pretty;
  transition: opacity 0.4s var(--ease-out), visibility 0s;
}
.values__panel.is-hidden {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s var(--ease-out), visibility 0s 0.25s;
}

.values__links {
  position: absolute;
  top: calc(722 * var(--u));
  left: calc(212 * var(--u) + 1px);
  display: grid;
  justify-items: start;   /* rows only as wide as their link, so the
                             slide-in offset never pokes past the screen */
  gap: 6px;
}
.values__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  font-size: clamp(15px, calc(17 * var(--u)), 17px);
  line-height: 1.2;
  color: var(--dark-2);
  transition: color 0.2s;
}
.values__link .arrow { width: 10px; height: 8px; }
.values__link:hover { color: var(--black); font-weight: 600; }
.values__link:hover .arrow { color: var(--black); transform: rotate(135deg) translateX(-3px); }
/* Links slide in from the right one after another as the section
   scrolls into view (class set by main.js) */
.has-reveal .values__links li {
  transition: transform 0.7s calc(var(--i) * 70ms) var(--ease-out);
}
.has-reveal .values:not(.is-in) .values__links li {
  transform: translateX(calc(30px + var(--i) * 10px));
}

/* =========================================================
   Inspiration
   Big heading top-left, intro text on the right, a photo that changes
   with the topic hovered in the list beside it. Framer px (--u).
   ========================================================= */
.inspo__shell {
  container-type: inline-size;
  --u: calc(100cqw / 1240);
}
.inspo {
  --u: var(--px);
  margin-top: calc(572 * var(--u));   /* same gap as the original */
}
.inspo__stage {
  position: relative;
  height: calc(1150 * var(--u));
}

.inspo__heading {
  position: absolute;
  top: 0;
  left: calc(213 * var(--u));
  margin: 0;
  font-size: calc(80 * var(--u));
  line-height: 1.2;
  font-weight: 700;
  white-space: nowrap;
  color: var(--black);
}
.inspo__muted { color: var(--grey); }

.inspo__text {
  position: absolute;
  top: calc(303 * var(--u));
  left: calc(826 * var(--u));
  width: calc(381 * var(--u));
  font-size: clamp(16px, calc(18 * var(--u)), 18px);
  line-height: 1.8;
  color: var(--grey);
  text-wrap: pretty;
}

.inspo__photo {
  position: absolute;
  top: calc(500 * var(--u));
  left: calc(324 * var(--u));
  width: calc(406 * var(--u));
}
.inspo__frame {
  position: relative;
  aspect-ratio: 406 / 619;
  overflow: hidden;
  border-radius: 6px;
  border: 1px solid var(--line);   /* the colour of the middle grid lines */
  background: var(--photo-bg);
}
/* All photos are stacked; the active one fades in over the others */
.inspo__img {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.5s var(--ease-out);
}
.inspo__img.is-active { opacity: 1; }
.inspo__img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Captions share one grid cell and crossfade like the photos. The row
   is clipped just under the photo and starts tucked up out of sight, so
   the first topic chosen slides it down as if from behind the photo; its
   height is kept from the start, so nothing below moves. */
.inspo__captions {
  display: block;
  padding-top: 10px;   /* padding, not margin: the clip edge is the photo's bottom */
  overflow: hidden;
}
.inspo__captions-track {
  display: grid;
  transform: translateY(calc(-100% - 12px));
  transition: transform 0.6s var(--ease-out);
}
.inspo__photo.is-captioned .inspo__captions-track { transform: none; }
.inspo__caption {
  grid-area: 1 / 1;
  font-size: 16px;
  line-height: 1.2;
}
/* The fade is a change of text colour, not of opacity: every word is
   repainted together each frame, so the bold and regular ones can't drift
   apart (with an opacity fade Safari paints the bold run first). Both
   parts share one timing; hidden captions are also out of reach of
   screen readers once faded. */
.inspo__caption,
.inspo__caption strong {
  color: transparent;
  visibility: hidden;
  transition: color 0.25s var(--ease-out), visibility 0s 0.25s;
}
.inspo__caption strong { font-weight: 600; }
.inspo__caption.is-active,
.inspo__caption.is-active strong {
  visibility: visible;
  transition: color 0.4s var(--ease-out), visibility 0s;
}
.inspo__caption.is-active { color: var(--grey); }
.inspo__caption.is-active strong { color: var(--black); }

/* Topics: bottom-aligned with the photo */
.inspo__topics {
  justify-items: start;
  position: absolute;
  top: calc(1119 * var(--u));
  left: calc(826 * var(--u));
  translate: 0 -100%;
  display: grid;
  gap: 2px;
}
.inspo__topic {
  display: block;
  height: 30px;
  padding: 0;
  font-size: clamp(15px, calc(17 * var(--u)), 17px);
  line-height: 1.2;
  color: var(--dark-2);
  transition: color 0.2s;
}
.inspo__topic[aria-pressed="true"] { color: var(--black); font-weight: 600; }
/* Mouse only: a phone keeps the last tapped button "hovered", which would
   leave it dark after tapping it again to go back to the portrait */
@media (hover: hover) and (pointer: fine) {
  .inspo__topic:hover { color: var(--black); font-weight: 600; }
}
/* Desktop only: the topics slide in one after another, like the Values
   links (main.js sets `is-in` when scrolled down to them) */
/* Desktop: each topic's hover area fills its row across the whole column
   (to the next grid line) with no gaps between rows, so moving from one
   topic to the next never leaves the list; leaving it brings the portrait
   back (main.js). Same 32px rhythm as before (30px rows + 2px gaps). */
@media (min-width: 1000px) {
  .inspo__topics { gap: 0; justify-items: stretch; width: calc(202 * var(--u)); }
  .inspo__topic { width: 100%; height: 32px; text-align: left; }
}
@media (min-width: 1000px) {
  .has-reveal .inspo__topics li {
    transition: transform 0.7s calc(var(--i) * 55ms) var(--ease-out);
  }
  .has-reveal .inspo:not(.is-in) .inspo__topics li {
    transform: translateX(calc(25px + var(--i) * 5px));
  }
}

/* =========================================================
   Photos
   Heading, then a wide strip of photos laid out like a collage
   (positions from the original, in Framer px) that scrolls sideways.
   ========================================================= */
.photos__shell {
  container-type: inline-size;
  --u: calc(100cqw / 1240);
}
.photos {
  --u: var(--px);
  margin-top: calc(494 * var(--u));   /* same gap as the original */
}
.photos__stage {
  position: relative;
  height: calc(1238 * var(--u));
  --pu: var(--u);   /* 1 strip px: the photos scale with the page */
}
.photos__heading {
  position: absolute;
  top: calc(50 * var(--u));
  left: calc(213 * var(--u));
  margin: 0;
  font-size: calc(80 * var(--u));
  line-height: 1.2;
  font-weight: 700;
  white-space: nowrap;
  color: var(--black);
}
.photos__muted { color: var(--grey); }

/* Spans columns 2–6, clipped at the 2nd and the outer grid lines */
.photos__gallery {
  position: absolute;
  top: calc(342 * var(--u));
  left: calc(212 * var(--u) + 1px);
  right: 1px;
}
.photos__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 20px;
  padding-inline: 1px 44px;
}
.photos__label,
.photos__hint {
  font-size: 13px;
  line-height: 1.2;
}
.photos__label { font-weight: 400; color: var(--grey); }   /* same as the hint */
/* Desktop: the hint starts on the last column line, like the label on the
   2nd one; on a narrow window it grows leftwards rather than overflow */
@media (min-width: 1000px) {
  .photos__bar { padding-right: 0; }
  .photos__hint {
    width: calc(212 * var(--u) - 3px);
    min-width: max-content;
  }
}
/* Mouse wording by default, touch wording on touch screens */
.photos__hint-touch { display: none; }
@media (hover: none), (pointer: coarse) {   /* some Android phones claim hover */
  .photos__hint-mouse { display: none; }
  .photos__hint-touch { display: inline; }
}
.photos__hint {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 400;
  color: var(--grey);
}
/* The ↔ arrow in a horizontal pill, outlined at the arrow's weight */
.photos__hint-pill {
  display: grid;
  place-items: center;
  width: 28px;
  height: 15px;
  border: 1.3px solid color-mix(in srgb, currentColor 55%, transparent);   /* softer than the arrow */
  border-radius: 999px;
}
.photos__hint-pill svg {
  width: 13px;
  height: 6.5px;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The window onto the strip; main.js moves the track inside it */
.photos__scroller {
  /* Room above and below for the photos' shadows, which the clipping would
     otherwise cut off; the negative margins keep the layout where it was */
  --shadow-room: 24px;
  margin-top: calc(25 * var(--u) - var(--shadow-room));
  margin-bottom: calc(-1 * var(--shadow-room));
  padding-block: var(--shadow-room);
  overflow: hidden;
  touch-action: pan-y;   /* vertical swipes still scroll the page */
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}
.photos__scroller.is-dragging { cursor: grabbing; }
.photos__scroller:focus-visible { outline-offset: -2px; }
/* One set of photos is --loop strip px long (the last photo, then the
   usual 61px gap before the first comes round again); the copy sits
   right after it so the seam is never seen */
.photos__track {
  --loop: 8684;
  position: relative;
  height: calc(744 * var(--pu));
  will-change: transform;
}
.photos__set {
  position: absolute;
  top: 0;
  left: 0;
  width: calc(var(--loop) * var(--pu));
  height: 100%;
}
.photos__set + .photos__set { left: calc(var(--loop) * var(--pu)); }
.photos__item {
  position: absolute;
  left: calc(var(--x) * var(--pu));
  top: calc(var(--y) * var(--pu));
  width: calc(var(--w) * var(--pu));
  height: calc(var(--h) * var(--pu));
  margin: 0;
  overflow: hidden;
  border-radius: 12px;
  background: var(--photo-bg);
  box-shadow: var(--shadow-photo);   /* lifts it off the page a little */
}
.photos__item picture { display: contents; }
.photos__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-user-drag: none;
}

/* =========================================================
   Experience
   Company name, then its roles: title from the 3rd grid line, dates
   from the 6th, details as a bulleted list under the title.
   Framer px (--u), flowing rather than absolutely placed.
   ========================================================= */
.exp__shell {
  container-type: inline-size;
  --u: calc(100cqw / 1240);
}
.exp {
  --u: var(--px);
  margin-top: calc(572 * var(--u));   /* same gap as the original */
  padding-bottom: calc(160 * var(--u));
}
.exp__company + .exp__company { margin-top: calc(121 * var(--u)); }
.exp__name {
  margin: 0 0 0 calc(213 * var(--u));
  font-size: calc(80 * var(--u));
  line-height: 1.2;
  font-weight: 700;
  color: var(--black);
}
.exp__roles {
  margin: calc(60 * var(--u)) 0 0;
  padding: 0;
  list-style: none;
}
.exp__role {
  display: grid;
  grid-template-columns: calc((1032 - 421) * var(--u)) 1fr;
  align-items: center;
  padding-left: calc(421 * var(--u));   /* just after the 3rd grid line */
}
.exp__role + .exp__role { margin-top: calc(41 * var(--u)); }
.exp__title {
  margin: 0;
  font-size: clamp(24px, calc(32 * var(--u)), 32px);
  line-height: 1.2;
  font-weight: 500;
  color: var(--black);
}
.exp__dates {
  font-size: clamp(14px, calc(16 * var(--u)), 16px);
  line-height: 1.2;
  color: var(--grey);
  white-space: nowrap;
}
.exp__details {
  grid-column: 1;
  display: grid;
  gap: calc(18 * var(--u));
  margin: calc(40 * var(--u)) 0 0;
  padding: 0 calc(16 * var(--u)) 0 16px;
  list-style: none;
}
.exp__details li {
  position: relative;
  font-size: 16px;
  line-height: 1.2;
  color: var(--dark-2);
  text-wrap: pretty;
}
.exp__details li::before {
  content: "";
  position: absolute;
  top: 0.5em;
  left: -11px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--grey);
}

/* =========================================================
   Footer
   A mirror of the header: a 60px bar closed off by the separator line
   on top, credits left, a little joke centred, the version right.
   ========================================================= */
.site-footer { margin-top: calc(180 * var(--px)); }
.site-footer__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: 60px;
  padding: 0 33px 0 20px;   /* same as the header: lines up with the logo and "Based in" */
  background: var(--bg);
  border-top: 1px solid var(--separator);
  border-inline: 1px solid var(--separator);
  font-size: 14px;
  line-height: 1.2;
}
.site-footer__by,
.site-footer__coded { font-weight: 500; color: var(--black); }
.site-footer__coded {
  justify-self: end;
  display: inline-flex;
  align-items: baseline;
  gap: 0.3em;
}
/* The wordmark's tall letters match the text's "l" and "Y", and its
   bottom sits on the text baseline (the spark dips a little below).
   A thin outline gives the serif the weight of the medium-weight name. */
.site-footer__claude {
  width: auto;
  height: 0.93em;
  margin-bottom: -0.08em;
}
.site-footer__claude path:last-child {
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linejoin: round;
}
.site-footer__dim { font-weight: 400; color: var(--grey); }
.site-footer__smile { color: var(--grey); }
.site-footer__br { display: none; }   /* phones only */
.site-footer__smile a {
  font-weight: 500;
  color: var(--black);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: text-underline-offset 0.2s var(--ease-out);
}
.site-footer__smile a:hover { text-underline-offset: 4px; }

/* =========================================================
   Photo viewer (lightbox)
   A native <dialog>: the photo as large as fits, arrows either side, a
   close button top-right and a counter underneath. Dark in both themes.
   ========================================================= */
.photos__item { cursor: zoom-in; }
.photos__scroller.is-dragging .photos__item { cursor: grabbing; }

.photos__item:focus-visible { outline: 2px solid var(--figma-blue); outline-offset: 2px; }

.lightbox {
  position: fixed;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  /* 70% black over the page, which is blurred while the viewer is open
     (.viewer-open below; blurring the page itself works in every
     browser, unlike a backdrop-filter on the dialog) */
  background: rgba(0, 0, 0, 0.7);
  color: #f5f5f5;
  overflow: hidden;
}
.lightbox::backdrop { background: transparent; }
/* (not the footer: blurring it paints a black square in Safari's
   top-left corner; it is far off screen while the viewer is open anyway) */
.grid-bg, .site-header, .sidebar, main { transition: filter 0.3s var(--ease-out); }
.viewer-open :is(.grid-bg, .site-header, .sidebar, main) { filter: blur(14px); }
.lightbox[open] { animation: lightbox-in 0.3s var(--ease-out); }
@keyframes lightbox-in { from { opacity: 0; } }

.lightbox__figure {
  position: absolute;
  inset: 0;
  margin: 0;
  touch-action: pan-y;   /* sideways swipes change photo */
}
/* The photo is centred in the area left free by the buttons, the counter
   and the thumbnail row */
.lightbox__frame {
  position: absolute;
  inset: 72px 96px 144px;
  display: grid;
  place-items: center;
}
.lightbox__frame picture { display: contents; }
.lightbox__frame source { display: none; }   /* Safari would lay them out as rows */
.lightbox__frame img {
  max-width: 100%;
  max-height: calc(100vh - 216px);
  max-height: calc(100dvh - 216px);
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
  user-select: none;
  -webkit-user-drag: none;
  animation: lightbox-photo 0.35s var(--ease-out);
}
@keyframes lightbox-photo { from { opacity: 0; transform: scale(0.98); } }
/* Project pages: one picture, no arrows, counter or thumbnails, so it
   gets nearly the whole screen */
.lightbox--single .lightbox__frame { inset: 72px 72px 40px; }
.lightbox--single .lightbox__frame img {
  max-height: calc(100vh - 112px);
  max-height: calc(100dvh - 112px);
}
/* A whole block from "How we've built it" (main.js): a scaled copy of its
   part of the Framer canvas, on the page's background */
.lightbox__region {
  position: relative;
  container-type: inline-size;
  width: min(100%, calc((100dvh - 112px) * var(--ar)));
  aspect-ratio: var(--ar);
  overflow: hidden;
  border-radius: 26px;
  background: var(--bg);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
  color: var(--black);
  animation: lightbox-photo 0.35s var(--ease-out);
}
.lightbox__region > * { position: absolute; --fu: calc(100cqw / var(--rw)); }
.lightbox__region img { cursor: default; }
/* ...where its pictures keep their page layout, not the viewer's photo rules */
.lightbox--single .lightbox__region .fr-m { display: block; }
.lightbox--single .lightbox__region .fr-m img {
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  max-width: none;
  max-height: none;
  margin: -1px;
  border-radius: 0;
  box-shadow: none;
  animation: none;
}
/* Rounded corners hide the white corners of the screen captures */
.lightbox--single .lightbox__frame img { border-radius: 26px; }
/* ...unless it is one of a product's pictures (Sportsbook, Casino,
   Platform): then the Photos viewer's layout, with the product's name
   top left (arrows, counter, thumbnail row) */
.lightbox--single:not(.is-gallery) :is(.lightbox__nav, .lightbox__count, .lightbox__thumbs, .lightbox__title) { display: none; }
.lightbox--single.is-gallery .lightbox__frame { inset: 72px 96px 144px; }
.lightbox--single.is-gallery .lightbox__frame img {
  max-height: calc(100vh - 216px);
  max-height: calc(100dvh - 216px);
}
.lightbox__title {
  position: absolute;
  top: 16px;
  left: 24px;
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  line-height: 48px;   /* centred on the close button */
  color: #f5f5f5;
}
/* Tall phone screens: their thumbnails show the top of the screen */
.lightbox--single .lightbox__thumb img { object-position: top; }
/* Pictures that open in it */
.pj-zoomable { cursor: zoom-in; }

/* Thumbnail row along the bottom: every photo, the current one bright
   and kept in the middle (main.js), the rest dimmed; edges fade out */
.lightbox__thumbs {
  position: absolute;
  left: 50%;
  bottom: 24px;
  translate: -50% 0;
  display: flex;
  gap: 8px;
  width: min(760px, 100vw - 240px);
  padding: 4px 0;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.lightbox__thumbs::-webkit-scrollbar { display: none; }
/* Room either side so the first and last thumbnails can sit in the middle */
.lightbox__thumbs::before,
.lightbox__thumbs::after { content: ""; flex: 0 0 calc(50% - 30px); }
.lightbox__thumb {
  flex: none;
  width: 52px;
  height: 52px;
  padding: 0;
  overflow: hidden;
  border-radius: 6px;
  opacity: 0.4;
  transition: opacity 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.lightbox__thumb:hover { opacity: 0.75; }
.lightbox__thumb[aria-current="true"] {
  opacity: 1;
  box-shadow: 0 0 0 2px rgba(245, 245, 245, 0.9);
}
.lightbox__thumb picture { display: contents; }
.lightbox__thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-user-drag: none;
}
.lightbox__count {
  position: absolute;
  left: 50%;
  bottom: 96px;
  translate: -50% 0;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: rgba(245, 245, 245, 0.6);
}

.lightbox__btn {
  position: absolute;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: #f5f5f5;
  transition: background-color 0.2s;
}
.lightbox__btn:hover { background: rgba(255, 255, 255, 0.18); }
.lightbox__btn:focus-visible { outline-color: #f5f5f5; }
.lightbox__close { top: 16px; right: 16px; }
.lightbox__close svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}
.lightbox__nav { top: 50%; translate: 0 -50%; }
.lightbox__nav--prev { left: 24px; }
.lightbox__nav--next { right: 24px; }
.lightbox__nav .arrow { width: 14px; height: 11px; color: currentColor; }
.lightbox__nav--next .arrow { transform: rotate(180deg); }   /* source points left */

/* =========================================================
   Case study pages (case-*.html)
   Same header, grid, sidebar and footer as the home page. Section titles
   sit in the 2nd column; text and visuals run across columns 3–6.
   Framer px (--u) like the rest of the site.
   ========================================================= */
.cs__shell {
  container-type: inline-size;
  --u: calc(100cqw / 1240);
}
/* Placeholders to replace: tinted so they're easy to spot */
.ph {
  background: color-mix(in srgb, var(--figma-blue) 14%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--figma-blue) 14%, transparent);
  border-radius: 2px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}


/* --- Hero: eyebrow, title, lead, facts, "In short", image --- */
.cs-hero { padding: calc(var(--header-h) + 120 * var(--px)) 0 0; }
.cs-hero .cs__shell > * { margin-left: calc(213 * var(--u)); }
.cs-eyebrow {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--grey);
}
.cs-title {
  max-width: calc(860 * var(--u));
  margin: 20px 0 0;
  font-size: clamp(36px, calc(64 * var(--u)), 64px);
  line-height: 1.12;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--black);
  text-wrap: balance;
}
.cs-lead {
  max-width: calc(620 * var(--u));
  margin-top: 24px;
  font-size: clamp(17px, calc(20 * var(--u)), 20px);
  line-height: 1.5;
  color: var(--grey);
}
/* One fact per grid column (cols 2–6), each under a hairline */
.cs-glance {
  display: grid;
  grid-template-columns: 204fr 204fr 204fr 204fr 212fr;   /* the grid's own columns */
  margin: calc(72 * var(--u)) 0 0;
  margin-left: calc(212 * var(--u)) !important;
}
.cs-glance > div {
  padding: 14px calc(16 * var(--u)) 0 1px;
  border-top: 1px solid var(--separator);
}
.cs-glance dt { font-size: 13px; color: var(--grey); }
.cs-glance dd { margin: 6px 0 0; font-size: 16px; line-height: 1.35; color: var(--dark-2); }

.cs-tldr {
  max-width: calc(620 * var(--u));
  margin-top: calc(56 * var(--u));
  padding: 24px 28px;
  border-radius: 8px;
  background: var(--card-bg);
}
.cs-tldr__title {
  margin-bottom: 12px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--grey);
}
.cs-tldr strong { font-weight: 600; color: var(--black); }
.cs-hero .cs-figure { margin-top: calc(72 * var(--u)); margin-left: calc(212 * var(--u) + 1px) !important; margin-right: 1px; }

/* --- Sections: title in column 2 (sticks while reading), body in 3–6 --- */
.cs-section { padding-top: calc(160 * var(--px)); }
.cs-section__grid {
  display: grid;
  grid-template-columns: calc(204 * var(--u)) 1fr;
  padding-left: calc(213 * var(--u));
}
.cs-section__head {
  position: sticky;
  top: calc(var(--header-h) + 32px);
  align-self: start;
  padding-right: 24px;
}
.cs-section__num { font-size: 13px; font-variant-numeric: tabular-nums; color: var(--grey); }
.cs-section__title {
  margin: 8px 0 0;
  font-size: clamp(22px, calc(28 * var(--u)), 28px);
  line-height: 1.2;
  font-weight: 700;
  color: var(--black);
}
.cs-section__body {
  display: grid;
  gap: 24px;
  min-width: 0;
  padding-right: calc(80 * var(--u));
}
.cs-section__body > .cs-text,
.cs-section__body > .cs-list,
.cs-section__body > .cs-sub { max-width: calc(640 * var(--u)); }
.cs-text {
  font-size: clamp(16px, calc(18 * var(--u)), 18px);
  line-height: 1.7;
  color: var(--dark-2);
  text-wrap: pretty;
}
.cs-sub {
  margin: 24px 0 -8px;
  font-size: 20px;
  font-weight: 600;
  color: var(--black);
}
.cs-list {
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0 0 0 18px;
  list-style: none;
}
.cs-list li {
  position: relative;
  font-size: 16px;
  line-height: 1.55;
  color: var(--dark-2);
}
.cs-list li::before {
  content: "";
  position: absolute;
  top: 0.65em;
  left: -14px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--grey);
}

/* Callout box */
.cs-note {
  display: grid;
  gap: 12px;
  max-width: calc(640 * var(--u));
  padding: 22px 26px;
  border-left: 2px solid var(--black);
  background: var(--card-bg);
}
.cs-note__title { font-size: 14px; font-weight: 600; color: var(--black); }

/* Findings: three cards side by side */
.cs-findings {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
.cs-card {
  display: grid;
  align-content: start;
  gap: 8px;
  padding: 22px;
  border-radius: 8px;
  background: var(--card-bg);
  font-size: 15px;
  line-height: 1.5;
  color: var(--dark-2);
}
.cs-card__num { font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--grey); }
.cs-card__title { margin: 0; font-size: 17px; font-weight: 600; color: var(--black); }

/* Options table */
.cs-table-wrap { overflow-x: auto; }
.cs-table {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  font-size: 15px;
  line-height: 1.45;
  color: var(--dark-2);
}
.cs-table th,
.cs-table td {
  padding: 14px 16px 14px 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.cs-table thead th {
  padding-top: 0;
  border-bottom-color: var(--separator);
  font-size: 13px;
  font-weight: 500;
  color: var(--grey);
}
.cs-table tbody th { font-weight: 600; color: var(--black); }

/* Image / diagram slots */
.cs-figure { margin: 8px 0 0; }
.cs-figure__ph {
  display: grid;
  place-items: center;
  padding: 24px;
  border: 1px dashed var(--separator);
  border-radius: 8px;
  background: var(--photo-bg);
  font-size: 14px;
  text-align: center;
  color: var(--grey);
}
.cs-figure img { width: 100%; height: auto; border-radius: 8px; }
.cs-figure figcaption { margin-top: 10px; font-size: 13px; line-height: 1.4; color: var(--grey); }

/* Results: four big numbers under hairlines, then quotes */
.cs-metrics {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0 calc(24 * var(--u));
  margin: 8px 0;
}
.cs-metrics > div { padding-top: 14px; border-top: 1px solid var(--separator); }
.cs-metrics dt { font-size: 13px; line-height: 1.35; color: var(--grey); }
.cs-metrics dd {
  margin: 10px 0 0;
  font-size: clamp(32px, calc(44 * var(--u)), 44px);
  line-height: 1.1;
  font-weight: 700;
  color: var(--black);
}
.cs-quote {
  max-width: calc(640 * var(--u));
  margin: 8px 0 0;
  padding-left: 24px;
  border-left: 2px solid var(--separator);
}
.cs-quote p { font-size: clamp(18px, calc(22 * var(--u)), 22px); line-height: 1.45; color: var(--black); }
.cs-quote footer { margin-top: 12px; font-size: 14px; color: var(--dark-2); }
.cs-quote footer span { color: var(--grey); }

/* End of page: back / next */
.cs-end { padding: calc(160 * var(--px)) 0 calc(120 * var(--px)); }
/* Hairline from the 2nd grid line, back link left, next case right */
.cs-end__inner {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  margin-left: calc(212 * var(--u));
  padding: 28px calc(80 * var(--u)) 0 1px;
  border-top: 1px solid var(--separator);
}
.cs-end__link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: clamp(18px, calc(22 * var(--u)), 22px);
  font-weight: 600;
  color: var(--black);
}
.cs-end__link .arrow { color: currentColor; transition: transform 0.3s var(--ease-out); }
.cs-end__link:hover .arrow { transform: translateX(-4px); }
.cs-end__link--next .arrow { transform: rotate(180deg); }
.cs-end__link--next:hover .arrow { transform: rotate(180deg) translateX(-4px); }

/* =========================================================
   Project pages (project-*.html)
   Same shell as the case studies. Laid out like the Framer project pages:
   titles from the 2nd grid line, pictures across columns 2–6 (or 3–6),
   product shots in three stacks. Image slots (pj-ph) keep the original
   pictures' proportions until the real files go in.
   ========================================================= */
.pj .cs__shell { --pj-x: calc(215 * var(--u)); }   /* 3px clear of the 2nd grid line (set where --u is the grid's) */
.pj-ph {
  display: grid;
  place-items: center;
  padding: 12px;
  border: 1px dashed var(--separator);
  border-radius: 8px;
  background: var(--photo-bg);
  font-size: 13px;
  line-height: 1.35;
  text-align: center;
  color: var(--grey);
}
.pj-text {
  font-size: clamp(16px, calc(18 * var(--u)), 18px);
  line-height: var(--body-lh);
  color: var(--dark-2);   /* body text dark enough to read at length; bold
                             marks at most one short phrase per paragraph */
  text-wrap: pretty;
}
.pj-text strong { font-weight: 600; color: var(--black); }

/* Hero: title and summary across columns 2–5, role and period in 6 */
/* Opening block: the space above the title, between the facts and the
   line, between the line and the numbers, and down to the image is one
   and the same (56 on desktop), so the title block sits centred between
   the header and the line, and the results between the line and image.
   Each value is 56 less the gap the text's own line box adds. */
.pj-hero { padding-top: calc(var(--header-h) + 45 * var(--px)); }
.pj-hero__grid {
  display: grid;
  grid-template-columns: calc(815 * var(--u)) 1fr;
  padding-left: var(--pj-x);
}
/* Back link above the title: phones and tablets only (desktop has it in
   the sidebar) */
.pj-back { display: none; }
.pj-title {
  margin: 0;
  font-size: clamp(34px, calc(46 * var(--u)), 46px);
  line-height: 1.2;
  font-weight: 700;
  color: var(--black);
}
.pj-lead {
  max-width: calc(560 * var(--u));
  margin-top: 20px;
  font-size: 17px;   /* 15px on phones and tablets */
  line-height: var(--body-lh);
  color: var(--grey);
}
.pj-meta { display: grid; gap: 18px; align-content: start; margin: 10px 0 0 3px; }
/* Split hero (Betslip): title, lead and the facts in columns 2–3, the
   video from the 4th grid line to the frame's right edge, as on Framer;
   key results below both */
.pj-split {
  display: grid;
  grid-template-columns: calc(405 * var(--u)) calc(619 * var(--u));
  align-items: start;
  margin-left: var(--pj-x);
}
.pj-split__intro { padding-right: calc(16 * var(--u)); }
.pj-hero--split .pj-title { font-size: clamp(32px, calc(42 * var(--u)), 42px); }   /* as on Framer: two lines */
.pj-hero--split .pj-metrics dt { text-wrap: balance; }   /* no single word left on a line */
.pj-split__media { aspect-ratio: 619 / 748; overflow: hidden; border: 1px solid var(--line); border-right: 0; border-left-color: transparent; border-radius: 0; background: var(--photo-bg) padding-box; }   /* the grid line itself shows through on the left: a border there would double it */
.pj-split__media video { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Desktop: the key results start right under the video, whose bottom line is
   theirs, and close with a line of their own */
@media (min-width: 1000px) {
  .pj-split__media { border-bottom: 0; }
  .pj-hero--split .pj-metrics { margin-top: 0; padding-bottom: calc(47 * var(--u)); border-bottom: 1px solid var(--line); }
}
.pj-hero--split .pj-glance--split {
  grid-template-columns: 1fr 1fr;
  gap: 32px 16px;
  margin: calc(48 * var(--u)) 0 0 !important;
}
.pj-hero--split .pj-glance--split > div { padding-left: 0; }
/* Desktop: the facts sit centred between the intro text and the key results */
@media (min-width: 1000px) {
  .pj-split { align-items: stretch; }
  .pj-split__intro { display: flex; flex-direction: column; }
  .pj-hero--split .pj-glance--split { margin-block: auto !important; padding-block: calc(32 * var(--u)); }
}
/* The Bet Builder phone video: sticks below the header while the three
   texts beside it scroll past (build_betslip.py makes the track) */
.fr-sticky > .fr-g { position: sticky; top: calc(var(--header-h) + 40px); width: 100%; }
/* Winnings Change on Odds Update: the two amounts take turns */
.fr-tick { animation: fr-tick 4s ease-in-out infinite; }
.fr-tick--b { animation-delay: -2s; }
@keyframes fr-tick { 0%, 40% { opacity: 1; translate: 0 0; } 50%, 90% { opacity: 0; translate: 0 -6px; } }
@media (prefers-reduced-motion: reduce) { .fr-tick { animation: none; } .fr-tick--b { opacity: 0; } }
/* A section with a separate phone layout (Betslip, Motion cues) */
.fr-canvas--phone { display: none; }
/* Framer's bulleted lists, with its own indents kept */
.fr-ul { margin: 0; padding-left: 1.25em; list-style: disc; white-space: pre-wrap; }
/* Dashed arrows between screens (decoration, desktop only) */
.fr-canvas > .fr-svg { z-index: 0; color: var(--black); pointer-events: none; }
.fr-svg svg { display: block; width: 100%; height: 100%; overflow: visible; }
.pj-meta dt { font-size: clamp(16px, calc(18 * var(--u)), 18px); color: var(--grey); }
.pj-meta dd { margin: 2px 0 0; font-size: 17px; font-weight: 500; color: var(--black); }

/* Pictures: columns 2–6 (between the grid lines), or 3–6 for --mid */
.pj-figure { margin: calc(64 * var(--u)) 1px 0 calc(212 * var(--u) + 1px); }
.pj-figure--hero { margin-top: calc(54 * var(--u)); }
.pj-figure--mid,
.pj-figure--stack,
.pj-figure--compare { margin-left: calc(416 * var(--u) + 1px); }

/* Sections */
.pj-section { padding-top: calc(180 * var(--px)); }
.pj-section__title {
  margin: 0 0 0 var(--pj-x);
  font-size: clamp(32px, calc(46 * var(--u)), 46px);
  line-height: 1.2;
  font-weight: 700;
  color: var(--black);
}
.pj-section__title--offset,
.pj-offset { margin-left: calc(416 * var(--u) + 3px); }
.pj-offset { display: grid; gap: 16px; max-width: calc(500 * var(--u)); margin-top: 24px; }
.pj-intro {
  display: grid;
  gap: 16px;
  max-width: calc(800 * var(--u));
  margin: 24px 0 0 var(--pj-x);
}
.pj-text--lead { color: var(--black); }
/* Two texts side by side: columns 2–3 and 4–5 */
.pj-cols2 {
  display: grid;
  grid-template-columns: calc(408 * var(--u)) calc(408 * var(--u));
  margin: 24px 0 0 var(--pj-x);
}
.pj-cols2 > * { padding-right: calc(40 * var(--u)); }
/* My role and the team: list text set like the section body text
   (18px, 1.5, dark grey, as under "How we've built it") */
.pj-cols2 .cs-list li { font-size: clamp(16px, calc(18 * var(--u)), 18px); line-height: 1.4; color: var(--dark-2); }   /* list items: a touch tighter than paragraphs */
.pj-section > .shell > .pj-text { max-width: calc(620 * var(--u)); margin: 40px 0 0 var(--pj-x); }

/* Sub-blocks (tokens, library, variants): title in columns 2–3, text in 4–6 */
.pj-block { margin-top: calc(120 * var(--u)); }
.pj-block__head {
  display: grid;
  grid-template-columns: calc(408 * var(--u)) 1fr;
  align-items: start;
  padding: 0 calc(60 * var(--u)) 0 var(--pj-x);
}
.pj-block__title,
.pj-product__title {
  margin: 0;
  font-size: clamp(26px, calc(38 * var(--u)), 38px);
  line-height: 1.2;
  font-weight: 700;
  color: var(--black);
}
.pj-block__head .pj-text { font-size: 16px; }

/* Products: heading, then the shots */
.pj-product { margin-top: calc(140 * var(--u)); }
.pj-product__head { display: grid; gap: 14px; max-width: calc(420 * var(--u)); margin-left: var(--pj-x); }
.pj-product__head .pj-text { font-size: 16px; }
.pj-product--centred .pj-product__head {
  max-width: calc(680 * var(--u));
  margin-left: calc(386 * var(--u));   /* centred on columns 2–6 */
  text-align: center;
}
.pj-gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: start;
  gap: calc(56 * var(--u)) calc(24 * var(--u));
  margin: calc(48 * var(--u)) 1px 0 calc(212 * var(--u) + 1px);
}
.pj-col { display: grid; gap: calc(56 * var(--u)); min-width: 0; }
.pj-col--wide { grid-column: span 2; }
.pj-shot--full { grid-column: 1 / -1; }
.pj-shot { display: grid; gap: 8px; margin: 0; min-width: 0; }
.pj-shot figcaption { font-size: 14px; font-weight: 500; color: var(--dark-2); }
.pj-pair { display: grid; grid-template-columns: 1fr 1fr; align-items: start; gap: calc(24 * var(--u)); }

/* Impact */
.pj-results__title { font-size: clamp(18px, calc(22 * var(--u)), 22px); font-weight: 600; color: var(--black); }
.pj-results { display: grid; gap: 20px; margin: 4px 0 0; padding: 0; list-style: none; }
.pj-results li { font-size: clamp(16px, calc(18 * var(--u)), 18px); line-height: 1.5; color: var(--dark-2); }
.pj-results strong { font-weight: 600; color: var(--black); }

/* Before & after */
.pj-note { margin-left: var(--pj-x); font-size: 16px; color: var(--grey); }
.pj-figure--compare { margin-top: 20px; }

/* Next project: one card across columns 2–6 */
.pj-next { padding: calc(180 * var(--px)) 0 calc(120 * var(--px)); }
.pj-next__card {
  display: grid;
  grid-template-columns: calc(452 * var(--u)) 1fr;
  gap: calc(36 * var(--u));
  margin: calc(40 * var(--u)) 1px 0 calc(212 * var(--u) + 1px);
  padding: calc(24 * var(--u));
  border-radius: 8px;
  background: var(--card-bg);
}
.pj-next__body { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.pj-next__title {
  font-size: clamp(26px, calc(44 * var(--u)), 44px);
  line-height: 1.2;
  font-weight: 700;
  color: var(--black);
}
.pj-next__desc { font-size: clamp(16px, calc(18 * var(--u)), 18px); line-height: var(--body-lh); color: var(--grey); }
.pj-next__foot { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-top: auto; }
.pj-next__focus { font-size: 16px; line-height: var(--body-lh); color: var(--dark-2); }
.pj-next__focus > span:first-child { display: block; color: var(--grey); }

/* --- Preview structure (project-all-in-one.html): results first,
   role, decisions, a few annotated screens per product --- */
.pj-glance { margin-top: calc(56 * var(--u)); }
.pj-glance > div { border-top: 0; padding-top: 0; padding-left: 3px; }
/* Labels bold and dark, values grey; Timeline skips a column, so the row
   reads Role · (gap) · Timeline · Scope · Team */
.pj-glance dt { font-size: 16px; font-weight: 600; color: var(--black); }
.pj-glance dd { margin-top: 14px; font-size: 16px; line-height: 1.4; color: var(--grey); }
.pj-glance__timeline { grid-column: 3; }
.pj-role-note { display: block; font-size: 14px; font-style: italic; }   /* second row under the role */
.pj-glance__list { display: grid; justify-items: start; gap: 6px; }
/* Team: each core team opens a small card with its people (hover or focus
   on desktop, tap on phones; main.js handles taps, Escape, outside clicks) */
.pj-team { position: relative; justify-self: stretch; }   /* full column width: the card lines up with its right edge */
.pj-team__btn {
  font: inherit;
  color: inherit;
  text-decoration: underline dotted;
  text-decoration-color: var(--grey);
  text-underline-offset: 3px;
  cursor: pointer;
}
.pj-team__btn[aria-expanded="true"] { color: var(--black); text-decoration-color: currentColor; }
.pj-team__pop {
  position: absolute;
  z-index: 15;
  top: -15px;
  right: calc(100% + 12px);   /* opens to the left of the name, level with it, so the other teams below stay visible */
  display: grid;
  gap: 8px;
  min-width: 220px;
  padding: 14px 16px;
  border: 1px solid var(--separator);
  border-radius: 8px;
  background: var(--card-bg);
  box-shadow: var(--shadow-pop);
  font-size: 15px;
  line-height: 1.35;
  white-space: nowrap;
}
.pj-team__pop[hidden] { display: none; }
/* Invisible bridge over the gap on the card's right, so moving the mouse
   from the name into the card never counts as leaving */
.pj-team__pop::before { content: ""; position: absolute; top: 0; bottom: 0; left: 100%; width: 16px; }
.pj-team__title { font-size: 12px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; color: var(--grey); }
.pj-team__person { display: grid; color: var(--black); }
/* A hairline between people, in the grid-line colour */
.pj-team__person + .pj-team__person { padding-top: 8px; border-top: 1px solid var(--line); }
.pj-team__role { font-size: 13px; color: var(--grey); }
.pj-team__more { font-style: italic; color: var(--grey); }   /* the rest of a team, as a count: name size, grey */
.pj-team__link { display: inline-flex; align-items: center; gap: 6px; justify-self: start; }
.pj-team__link .arrow { width: 9px; height: 8px; color: var(--grey); transition: color 0.2s, transform 0.3s var(--ease-out); }
@media (hover: hover) {
  .pj-team__link:hover { text-decoration: underline; text-underline-offset: 3px; }
  .pj-team__link:hover .arrow { color: var(--black); transform: rotate(135deg) translateX(-2px); }
}
/* Mentor: first in the Team list, styled like the teams; his card holds
   his title and a short note */
.pj-mentor__sep { margin: 0 10px; color: var(--separator); }
.pj-mentor__note { width: 220px; font-size: 14px; font-style: italic; line-height: 1.4; color: var(--grey); white-space: normal; }
/* Key results: three big numbers on the grid (columns 2–3, 4–5, 6) */
.pj-metrics {
  display: grid;
  grid-template-columns: calc(408 * var(--u)) calc(408 * var(--u)) 1fr;
  margin: calc(54 * var(--u)) 0 0 calc(212 * var(--u));
}
.pj-metrics > div {
  display: grid;
  align-content: start;   /* numbers on one line, whatever the label's length */
  gap: 6px;
  padding: calc(47 * var(--u)) calc(32 * var(--u)) 0 3px;
  border-top: 1px solid var(--line);   /* the colour of the middle grid lines */
}
.pj-metrics dd {
  margin: 0;
  font-size: clamp(36px, calc(56 * var(--u)), 56px);
  line-height: 1;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--black);
  font-variant-numeric: tabular-nums;   /* equal-width digits: nothing shifts as they count up */
}
.pj-metrics dd { order: -1; }   /* number above its label */
/* Labels: the full sentence on desktop, a short one on phones */
.pj-short { display: none; }
/* Each label stays within one grid column (204), 2px clear of the next line */
.pj-metrics dt { max-width: calc(204 * var(--u) - 16px); font-size: 15px; line-height: 1.4; color: var(--grey); }
.pj-text--wide { max-width: calc(620 * var(--u)); margin: 28px 0 0 var(--pj-x); }
.pj-subhead {
  margin-bottom: 14px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--grey);
}
.pj-offset--wide { max-width: calc(640 * var(--u)); gap: 24px; }
/* What was hard: "What I changed because of it" under the story, with a
   small uppercase title like "What I owned" (no box) */
.pj-changed { margin-top: 16px; }

/* Key decisions: three cards across columns 2–6 */
.pj-decisions {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(24 * var(--u));
  margin: calc(40 * var(--u)) 1px 0 calc(212 * var(--u) + 1px);
}
.pj-decision {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: calc(24 * var(--u)) calc(24 * var(--u)) calc(24 * var(--u));
  border-radius: 8px;
  background: var(--card-bg);
}
.pj-decision__num { font-size: 12px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; color: var(--grey); }
.pj-decision__title { margin: 0; font-size: clamp(19px, calc(22 * var(--u)), 22px); line-height: 1.25; font-weight: 700; color: var(--black); }
.pj-decision__steps { display: grid; gap: 12px; margin: 0 0 6px; }
.pj-decision__steps dt { font-size: 12px; font-weight: 500; color: var(--grey); }
.pj-decision__steps dd { margin: 2px 0 0; font-size: 15px; line-height: 1.45; color: var(--dark-2); }
.pj-decision .pj-ph { margin-top: auto; }

/* Products: one hero screen, then a few screens each with a short note */
.pj-figure--product { margin-top: calc(40 * var(--u)); }
.pj-noted {
  display: grid;
  grid-template-columns: repeat(4, 1fr);   /* phone screens one slot, landscape ones two */
  align-items: start;
  gap: calc(48 * var(--u)) calc(24 * var(--u));
  margin: calc(40 * var(--u)) 1px 0 calc(212 * var(--u) + 1px);
}
.pj-shot--wide { grid-column: span 2; }
.pj-shot--noted figcaption { font-size: 14px; font-weight: 400; line-height: 1.45; color: var(--grey); }
.pj-shot--noted figcaption strong { font-weight: 600; color: var(--black); }
.pj-all {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  margin: 32px 0 0 var(--pj-x);
  padding: 0 18px;
  border: 1px solid var(--separator);
  border-radius: 6px;
  font-size: 14px;
  color: var(--dark-2);
  transition: background-color 0.2s;
}
.pj-all .arrow { color: currentColor; transform: rotate(180deg); }
@media (hover: hover) { .pj-all:hover { background: var(--card-bg); } }

/* The design system in numbers (under "The problem"): drawn in code.
   Four soft embossed figures in the corners and the company logo in the
   middle, selected like an object in Figma (red dashed frame, glow and
   resize handles). Sizes follow the grid (--u), so it scales like a
   picture; phones get their own sizes below. */
.pj-stats {
  --emb-front: #f9f9f9;     /* front face */
  --emb-hi: #ffffff;        /* diamonds: white at the top … */
  --emb-lo: #e3e3e3;        /* … light grey at the bottom */
  --emb-back: #efefef;      /* the extruded side behind it */
  --emb-line: #c6c6c6;      /* outline of both */
  --emb-shadow: rgba(0, 0, 0, 0.08);
  --emb-label: #b9b9b9;
  --sel: #ff2a2a;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);   /* never wider than the card */
  grid-template-rows: 1fr auto 1fr;
  grid-template-areas: "a . b" ". s ." "c . d";
  aspect-ratio: 1026 / 594;
  margin: calc(64 * var(--u)) 1px 0 calc(212 * var(--u) + 1px);
  padding: calc(48 * var(--u)) calc(44 * var(--u));
  border: 1px solid rgba(0, 0, 0, 0.05);
  background: #fff;   /* white in both themes */
  user-select: none;
}
.pj-stats__grid { display: contents; }
.pj-stat { display: flex; flex-direction: column; }
.pj-stat--a { grid-area: a; }
.pj-stat--b { grid-area: b; justify-self: end; }
.pj-stat--c { grid-area: c; align-self: end; }
.pj-stat--d { grid-area: d; justify-self: end; align-self: end; }
.pj-stat dd {
  order: -1;   /* figure above its label */
  margin: 0;
  font-family: Montserrat, var(--font);
  font-size: calc(84 * var(--u));
  line-height: 1;
  font-weight: 800;
  letter-spacing: -0.01em;
}
/* Extruded figures: the element is the front face, ::before the grey side
   behind it, offset down and right. The face is outlined with a 1px ring
   of shadows rather than a text stroke: Montserrat's letters are built
   from overlapping pieces, and a stroke would trace those inside the
   letter (the A's crossbar, the a's bowl); the ring only follows the
   outside. The side keeps its stroke: there it reads as depth. */
.pj-emb {
  position: relative;
  z-index: 0;   /* keeps the side behind the face but above the card */
  white-space: nowrap;
  font-variant-numeric: tabular-nums;   /* steady width while counting */
  color: var(--emb-front);
  text-shadow:
    1px 0 var(--emb-line), -1px 0 var(--emb-line), 0 1px var(--emb-line), 0 -1px var(--emb-line),
    0.7px 0.7px var(--emb-line), -0.7px 0.7px var(--emb-line), 0.7px -0.7px var(--emb-line), -0.7px -0.7px var(--emb-line);
}
.pj-emb::before {
  content: attr(data-text);
  position: absolute;
  z-index: -1;
  left: calc(4 * var(--u));
  top: calc(4 * var(--u));
  color: var(--emb-back);
  -webkit-text-stroke: max(1px, calc(1.2 * var(--u))) var(--emb-line);
  text-shadow: 0 calc(4 * var(--u)) calc(10 * var(--u)) var(--emb-shadow);
}
.pj-stat dt { font-family: Montserrat, var(--font); font-size: calc(24 * var(--u)); line-height: 1.2; color: var(--emb-label); }
.pj-stat--a dt { padding-left: calc(118 * var(--u)); }
.pj-stat--c dt { padding-left: calc(200 * var(--u)); }
.pj-stat--type dd { display: flex; align-items: center; gap: calc(12 * var(--u)); }
.pj-stat__tag {
  display: inline-flex;
  align-items: center;
  gap: calc(10 * var(--u));
  font-size: calc(42 * var(--u));
  font-weight: 300;
  letter-spacing: 0;
  color: var(--emb-label);
}
/* Four glossy diamonds, each with the same raised side as the figures */
.pj-stat__spacing { width: 1.25em; height: 1.25em; overflow: visible; }
.pj-stat__spacing path { stroke: var(--emb-line); stroke-width: 0.55; stroke-linejoin: round; }
.pj-stat__spacing-back path { fill: var(--emb-back); }
.pj-stat__spacing-front path { fill: url(#pj-gloss); }
#pj-gloss stop:first-child { stop-color: var(--emb-hi); }
#pj-gloss stop:last-child { stop-color: var(--emb-lo); }

/* The selected logo */
.pj-select {
  grid-area: s;
  position: relative;
  display: grid;
  place-items: center;
  width: calc(352 * var(--u));
  height: calc(154 * var(--u));
}
/* The dashed frame: an SVG rectangle so the dashes are thick, round-ended
   and follow rounded corners; it and the handles glow, the logo doesn't */
.pj-select__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  filter: drop-shadow(0 0 calc(5 * var(--u)) rgba(255, 42, 42, 0.55));
}
.pj-select__frame path {
  fill: none;
  stroke: var(--sel);
  stroke-width: 7;            /* design units: 7px at full desktop size */
  stroke-linecap: butt;       /* flat dash ends … */
  stroke-linejoin: round;     /* … and a softly rounded outside at each corner */
}
.pj-select__handle {
  --hs: calc(40 * var(--u));   /* its size: the opening starts the bottom one on top of the top one */
  position: absolute;
  right: calc(-20 * var(--u));
  width: calc(40 * var(--u));
  height: calc(40 * var(--u));
  border-radius: calc(5 * var(--u));
  /* red ring, white ring, red centre */
  background: #fff;
  /* red, white, red rings round a small white centre, as in Figma */
  box-shadow: inset 0 0 0 calc(6 * var(--u)) var(--sel), inset 0 0 0 calc(10 * var(--u)) #fff,
    inset 0 0 0 calc(16 * var(--u)) var(--sel), 0 0 calc(10 * var(--u)) rgba(255, 42, 42, 0.5);
}
.pj-select__handle--top { top: calc(-20 * var(--u)); }
.pj-select__handle--bottom { bottom: calc(-20 * var(--u)); }
.pj-select__logo { width: calc(214 * var(--u)); height: auto; }
/* Opening, once the card is in view (main.js sets .is-armed up front and
   .is-open when it's seen): the top-right handle pops in, the frame is
   dragged open from that corner (revealed down and to the left while the
   bottom handle travels down with its edge), then the logo pops out */
.pj-select.is-armed .pj-select__handle--top { transform: scale(0); }
.pj-select.is-armed .pj-select__frame { clip-path: inset(-16px -16px calc(100% + 16px) calc(100% + 16px)); }
.pj-select.is-armed .pj-select__handle--bottom { opacity: 0; bottom: calc(100% - var(--hs) / 2); }
.pj-select.is-armed .pj-select__logo { opacity: 0; transform: scale(0.4); }
.pj-select.is-open .pj-select__handle--top { animation: sel-pop 0.45s var(--ease-spring) forwards; }
.pj-select.is-open .pj-select__frame { animation: sel-open 0.8s 0.3s var(--ease-out) forwards; }
.pj-select.is-open .pj-select__handle--bottom { animation: sel-drag 0.8s 0.3s var(--ease-out) forwards; }
.pj-select.is-open .pj-select__logo { animation: sel-logo 0.6s 1s var(--ease-spring) forwards; }
@keyframes sel-pop  { to { transform: none; } }
@keyframes sel-open { to { clip-path: inset(-16px); } }
@keyframes sel-drag {
  from { opacity: 1; bottom: calc(100% - var(--hs) / 2); }
  to   { opacity: 1; bottom: calc(var(--hs) / -2); }
}
@keyframes sel-logo { to { opacity: 1; transform: none; } }

/* Sections copied from the Framer page (generated): each is a "canvas",
   a scaled copy of the Framer layout across columns 2–6. Everything is
   placed in Framer px times --fu (canvas width / 1238). Pictures that
   overlap, the grey screen cards and their labels form groups (.fr-g)
   with their own unit (--gu), so on phones they keep their layout while
   the canvas turns into a single column. */
.fr-section { padding-top: 0; }
/* after "What was hard" (not on Framer) the copy picks up again */
#before-after.fr-section { padding-top: calc(100 * var(--px)); }
/* "How we've built it" follows "My role and the team": the same 180 above
   its title as every other section (its title sits 25 into the canvas) */
@media (min-width: 1000px) { #built.fr-section { padding-top: calc(155 * var(--px)); } }
.fr-canvas {
  position: relative;
  container-type: inline-size;
  margin: 0 1px 0 calc(212 * var(--u) + 1px);
}
.fr-canvas > * { position: absolute; --fu: calc(100cqw / 1238); }
.fr-panel { left: 0; right: 0; z-index: 0; background: var(--card-bg); }
.fr-all { display: none; }   /* "See All Images": phones only */
.fr-g { z-index: 1; container-type: inline-size; }
.fr-g > * { position: absolute; --gu: calc(100cqw / var(--gw)); }
.fr-t { z-index: 2; }
.fr-t .fr-p { margin: 0; font: inherit; color: inherit; letter-spacing: normal; }
.fr-t--lines .fr-l { display: block; white-space: nowrap; }
.fr-t--one { white-space: nowrap; }
/* White-Label Scalability: Framer's card stack of nine brand screens. The
   list is the front card's box; each card further back (--i) is 7% smaller,
   sits 6% of its height higher (Framer: 7%, so less of each shows) and is
   3% darker. main.js moves the front
   card: dragged aside far enough it flies off and rejoins at the back, and
   the others step forward. */
.wl-stack__list {
  left: 0;
  top: calc(121.5 * var(--gu));   /* room for the back cards above it */
  width: 100%;
  height: calc(607.5 * var(--gu));
  margin: 0;
  padding: 0;
  list-style: none;
  outline: none;
}
.wl-stack__card {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: calc(16 * var(--gu));
  z-index: calc(9 - var(--i));
  transform: translateY(calc(var(--i) * -6%)) scale(calc(1 - var(--i) * 0.07));
  filter: brightness(calc(1 - var(--i) * 0.03));
  user-select: none;
  transition: transform 0.5s var(--ease-out), filter 0.5s var(--ease-out), opacity 0.3s;
}
.wl-stack__card picture { display: block; width: 100%; height: 100%; }
.wl-stack__card img { display: block; width: 100%; height: 100%; object-fit: cover; pointer-events: none; -webkit-user-drag: none; }
.wl-stack__card.is-front { cursor: grab; }
.wl-stack { touch-action: pan-y; }   /* sideways drags move the stack, vertical ones scroll */
.wl-stack__card.is-dragging { cursor: grabbing; transition: none; }
/* Custom cursor (main.js moves it): a frosted circle in place of the
   pointer on mouse devices: a four-way arrow over the card stack and the
   lobby's photo strip, an expand icon over pictures that open in a viewer */
.drag-cursor {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin: -20px 0 0 -20px;
  border-radius: 50%;
  /* Framer's was white at 25%: lost over light screens. A darker glass
     with a light rim and a soft shadow reads on light and dark alike */
  background: rgba(24, 24, 24, 0.32);
  -webkit-backdrop-filter: blur(15px);
  backdrop-filter: blur(15px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.35), 0 4px 16px rgba(0, 0, 0, 0.22);
  pointer-events: none;
  opacity: 0;
  transition: scale 0.15s var(--ease-out);   /* appears and hides at once; only the press shrink eases */
}
.drag-cursor.is-on { opacity: 1; }
.drag-cursor.is-on.is-pressed { scale: 0.85; }
.drag-cursor svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: #fff;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}
@media (hover: hover) and (pointer: fine) {
  .wl-stack, .wl-stack *, .pj-zoomable, .photos__scroller, .photos__scroller * { cursor: none !important; }
}
/* Same hint as the photo strip: centred, 16px under the stack (its top + height) */
.fr-canvas > .wl-stack__hint { left: 0; right: 0; top: calc(1176.9 * var(--fu) + 16px); width: auto; min-width: 0; margin: 0; justify-content: center; }
.wl-stack__list:focus-visible .wl-stack__card.is-front { outline: 2px solid var(--figma-blue); outline-offset: 3px; }
/* Section body text copied from Framer: set like the page's own body text
   (.pj-text, as under "The problem"): 18px, 1.5 line height, dark grey, with
   the highlighted words in black semibold. Framer had greys at 1.8. */
.fr-t--body {
  font-size: clamp(16px, calc(18 * var(--fu)), 18px) !important;
  line-height: var(--body-lh) !important;
  color: var(--dark-2) !important;
}
.fr-t--body span[style*="color:var(--grey)"] { color: var(--dark-2) !important; font-weight: 400; }
.fr-t--body span:is([style*="color:var(--black)"], [style*="color:var(--dark-2)"]),
.fr-t--body[style*="color:var(--black)"] { color: var(--black) !important; font-weight: 600 !important; }
/* Screen labels and product descriptions: fixed sizes at every screen
   width instead of scaling with the layout (they'd drop to ~11px) */
.fr-t--label { font-size: 13px !important; }
/* 15px from a 1440px-wide window up; on smaller desktops it shrinks with
   the layout (18.1 frame px = 15px at 1440), or it would run into the
   pictures below */
.fr-canvas > .fr-t--small { font-size: min(15px, 18.1 * var(--fu)) !important; }
/* The product descriptions (Sportsbook, Casino, Platform): a size up */
#products .fr-canvas > .fr-t--small { font-size: min(16px, 18.1 * var(--fu)) !important; line-height: var(--body-lh) !important; text-wrap: balance; }   /* lines of even length */
#products .fr-canvas > .fr-t--small br { display: none; }   /* Framer's hard breaks would undo the balance */
/* The before & after caption: 15px at every width */
#before-after .fr-canvas > .fr-t--small { font-size: 15px !important; width: 87.076% !important; white-space: normal; }   /* as wide as the slider; wraps on the narrowest desktops */
.fr-g > .fr-t--small { font-size: min(15px, 18.1 * var(--gu)) !important; }
/* Framer's line breaks were drawn for the smaller, scaled size: at 15px
   they ran past the box, so these paragraphs wrap inside it instead */
.fr-t--small.fr-t--lines .fr-l { display: inline; white-space: normal; }
.fr-t--small.fr-t--one { white-space: normal; }
.fr-g--clip { overflow: hidden; }
.fr-tile { pointer-events: none; }
.fr-m { display: block; overflow: hidden; border-radius: var(--r, 0); box-shadow: var(--sh, none); }
.fr-m img,
video.fr-m { width: 100%; height: 100%; }
.fr-m img { display: block; border-radius: 0; }
/* Each picture runs 1px past its rounded frame, which clips it: otherwise
   at some screen widths (and in Safari) a sub-pixel gap lets the light
   card behind show as a hairline along the screen's edge */
.fr-m img { width: calc(100% + 2px); max-width: none; height: calc(100% + 2px); margin: -1px; }
.fr-g--compare .pj-compare { position: absolute; inset: 0; aspect-ratio: auto; }
/* Tokens & Variables: one node at a time is active (blue square, bold
   name) and the table below shows its tokens. main.js moves the active
   step along, sending a blue pulse down the line to the next node first. */
/* The system's three blocks sit on white pictures, so they keep the light
   theme's colours in both themes, on the page and in the lightbox's copy */
#built .fr-canvas > :is(.sys-title, .sys-text, .sys-media),
.lightbox__region { --black: #000; --bg: #f8f8f8; --grey: #808080; --line: rgba(0, 0, 0, 0.05); color: var(--black); }
/* A grid-line stroke along the top and bottom of each block */
#built .fr-canvas > .sys-media::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-block: 1px solid var(--line);
  pointer-events: none;
}
.fr-g--tokens .tok-sq {
  background: rgb(197, 197, 197);
  box-shadow: inset 0 0 0 3px rgba(255, 255, 255, 0.35);
  transition: background-color 0.45s;   /* same length as the pop, so colour and size land together */
}
/* Turning blue: a tiny pop */
.fr-g--tokens .tok-sq.is-on { background: rgb(51, 170, 255); animation: tok-pop 0.45s var(--ease-spring); }
@keyframes tok-pop { 40% { transform: scale(1.14); } }
/* The cards stay solid (the line ends behind them must not show through);
   an inactive node only dims its name */
.fr-g--tokens .tok-card { box-shadow: 0 0 0 transparent; transition: box-shadow 0.45s; }
.fr-g--tokens .tok-card.is-on { box-shadow: 4px 4px 15px 0 rgba(0, 0, 0, 0.15); }   /* only the active card lifts */
.fr-g--tokens .tok-label { font-weight: 400; opacity: 0.7; transition: opacity 0.45s; }
.fr-g--tokens .tok-label.is-on { font-weight: 600; opacity: 1; }
/* Switching tables: the old one drops out of the bottom of the frame,
   then the new one rises into place */
.fr-g--tokens .tok-table {
  box-shadow: 0 0 16px 0 rgba(0, 0, 0, 0.22);   /* Framer's was left only; this shows on all sides */
  pointer-events: none;
  transform: translateY(115%);
  transition: transform 0.6s cubic-bezier(0.55, 0, 0.75, 0.2);
}
.fr-g--tokens .tok-table.is-on {
  pointer-events: auto;
  transform: none;
  transition: transform 0.7s 0.5s var(--ease-out);   /* rises as the old one leaves the frame */
}
/* The sport/gray table is a little taller than its frame: show it from the
   top instead of the middle, which sits it 10 frame px lower */
.fr-g--tokens .tok-table[data-tok="2"] img { object-position: 50% 0; }
/* The pulse: a few dashes centred on one point, longer ones thinner, so
   it tapers to its ends (lengths, widths and start offsets in the markup) */
.tok-wires { left: 0; top: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.tok-pulse { filter: drop-shadow(0 0 3px rgba(51, 170, 255, 0.9)); }
.tok-wire { fill: none; stroke: rgb(51, 170, 255); stroke-linecap: round; }

/* Real pictures and videos on project pages */
.pj-media { display: block; }
.pj-media img,
img.pj-media,
video.pj-media { display: block; width: 100%; height: auto; border-radius: 8px; }
/* Crop to a set shape (the hero, the next-project card) */
.pj-crop { overflow: hidden; border-radius: 8px; }
.pj-crop picture,
.pj-crop img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.pj-next__media { aspect-ratio: 452 / 440; }
.pj-crop video { display: block; width: 100%; height: 100%; object-fit: cover; }
.pj-next__item { display: block; }
/* Hero: square corners and a grid-coloured line above and below; with the
   grid lines either side it sits in its own cell */
.pj-figure--hero .pj-crop { border-block: 1px solid var(--line); border-radius: 0; }
.pj-decision .pj-media { margin-top: auto; }

/* Nine brand themes stacked, largest in front, as on the Framer page */
.pj-stack { position: relative; aspect-ratio: 1080 / 778; }
.pj-stack__item { position: absolute; }
.pj-stack__item img { border-radius: 6px; box-shadow: var(--shadow-shot); }

/* Before / after: the "before" picture on top, cut off at the handle;
   an invisible range input across the picture does the dragging (and
   arrow keys work) */
.pj-compare {
  position: relative;
  aspect-ratio: 1012 / 567;
  overflow: hidden;
  border-radius: 8px;
  background: var(--photo-bg);
}
.pj-compare picture { position: absolute; inset: 0; }
.pj-compare img { width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.pj-compare__before { clip-path: inset(0 calc(100% - var(--pos)) 0 0); }
.pj-compare__handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos);
  width: 2px;
  margin-left: -1px;
  background: #fff;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.35);
  pointer-events: none;
}
/* The arrow is a picture: as a text character its size and centring
   changed with each device's font (small and off-centre on Android) */
.pj-compare__handle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8'%3E%3Cpath d='M1 4h14M4 1 1 4l3 3M12 1l3 3-3 3' fill='none' stroke='%23141414' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 28px 14px no-repeat;
  translate: -50% -50%;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.pj-compare__label {
  position: absolute;
  bottom: 12px;
  padding: 6px 10px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 13px;
  font-weight: 500;
  pointer-events: none;
}
.pj-compare__label--before { left: 12px; }
.pj-compare__label--after { right: 12px; }
.pj-compare__range {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
  touch-action: pan-y;   /* vertical swipes still scroll the page */
}
.pj-compare:has(.pj-compare__range:focus-visible) { outline: 2px solid var(--figma-blue); outline-offset: 2px; }
@media (max-width: 999px) { .pj-compare__handle::after { width: 44px; height: 44px; background-size: 24px 12px; } }

/* =========================================================
   Entrance animations
   ========================================================= */
/* Only plays when <html> has `.intro` (set in <head>: first arrival on the
   site or a reload of this page — never on back/forward or internal links).
   Without `.intro` every element simply renders in its final state.

   Sequence (--at-* start times are computed in main.js):
   empty screen → 0.5s → title → secondary text
   → hold, during which the grid lines draw down one after another
   → photo, header, sidebar nav + "Based in" staggered and overlapping
   (cursor pops in as the photo lands) */
.word { display: inline-block; white-space: nowrap; }
.char { display: inline-block; }

/* Elements clip at the container's outer grid lines so they appear to
   emerge from underneath them */
.sidebar__inner { overflow: clip; }
.hero__shell { overflow-x: clip; }

/* No scrolling while the intro plays (class set in <head>, removed by
   main.js once the last element has landed). The scrollbar is hidden
   (see Base), so nothing shifts when it comes back. */
.scroll-lock,
.scroll-lock body { overflow: hidden; }

/* --- Hidden starting states --- */
.intro .grid-bg__cols span::before,
.intro .grid-bg__cols::after { transform: translateY(-100%); }
.intro .char {
  opacity: 0;
  filter: blur(12px);
  transform: translateY(0.18em);
}
.intro .hero__extra {
  opacity: 0;
  filter: blur(10px);
  transform: translateY(12px);
}
/* photo left 924 + width 230 + gap 86 ≈ 330 Framer px past the right edge */
.intro .hero__photo { translate: calc(330 * var(--u)) 0; }
.intro .figma-cursor__icon,
.intro .figma-cursor__label { opacity: 0; transform: scale(0.4); }
.intro .site-header__inner { transform: translateY(-100%); }
/* `translate` so it doesn't fight the nav's centering transform */
.intro .section-nav,
.intro .based { translate: calc(-100% - 40px) 0; }

/* --- Timeline --- */
/* Lines slide down from above the viewport, left → right; each starts --line-lag after the
   previous one so its tip trails ~250px behind (lag computed in main.js) */
.intro.is-ready .grid-bg__cols span::before,
.intro.is-ready .grid-bg__cols::after {
  animation: line-draw var(--line-dur) cubic-bezier(0.45, 0, 0.55, 1) forwards;
  animation-delay: calc(var(--at-grid) + var(--l, 0) * var(--line-lag));
}
.intro.is-ready .char {
  animation: char-in 0.9s var(--ease-out) forwards;
  animation-delay: calc(var(--at-title) + var(--i) * 35ms);
}
.intro.is-ready .hero__extra {
  animation: fade-up-in 0.9s var(--at-extra) var(--ease-out) forwards;
}
.intro.is-ready .hero__photo {
  animation: slide-in-x 0.8s var(--at-photo) var(--ease-out) forwards;
}
.intro.is-ready .figma-cursor__icon {
  animation: pop-in 0.55s var(--at-cursor) var(--ease-spring) forwards;
}
.intro.is-ready .figma-cursor__label {
  animation: pop-in 0.55s calc(var(--at-cursor) + 100ms) var(--ease-spring) forwards;
}
.intro.is-ready .site-header__inner {
  animation: header-drop 0.8s var(--at-header) var(--ease-out) forwards;
}
.intro.is-ready .section-nav,
.intro.is-ready .based {
  animation: slide-in-x 0.8s var(--at-sidebar) var(--ease-out) forwards;
}
/* Mobile scroll hint fades in with the sidebar step */
.intro .scroll-hint { opacity: 0; }
.intro.is-ready .scroll-hint {
  animation: fade-up-in 0.8s var(--at-sidebar) var(--ease-out) forwards;
}

@keyframes char-in    { to { opacity: 1; filter: blur(0); transform: none; } }
@keyframes fade-up-in { to { opacity: 1; filter: blur(0); transform: none; } }
@keyframes slide-in-x { to { translate: 0 0; } }
@keyframes pop-in     { to { opacity: 1; transform: none; } }
@keyframes line-draw  { to { transform: none; } }
@keyframes header-drop { to { transform: none; } }

/* =========================================================
   Project pages: 6 columns (desktop)
   With the sidebar gone, titles and text keep their places (from the 2nd
   grid line, like the Framer sections) and pictures, cards and the Framer
   panels take the whole grid, columns 1–6.
   ========================================================= */
@media (min-width: 1000px) {
  .page-case .cs-hero .cs-figure { margin-left: 1px !important; }
  .page-case .pj-figure,
  .page-case .pj-gallery,
  .page-case .pj-decisions,
  .page-case .pj-noted,
  .page-case .pj-next__card,
  .page-case .fr-canvas { margin-left: 1px; }
  .page-case :is(.pj-figure--mid, .pj-figure--stack, .pj-figure--compare) { margin-left: calc(416 * var(--u) + 1px); }
  .page-case .pj-next__card { grid-template-columns: calc(562 * var(--u)) 1fr; }   /* text from the 4th line */
  /* The design system in numbers: Framer's 1026 × 595 card, centred, with
     each figure and the selected logo where Framer has them (card px) */
  .page-case .pj-stats { position: relative; display: block; width: calc(1026 * var(--u)); margin-inline: auto; padding: 0; }
  .page-case .pj-stats :is(.pj-stat, .pj-select) { position: absolute; }
  .page-case .pj-stat--a { left: calc(40 * var(--u)); top: calc(43 * var(--u)); }
  .page-case .pj-stat--b { left: calc(796 * var(--u)); top: calc(56 * var(--u)); }
  .page-case .pj-stat--b dd { font-size: calc(114 * var(--u)); }   /* the 3 is bigger on Framer */
  .page-case .pj-stat--c { left: calc(40 * var(--u)); top: calc(429 * var(--u)); }
  .page-case .pj-stat--d { left: calc(640 * var(--u)); top: calc(461 * var(--u)); }
  .page-case .pj-select { left: calc(320 * var(--u)); top: calc(209 * var(--u)); width: calc(367 * var(--u)); height: calc(160 * var(--u)); }
  .page-case .pj-select__handle { --hs: calc(45 * var(--u)); right: calc(-22.5 * var(--u)); width: calc(45 * var(--u)); height: calc(45 * var(--u)); }
  .page-case .pj-select__handle--top { top: calc(-22.5 * var(--u)); }
  .page-case .pj-select__handle--bottom { bottom: calc(-22.5 * var(--u)); }
  .page-case .pj-select__logo { width: calc(241 * var(--u)); }
}

/* =========================================================
   Responsive
   ========================================================= */
/* Mobile + tablet (< 1000px). Built from a 580px-wide design frame:
   positions are in that frame's px and scale with the viewport, the same
   way desktop scales from its 1240px frame. Text has readable minimums. */
@media (max-width: 999px) {
  :root {
    /* 1 frame px for header sizes: the smaller of the width and height
       scales, so the header stays compact on short, wide screens */
    --f: min(calc(100vw / 580), calc(100svh / 1046));
    --gutter: calc(16 * 100vw / 580);     /* grid edges follow the width */
    --header-h: clamp(56px, calc(70 * var(--f)), 105px);
    --cols: 127fr 145fr 136fr 135fr;     /* lines at 16 · 143 · 288 · 424 · 559 */
    --burger-w: clamp(17px, calc(17 * var(--f)), 24.5px);   /* sized to the moon/sun */
    --burger-gap: clamp(3.8125px, calc(4.78 * var(--f)), 6.375px);   /* line spacing keeps the 16px burger's proportions */
    --nav-gap: 12px;   /* fixed at every phone/tablet size */
    /* Burger gets the same space on both sides as the Contacts link */
    --header-pad-r: var(--nav-gap);
    --hit-x: 11px;   /* the 12px phone gap, stopping just short of the separator */
    --hit-h: 52px;   /* of the 56px phone header */
  }

  /* Four columns: 5 lines (edges + 3 inner) */
  .grid-bg__cols span:nth-child(n + 5) { display: none; }
  .grid-bg__cols::after { --l: 4; }

  /* --- Header: full width, YP · CV | Contacts | ☰ --- */
  .site-header__inner {
    width: 100%;
    border-inline: none;
    padding: 0 var(--header-pad-r) 0 max(16px, calc(19 * var(--f)));
  }
  .logo { font-size: clamp(28px, calc(34 * var(--f)), 60px); }
  .top-nav { gap: var(--nav-gap); }
  .top-link { font-size: clamp(15px, calc(17 * var(--f)), 24px); }
  .divider { height: clamp(22px, calc(34 * var(--f)), 52px); }
  .menu-only.divider { display: block; }
  .menu-toggle { display: inline-flex; }
  .top-nav > .menu-toggle::after { right: calc(-1 * var(--header-pad-r)); }   /* reach the screen edge */  .theme-toggle { width: 28px; height: 28px; }
  .theme-toggle__icon { width: 24px; height: 24px; }

  /* CV moves from the header bar into the Contacts dropdown */
  .desktop-only { display: none; }
  .menu-only-item { display: list-item; }

  /* --- Dropdowns (Contacts, menu): the header itself grows downward ---
     The panel sits right on the header's bottom line and its height animates
     from 0 to its content (grid rows 0fr → 1fr, toggled by .is-open in
     main.js). While a panel is open the header's own line is hidden and the
     panel's bottom border takes over, so the line travels down with it. */
  .contacts,
  .menu-sheet:not([hidden]) {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: grid;
    grid-template-rows: 0fr;
    /* stretch (not desktop's `center`) so the content is clipped by the
       shrinking row instead of overflowing up over the header */
    align-items: stretch;
    padding: 0 max(16px, calc(19 * var(--f)));
    background: var(--bg);
    border-bottom: 1px solid var(--separator);
    transition:
      grid-template-rows 0.5s var(--ease-out),
      padding 0.5s var(--ease-out);
  }
  .contacts.is-open { grid-template-rows: 1fr; padding-block: 12px 20px; }
  .menu-sheet.is-open { grid-template-rows: 1fr; padding-block: 20px 24px; }
  .contacts__inner,
  .menu-sheet__inner {
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }
  .contacts__inner { gap: 4px; justify-content: flex-start; align-items: stretch; }
  /* Links on the left, "Based in" on the right; the clock's baseline lines
     up with the last link (Experience) along the bottom of the dropdown */
  .menu-sheet__inner {
    flex-direction: row;
    justify-content: space-between;
    align-items: flex-end;              /* fallback */
    align-items: last baseline;
    gap: 16px;
  }
  .site-header__inner.has-open { border-bottom-color: transparent; }

  .contacts__inner > .divider,
  .contacts > .divider { display: none; }
  .contacts__inner > :last-child { margin-right: 0; }
  .contacts__socials { flex-direction: column; gap: 0; }
  /* Bigger text and taller full-width rows: easier to read and to tap */
  .contacts__socials .top-link { width: 100%; height: 52px; font-size: 17px; gap: 7px; }
  .contacts__socials .arrow { opacity: 1; transform: rotate(135deg); width: 12px; height: 10px; }
  .email-pill { height: 50px; margin-top: 8px; font-size: 16.5px; }
  .contacts-toggle { margin-left: 0; }   /* mobile keeps its 12px gaps */
  .contacts-toggle .arrow--toggle,
  .contacts-toggle:hover .arrow--toggle { opacity: 1; transform: rotate(-90deg); }
  .contacts-toggle[aria-expanded="true"] .arrow--toggle { transform: rotate(90deg); }

  /* Menu: section links + location (replaces the desktop sidebar) */
  .menu-sheet__links { display: grid; gap: 4px; }
  .menu-sheet__links a {
    display: block;
    padding: 6px 0;
    font-size: clamp(24px, calc(26 * var(--f)), 40px);
    line-height: 1.15;
    color: var(--grey);
    transition: color 0.2s;
  }
  .menu-sheet__links a:hover,
  .menu-sheet__links a[aria-current="true"] { color: var(--active, var(--dark-2)); font-weight: 700; }
  .menu-sheet__links .section-nav__toggle { width: 40px; height: 40px; margin: 0; padding-left: 7.86px; }   /* tip 6px after the text */
  .menu-sheet__links .section-nav__toggle::before { width: 9px; height: 9px; border-width: 0 2px 2px 0; }
  .menu-sheet__links .section-nav__sub { display: grid; gap: 0; min-height: 0; overflow: hidden; padding-left: 18px; }
  .menu-sheet__links .section-nav__sub > li:first-child { margin-top: 0; }
  .menu-sheet__links .section-nav__sub a { padding: 4px 0; font-size: clamp(19px, calc(20 * var(--f)), 30px); }
  /* "Based in" sits bottom-right of the menu, right-aligned */
  .menu-sheet__based {
    display: grid;
    gap: 8px;
    justify-items: end;
    text-align: right;
  }

  .sidebar { display: none; }

  /* --- Hero: exactly one screen tall, laid out on the 580 × 1046 design
     frame (header included). Positions are measured from the screen's
     top-left corner:
       --ux  1 frame px horizontally (follows screen width → stays on the grid)
       --uy  1 frame px vertically   (follows screen height → fills 100vh)
       --us  the smaller of the two, for font and photo sizes so nothing
             overflows on unusually short or wide screens --- */
  .hero {
    height: 100vh;
    height: 100svh;
    min-height: 0;
    padding: 0;
    align-items: stretch;
  }
  .hero__shell { width: 100%; }
  .hero__stage {
    --ux: calc(100cqw / 580);
    --uy: calc(100svh / 1046);
    --us: min(var(--ux), var(--uy));
    --u: var(--us);
    height: 100%;
  }

  /* Mobile layout v2 (the previous "primary" version is git tag
     mobile-primary): headline at the 1st grid line, subtext at the 2nd,
     cursor above-left of the photo, bigger photo on the right,
     scroll hint bottom-left */
  .hero__title {
    top: calc(197 * var(--uy));
    /* Flush after the 1st (left edge) grid line, which is 1px wide; the
       letters' own side spacing keeps them just clear of it */
    left: calc(var(--gutter) + 1px);
  }
  .hero__hi { font-size: calc(65 * var(--us)); }
  .hero__name { font-size: calc(76 * var(--us)); }

  .hero__extra {
    top: var(--extra-top);
    /* 2px clear of the 2nd grid line (line = gutter + 127/543 of the
       inner width; the line itself is 1px wide) */
    left: calc(var(--gutter) + (100cqw - 2 * var(--gutter)) * 127 / 543 + 1px + 2px);
    right: calc(var(--gutter) + 1px + 10px);   /* 10px clear of the 1px right grid line */
    gap: max(6px, calc(8 * var(--us)));
    /* Usual size, but never so big that "Product designer who brings
       visual polish" (~19em wide) can't fit on its first row: the cap is
       the text's own width (2nd grid line to 11px before the last) / 19.7,
       so narrow phones get slightly smaller text instead of a third row */
    font-size: min(
      max(14px, calc(12.5 * var(--us))),
      calc(((100cqw - 2 * var(--gutter)) * 416 / 543 - 14px) / 19.7)
    );
    max-width: none;   /* phones use left/right bounds instead */
  }

  /* Photo on the right, 5% under its 291 design width, centred between
     the 3rd and 4th grid lines (288 and 424: line = gutter + inner width
     × 272/543 and × 408/543, each 1px wide, so the midpoint is 340/543 + .5px) */
  .hero__stage {
    /* Secondary text always 24px under the headline, whatever the
       screen's shape: headline top + its two lines (65 + 76 at
       line-height 1.1) + 24px */
    --extra-top: calc(197 * var(--uy) + (65 + 76) * 1.1 * var(--us) + 24px);
    --photo-w: calc(291 * 0.95 * var(--us));
    --photo-left: calc(var(--gutter) + (100cqw - 2 * var(--gutter)) * 340 / 543 + 0.5px - var(--photo-w) / 2);
  }
  .hero__photo {
    /* Its usual spot, but never closer than ~16px under the secondary
       text (up to 4 lines, ~94px) on short screens */
    top: max(calc(523 * var(--uy)), calc(var(--extra-top) + 110px));
    left: var(--photo-left);
    width: var(--photo-w);
  }
  /* Enters from the right, emerging from under the right grid line: it
     starts just past that line, and the stage is clipped at the line on
     the right (nothing else extends that far, so the clip is invisible
     once the photo has landed) */
  .hero__stage { clip-path: inset(-100vh calc(var(--gutter) + 1px) -100vh -100vw); }
  .intro .hero__photo { translate: calc(100cqw - var(--gutter) - var(--photo-left)) 0; }

  /* "scroll" hint: bottom left, just inside the left grid line */
  .hero { position: relative; }
  .scroll-hint {
    position: absolute;
    left: calc(var(--gutter) + 8px);
    bottom: calc(100svh * 68 / 1046);   /* 60 px of the 1046px-tall design frame */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    color: var(--grey);
    pointer-events: none;
  }

  /* Arrow + one-row label (1px smaller than desktop), centred as one group
     between the 1st grid line and the photo's left edge. The label is in
     the flow here so the group's width is known; the drift in main.js is
     clamped so it never crosses onto the photo. */
  .figma-cursor {
    top: calc(515 * var(--uy) + 62px);   /* beside the photo's top-left */
    left: calc((var(--gutter) + 1px + var(--photo-left)) / 2);
    translate: -50% 0;
    width: max-content;
  }
  .figma-cursor__label {
    position: static;
    display: block;
    margin: -1px 0 0 14px;   /* same spot as before: under-right of the arrow */
    font-size: 11px;
  }

  /* --- Work: cards span the full grid, image on top, then the text --- */
  .work {
    margin-top: 0;
    padding: 40px 0 64px;
  }
  /* Section label: a cell in the first column, boxed by a grid-coloured
     line above and below, opening every section */
  .section-label {
    position: static;
    width: calc(100% * 127 / 543 - 1px);
    height: auto;
    overflow: visible;
    clip: auto;
    margin: 0 0 24px 1px;
    padding: 8px 0 9px;   /* keeps the cell 33px tall at the smaller size */
    border-block: 1px solid var(--line);
    font-size: var(--label-size, 14px);   /* main.js shrinks it only if a label can't fit */
    font-weight: 450;
    line-height: 1;
    text-align: center;
    text-transform: lowercase;
    color: var(--label);
  }

  .work__list {
    gap: 24px;
    margin-left: 1px;
  }
  .work-card,
  .work-card--platform,
  .work-card--betslip,
  .work-card--bonus,
  .work-card--archive {
    grid-template-columns: 1fr;
    gap: 20px;
    padding: 16px;
  }
  .work-card:not(.work-card--betslip) .work-card__media { order: 0; }
  /* A gentler rise than desktop: the cards fill most of a phone screen */
  .has-reveal .work-card { transition-duration: 0.9s; }
  .has-reveal .work-card:not(.is-in) { transform: translateY(36px); }
  .work-card__body { gap: 24px; }
  .work-card__title { font-size: clamp(28px, calc(36 * 100vw / 580), 40px); }
  .work-card__title br { display: none; }   /* wrap to the screen instead */
  .work-card__desc { margin-top: 10px; font-size: 16px; }
  .work-card__label { font-size: 12px; }
  .work-card__facts li { font-size: 13px; }
  .work-card__facts li br { display: none; }
  /* List on the left, the "View Project" button bottom-right, its bottom
     level with the list's last row */
  .work-card__foot,
  .work-card--betslip .work-card__foot,
  .work-card--bonus .work-card__foot,
  .work-card--archive .work-card__foot {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
  }
  .work-card__facts { flex: 1; min-width: 0; }
  .btn-project { height: 40px; padding: 0 14px 0 18px; font-size: 14px; }   /* ≤140px wide */

  /* Labels can open a section in another column: --col2 sits between
     the 2nd and 3rd grid lines */
  .section-label--col2 {
    margin-left: calc(100% * 127 / 543 + 1px);
    width: calc(100% * 145 / 543 - 1px);
  }
  /* --col3: between the 3rd and 4th grid lines */
  .section-label--col3 {
    margin-left: calc(100% * 272 / 543 + 1px);
    width: calc(100% * 136 / 543 - 1px);
  }

  /* --- Values: words full width, then the switch + text and the links
     in the second column (like the hero's secondary text) --- */
  .values {
    margin-top: 0;
    padding: 96px 0 64px;   /* + Work's 64px bottom = 160px between the sections */
  }
  .values__stage {
    position: static;
    height: auto;
    display: grid;
    --wf: clamp(36px, calc(68 * 100vw / 580), 72px);   /* big-word size */
    --shift-0: 100cqw;
    --shift-1: 140cqw;
    --shift-2: 180cqw;
  }
  .values__words {
    position: relative;
    top: auto;
    left: auto;
    width: auto;
    margin: 0 1px;
    height: calc(var(--wf) * (1.2 + 2 * 1.16));
  }
  .values__line { left: 0; font-size: var(--wf); }
  .values__line:nth-child(2) { top: calc(var(--wf) * 1.16); }
  .values__line:nth-child(3) { top: calc(var(--wf) * 2.32); }

  .values__about,
  .values__links {
    position: static;
    width: auto;
    margin-left: calc(100% * 127 / 543 + 3px);   /* 2px clear of the 2nd line */
    margin-right: 11px;
  }
  .values__about { margin-top: 32px; }
  .values__tabs { gap: 24px; }
  .values__tab { font-size: 16px; }
  .values__panels { margin-top: 14px; }
  .values__panel { font-size: 15px; line-height: 1.7; }
  .values__links { margin-top: 28px; margin-left: 3px; gap: 2px; }   /* back at the 1st line */
  .values__link { font-size: 15px; }

  /* --- Inspiration: heading full width from the 1st line; text, topics
     and photo in the second column --- */
  .inspo {
    margin-top: 0;
    padding: 96px 0 64px;   /* + Values' 64px bottom = 160px between the sections */
  }
  .inspo__stage {
    position: static;
    height: auto;
    display: grid;
  }
  .inspo__heading,
  .inspo__text,
  .inspo__photo,
  .inspo__topics {
    position: static;
    width: auto;
    translate: none;
  }
  .inspo__heading {
    margin: 0 1px;
    font-size: clamp(36px, calc(68 * 100vw / 580), 72px);
    line-height: 1.15;
    white-space: normal;
  }
  .inspo__heading br { display: none; }   /* wrap to the screen instead */
  .inspo__text,
  .inspo__topics {
    margin-left: calc(100% * 127 / 543 + 3px);   /* 2px clear of the 2nd line */
    margin-right: 11px;
  }
  .inspo__text { margin-top: 28px; font-size: 15px; line-height: 1.7; }
  .inspo__topics {
    display: flex;
    flex-wrap: wrap;
    gap: 0 18px;
    margin-top: 20px;
  }
  .inspo__topic { font-size: 15px; }
  .inspo__photo {
    order: 1;   /* after the topics, so a tap changes the photo just below */
    margin: 16px 1px 0 calc(100% * 127 / 543 + 1px);   /* 2nd line to the outer line */
  }
  .inspo__frame {
    border-radius: 0;   /* square corners on phones */
    border-inline: none;   /* the grid lines already run down each side */
  }
  .inspo__caption { font-size: 15px; }

  /* Label in the 4th column (from the 4th grid line to the outer one) */
  .section-label--col4 {
    margin-left: calc(100% * 408 / 543 + 1px);
    width: calc(100% * 135 / 543 - 2px);
  }

  /* --- Photos: heading full width, then the strip across the whole grid,
     photos at about half their desktop size --- */
  .photos {
    margin-top: 0;
    padding: 96px 0 64px;   /* + Inspiration's 64px bottom = 160px */
  }
  .photos__stage {
    position: static;
    height: auto;
    --pu: calc(100vw / 780);
  }
  .photos__heading,
  .photos__gallery {
    position: static;
  }
  /* Same size as the other section headings; "What I see," keeps its own
     line and the rest wraps to the screen */
  .photos__heading {
    margin: 0 1px;
    font-size: clamp(36px, calc(68 * 100vw / 580), 72px);
    line-height: 1.15;
    white-space: normal;
  }
  .photos__gallery { margin: 32px 1px 0; }
  .photos__bar { padding-inline: 2px 10px; }
  .photos__scroller { margin-top: calc(14px - var(--shadow-room)); }
  .photos__item { border-radius: 8px; }

  /* --- Experience: company names full width from the 1st line; roles
     in the second column, dates under each title --- */
  .exp {
    margin-top: 0;
    padding: 96px 0 96px;   /* + Photos' 64px bottom = 160px */
  }
  .exp__company + .exp__company { margin-top: 56px; }
  .exp__name {
    margin: 0 1px;
    font-size: clamp(36px, calc(68 * 100vw / 580), 72px);
    line-height: 1.15;
  }
  .exp__roles { margin-top: 24px; }
  .exp__role {
    grid-template-columns: 1fr;
    align-items: start;
    padding: 0 11px 0 calc(100% * 127 / 543 + 3px);   /* 2px clear of the 2nd line */
  }
  .exp__role + .exp__role { margin-top: 20px; }
  .exp__title { font-size: 20px; }
  .exp__dates { margin-top: 4px; font-size: 14px; }
  .exp__details { gap: 10px; margin-top: 14px; padding-right: 0; }
  .exp__details li { font-size: 14px; line-height: 1.35; }

  /* --- Footer: one bar as tall as the header, full width like it; the
     credits and version stacked on the left, the smile on two lines on
     the right. Every line has the same 19px line box, so the right
     column's two lines sit level with the two rows on the left. --- */
  .exp { padding-bottom: 64px; }
  .site-footer { margin-top: 0; }
  .site-footer__inner {
    width: 100%;
    height: var(--header-h);   /* exactly the header's height */
    grid-template-columns: 1fr auto;
    grid-template-rows: auto auto;
    align-content: center;
    align-items: start;
    column-gap: 16px;
    padding: 0 var(--gutter);
    border-inline: none;
    font-size: 12px;
    line-height: 19px;
  }
  .site-footer__by { grid-area: 1 / 1; }
  .site-footer__coded { grid-area: 2 / 1; justify-self: start; }
  .site-footer__smile { grid-area: 1 / 2 / 3 / 3; text-align: right; }
  .site-footer__br { display: inline; }

  /* --- Photo viewer: full width photo; thumbnails, then the arrows and
     counter along the bottom --- */
  .lightbox__frame { inset: 68px 12px 152px; }
  .lightbox--single .lightbox__frame { inset: 68px 12px 24px; }
  .lightbox--single .lightbox__frame img { max-height: calc(100dvh - 92px); }
  .lightbox--single .lightbox__frame img { border-radius: 14px; }   /* 26px on desktop */
  .lightbox__region { width: 100%; border-radius: 14px; }
  .lightbox--single.is-gallery .lightbox__frame { inset: 68px 12px 152px; }
  .lightbox--single.is-gallery .lightbox__frame img { max-height: calc(100dvh - 220px); }
  .lightbox__title { top: 12px; left: 16px; font-size: 16px; line-height: 44px; }
  .lightbox__frame img {
    max-height: calc(100vh - 220px);
    max-height: calc(100dvh - 220px);
  }
  .lightbox__nav { top: auto; bottom: 20px; translate: none; width: 44px; height: 44px; }
  .lightbox__nav--prev { left: 16px; }
  .lightbox__nav--next { right: 16px; }
  .lightbox__count { bottom: 34px; }
  .lightbox__thumbs { bottom: 80px; width: calc(100vw - 24px); gap: 6px; }
  .lightbox__thumbs::before,
  .lightbox__thumbs::after { flex-basis: calc(50% - 25px); }
  .lightbox__thumb { width: 44px; height: 44px; }
  .lightbox__close { top: 12px; right: 12px; width: 44px; height: 44px; }

  /* --- Case study pages: one column, text from the 1st grid line --- */
  .cs-hero { padding-top: calc(var(--header-h) + 56px); }
  .cs-hero .cs__shell > *,
  .cs-glance,
  .cs-hero .cs-figure { margin-left: 3px !important; margin-right: 11px; }
  .cs-title, .cs-lead, .cs-tldr { max-width: none; }
  .cs-glance { grid-template-columns: 1fr 1fr; gap: 20px 16px; margin-top: 40px; }
  .cs-glance > div { padding-right: 0; }
  .cs-tldr { margin-top: 32px; padding: 20px; }
  .cs-hero .cs-figure { margin-top: 32px; }
  .cs-section { padding-top: 88px; }
  .cs-section__grid {
    grid-template-columns: 1fr;
    gap: 20px;
    padding: 0 11px 0 3px;
  }
  .cs-section__head { position: static; padding-right: 0; }
  .cs-section__body { padding-right: 0; }
  .cs-section__body > .cs-text,
  .cs-section__body > .cs-list,
  .cs-section__body > .cs-sub,
  .cs-note, .cs-quote { max-width: none; }
  .cs-findings { grid-template-columns: 1fr; }
  .cs-metrics { grid-template-columns: 1fr 1fr; gap: 24px 16px; }
  .cs-end { padding: 88px 0 64px; }
  .cs-end__inner { margin: 0 11px 0 3px; padding: 24px 0 0; }

  /* --- Project pages: one column, text from the 1st grid line, pictures
     between the outer lines --- */
  .pj .cs__shell { --pj-x: 3px; }
  .pj-br { display: none; }   /* phones wrap to the screen instead */
  .pj-lead { font-size: 15px; }
  .pj-hero { padding-top: calc(var(--header-h) + 32px); }
  .pj-hero__grid { grid-template-columns: 1fr; gap: 28px; padding-right: 11px; }
  .pj-lead, .pj-intro, .pj-offset, .pj-product__head { max-width: none; }
  .pj-meta { grid-template-columns: 1fr 1fr; margin: 0 0 0 var(--pj-x); }
  .pj-figure,
  .pj-figure--mid,
  .pj-figure--stack,
  .pj-figure--compare,
  .pj-gallery,
  .pj-next__card { margin-left: 1px; margin-right: 1px; }
  .pj-figure { margin-top: 32px; }
  .pj-figure--hero { margin-top: 26px; }
  .pj-section { padding-top: 96px; }
  .pj-section__title--offset,
  .pj-offset { margin-left: var(--pj-x); }
  .pj-intro, .pj-offset, .pj-cols2 { margin-right: 11px; }
  .pj-cols2 { grid-template-columns: 1fr; gap: 16px; }
  .pj-cols2 > * { padding-right: 0; }
  .pj-block, .pj-product { margin-top: 72px; }
  .pj-block__head { grid-template-columns: 1fr; gap: 12px; padding-right: 11px; }
  .pj-product__head,
  .pj-product--centred .pj-product__head { margin: 0 11px 0 var(--pj-x); text-align: left; }
  .pj-gallery { grid-template-columns: 1fr; gap: 40px; margin-top: 28px; }
  .pj-col { gap: 40px; }
  .pj-col--wide { grid-column: auto; }
  .pj-pair { gap: 12px; }
  .pj-shot figcaption { padding-left: 2px; }   /* text 2px clear of the line, like the rest */
  .pj-section > .shell > .pj-text { margin-right: 11px; }
  .pj-note { margin-right: 11px; }
  .pj-next { padding: 96px 0 64px; }
  .pj-next__card { grid-template-columns: 1fr; gap: 24px; margin-top: 28px; padding: 16px; }
  .pj-next__foot { flex-wrap: wrap; }
  /* Phones: the three results side by side under one line, short labels */
  .pj-metrics { grid-template-columns: repeat(3, 1fr); margin: 28px 1px 0; border-top: 1px solid var(--line); }
  .pj-metrics > div { padding: 22px 8px 0 2px; border-top: 0; }
  .pj-metrics dd { font-size: clamp(28px, 9vw, 40px); }
  .pj-metrics dt { max-width: none; font-size: 13px; line-height: 1.35; }
  .pj-long { display: none; }
  .pj-short { display: inline; }
  .pj-glance > div { padding-left: 0; }   /* phones: in line with the title */
  .pj-glance dd { font-size: 15px; }
  .pj-glance__timeline { grid-column: auto; }
  /* Brand stack and before/after slider: 5px clear of the outer lines */
  #scalability .wl-stack,
  #before-after .fr-g--compare { width: calc(100% - 10px) !important; margin-inline: 5px; }
  /* Team cards fill the left column at most (it's 16px away), so they
     stay on screen; long lines wrap */
  .pj-team__pop { width: min(220px, calc(100% + 4px)); min-width: 0; padding: 12px; font-size: 14px; white-space: normal; }
  .pj-mentor__note { width: auto; }
  .pj-text--wide { margin-right: 11px; }
  .pj-decisions,
  .pj-noted { grid-template-columns: 1fr; gap: 24px; margin: 28px 1px 0; }
  .pj-noted { gap: 36px; }
  .pj-shot--wide { grid-column: auto; }
  .pj-decision { padding: 20px 16px; }
  .pj-shot--noted figcaption { padding: 0 11px 0 2px; }
  .pj-all { margin-left: var(--pj-x); }
  /* Copied Framer sections on phones: one column in reading order; the
     groups (screen cards, diagrams) keep their layout, scaled to fit */
  .fr-section { padding-top: 72px; }
  .fr-canvas { display: flex; flex-direction: column; gap: 24px; margin: 0 1px; aspect-ratio: auto !important; overflow-x: clip; }   /* fixed-size labels in scaled groups can poke out */
  .fr-canvas > * { position: relative; left: auto !important; top: auto !important; width: auto !important; }
  .fr-panel { display: none; }
  .fr-g { width: 100% !important; }
  .fr-canvas > .fr-t { padding: 0 11px 0 2px; text-align: left !important; line-height: 1.45 !important; }
  .fr-canvas > .fr-t--body { line-height: var(--body-lh) !important; }   /* body text: the shared height */
  .fr-canvas > .fr-t .fr-p { text-align: left !important; }
  .fr-canvas > .fr-t--lines .fr-l,
  .fr-canvas > .fr-t--one { white-space: normal; }
  .fr-canvas > .fr-t--lines .fr-l { display: inline; }
  .fr-canvas > .fr-t--h2 { font-size: 32px !important; line-height: 1.15 !important; }
  .fr-canvas > .fr-t--h3 { margin-top: 16px; font-size: 24px !important; line-height: 1.2 !important; }
  .fr-canvas > .fr-t--body { font-size: 15px !important; }
  /* The same size for all the project pages' reading text */
  .pj-text, .pj-block__head .pj-text, .pj-product__head .pj-text, .pj-next__desc, .pj-next__focus, .pj-cols2 .cs-list li { font-size: 15px; }
  .fr-canvas > .fr-t--chip { font-size: 13px !important; }
  .fr-canvas > .fr-t--small { font-size: 14px !important; }
  #before-after .fr-canvas > .fr-t--small { font-size: 14px !important; }
  #products .fr-canvas > .fr-t--small { font-size: 14px !important; line-height: 1.45 !important; }   /* as the system cards' text */
  /* Betslip: the split hero stacks: title, lead, facts, key results, then
     the video between the outer lines */
  .pj-hero--split .cs__shell { display: flex; flex-direction: column; }
  .pj-split { display: contents; }
  .pj-split__intro { padding: 0 11px 0 0; margin-left: var(--pj-x); }
  .pj-hero--split .pj-metrics { order: 1; }
  .pj-split__media { order: 2; margin: 32px 1px 0; }
  .pj-hero--split .pj-glance--split { margin-top: 32px !important; gap: 20px 16px; }
  .fr-canvas > .wl-stack__hint { margin-top: -8px; right: auto; }
  .fr-canvas > .fr-sticky { height: auto !important; }
  .fr-sticky > .fr-g { position: relative; top: auto; }
  /* Sections on a white panel on Framer: the whole canvas is the panel */
  .fr-section--panel .fr-canvas { padding: 28px 4px; background: var(--card-bg); }
  .fr-canvas > .fr-svg { display: none; }
  .fr-canvas--desk { display: none; }
  .fr-canvas--phone { display: flex; }
  /* Products (Sportsbook, Casino, Platform): each on one card-coloured
     panel, as on desktop, where the hidden .fr-panel does it. Every item
     paints the panel behind itself and 12px into the gaps above and below
     (border-image ignores rounded corners and doesn't touch the layout);
     the title and the last item reach 28px out for the panel's padding,
     and a margin keeps the panels apart */
  /* Items sit 4px in from the panel's sides; the panel reaches back out */
  #products .fr-canvas > .fr-t--h3,
  #products .fr-canvas > .fr-t--h3 ~ * { margin-inline: 4px; border-image: linear-gradient(var(--card-bg), var(--card-bg)) fill 0 / 0 / 12px 4px; }
  #products .fr-canvas > .fr-t--h3 ~ .fr-g { width: calc(100% - 8px) !important; }
  #products .fr-canvas > .fr-t--h3 { margin-top: 64px; border-image-outset: 28px 4px 12px; }
  #products .fr-canvas > .fr-t--h3 ~ :is(:has(+ .fr-t--h3), :last-child) { border-image-outset: 12px 4px 28px; }
  /* Two cards per product (.fr-g--keep), then "See All Images", which opens
     the product's whole gallery (main.js) */
  #products .fr-canvas > .fr-g--card:not(.fr-g--keep) { display: none; }
  /* Casino: its mobile lobby (.fr-g--lead) comes before Hot & Cold */
  #products .fr-canvas > .fr-g--lead { order: 1; }
  #products .fr-canvas > .fr-g--lead ~ *,
  #products .fr-canvas > .fr-t--h3:has(#casino) ~ .fr-g--keep:has(~ .fr-g--lead) { order: 2; }
  #products .fr-canvas > .fr-all {
    display: inline-flex;
    align-self: center;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    padding: 12px 20px;
    position: relative;
    z-index: 2;   /* over a shrunk card's taller box (.fr-g is 1) */
    isolation: isolate;
    border-radius: 999px;
    font: inherit;
    font-size: 15px;
    line-height: 1.2;
    color: var(--inverse-fg);
    cursor: pointer;
  }
  #products .fr-canvas > .fr-all .fr-all__icon { width: 18px; height: 18px; flex: none; }
  /* Solid, to stand out (near-white in dark). Drawn by ::before, since the
     panel's border-image would paint over the button's own background */
  #products .fr-canvas > .fr-all::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background: var(--black);
  }
  /* Its panel reaches over its 8px margin and out to the column's sides
     (the button is only as wide as its text; the column clips the rest) */
  #products .fr-canvas { overflow-x: clip; }
  #products .fr-canvas > .fr-t--h3 ~ .fr-all { border-image-outset: 20px 50vw 28px; }
  /* Their title and opening text centred */
  #products .fr-canvas > .fr-t--h3,
  #products .fr-canvas > .fr-t--h3 + .fr-t--small { padding-inline: 16px; text-align: center !important; }
  #products .fr-canvas > :is(.fr-t--h3, .fr-t--h3 + .fr-t--small) .fr-p { text-align: center !important; }
  /* Cards with a label over their screens (all in the product panels):
     15px above the 13px label and 15px between it and the screens, on
     every card. In Framer the label sits at 15 and the screens at 46.8
     card units, which scale with each card's width, so the screens move
     by S (positive: down, the card grows at the top; negative: up, the
     card shrinks at the bottom). The card is 8px narrower than the column
     (100cqw: 4px panel padding each side). */
  .fr-g--card {
    --s: calc(45.6px - 46.8 * (100cqw - 8px) / var(--gw));
    box-sizing: content-box;
    padding-top: max(0px, var(--s));
    margin-bottom: min(0px, var(--s));
  }
  .fr-g--card > * { --s: calc(45.6px - 46.8 * var(--gu)); }
  .fr-g--card > .fr-tile { top: 0 !important; height: calc(100% + min(0px, var(--s))) !important; }
  .fr-g--card > .fr-t--label { top: 15px !important; }
  .fr-g--card > .fr-m { translate: 0 var(--s); }
  /* Cards that clip their screens: their corner radius is in page units
     (--fu), tiny on phones next to the tile's own corners (card units), so
     a screen showed past the tile's rounded corners. Read --fu in card
     units here instead, and on a card that shrank (negative S) end the
     clip at the tile's bottom rather than the taller box's */
  #products .fr-g--card { --fu: calc((100cqw - 8px) / var(--gw)); }
  #products .fr-g--clip.fr-g--card { clip-path: inset(0 0 max(0px, -1 * var(--s)) 0 round calc(20 * var(--fu))); }
  /* Other labels in groups keep their bottom edge where the scaled-down
     label had it, so the larger text grows upwards, away from the screens */
  .fr-g:not(.fr-g--card) > .fr-t--label { translate: 0 min(0px, 16.8 * var(--gu) - 15.6px); }
  /* The system's three blocks (Tokens & Variables, Component Library,
     Variants & Booleans): title, text and picture on one white card each
     (white in both themes, like the pictures themselves) */
  #built .fr-canvas > :is(.sys-title, .sys-text) { background: #fff; padding-inline: 16px; }
  #built .fr-canvas > .sys-title { padding-top: 24px; border-top: 1px solid var(--line); }
  #built .fr-canvas > .sys-media::after { border-top: 0; }   /* the block's top is its title here */
  #built .fr-canvas > .sys-text { margin-top: -24px; padding-top: 12px; }
  /* Each picture starts with empty white above its content (a share of the
     screen width): crop it so the content sits 28px under the text in all
     three */
  #built .fr-canvas > .sys-media { --crop: 0px; margin-top: calc(-24px - var(--crop)); clip-path: inset(var(--crop) 0 0 0); }
  #built .fr-canvas > .sys-media--tokens { --crop: max(0px, 8.74cqw - 28px); }   /* to the top of the enlarged "grays" card */
  #built .fr-canvas > .sys-media--library { --crop: max(0px, 25.92cqw - 28px); }   /* (the enlarged picture, below) */
  #built .fr-canvas > .sys-media--variants { --crop: max(0px, 27cqw - 28px); }
  /* Tokens: title first. The diagram is enlarged and its right side, empty
     room for the desktop text, cropped off, so the nodes and table run
     edge to edge (80.4% of it shows) */
  #built .fr-canvas { overflow-x: clip; }
  #built .fr-canvas > .tok-text,
  #built .fr-canvas > .tok-text ~ * { order: 2; }
  #built .fr-canvas > .tok-title.tok-title { order: 1; }
  #built .fr-canvas > .fr-g--tokens { width: calc(100% / 0.804) !important; }
  /* Component Library: enlarged to show only the file sidebar and the
     Elements panel (x 20–475 of the 800px picture: 56.9% of it, starting
     2.5% in) */
  #built .fr-canvas > .sys-media--library { width: calc(100% / 0.569) !important; margin-left: calc(-2.5% / 0.569); }
  /* The table (all three steps) a size up, 88% of the card instead of 80%,
     centred in the visible part (its centre at 40.2% of the diagram) */
  #built .fr-g--tokens > .tok-table { left: 4.82% !important; width: 70.75% !important; height: calc(365 * var(--gu)) !important; }
  /* The three nodes 1.45× bigger, each growing around its card's centre
     (square and name scale from that same point, in diagram units). White
     patches on the background picture (under the cards and their shadows)
     hide the "Level n" notes baked into it */
  #built .fr-g--tokens > :is(.tok-card, .tok-sq, .tok-label) { scale: 1.45; }
  /* The square's light inner ring in diagram units, so it keeps the
     desktop proportion (3 of 30) instead of a fixed 3px on a small square */
  #built .fr-g--tokens > .tok-sq { box-shadow: inset 0 0 0 calc(3 * var(--gu)) rgba(255, 255, 255, 0.35); }
  /* Node names at least 11px as seen (after the 1.45× scale) */
  #built .fr-g--tokens > .tok-label { font-size: max(20 * var(--gu), 11px / 1.45) !important; }
  #built .fr-g--tokens > .tok-sq[data-tok="1"] { transform-origin: calc(65 * var(--gu)) calc(15 * var(--gu)); }
  #built .fr-g--tokens > .tok-sq[data-tok="2"] { transform-origin: calc(98 * var(--gu)) calc(15 * var(--gu)); }
  #built .fr-g--tokens > .tok-sq[data-tok="3"] { transform-origin: calc(101 * var(--gu)) calc(15 * var(--gu)); }
  #built .fr-g--tokens > .tok-label[data-tok="1"] { transform-origin: calc(35 * var(--gu)) calc(12 * var(--gu)); }
  #built .fr-g--tokens > .tok-label[data-tok="2"] { transform-origin: calc(68 * var(--gu)) calc(12 * var(--gu)); }
  #built .fr-g--tokens > .tok-label[data-tok="3"] { transform-origin: calc(71 * var(--gu)) calc(12 * var(--gu)); }
  #built .fr-g--tokens > picture:first-child::after {
    content: "";
    position: absolute;
    inset: 0;
    --w: linear-gradient(#fff, #fff);
    background:
      var(--w) calc(80 * var(--gu)) calc(153 * var(--gu)) / calc(46 * var(--gu)) calc(14 * var(--gu)) no-repeat,
      var(--w) calc(360 * var(--gu)) calc(259 * var(--gu)) / calc(48 * var(--gu)) calc(15 * var(--gu)) no-repeat,
      var(--w) calc(703 * var(--gu)) calc(365 * var(--gu)) / calc(50 * var(--gu)) calc(16 * var(--gu)) no-repeat;
  }
  /* Numbers card on phones: 2 × 2 figures around the logo, fixed sizes */
  .pj-stats {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    grid-template-areas: "a b" "s s" "c d";
    gap: 28px 12px;
    aspect-ratio: auto;
    margin: 40px 1px 0;
    padding: 28px 14px;
  }
  .pj-stat dd { font-size: clamp(32px, 11.2vw, 42px); }   /* a little smaller on the narrowest phones */
  .pj-emb::before { left: 2px; top: 2px; -webkit-text-stroke-width: 1px; text-shadow: 0 2px 4px var(--emb-shadow); }
  .pj-stat dt { font-size: 14px; }
  .pj-stat--a dt { padding-left: 16vw; }
  .pj-stat--c dt { padding-left: 17vw; }
  .pj-stat--type dd { gap: 8px; }
  .pj-stat__tag { font-size: clamp(18px, 6.4vw, 24px); gap: 5px; }
  .pj-select { justify-self: center; width: 210px; height: 92px; }
  .pj-select__frame { filter: drop-shadow(0 0 4px rgba(255, 42, 42, 0.55)); }
  .pj-select__handle { --hs: 24px; right: -12px; width: 24px; height: 24px;
    border-radius: 3px; box-shadow: inset 0 0 0 4px var(--sel), inset 0 0 0 6px #fff, inset 0 0 0 10px var(--sel), 0 0 6px rgba(255, 42, 42, 0.5); }
  .pj-select__handle--top { top: -12px; }
  .pj-select__handle--bottom { bottom: -12px; }
  .pj-select__logo { width: 138px; }   /* 2/3 of the frame, as on desktop */


  /* Jumping to a section from the menu lands with its label right under
     the header: the space above the label scrolls away behind it */
  .work { scroll-margin-top: -40px; }
  .values, .inspo, .photos, .exp { scroll-margin-top: -96px; }
}

/* =========================================================
   Portrait tablets (iPad mini to iPad Pro 11", upright): the phone layout,
   with reading text a size up so the wider columns don't make long, small
   lines, and the tall pictures held to a size that leaves room around them.
   The hero scales with the screen already and is left as it is.
   ========================================================= */
@media (min-width: 768px) and (max-width: 999px) {
  .work-card__desc { font-size: 17px; }
  .work-card__label { font-size: 13px; }
  .work-card__facts li { font-size: 15px; }

  .values__tab { font-size: 17px; }
  .values__panel { font-size: 17px; }
  .values__link { font-size: 16px; }

  .inspo__text { font-size: 17px; }
  .inspo__topic { font-size: 17px; }
  .inspo__caption { font-size: 16px; }
  /* Photo from the 2nd grid line to the 4th instead of the outer one */
  .inspo__photo { margin-right: calc(100% * 135 / 543 + 1px); }

  /* Strip photos ~25% smaller than the phone scale would make them */
  .photos__stage { --pu: calc(100vw / 1040); }

  .exp__title { font-size: 22px; }
  .exp__dates { font-size: 15px; }
  .exp__details li { font-size: 16px; line-height: 1.45; }

  /* Project pages: shots in two stacks, the next-project card side by side */
  .pj-gallery { grid-template-columns: 1fr 1fr; gap: 40px 20px; }
  .pj-col--wide { grid-column: 1 / -1; }
  .pj-next__card { grid-template-columns: 1fr 1fr; }
  .pj-metrics { grid-template-columns: repeat(3, 1fr); gap: 16px; }
  .pj-noted { grid-template-columns: 1fr 1fr; gap: 40px 20px; }
  .pj-shot--wide { grid-column: 1 / -1; }

  /* Products: phone screens two per row, near their phone size, instead of
     filling the column. Margins add 8px, so the cards sit 16px apart. Cards
     read their width from --cw (the phone rules use the whole column) */
  #products .fr-canvas { display: grid; grid-template-columns: 1fr 1fr; column-gap: 8px; }
  #products .fr-canvas > * { grid-column: 1 / -1; }
  #products .fr-canvas > .fr-all { justify-self: center; }
  #products .fr-canvas > .fr-g--card {
    grid-column: auto;
    align-self: start;
    --cw: calc((100cqw - 24px) / 2);
    --s: calc(45.6px - 46.8 * var(--cw) / var(--gw));
    --fu: calc(var(--cw) / var(--gw));
  }
  #products .fr-canvas > .fr-g--card > * { --fu: var(--gu); }
  /* Rows of unequal height: each card paints the panel across its row. The
     right card is drawn later, so it stays on top of the left card's fill */
  #products .fr-canvas > .fr-t--h3 ~ .fr-g--card { border-image-outset: 12px calc(50cqw + 8px) 12px 4px; }
  /* Platform's right card is the taller one: it paints the row instead */
  #products .fr-canvas > .fr-t--h3:has(#platform) ~ .fr-g--keep { z-index: 2; border-image-outset: 12px 4px; }
  #products .fr-canvas > .fr-t--h3:has(#platform) ~ .fr-g--keep ~ .fr-g--keep { z-index: 1; border-image-outset: 12px 4px 12px calc(50cqw + 8px); }
  /* Sportsbook: Match Statistics under League View, cropped so the right
     column ends level with the long lobby (card heights 1471 and 836) */
  #products .fr-canvas > .fr-t--h3:has(#sportsbook) ~ .fr-g--keep:not(.fr-g--clip) { grid-row: span 2; }
  #products .fr-canvas > .fr-g--card.fr-g--fill {
    display: block;
    height: calc(var(--cw) * (1471 - 836) / 389 - 24px - var(--s));
    clip-path: inset(0 0 max(0px, -1 * var(--s)) 0 round calc(20 * var(--fu)));
  }
  /* Casino: Game Info beside the mobile lobby, the live game centred in the
     space under it (card heights 1194.6, 616.2, 300.4), Hot & Cold wide below.
     The margins make up the lobby's height, so the row keeps its place */
  #products .fr-canvas > .fr-g--lead { order: 0; grid-row: span 2; }
  #products .fr-canvas > .fr-g--card.fr-g--pair { display: block; order: 1; }
  #products .fr-canvas > .fr-g--card.fr-g--mid {
    --x: calc((var(--cw) * (1194.6 - 616.2 - 300.4) / 389 - var(--s)) / 2);
    display: block;
    order: 1;
    margin-top: calc(var(--x) - 24px);
    margin-bottom: calc(var(--x) + min(0px, var(--s)));
  }
  #products .fr-canvas > .fr-t--h3:has(#casino) ~ .fr-g--keep:has(~ .fr-g--lead) {
    grid-column: 1 / -1;
    --cw: calc(100cqw - 8px);
    border-image-outset: 12px 4px;
  }
}

/* Mentor card: too narrow here for both roles on a line, so one role a line
   rather than "Head of Design" breaking in two */
@media (max-width: 479px) {
  .pj-mentor .pj-team__title { display: grid; white-space: nowrap; }
  .pj-mentor__sep { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
  }
  .scroll-hint__chevrons path { animation: none !important; }
}
