/* Folio — shared styles
   Layout mirrors the Figma frames (1512px wide, 12-col grid, 1.5px #333 gutters) at every width
   from 640px up; below that the grid becomes a single column.
   Everything scales from the design so proportions match desktop at every breakpoint:
   - --k: 1 design px relative to the tile's own width (type, in-tile geometry). Children only.
   - --u: 1 design px relative to the page width (padding, buttons), usable on tiles themselves.
     Equals --k for the desktop grid; on mobile, tiles are full width so --u = 100vw / 753.75. */

@font-face {
  font-family: "Humane";
  src: url("fonts/Humane-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  --ink: #e5e7d5;
  --tile: #000;
  --tile-hover: #141414;            /* #000 + 8% white overlay */
  --line: #333;
  --edge: #1c1c1c;
  --gap: 1.5px;                     /* snapped to whole screen pixels by the inline <head> script */
  --max: 1920px;                    /* widest the site gets; black space either side beyond this */
  --u: calc(min(100vw, var(--max)) / 1512);
  --pad: calc(32 * var(--u));
  --btn: calc(64 * var(--u));
  --type-max: 1700px;               /* text and buttons stop growing at this page width */
  --serif: "Instrument Serif", Georgia, "Times New Roman", serif;
  --display: "Humane", "Arial Narrow", Impact, sans-serif;
}

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

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

body {
  margin: 0;
  background: #000;
  color: var(--ink);
  font-family: var(--serif);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { display: block; }
h1, h2, p { margin: 0; font-weight: inherit; font-size: inherit; }
a { color: inherit; text-decoration: none; }
/* No browser focus ring on mouse or touch clicks (it shows in the system accent colour); keyboard
   users get the site's own outline instead. */
a:focus:not(:focus-visible), a:focus:not(:focus-visible) * { outline: none; }
a:focus-visible { outline: 2px solid var(--ink); outline-offset: -6px; }

/* ---------- Grid ---------- */

.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gap);
  padding: var(--gap);
  max-width: var(--max);
  margin: 0 auto;
  background: var(--line);          /* shows through the gaps as the 1.5px lines */
}

.tile {
  --base: 753.75;                   /* tile width in the design (px) */
  --px: calc(2 * var(--pad));       /* total horizontal padding */
  --k: calc((100cqi + var(--px)) / var(--base));   /* use on children only */
  --t: var(--k);                    /* type size: --k, but it stops growing past 1700px wide (below) */
  position: relative;
  container-type: inline-size;
  align-self: stretch;              /* every tile fills its row, so taller neighbours never leave gaps */
  justify-self: stretch;            /* exactly its columns' width: with an aspect ratio, a tile stretched */
  min-width: 0;                     /* to its row's height would otherwise widen into the gap beside it */
  padding: var(--pad);
  background: var(--tile);
  transition: background-color 0.3s ease;
}
/* text blocks only (project cards, "Let's work together"); image previews keep their black frame */
a.tile:not(.tile--img):focus-visible { background-color: var(--tile-hover); }
/* Hover effects only with a mouse or trackpad: on touch screens, scrolling past a block would
   otherwise trigger them. */
@media (hover: hover) and (pointer: fine) {
  a.tile:not(.tile--img):hover { background-color: var(--tile-hover); }
}

.s4  { grid-column: span 4;  --base: 502; }
.s6  { grid-column: span 6; }
.s8  { grid-column: span 8;  grid-row: span 2; --base: 1005; }
.s12 { grid-column: span 12; --base: 1508; }
/* "Two landscape" rows in the videos' own shape: side by side both pictures are the same height and the
   row is shared out by width (each block grows by its picture's shape, --mr; both have the same
   padding), so nothing is cropped */
.pair { grid-column: 1 / -1; display: flex; gap: var(--gap); min-width: 0; }
.pair > .tile { flex: var(--mr) 1 0%; aspect-ratio: auto !important; }
.pair > .tile--img > .media { flex: none; aspect-ratio: var(--mr); }
.bd { --px: calc(2 * var(--pad) + 2px); border-right: 2px solid var(--edge); border-bottom: 2px solid var(--edge); }

/* ---------- Type ---------- */

.title-xl, .title-lg, .hero__title {
  font-family: var(--display);
  font-weight: 600;
  line-height: 0.78;
  text-transform: uppercase;
  text-wrap: balance;
  overflow-wrap: break-word;
  font-feature-settings: "ordn" 1, "salt" 1, "dlig" 1;
  text-box: trim-both cap alphabetic;
}
.title-xl { font-size: calc(244 * var(--t)); }
.title-lg { font-size: calc(128 * var(--t)); }

.body-lg, .body-sm, .cta {
  font-family: var(--serif);
  letter-spacing: -0.02em;
  font-feature-settings: "ordn" 1;
  text-box: trim-both cap alphabetic;
}
.body-lg, .body-sm {
  line-height: 1.06;
  text-wrap: pretty;                /* fill lines to the edge, but no lone last word */
  /* Right edge sits at 80% of the block's width, leaving a 20% gap on the right in every block
     (block width = content width + horizontal padding). */
  width: calc(0.8 * (100cqi + var(--px)) - var(--pad));
  max-width: none;
}
/* Paragraphs scale with the design but never drop below a comfortable reading size. */
.body-lg { font-size: max(19px, calc(34.2 * var(--t))); }
.body-sm { font-size: max(17px, calc(24 * var(--t))); }

/* ---------- Buttons ---------- */

.btn {
  position: relative;
  display: block;
  flex: none;
  width: var(--btn);
  height: var(--btn);
}
.btn svg {
  position: absolute;
  top: -2.34%;
  left: -2.34%;
  width: 104.68%;
  height: 104.68%;
  overflow: visible;
  transition: transform 0.3s ease;
}
/* The ring keeps the gutter width (1.5px) at every button size (non-scaling stroke). */
.btn__ring { fill: none; stroke: var(--line); stroke-width: var(--gap); transition: stroke 0.3s ease; }
.btn__arrow { fill: var(--ink); }
a:focus-visible .btn svg { transform: scale(1.08); }
a:focus-visible .btn__ring { stroke: #444444; }
@media (hover: hover) and (pointer: fine) {
  a:hover .btn svg { transform: scale(1.08); }
  a:hover .btn__ring { stroke: #444444; }
  /* on a whole-block link (project cards, "Let’s work together") the button grows while the block is
     hovered, and settles back to its normal size while the pointer is on the button itself */
  a.tile:hover .btn:hover svg { transform: none; }
}
/* In the footer "Fearless" block the logo and the back arrow are separate links with separate hovers:
   the button reacts only to itself, and the logo redraws once when the pointer enters the block. */

/* ---------- Case study intro ---------- */

.tile--intro {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 80px;                        /* the least space between the heading and the paragraph */
}
.intro__heading {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(56 * var(--k));
  width: 100%;
}
.back { position: relative; display: flex; height: var(--btn); }
.back__logo {
  position: absolute;
  left: calc(var(--btn) - 24.54 * var(--k));   /* 39.46 at desktop; stays clear of a larger button */
  top: calc(12.09 * var(--k));
  width: calc(186.778 * var(--k));
  height: calc(84.316 * var(--k));
  max-width: none;
  transform: rotate(-8deg);
  cursor: pointer;                  /* part of the back link: clicking the logo goes home too */
}

/* ---------- Image + text tiles ---------- */

.tile--img { display: flex; flex-direction: column; overflow: hidden; }
.media { position: relative; flex: 1 1 0; min-height: 1px; width: 100%; overflow: hidden; }
/* Each image overhangs its frame by 2px on every side; .media clips the overhang, hiding any
   discoloured edge pixels from the exports or compression. */
.media img {
  position: absolute;
  top: -2px;
  left: -2px;
  width: calc(100% + 4px);
  height: calc(100% + 4px);
  max-width: none;
}
.fit-cover { object-fit: cover; } /* images and videos are only ever cropped, never stretched */

/* Work videos: always fill the block, cropped to its shape (no bars). An optional restart button bottom left and
   sound bottom right, the same size and padding as the arrow buttons, in "liquid glass": the video behind is
   blurred and brightened, with a light edge and a soft highlight across the top. Built only from
   effects the graphics chip draws directly (backdrop blur, gradients, shadows; no SVG filters) on
   small circles, so it stays smooth over playing video. */
.media video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; background: #000; }
.vbtn {
  position: absolute;
  bottom: var(--pad);
  z-index: 2;
  width: var(--btn);
  height: var(--btn);
  padding: 0;
  border: 0;
  border-radius: 50%;
  overflow: hidden;
  color: #fff;
  cursor: pointer;
  /* the video behind is dimmed just slightly (keeping its colour), so the white icon always reads */
  background: linear-gradient(180deg, rgb(255 255 255 / 0.16), rgb(255 255 255 / 0.03) 55%, rgb(255 255 255 / 0.07));
  -webkit-backdrop-filter: blur(14px) saturate(170%) brightness(0.85);
  backdrop-filter: blur(14px) saturate(170%) brightness(0.85);
  box-shadow:
    inset 0 1px 0.5px rgb(255 255 255 / 0.28),   /* soft rim along the top */
    inset 0 -1px 1px rgb(255 255 255 / 0.07),    /* faint rim along the bottom */
    inset 0 0 0 0.5px rgb(255 255 255 / 0.12),   /* hairline edge all round */
    0 4px 16px rgb(0 0 0 / 0.07);                /* lifts it gently off the video */
  transform: translateZ(0);                      /* its own layer: the video never repaints it */
  transition: transform 0.3s ease, background-color 0.3s ease;
}
.vbtn::before { /* the curved highlight of the glass */
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(120% 75% at 30% 0%, rgb(255 255 255 / 0.28), rgb(255 255 255 / 0) 55%);
  pointer-events: none;
}
.vbtn--restart { left: var(--pad); }
.vbtn--sound { right: var(--pad); }
.vbtn svg { position: relative; display: block; width: 100%; height: 100%; overflow: visible;
  filter: drop-shadow(0 0.5px 1.5px rgb(0 0 0 / 0.3)); } /* keeps the white icon readable over pale footage */
.vbtn .btn__ring { display: none; }
.vbtn__i { fill: currentColor; }
.vbtn__line { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
.vbtn .vbtn__i--sound, .vbtn.is-on .vbtn__i--muted { display: none; }
.vbtn.is-on .vbtn__i--sound { display: inline; }
.vbtn:focus-visible { outline: 2px solid #fff; outline-offset: 3px; transform: translateZ(0) scale(1.06); }
@media (hover: hover) and (pointer: fine) {
  .vbtn:hover { transform: translateZ(0) scale(1.06); }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .vbtn { background: rgb(40 40 40 / 0.55); }
}

/* With a mouse or trackpad the buttons only appear while the pointer is moving over the video
   (site.js adds .is-controls, removed after 5s still or when it leaves), and show for keyboard focus. */
@media (hover: hover) and (pointer: fine) {
  .tile--video .vbtn { opacity: 0; pointer-events: none; transition: opacity 0.35s ease, transform 0.3s ease; }
  /* (two rules: a browser without :has would otherwise drop both) */
  .tile--video.is-controls .vbtn { opacity: 1; pointer-events: auto; transition-duration: 0.2s, 0.3s; } /* fades in over 200ms */
  .tile--video:has(.vbtn:focus-visible) .vbtn { opacity: 1; pointer-events: auto; transition-duration: 0.2s, 0.3s; }
}
/* Touch screens show the buttons, but once the visitor has stopped scrolling for 5s (site.js adds
   .is-scroll-idle to <html>) they fade, back again at the next scroll or touch. */
@media not ((hover: hover) and (pointer: fine)) {
  .tile--video .vbtn { transition: opacity 0.2s ease, transform 0.3s ease; }
  .is-scroll-idle .tile--video .vbtn { opacity: 0; pointer-events: none; transition-duration: 0.35s, 0.3s; }
}
@media (prefers-reduced-transparency: reduce) {
  .vbtn { background: rgb(40 40 40 / 0.85); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
@media (max-width: 639px) {
  .vbtn .vbtn__i { transform-box: fill-box; transform-origin: center; scale: 1.0909; } /* as the arrows */
}
a.tile--img .media img { transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1); }
/* .is-hover: hovering a project's text card zooms its image too (site.js); not the other way round */
a.tile--img.is-hover .media img { transform: scale(1.03); }
@media (hover: hover) and (pointer: fine) {
  a.tile--img:hover .media img { transform: scale(1.03); }
}

.tile--text { display: flex; flex-direction: column; justify-content: flex-end; }

/* ---------- Project cards (homepage) ---------- */

.tile--card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  --px: calc(3 * var(--pad) + var(--btn));
  padding-right: calc(2 * var(--pad) + var(--btn));
}
/* paragraph sits at the bottom, at least 80px below the title */
.tile--card .title-lg { margin-bottom: max(80px, calc(80 * var(--k))); }
.tile--card .body-sm { margin-top: auto; }
.tile--card .title-lg { width: 100%; }
.tile--card .btn { position: absolute; top: var(--pad); right: var(--pad); }
.tile--card-fixed { aspect-ratio: 502 / 613.93; justify-content: space-between; }

/* Tick-over heading: each time the pointer enters a card (script.js adds .is-ticking), every letter
   rolls up once like an odometer digit, staggered left to right.
   Capitals span -0.031em..0.681em of each 0.78em line. Each letter is clipped to just its capitals
   (-0.036em..0.686em, allowing for antialiasing), so neighbouring lines always keep a 0.058em gap and
   cut letter edges never meet. A 0.8em roll moves each copy fully out of its window and keeps the
   outgoing and incoming copies 0.088em apart. */
.tick__w { white-space: nowrap; }
.tick__c {
  position: relative;
  display: inline-block;
  clip-path: inset(-0.036em -0.15em 0.094em -0.15em);
}
.tick__c > span { display: block; }
.tick__c > span + span { position: absolute; top: 0; left: 0; transform: translateY(0.8em); }
.tick.is-ticking .tick__c > span {
  animation: 0.5s cubic-bezier(0.65, 0, 0.25, 1) calc(var(--i) * var(--tick-step, 35ms)) both;
  /* the same curve with a gentler finish: the last ~15% of the roll at a quarter speed (same 0.5s
     in total); browsers without linear() keep the cubic-bezier above */
  animation-timing-function: linear(0, 0.0005, 0.0022, 0.0051, 0.0094, 0.0153, 0.023, 0.0328, 0.045, 0.06, 0.0783, 0.1007, 0.128, 0.1613, 0.2023, 0.2528, 0.3147, 0.3891, 0.473, 0.5586, 0.6373, 0.7048, 0.761, 0.8075, 0.8462, 0.8786, 0.9059, 0.929, 0.9485, 0.9648, 0.9771, 0.9857, 0.991, 0.9941, 0.9959, 0.9972, 0.9983, 0.9991, 0.9996, 0.9999, 1);
}
.tick.is-ticking .tick__c > span:first-child { animation-name: tick-out; }
.tick.is-ticking .tick__c > span + span { animation-name: tick-in; }
@keyframes tick-out { from { transform: translateY(0); } to { transform: translateY(-0.8em); } }
@keyframes tick-in { from { transform: translateY(0.8em); } to { transform: translateY(0); } }

/* Load-in tick (first heading on each page, and the "Fearless…" headings): as its block is revealed, site.js adds .is-ticking-in and
   the letters roll up into place, staggered left to right. Only the incoming copy moves; the resting
   copy stays hidden until the roll ends, so the result is identical to the static heading. */
.tick.is-ticking-in .tick__c > span:first-child { visibility: hidden; }
/* the "Fearless…" title sets its own start and length per letter (site.js: shapeHeroTick) */
.tile--hero .tick.is-ticking-in .tick__c > span + span { animation-delay: var(--tick-at, 0ms) !important; animation-duration: var(--tick-ms, 0.5s) !important; }
.tick.is-ticking-in .tick__c > span + span {
  animation: tick-in 0.5s cubic-bezier(0.65, 0, 0.25, 1) calc(var(--i) * var(--tick-step, 35ms)) both;
  /* the same curve with a gentler finish: the last ~15% of the roll at a quarter speed (same 0.5s
     in total); browsers without linear() keep the cubic-bezier above */
  animation-timing-function: linear(0, 0.0005, 0.0022, 0.0051, 0.0094, 0.0153, 0.023, 0.0328, 0.045, 0.06, 0.0783, 0.1007, 0.128, 0.1613, 0.2023, 0.2528, 0.3147, 0.3891, 0.473, 0.5586, 0.6373, 0.7048, 0.761, 0.8075, 0.8462, 0.8786, 0.9059, 0.929, 0.9485, 0.9648, 0.9771, 0.9857, 0.991, 0.9941, 0.9959, 0.9972, 0.9983, 0.9991, 0.9996, 0.9999, 1);
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Hero ("Fearless…") + call to action ---------- */

.tile--hero { --pad: 0px; aspect-ratio: 753.75 / 928.69; overflow: hidden; }
.hero__title {
  position: absolute;
  left: calc(32 * var(--k));
  right: calc(32 * var(--k));
  top: calc(247.35 * var(--k));
  font-size: calc(180 * var(--t));
  text-align: center;
}
.hero__title > span { display: block; text-wrap: balance; }
.hero__logo {
  position: absolute;
  left: calc(141.34 * var(--k));
  top: calc(105.63 * var(--k));
  width: calc(412.328 * var(--k));
  height: calc(186.136 * var(--k));
  max-width: none;
  transform: rotate(-8deg);
  z-index: 1;                       /* logo overlaps the title, as in the design */
}
.hero__back { position: absolute; left: calc(32.5 * var(--k)); top: calc(31.75 * var(--k)); }
.hero__up .btn__arrow { rotate: 90deg; transform-box: fill-box; transform-origin: center; }   /* the back arrow, pointing up */

/* The "Fearless…" logo links home. The link takes no box of its own, so the logo keeps its position. */
.hero__logo-link { display: contents; }
.hero__logo-link .hero__logo { cursor: pointer; }
.hero__logo-link:focus-visible .hero__logo { outline: 2px solid var(--ink); outline-offset: 4px; }

/* Project page → homepage hand-off (site.js): the footer back button fades away as it is clicked, and
   on arrival the homepage shows its top row in place with no load-in animation. */
.js-reveal .tile > .hero__back.is-leaving, .hero__back.is-leaving {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  transition-delay: 0s;
}
.handoff .grid > .tile:nth-child(-n + 2) > * { opacity: 1; translate: none; transition: none; }

/* First-visit loading screen (site.js): black from the very first paint, the page hidden beneath, the
   logo writing in and out at half the screen's width. Fades away once everything has downloaded. */
html.is-loading, html.is-loading body { background: #000; overflow: hidden; }
html.is-loading main { visibility: hidden; }
.loader {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  background: #000;
  transition: opacity 0.6s ease;
}
.loader.is-done { opacity: 0; pointer-events: none; }
.loader__logo {
  /* the same size as the logo in the "Fearless…" block (site.js copies its exact size) */
  width: calc(412.328 * var(--u));
  height: calc(186.136 * var(--u));
  max-width: none;
  transform: rotate(-8deg);         /* as everywhere else on the site */
}

/* Homepage → project transition (TEST: transition-test.html → project pages with ?vt=1). The clicked
   preview image glides and resizes into the project's first image while the pages cross-fade softly.
   Images keep their crop while the frame changes shape (no stretching). */
.vt-arrive #lead-image > * { opacity: 1; translate: none; transition: none; }
::view-transition-group(project-image) {
  animation-duration: 0.7s;
  animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
}
::view-transition-old(project-image),
::view-transition-new(project-image) {
  height: 100%;
  object-fit: cover;
  animation-duration: 0.7s;
}
::view-transition-old(root) { animation: 0.35s ease-out both vt-fade-out; }
::view-transition-new(root) { animation: 0.45s ease-out 0.15s both vt-fade-in; }
@keyframes vt-fade-out { to { opacity: 0; } }
@keyframes vt-fade-in { from { opacity: 0; } }

.tile--cta {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 754 / 929;
}
.cta {
  font-size: max(19px, calc(34.2 * var(--t)));
  line-height: 1.16;
  text-align: center;
  white-space: nowrap;
}
a.u { color: inherit; } /* links in paragraphs keep the paragraph colour */
.u {
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-decoration-skip-ink: none;
  /* the gap between the text and its underline (half of the font’s 0.18em + 2px) */
  text-underline-offset: calc(0.09em + 1px);
  transition: text-underline-offset 0.35s ease;
}
/* hovering the link text itself: the underline glides 3.2px further down */
@media (hover: hover) and (pointer: fine) {
  .u:hover { text-underline-offset: calc(0.09em + 4.2px); }
}
.tile--cta .btn { position: absolute; right: var(--pad); bottom: var(--pad); }

/* ---------- Reveal on load / scroll ---------- */
/* site.js adds .is-revealed (with a staggered --reveal-delay) as each block enters the viewport.
   Only the contents move, so the black blocks and grey gutters stay put. `translate` is used rather
   than `transform` so it combines with existing transforms such as the rotated logo. */
.js-reveal .tile > * {
  opacity: 0;
  translate: 0 24px;
  transition: opacity 2s cubic-bezier(0.2, 0.7, 0.2, 1), translate 2s cubic-bezier(0.2, 0.7, 0.2, 1);
  transition-delay: var(--reveal-delay, 0ms);
}
.js-reveal .tile.is-revealed > * { opacity: 1; translate: none; }

/* ---------- Tablet + mobile scale tweaks ---------- */
/* Same layout as desktop, but buttons read slightly larger and serif text slightly smaller than a
   pure scale-down: buttons +10%, serif text -10% (including its minimum sizes). */
@media (max-width: 1023px) {
  :root { --btn: calc(70.4 * var(--u)); }
  .body-lg, .cta { font-size: max(17.1px, calc(30.78 * var(--k))); }
  .body-sm { font-size: max(15.3px, calc(21.6 * var(--k))); }
}

/* ---------- Mobile: single column ---------- */

@media (max-width: 639px) {
  :root {
    --u: calc(100vw / 753.75);          /* tiles are full width, scaled like a desktop half-tile */
    --pad: calc(32 * var(--u) + 8px);   /* 8px more inset inside every block */
  }
  .hero__back { left: calc(32.5 * var(--k) + 8px); top: calc(31.75 * var(--k) + 8px); }
  .hero__title { left: calc(32 * var(--k) + 8px); right: calc(32 * var(--k) + 8px); }
  .grid > .tile { grid-column: 1 / -1; grid-row: auto; --base: 753.75; }
  .pair { flex-direction: column; }
  .pair > .tile { flex: none; --base: 753.75; }

  /* pair each homepage preview with its card */
  .page-home .tile { order: var(--o, 0); }
  .tile--card-fixed { aspect-ratio: auto; }
  .tile--no-phone { display: none; }   /* feature rows keep only their large image */

  /* images and videos keep exactly their desktop shape: the picture takes that shape (--mr, set per
     block by the build) and the block grows around it with the phone's padding */
  .grid > .tile--img { aspect-ratio: auto !important; }
  .tile--img > .media { flex: none; aspect-ratio: var(--mr); }

  /* text blocks 25% shorter (not the "Fearless" blocks); --ar-phone is set per block by the build */
  .tile--intro, .tile--text, .pair > .tile--text { aspect-ratio: var(--ar-phone) !important; }
  .tile--cta { aspect-ratio: 754 / 557.4; }   /* 40% shorter than desktop (25%, then 20% more) */
  /* at least 64px between a heading and its paragraph; blocks grow taller when they need the room */
  .tile--intro { gap: 64px; }
  .tile--card .title-lg { margin-bottom: max(64px, calc(80 * var(--k))); }

  /* arrow buttons 10% larger, their arrows 20% larger (ring stroke stays 1.5px) */
  :root { --btn: calc(77.44 * var(--u)); }
  .btn__arrow { transform-box: fill-box; transform-origin: center; scale: 1.0909; }

  /* paragraphs reach 92% of the block width (80% on larger screens) */
  .body-lg, .body-sm { width: calc(0.92 * (100cqi + var(--px)) - var(--pad)); }

  /* serif text 32% larger than on tablet (20%, then 10% more; minimum sizes too) */
  .body-lg, .cta { font-size: max(22.57px, calc(40.63 * var(--k))); }
  .body-sm { font-size: max(22.2px, calc(28.51 * var(--k) + 2px)); }   /* +2px on top of the scaling */
  .title-xl { font-size: calc(244 * var(--k) - 8px); }   /* project page headings 8px smaller */
  /* homepage card titles 10% larger (project page headings and the "Fearless" blocks unchanged) */
  .title-lg { font-size: calc(140.8 * var(--k)); }
}

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

/* ---------- Cursor (mouse / trackpad only) ----------
   A 24px circle at 80% white instead of the standard cursor, everywhere on the site. It is a real
   cursor image, drawn by the operating system, so it moves as smoothly as the normal cursor whatever the page is doing. */
@media (hover: hover) and (pointer: fine) {
  /* important: overrides the pointing-hand cursor set on links and logos (not inside the editor) */
  /* sharp on high-resolution screens (image-set), with the vector circle for browsers without it */
  html:not(.is-editing), html:not(.is-editing) * {
    cursor: url("assets/ui/cursor.svg") 12 12, auto !important;
    cursor: -webkit-image-set(url("assets/ui/cursor.png") 1x, url("assets/ui/cursor-2x.png") 2x) 12 12, auto !important;
    cursor: image-set(url("assets/ui/cursor.png") 1x, url("assets/ui/cursor-2x.png") 2x) 12 12, auto !important;
  }
}

/* Wide screens: past 1700px the layout keeps growing (to 1920px) but text and buttons stay the size
   they are at 1700px. On the desktop grid one design px of a block equals one of the page (--k = --u),
   so the type size is the page scale, capped. */
@media (min-width: 1700px) {
  :root { --btn: calc(64 * min(100vw, var(--type-max)) / 1512); }
  .tile { --t: calc(min(100vw, var(--type-max)) / 1512); }
}

/* ---------- Older browsers ---------- */
/* Browsers without container query units (Safari before 16, Chrome before 105, Firefox before 110)
   would drop every size built on them. There each block takes its scale from the page instead: one
   design px of a block equals one of the page (--k = --u), so this matches everywhere except a
   "Two landscape" row in its own shape, which comes out close. Paragraph widths use the block's
   content width (100%) in place of 100cqi. */
@supports not (width: 1cqi) {
  .tile { --k: var(--u); }
  .body-lg, .body-sm { width: calc(0.8 * (100% + var(--px)) - var(--pad)); }
  @media (max-width: 639px) {
    .body-lg, .body-sm { width: calc(0.92 * (100% + var(--px)) - var(--pad)); }
  }
}
