/* ==========================================================================
   Danyal Sarfraz · Portfolio
   One stylesheet for every page. Light by default; dark follows the system
   setting unless the visitor picks one (html[data-theme="light" | "dark"],
   set before first paint). .theme-dark forces dark on any element (the
   Design page and a few dark tiles use it).
   ========================================================================== */

:root {
  color-scheme: light;
  --bg: #ffffff;
  --bg-2: #f5f5f7;
  --bg-3: #e8e8ed;
  --fg: #1d1d1f;
  --fg-2: #6e6e73;
  --fg-3: #86868b;
  --line: #d2d2d7;
  --line-soft: rgb(0 0 0 / 0.08);
  --link: #0066cc;
  --btn: #0071e3;
  --btn-hover: #0066cc;
  --accent: #5856d6;
  --accent-text: #4c4ac4;
  --accent-2: #30b0c7;
  --good: #248a3d;
  --grad: linear-gradient(90deg, #5856d6 0%, #0071e3 100%);
  --nav-bg: rgb(255 255 255 / 0.8);
  --tile: #f5f5f7;
  --tile-2: #ffffff;
  --glass: rgb(255 255 255 / 0.72);
  --glass-edge: rgb(255 255 255 / 0.9);
  --shadow-soft: 0 4px 24px rgb(0 0 0 / 0.06), 0 1px 2px rgb(0 0 0 / 0.04);
  --shadow-lift: 0 18px 50px -12px rgb(0 0 0 / 0.22);

  --font: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  /* Type scale: every font-size is one of these (or an em inside a line). */
  --fs-micro: 12px;
  --fs-small: 14px;
  --fs-body: 17px;
  --fs-body-l: 19px;
  --fs-title-s: 21px;
  --fs-eyebrow: clamp(17px, 1.6vw, 21px);
  --fs-lead: clamp(19px, 1.9vw, 24px);
  --fs-statement: clamp(21px, 2.6vw, 32px);
  --fs-title: clamp(24px, 2.4vw, 28px);
  --fs-h3: clamp(26px, 3vw, 36px);
  --fs-subhead: clamp(28px, 3.6vw, 44px);
  --fs-h2: clamp(32px, 4.6vw, 56px);
  --fs-h1: clamp(40px, 6vw, 72px);
  --fs-display: clamp(44px, 7.2vw, 84px);
  --fs-giant: clamp(56px, 7.4vw, 104px);

  --w-text: 692px;
  --w-main: 980px;
  --w-wide: 1200px;
  --g: clamp(20px, 6.25vw, 44px);
  --r-xl: 32px;
  --r-lg: 28px;
  --r-md: 18px;
  --r-sm: 12px;
  --nav-h: 48px;
  --lnav-h: 52px;
  --appbar-h: 70px;
  --ease: cubic-bezier(0.28, 0.11, 0.32, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.3, 0.64, 1);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #000000;
    --bg-2: #161617;
    --bg-3: #232326;
    --fg: #f5f5f7;
    --fg-2: #a1a1a6;
    --fg-3: #86868b;
    --line: #424245;
    --line-soft: rgb(255 255 255 / 0.1);
    --link: #2997ff;
    --btn: #0071e3;
    --btn-hover: #0066cc;
    --accent: #7d7aff;
    --accent-text: #9b99ff;
    --accent-2: #40c8e0;
    --good: #30d158;
    --grad: linear-gradient(90deg, #9b99ff 0%, #2997ff 100%);
    --nav-bg: rgb(22 22 23 / 0.8);
    --tile: #161617;
    --tile-2: #1d1d1f;
    --glass: rgb(40 40 44 / 0.7);
    --glass-edge: rgb(255 255 255 / 0.14);
    --shadow-soft: 0 4px 24px rgb(0 0 0 / 0.5);
    --shadow-lift: 0 18px 50px -12px rgb(0 0 0 / 0.7);
  }
}

:root[data-theme="dark"],
.theme-dark {
  color-scheme: dark;
  --bg: #000000;
  --bg-2: #161617;
  --bg-3: #232326;
  --fg: #f5f5f7;
  --fg-2: #a1a1a6;
  --fg-3: #86868b;
  --line: #424245;
  --line-soft: rgb(255 255 255 / 0.1);
  --link: #2997ff;
  --btn: #0071e3;
  --btn-hover: #0066cc;
  --accent: #7d7aff;
  --accent-text: #9b99ff;
  --accent-2: #40c8e0;
  --good: #30d158;
  --grad: linear-gradient(90deg, #9b99ff 0%, #2997ff 100%);
  --nav-bg: rgb(22 22 23 / 0.8);
  --tile: #161617;
  --tile-2: #1d1d1f;
  --glass: rgb(40 40 44 / 0.7);
  --glass-edge: rgb(255 255 255 / 0.14);
  --shadow-soft: 0 4px 24px rgb(0 0 0 / 0.5);
  --shadow-lift: 0 18px 50px -12px rgb(0 0 0 / 0.7);
  background-color: var(--bg);
  color: var(--fg);
}

/* ---------------------------------------------------------------- base */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--bg);
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--lnav-h) + 16px);
}

html:has(body.theme-dark) {
  color-scheme: dark;
  background: #000;
}

/* Scrolling up to an anchor brings the global nav back above the local nav,
   so leave room for both. */
html:has(body.has-lnav) {
  scroll-padding-top: calc(var(--nav-h) + var(--lnav-h) + 16px);
}

/* App pages also keep the shrunken app bar above the local nav. */
html:has(body.has-lnav .appbar--sticky) {
  scroll-padding-top: calc(var(--nav-h) + var(--appbar-h) + var(--lnav-h) + 16px);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.47059;
  font-weight: 400;
  letter-spacing: -0.016em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-optical-sizing: auto;
  text-rendering: optimizeLegibility;
}

img,
svg,
video,
canvas {
  display: block;
  max-width: 100%;
}

img,
video {
  height: auto;
}

/* Pictures and films can't be dragged out, selected, or saved from the
   long-press menu on iPhone (see also initNoSaving in site.js). */
img,
video,
canvas {
  -webkit-user-drag: none;
  user-select: none;
  -webkit-touch-callout: none;
}

h1,
h2,
h3,
h4,
h5 {
  margin: 0;
  font-weight: 600;
  text-wrap: balance;
}

p {
  margin: 0;
  text-wrap: pretty;
}

ul,
ol {
  margin: 0;
  padding: 0;
}

figure,
blockquote {
  margin: 0;
}

a {
  color: var(--link);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

button {
  font: inherit;
  color: inherit;
}

strong,
b {
  font-weight: 600;
}

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

sup {
  font-size: 0.55em;
  line-height: 0;
  vertical-align: 0.9em;
  margin-inline-start: 0.08em;
}

sup a {
  color: inherit;
}

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  inset-inline-start: 12px;
  top: -60px;
  z-index: 200;
  padding: 10px 16px;
  border-radius: 980px;
  background: var(--btn);
  color: #fff;
  font-size: var(--fs-small);
  transition: top 0.2s ease;
}

.skip-link:focus {
  top: 10px;
  text-decoration: none;
}

/* ---------------------------------------------------------------- languages
   The <head> script hides the page for the moment it takes to translate it, so
   English never flashes first. Arabic and Chinese get no negative tracking
   (it breaks Arabic joining and crowds Chinese) and a little more leading.
   System fonts cover both scripts. */

.i18n-wait body {
  visibility: hidden;
}

:lang(ar),
:lang(zh) {
  letter-spacing: 0 !important;
}

body:lang(ar) {
  line-height: 1.6;
}

body:lang(zh) {
  line-height: 1.65;
}

/* ---------------------------------------------------------------- layout */

.container,
.container-wide,
.container-text {
  width: min(var(--w-main), calc(100% - 2 * var(--g)));
  margin-inline: auto;
}

.container-wide {
  width: min(var(--w-wide), calc(100% - 2 * var(--g)));
}

.container-text {
  width: min(var(--w-text), calc(100% - 2 * var(--g)));
}

.section {
  padding-block: clamp(80px, 11vw, 150px);
}

.section--tight {
  padding-block: clamp(56px, 7vw, 96px);
}

.section--alt {
  background: var(--bg-2);
}

/* Two plain sections in a row share one gap. Only collapse when both sit on the
   page background; after an alt, dark or custom-coloured band the next section
   needs its full top padding, or its heading lands on the colour edge. */
.section:not(.section--alt):not(.theme-dark):not([style*="background"]) + .section:not(.section--alt):not(.theme-dark):not([style*="background"]) {
  padding-top: 0;
}

.section--alt + .section--alt {
  padding-top: 0;
}

.stack > * + * {
  margin-top: var(--stack, 24px);
}

/* Space above a block: one scale for the whole site, in place of inline
   margins. Utilities win over component margins, as the inline styles did. */
.mt-1 { margin-top: 8px !important; }
.mt-2 { margin-top: 20px !important; }
.mt-3 { margin-top: 32px !important; }
.mt-4 { margin-top: clamp(40px, 5vw, 64px) !important; }
.mt-5 { margin-top: clamp(48px, 6vw, 80px) !important; }
.mt-6 { margin-top: clamp(56px, 7vw, 96px) !important; }
.mt-7 { margin-top: clamp(64px, 8vw, 112px) !important; }

.center {
  text-align: center;
}

.divider {
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 0;
}

/* ---------------------------------------------------------------- type */

.t-display {
  font-size: var(--fs-display);
  line-height: 1.04;
  font-weight: 600;
  letter-spacing: -0.028em;
}

.t-h1 {
  font-size: var(--fs-h1);
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -0.025em;
}

.t-h2 {
  font-size: var(--fs-h2);
  line-height: 1.07;
  font-weight: 600;
  letter-spacing: -0.022em;
}

.t-h3 {
  font-size: var(--fs-h3);
  line-height: 1.11;
  font-weight: 600;
  letter-spacing: -0.018em;
}

.t-h4 {
  font-size: var(--fs-lead);
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.012em;
}

.t-lead {
  font-size: var(--fs-lead);
  line-height: 1.38;
  letter-spacing: -0.014em;
}

.t-small {
  font-size: var(--fs-small);
  line-height: 1.43;
  letter-spacing: -0.012em;
}

.t-fine {
  font-size: var(--fs-micro);
  line-height: 1.34;
  letter-spacing: -0.006em;
}

.t-eyebrow {
  display: block;
  font-size: var(--fs-eyebrow);
  line-height: 1.19;
  font-weight: 600;
  letter-spacing: -0.012em;
  color: var(--fg-2);
}

.t-muted {
  color: var(--fg-2);
}

.t-grad {
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Two-tone paragraph: gray copy with the key phrases in full color. */
.t-two-tone {
  font-size: var(--fs-statement);
  line-height: 1.24;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--fg-3);
}

.t-two-tone strong {
  color: var(--fg);
}

.t-mono {
  font-family: var(--mono);
  font-size: 0.88em;
  letter-spacing: 0;
}

.prose p + p {
  margin-top: 1em;
}

.prose p,
.prose li {
  color: var(--fg-2);
}

.prose strong {
  color: var(--fg);
}

.prose ul {
  padding-inline-start: 1.2em;
}

ul.prose {
  padding-inline-start: 1.2em;
}

.prose li + li {
  margin-top: 0.4em;
}

/* ---------------------------------------------------------------- links & buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 22px;
  border: 1px solid var(--btn);
  border-radius: 980px;
  background: var(--btn);
  color: #fff;
  font-size: var(--fs-body);
  line-height: 1;
  letter-spacing: -0.016em;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color 0.3s var(--ease),
    color 0.3s var(--ease),
    border-color 0.3s var(--ease),
    scale 0.35s var(--ease-spring);
}

.btn:hover {
  background: var(--btn-hover);
  border-color: var(--btn-hover);
  text-decoration: none;
}

.btn:active {
  scale: 0.96;
  transition-duration: 0.12s;
}

.btn--secondary {
  background: transparent;
  color: var(--link);
  border-color: var(--link);
}

.btn--secondary:hover {
  background: var(--link);
  border-color: var(--link);
  color: #fff;
}

.btn--sm {
  min-height: 28px;
  padding: 0 12px;
  font-size: var(--fs-micro);
  letter-spacing: -0.01em;
}

.btn--md {
  min-height: 36px;
  padding: 0 16px;
  font-size: var(--fs-small);
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px 28px;
}

.cta-row--start {
  justify-content: flex-start;
}

.link-more,
.link-ext {
  display: inline-flex;
  align-items: baseline;
  gap: 0.28em;
  color: var(--link);
  font-size: inherit;
}

.link-more::after,
.link-ext::after {
  content: "";
  display: inline-block;
  flex: none;
  width: 0.5em;
  height: 0.5em;
  background: currentColor;
  -webkit-mask: var(--chev) no-repeat center / contain;
  mask: var(--chev) no-repeat center / contain;
  transform: translateY(0.02em);
  transition: translate 0.4s var(--ease);
}

.link-more:hover::after,
a:hover .link-more::after {
  translate: 0.18em 0;
}

.link-ext:hover::after {
  translate: 0.1em -0.1em;
}

/* Right to left, the arrows point the other way. */
.link-more:dir(rtl)::after,
.link-ext:dir(rtl)::after {
  scale: -1 1;
}

.link-more:dir(rtl):hover::after,
a:hover .link-more:dir(rtl)::after {
  translate: -0.18em 0;
}

.link-ext:dir(rtl):hover::after {
  translate: -0.1em -0.1em;
}

.link-more {
  --chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 14'%3E%3Cpath d='M1.2 1.2 6.8 7l-5.6 5.8' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.link-ext {
  --chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 9 9 3M4 3h5v5' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.links-inline {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
}

.links-inline--center {
  justify-content: center;
}

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

.gnav {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--nav-h);
  background: var(--nav-bg);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--line-soft);
}

/* With a local nav, the global nav tucks away while scrolling down and slides
   back in on any scroll up. Both bars move by the same distance with the same
   timing, so the local nav stays fastened to the global nav's lower edge and no
   gap opens between them. Revealing glides in and settles softly; hiding is a
   touch quicker. A transition runs with the timing of the state it is heading
   to, hence the two blocks. Nothing fades: a fading bar would leave a gap. */
.has-lnav .gnav,
.has-lnav .lnav {
  transition: transform 0.6s var(--ease-out);
}

.has-lnav .lnav {
  top: var(--nav-h);
}

.gnav-hidden:not(.nav-open) .gnav,
.gnav-hidden:not(.nav-open) .lnav {
  transition: transform 0.45s var(--ease);
  transform: translateY(calc(-1 * var(--nav-h)));
}

.gnav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  width: min(1024px, calc(100% - 2 * var(--g)));
  height: 100%;
  margin-inline: auto;
}

.gnav__logo {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--fg);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

.gnav__logo:hover {
  text-decoration: none;
}

.gnav__logo svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.gnav__list {
  display: flex;
  align-items: center;
  gap: clamp(18px, 3vw, 38px);
  list-style: none;
}

.gnav__list a {
  color: var(--fg);
  font-size: var(--fs-micro);
  letter-spacing: -0.01em;
  opacity: 0.8;
  transition: opacity 0.2s ease;
}

.gnav__list a:hover,
.gnav__list a[aria-current="page"] {
  opacity: 1;
  text-decoration: none;
}

/* The current page reads heavier without changing the word's width, so the
   other links never shift between pages. */
.gnav__list a[aria-current="page"] {
  text-shadow: 0.35px 0 0 currentColor, -0.35px 0 0 currentColor;
}

/* Search, language and theme buttons. They need the script, so they stay
   hidden without it. */
.gnav__tools {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  gap: 2px;
  margin-inline-end: -6px;
}

html:not(.js) .gnav__tools {
  visibility: hidden;
}

/* Header markup from before the search/theme buttons, still in some browser
   caches for a few minutes after a deploy: keep it looking as it used to. */

.gnav__icon {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--fg);
  opacity: 0.8;
  cursor: pointer;
  transition: opacity 0.2s ease, background-color 0.2s ease;
}

.gnav__icon:hover {
  opacity: 1;
  background: var(--line-soft);
}

.gnav__icon svg {
  width: 18px;
  height: 18px;
  fill: currentColor;
}

/* The theme button shows the theme in use (set before first paint). */
.theme-icon {
  display: none;
}

:root:not([data-theme-now="dark"]) .theme-icon--light,
[data-theme-now="dark"] .theme-icon--dark {
  display: block;
}

/* Language menu, opened from the globe button. */
.lang-menu {
  position: absolute;
  top: calc(100% + 8px);
  inset-inline-end: 0;
  z-index: 120;
  display: grid;
  min-width: 172px;
  padding: 6px;
  border: 1px solid var(--line-soft);
  border-radius: 14px;
  background: var(--tile-2);
  box-shadow: var(--shadow-lift);
  animation: menu-in 0.24s var(--ease-out);
}

@keyframes menu-in {
  from {
    opacity: 0;
    translate: 0 -6px;
  }
}

.lang-menu__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 38px;
  padding: 0 12px;
  border: 0;
  border-radius: 9px;
  background: none;
  color: var(--fg);
  font-size: var(--fs-small);
  text-align: start;
  cursor: pointer;
}

.lang-menu__item:hover,
.lang-menu__item:focus-visible {
  background: var(--line-soft);
}

.lang-menu__item:focus-visible {
  outline-offset: -2px;
}

.lang-menu__item[aria-checked="true"] {
  font-weight: 600;
}

.lang-menu__item svg {
  flex: none;
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  visibility: hidden;
}

.lang-menu__item[aria-checked="true"] svg {
  visibility: visible;
}

/* A slim bar under the header: a language offer, or a note that the page is
   in English only. */
.lang-bar {
  border-bottom: 1px solid var(--line-soft);
  background: var(--bg-2);
  font-size: var(--fs-small);
  line-height: 1.4;
}

.lang-bar__inner {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px 16px;
  width: min(var(--w-main), calc(100% - 2 * var(--g)));
  margin-inline: auto;
  padding: 10px 36px;
}

.lang-bar__text {
  color: var(--fg-2);
}

.lang-bar__close {
  position: absolute;
  top: 50%;
  inset-inline-end: -6px;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--fg-2);
  cursor: pointer;
  translate: 0 -50%;
}

.lang-bar__close:hover {
  background: var(--line-soft);
  color: var(--fg);
}

.lang-bar__close svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

/* Equal side columns keep the link list centred on the page, whatever the
   logo and button widths. */
@media (min-width: 834px) {
  .gnav__inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
  }

  .gnav__logo {
    justify-self: start;
  }

  .gnav__tools {
    justify-self: end;
  }
}

.gnav__menu {
  display: none;
  place-items: center;
  width: 36px;
  height: 36px;
  margin-inline-end: -8px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.gnav__menu svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: var(--fg);
  stroke-width: 1.4;
  stroke-linecap: round;
}

.gnav__menu path {
  transform-box: view-box;
  transform-origin: center;
  transition: transform 0.5s var(--ease-in-out);
}

.nav-open .gnav__menu .l1 {
  transform: rotate(45deg) translateY(3px);
}

.nav-open .gnav__menu .l2 {
  transform: rotate(-45deg) translateY(-3px);
}

@media (max-width: 833px) {
  .gnav__menu {
    display: inline-grid;
  }

  .gnav__tools {
    margin-inline: auto 4px;
  }

  /* Anchored to .gnav: its backdrop-filter would trap position: fixed anyway. */
  .gnav__list {
    position: absolute;
    top: var(--nav-h);
    left: 0;
    right: 0;
    z-index: 99;
    height: calc(100vh - var(--nav-h));
    height: calc(100dvh - var(--nav-h));
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 18px var(--g) 40px;
    background: var(--bg);
    overflow-y: auto;
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.32s var(--ease), visibility 0s linear 0.32s;
  }

  .nav-open .gnav__list {
    visibility: visible;
    opacity: 1;
    transition: opacity 0.45s var(--ease-out), visibility 0s;
  }

  .gnav__list li {
    opacity: 0;
    transform: translate3d(0, -16px, 0);
    transition: opacity 0.2s var(--ease), transform 0.3s var(--ease);
  }

  .nav-open .gnav__list li {
    opacity: 1;
    transform: none;
    transition: opacity 0.6s var(--ease-out), transform 0.8s var(--ease-out);
  }

  .nav-open .gnav__list li:nth-child(1) { transition-delay: 0.05s; }
  .nav-open .gnav__list li:nth-child(2) { transition-delay: 0.1s; }
  .nav-open .gnav__list li:nth-child(3) { transition-delay: 0.15s; }
  .nav-open .gnav__list li:nth-child(4) { transition-delay: 0.2s; }
  .nav-open .gnav__list li:nth-child(5) { transition-delay: 0.25s; }
  .nav-open .gnav__list li:nth-child(6) { transition-delay: 0.3s; }
  .nav-open .gnav__list li:nth-child(7) { transition-delay: 0.35s; }

  .gnav {
    transition: background-color 0.4s var(--ease);
  }

  .nav-open .gnav {
    background: var(--bg);
  }

  .gnav__list a {
    display: block;
    padding: 9px 0;
    font-size: var(--fs-h3);
    font-weight: 600;
    letter-spacing: -0.02em;
    opacity: 1;
  }

  body.nav-open {
    overflow: hidden;
  }
}

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

.lnav {
  position: sticky;
  top: 0;
  z-index: 90;
  height: var(--lnav-h);
  background: var(--nav-bg);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--line-soft);
}

.lnav__inner {
  display: flex;
  align-items: center;
  gap: 20px;
  width: min(var(--w-main), calc(100% - 2 * var(--g)));
  height: 100%;
  margin-inline: auto;
}

.lnav__title {
  margin-inline-end: auto;
  color: var(--fg);
  font-size: var(--fs-title-s);
  font-weight: 600;
  letter-spacing: -0.012em;
  white-space: nowrap;
}

.lnav__title:hover {
  text-decoration: none;
}

.lnav__links {
  display: flex;
  gap: 22px;
  list-style: none;
}

.lnav__links a {
  position: relative;
  color: var(--fg);
  font-size: var(--fs-micro);
  opacity: 0.72;
  white-space: nowrap;
  transition: opacity 0.35s var(--ease);
}

/* The current section gets an underline that grows in, so the text never
   changes weight and neighbouring links never shift. */
.lnav__links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -5px;
  height: 1.5px;
  border-radius: 1px;
  background: currentColor;
  transform: scaleX(0);
  transition: transform 0.5s var(--ease);
}

.lnav__links a:hover,
.lnav__links a[aria-current="true"] {
  opacity: 1;
  text-decoration: none;
}

.lnav__links a[aria-current="true"]::after {
  transform: scaleX(1);
}

@media (max-width: 833px) {
  .lnav__links {
    display: none;
  }

  .lnav__title {
    font-size: var(--fs-body-l);
  }
}

/* ---------------------------------------------------------------- site search */

.search {
  flex-direction: column;
  width: min(640px, calc(100% - 32px));
  max-width: none;
  max-height: min(72vh, 600px);
  margin: min(12vh, 120px) auto auto;
  padding: 0;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--bg);
  color: var(--fg);
  box-shadow: var(--shadow-lift);
  overflow: hidden;
}

.search[open] {
  display: flex;
  animation: search-in 0.35s var(--ease-out);
}

.search::backdrop {
  background: rgb(0 0 0 / 0.32);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

@keyframes search-in {
  from {
    opacity: 0;
    transform: translateY(-8px) scale(0.985);
  }
}

.search__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line-soft);
}

.search__bar svg {
  flex: none;
  width: 18px;
  height: 18px;
  fill: var(--fg-2);
}

.search__input {
  flex: 1;
  min-width: 0;
  padding: 4px 0;
  border: 0;
  background: none;
  color: var(--fg);
  font: inherit;
  font-size: var(--fs-body);
  outline: none;
}

.search__input::-webkit-search-cancel-button {
  display: none;
}

.search kbd {
  padding: 2px 7px;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--fg-2);
  font: 500 11px/1.4 var(--font);
}

.search__results {
  margin: 0;
  padding: 8px;
  overflow-y: auto;
  list-style: none;
  overscroll-behavior: contain;
}

.search__results:empty {
  display: none;
}

.search__group {
  padding: 10px 12px 4px;
  color: var(--fg-2);
  font-size: var(--fs-micro);
  font-weight: 600;
}

.search__hit {
  display: block;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  color: var(--fg);
}

.search__hit:hover,
.search__hit[aria-selected="true"] {
  background: var(--bg-2);
  text-decoration: none;
}

.search__page {
  display: block;
  margin-bottom: 2px;
  color: var(--fg-2);
  font-size: var(--fs-micro);
}

.search__title {
  display: block;
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.search__snip {
  display: -webkit-box;
  margin-top: 3px;
  overflow: hidden;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.45;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.search mark {
  background: none;
  color: var(--accent-text);
  font-weight: 600;
}

.search__status {
  padding: 12px 20px 16px;
  color: var(--fg-2);
  font-size: var(--fs-small);
}

.search__status:empty {
  display: none;
}

/* The heading a search result lands on glows briefly. */
.search-target {
  border-radius: 6px;
  animation: search-target 2.4s var(--ease) 0.3s backwards;
}

@keyframes search-target {
  from {
    background-color: rgb(255 159 10 / 0.32);
    box-shadow: 0 0 0 6px rgb(255 159 10 / 0.32);
  }
  to {
    background-color: transparent;
    box-shadow: 0 0 0 6px transparent;
  }
}

/* ---------------------------------------------------------------- hero */

.hero {
  padding-top: clamp(44px, 6.4vw, 88px);
  text-align: center;
}

.hero__eyebrow {
  margin-bottom: 14px;
}

.hero__title {
  margin-inline: auto;
  max-width: 14ch;
}

.hero__title--wide {
  max-width: 18ch;
}

.hero__lead {
  max-width: 34em;
  margin: 22px auto 0;
  color: var(--fg-2);
}

.hero .cta-row {
  margin-top: 32px;
}

/* The film or picture under a case study's headline. */
.hero > .hero__media {
  margin-top: clamp(28px, 5vw, 56px);
}

/* A hero that fills most of the window (the 404 page). */
.hero--tall {
  min-height: 70vh;
  padding-bottom: 120px;
}

.page-hero {
  padding-top: clamp(64px, 9vw, 120px);
  padding-bottom: clamp(40px, 6vw, 72px);
}

.page-hero__title {
  max-width: 15ch;
}

.page-hero__lead {
  max-width: 36em;
  margin-top: 20px;
  color: var(--fg-2);
}

/* A visionOS-style window (Bangudae XR): rounded media with a grab bar beneath. */
.window {
  position: relative;
  margin: 0;
}

.window__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  border-radius: clamp(18px, 2.4vw, 30px);
  background: #1d1d1f;
  box-shadow:
    0 50px 100px -40px rgb(0 0 0 / 0.42),
    0 18px 40px -24px rgb(0 0 0 / 0.3);
  isolation: isolate;
}

.window__media--wide {
  aspect-ratio: 2.05 / 1;
}

.window__media::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.16);
  pointer-events: none;
}

.window__media > :is(img, video) {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The small grab bar visionOS shows under a window. */
.window__bar {
  display: block;
  width: clamp(44px, 7%, 80px);
  height: 6px;
  margin: 14px auto 0;
  border-radius: 3px;
  background: color-mix(in srgb, var(--fg) 20%, transparent);
}

/* ---------------------------------------------------------------- section heads */

.shead {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px 32px;
  margin-bottom: clamp(32px, 4.4vw, 56px);
}

.shead__title {
  max-width: 17ch;
}

.shead__text {
  max-width: 34em;
  margin-top: 16px;
  color: var(--fg-2);
}

.shead__link {
  font-size: var(--fs-body);
  white-space: nowrap;
}

/* ---------------------------------------------------------------- tiles & bento */

.bento {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(12px, 1.6vw, 20px);
}

.bento > * {
  grid-column: span 6;
}

@media (min-width: 734px) {
  .span-2 { grid-column: span 2; }
  .span-3 { grid-column: span 3; }
  .span-4 { grid-column: span 4; }
  .span-6 { grid-column: span 6; }
}

@media (min-width: 734px) and (max-width: 1068px) {
  .span-2 { grid-column: span 3; }
  .bento--thirds > .span-2 { grid-column: span 6; }
}

.tile {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--tile);
  color: var(--fg);
}

.tile--white {
  background: var(--tile-2);
}

.tile__body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(26px, 3.4vw, 44px);
}

.tile__body--center {
  align-items: center;
  text-align: center;
}

.tile__eyebrow {
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.tile__title {
  font-size: var(--fs-h3);
  line-height: 1.1;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.tile__title--sm {
  font-size: var(--fs-title);
}

.tile__text {
  color: var(--fg-2);
  max-width: 34em;
}

.tile__media {
  position: relative;
  margin-top: auto;
  overflow: hidden;
}

.tile__media img,
.tile__media video {
  width: 100%;
}

/* A picture with its own background (a white composite, say) sits inside the
   tile with all four corners rounded, never flush with one edge. */
.tile__media--inset {
  padding: 0 clamp(26px, 3.4vw, 44px) clamp(26px, 3.4vw, 44px);
}

.tile__media--inset > :is(img, video) {
  border-radius: var(--r-md);
}

a.tile {
  transition: transform 0.6s var(--ease), box-shadow 0.6s var(--ease);
}

a.tile:hover {
  text-decoration: none;
}

a.tile .tile__media > :is(img, video) {
  transition: transform 1.1s var(--ease-out);
  will-change: transform;
}

@media (hover: hover) and (pointer: fine) {
  a.tile:hover {
    transform: translateY(-6px);
    box-shadow: var(--shadow-lift);
  }

  a.tile:hover .tile__media > :is(img, video) {
    transform: scale(1.035);
  }
}

a.tile:active {
  transform: translateY(-2px) scale(0.992);
  transition-duration: 0.15s;
}

a.tile:hover .link-more {
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

.blend-white {
  mix-blend-mode: multiply;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .blend-white {
    mix-blend-mode: normal;
  }
}

:root[data-theme="dark"] .blend-white {
  mix-blend-mode: normal;
}

/* Product-on-white media keeps a white stage in dark mode. */
.white-stage {
  background: #fff;
}

.area-icon {
  width: 40px;
  height: 40px;
  margin-bottom: 10px;
  color: var(--accent);
}

/* ---------------------------------------------------------------- stats */

/* Stat tiles share a height; a stat beside text (no tile) sizes to its content. */
.tile.stat {
  justify-content: space-between;
  min-height: clamp(220px, 24vw, 300px);
}

.stat .tile__body {
  height: 100%;
  justify-content: space-between;
}

.stat__kicker {
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: -0.014em;
}

.stat__num {
  display: block;
  font-size: var(--fs-giant);
  line-height: 1;
  font-weight: 600;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.stat__num small {
  font-size: 0.42em;
  letter-spacing: -0.02em;
}

/* In a one-third tile the figure has less room. */
.bento--thirds .stat__num {
  font-size: var(--fs-h1);
}

.stat__cap {
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.4;
}

/* ---------------------------------------------------------------- figures & media */

.fig {
  margin: 0;
}

.fig__media {
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--bg-2);
}

/* A cinematic film strip (case study heroes); taller on phones. */
.fig__media--film {
  position: relative;
  aspect-ratio: 2.4 / 1;
  border-radius: var(--r-xl);
  background: #1d1d1f;
}

.fig__media--film > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 733px) {
  .fig__media--film {
    aspect-ratio: 16 / 10;
    border-radius: var(--r-lg);
  }
}

.fig__media--white {
  background: #fff;
}

/* The large radius of hero media, for a figure that leads a section. */
.fig__media--xl {
  border-radius: var(--r-xl);
}

.fig__media--pad {
  padding: clamp(16px, 3vw, 40px);
}

/* A vertical film (a reel cut for phones), kept to a phone's width and centred. */
.fig__media--portrait {
  max-width: 400px;
  margin-inline: auto;
}

.fig__media img,
.fig__media video {
  width: 100%;
}

.fig__cap {
  max-width: 44em;
  margin-top: 14px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.43;
}

.fig__cap strong {
  color: var(--fg);
}

.fig--center .fig__cap {
  margin-inline: auto;
  text-align: center;
}

.fig-row {
  display: grid;
  gap: clamp(12px, 1.6vw, 20px);
}

.fig-row--4 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 734px) {
  .fig-row--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fig-row--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .fig-row--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.ratio-1 { aspect-ratio: 1; object-fit: cover; }
.ratio-4-3 { aspect-ratio: 4 / 3; object-fit: cover; }
.ratio-3-4 { aspect-ratio: 3 / 4; object-fit: cover; }
.ratio-16-9 { aspect-ratio: 16 / 9; object-fit: cover; }
.ratio-16-10 { aspect-ratio: 16 / 10; object-fit: cover; }

/* Looping video with play/pause control. */
.loop {
  position: relative;
}

.loop video {
  width: 100%;
}

.loop__toggle {
  position: absolute;
  inset-inline-end: 14px;
  bottom: 14px;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgb(0 0 0 / 0.46);
  color: #fff;
  cursor: pointer;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: background-color 0.3s var(--ease), scale 0.35s var(--ease-spring);
}

.loop__toggle:hover {
  background: rgb(0 0 0 / 0.64);
}

.loop__toggle svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}

.loop__toggle .i-play,
.loop__toggle .i-replay { display: none; }
.loop.is-paused .loop__toggle .i-play { display: block; }
.loop.is-paused .loop__toggle .i-pause { display: none; }
.loop.is-ended .loop__toggle .i-play { display: none; }
.loop.is-ended .loop__toggle .i-replay { display: block; }

.loop__toggle:active {
  scale: 0.9;
}

.loop__label {
  position: absolute;
  inset-inline-start: 14px;
  top: 14px;
  padding: 5px 10px;
  border-radius: 980px;
  background: rgb(255 255 255 / 0.82);
  color: #1d1d1f;
  font-size: var(--fs-micro);
  font-weight: 600;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

/* ---------------------------------------------------------------- facts (spec sheet) */

.facts {
  display: grid;
  gap: 28px 32px;
  padding-top: 28px;
  border-top: 1px solid var(--line);
}

@media (min-width: 734px) {
  .facts {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.fact__label {
  display: block;
  margin-bottom: 6px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
}

.fact__value {
  font-size: var(--fs-body);
  line-height: 1.42;
}

.fact__value a {
  color: var(--link);
}

/* ---------------------------------------------------------------- steps */

.steps {
  display: grid;
  gap: clamp(12px, 1.6vw, 20px);
  counter-reset: step;
  list-style: none;
}

@media (min-width: 734px) {
  .steps--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .steps--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1069px) {
  .steps--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.step {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(24px, 3vw, 36px);
  border-radius: var(--r-lg);
  background: var(--tile);
}

.step__num {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  margin-bottom: 8px;
  border-radius: 50%;
  background: var(--fg);
  color: var(--bg);
  font-size: var(--fs-small);
  font-weight: 600;
}

.step__title {
  font-size: var(--fs-title-s);
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.012em;
}

.step__text {
  color: var(--fg-2);
}

.step__meta {
  margin-top: auto;
  padding-top: 10px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
}

/* ---------------------------------------------------------------- charts */

.chart {
  padding: clamp(24px, 3.4vw, 44px);
  border-radius: var(--r-lg);
  background: var(--tile);
}

.chart__title {
  font-size: var(--fs-title-s);
  font-weight: 600;
  letter-spacing: -0.012em;
}

.chart__sub {
  margin-top: 4px;
  color: var(--fg-2);
  font-size: var(--fs-small);
}

.bars {
  position: relative;
  display: grid;
  gap: 16px;
  margin-top: 28px;
  list-style: none;
}

.bar {
  display: grid;
  grid-template-columns: minmax(96px, 30%) 1fr auto;
  align-items: center;
  gap: 14px;
}

.bar__label {
  font-size: var(--fs-small);
  line-height: 1.25;
}

.bar__label small {
  display: block;
  color: var(--fg-2);
  font-size: var(--fs-micro);
}

/* Phones: each label sits on its own line above its bar. */
@media (max-width: 599px) {
  .bar {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 6px 12px;
  }

  .bar__label {
    grid-column: 1 / -1;
  }
}

.bar__track {
  position: relative;
  height: 28px;
  border-radius: 8px;
  background: var(--bg-3);
  overflow: hidden;
}

/* Bars grow in width (not scaleX) so their rounded ends never squash, and
   switching a segmented chart eases them to the new length. */
.bar__fill {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--v);
  border-radius: 8px;
  background: var(--fg);
  transition: width 1.4s var(--ease-out) calc(var(--rd, 0ms) + 120ms + var(--ci, 0) * 90ms);
}

.bar__fill--accent { background: var(--accent); }
.bar__fill--blue { background: var(--accent-2); }
.bar__fill--muted { background: var(--fg-3); }

.bar__value {
  min-width: 3.4ch;
  font-size: var(--fs-body);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.bar__value {
  transition: opacity 0.7s var(--ease) calc(var(--rd, 0ms) + 520ms + var(--ci, 0) * 90ms);
}

.js .bars:not(.in) .bar__fill {
  width: 0;
}

.js .bars:not(.in) .bar__value {
  opacity: 0;
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin-top: 20px;
  color: var(--fg-2);
  font-size: var(--fs-micro);
}

.legend span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.legend i {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  background: var(--fg);
}

/* Segmented control (switches the metric a chart shows) */
.seg {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px;
  margin-top: 20px;
  padding: 3px;
  border-radius: 980px;
  background: var(--bg-3);
}

.seg button {
  position: relative;
  z-index: 1;
  padding: 7px 16px;
  border: 0;
  border-radius: 980px;
  background: transparent;
  color: var(--fg);
  font-size: var(--fs-small);
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition: background-color 0.3s var(--ease), color 0.3s var(--ease);
}

.seg button[aria-pressed="true"] {
  background: var(--seg-on, #fff);
  color: var(--fg);
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.14);
}

/* With JS, a thumb slides between options instead of the background jumping. */
.seg.has-thumb {
  position: relative;
}

.seg.has-thumb button[aria-pressed="true"] {
  background: transparent;
  box-shadow: none;
}

.seg__thumb {
  position: absolute;
  left: 0;
  top: 0;
  border-radius: 980px;
  background: var(--seg-on, #fff);
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.14), 0 0 0 0.5px rgb(0 0 0 / 0.04);
  pointer-events: none;
}

.seg.is-ready .seg__thumb {
  transition: translate 0.5s var(--ease), width 0.5s var(--ease), height 0.5s var(--ease);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .seg { --seg-on: #48484a; }
}

:root[data-theme="dark"] .seg { --seg-on: #48484a; }

.theme-dark .seg { --seg-on: #48484a; }

/* Grouped comparison (e.g. variant ratings) */
.gchart {
  display: grid;
  gap: 22px;
  margin-top: 28px;
}

.gchart__row {
  display: grid;
  grid-template-columns: minmax(110px, 22%) 1fr;
  gap: 14px;
  align-items: center;
}

.gchart__name {
  font-size: var(--fs-small);
  font-weight: 600;
}

.gchart__bars {
  display: grid;
  gap: 5px;
}

.gchart__bar {
  display: grid;
  grid-template-columns: 1fr 3.2ch;
  align-items: center;
  gap: 10px;
}

.gchart__bar .bar__track {
  height: 14px;
  border-radius: 5px;
}

.gchart__bar .bar__fill {
  border-radius: 5px;
}

.gchart__bar b {
  font-size: var(--fs-micro);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: end;
}

/* ---------------------------------------------------------------- tables */

.table-wrap {
  overflow-x: auto;
  border-radius: var(--r-lg);
  background: var(--tile);
}

.table {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  font-size: var(--fs-small);
  font-variant-numeric: tabular-nums;
}

.table caption {
  padding: 24px 28px 8px;
  font-size: var(--fs-title-s);
  font-weight: 600;
  text-align: start;
  letter-spacing: -0.012em;
}

.table th,
.table td {
  padding: 14px 28px;
  border-bottom: 1px solid var(--line);
  text-align: start;
}

.table thead th {
  color: var(--fg-2);
  font-size: var(--fs-micro);
  font-weight: 600;
}

.table tbody tr:last-child th,
.table tbody tr:last-child td {
  border-bottom: 0;
}

.table td.num,
.table th.num {
  text-align: end;
}

/* Statistics such as "< .001" keep their order in right-to-left tables. */
.table .num {
  unicode-bidi: plaintext;
}

.table tfoot td {
  padding-top: 12px;
  padding-bottom: 20px;
  border-bottom: 0;
  color: var(--fg-2);
  font-size: var(--fs-micro);
}

.table .hi {
  color: var(--accent-text);
  font-weight: 600;
}

.table .num {
  white-space: nowrap;
}

/* Phones: let the term column wrap so the numbers stay on screen. */
@media (max-width: 599px) {
  .table {
    min-width: 0;
    font-size: var(--fs-small);
  }

  .table caption {
    padding: 20px 18px 6px;
    font-size: var(--fs-body-l);
  }

  .table th,
  .table td {
    padding: 12px 18px;
  }

  .table th + td,
  .table td + td,
  .table thead th + th {
    padding-inline-start: 6px;
  }
}

/* Stimulus matrix */
.matrix {
  display: grid;
  grid-template-columns: minmax(96px, 1fr) repeat(4, minmax(0, 1fr));
  gap: 8px;
  font-size: var(--fs-small);
}

/* Rows exist for screen readers only; their cells sit on the grid. */
.matrix > [role="row"] {
  display: contents;
}

.matrix__head {
  padding: 4px 6px 8px;
  color: var(--fg-2);
  font-size: var(--fs-micro);
  font-weight: 600;
  line-height: 1.3;
}

.matrix__head small {
  display: block;
  font-weight: 400;
}

.matrix__row {
  display: flex;
  align-items: center;
  font-weight: 600;
}

.matrix__cell {
  display: grid;
  place-items: center;
  min-height: 64px;
  border-radius: var(--r-sm);
  background: var(--tile-2);
  font-size: var(--fs-body-l);
  font-weight: 600;
}

.matrix__cell--real {
  background: color-mix(in srgb, var(--accent-2) 16%, var(--tile-2));
}

.matrix__cell--ai {
  background: color-mix(in srgb, var(--accent) 16%, var(--tile-2));
}

/* Phones: transpose (items are row-major, so column flow flips the grid).
   Sources become rows with room for their model names; themes become columns. */
@media (max-width: 599px) {
  .matrix {
    grid-auto-flow: column;
    grid-template-rows: repeat(5, auto);
    grid-template-columns: minmax(0, 1.8fr) repeat(3, minmax(0, 1fr));
    gap: 6px;
    font-size: var(--fs-micro);
  }

  .matrix__head {
    align-self: center;
    padding: 0 4px 0 0;
    font-size: var(--fs-micro);
  }

  .matrix__row {
    justify-content: center;
    padding-bottom: 4px;
    text-align: center;
    overflow-wrap: anywhere;
  }

  .matrix__cell {
    min-height: 44px;
    font-size: var(--fs-body);
  }
}

/* ---------------------------------------------------------------- findings */

.findings {
  display: grid;
  gap: clamp(12px, 1.6vw, 20px);
}

@media (min-width: 734px) {
  .findings { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.finding {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: clamp(24px, 3vw, 36px);
  border-radius: var(--r-lg);
  background: var(--tile);
}

.finding__num {
  font-size: var(--fs-subhead);
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

.finding__text {
  color: var(--fg-2);
}

.finding__text strong {
  color: var(--fg);
}

/* ---------------------------------------------------------------- pull quote */

.pullquote {
  margin: 0;
  text-align: center;
}

.pullquote p {
  max-width: 24ch;
  margin-inline: auto;
  font-size: var(--fs-subhead);
  line-height: 1.12;
  font-weight: 600;
  letter-spacing: -0.024em;
}

.pullquote footer {
  margin-top: 20px;
  color: var(--fg-2);
  font-size: var(--fs-body);
}

/* ---------------------------------------------------------------- feature rows (media + text) */

.feature {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(24px, 4vw, 64px);
  align-items: center;
}

/* A feature inside a tile takes the tile's padding. */
.feature.feature--inset {
  padding: clamp(26px, 3.4vw, 44px);
}

@media (min-width: 834px) {
  .feature {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .feature--flip .feature__media {
    order: 2;
  }
}

.feature__text > * + * {
  margin-top: 16px;
}

.feature__text p {
  color: var(--fg-2);
}

.feature__text p strong {
  color: var(--fg);
}

/* ---------------------------------------------------------------- chips */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
}

.chips li {
  padding: 7px 14px;
  border-radius: 980px;
  background: var(--tile);
  color: var(--fg);
  font-size: var(--fs-small);
  line-height: 1.2;
}

.chips--line li {
  background: none;
  border: 1px solid var(--line);
}

/* ---------------------------------------------------------------- rail (horizontal gallery) */

.rail {
  position: relative;
}

.rail__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(78vw, 360px);
  gap: 20px;
  padding: 4px max(var(--g), calc((100vw - var(--w-main)) / 2)) 24px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: max(var(--g), calc((100vw - var(--w-main)) / 2));
  scrollbar-width: none;
  list-style: none;
}

.rail__track::-webkit-scrollbar {
  display: none;
}

.rail__item {
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r-md);
  background: var(--tile);
}

.rail__item img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.rail__body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 20px 22px 24px;
}

.rail__date {
  color: var(--fg-2);
  font-size: var(--fs-micro);
  font-weight: 600;
}

.rail__title {
  font-size: var(--fs-body-l);
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.012em;
}

.rail__controls {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  width: min(var(--w-main), calc(100% - 2 * var(--g)));
  margin: 6px auto 0;
}

.paddle {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--bg-3);
  color: var(--fg);
  cursor: pointer;
  transition: opacity 0.2s ease, background-color 0.2s ease;
}

.paddle:hover {
  background: var(--line);
}

.paddle:disabled {
  opacity: 0.36;
  cursor: default;
}

.paddle svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.paddle:dir(rtl) svg {
  scale: -1 1;
}

/* ---------------------------------------------------------------- lists: timeline, publications, tools */

.rows {
  list-style: none;
  border-top: 1px solid var(--line);
}

.row {
  display: grid;
  gap: 6px 32px;
  padding: 24px 0;
  border-bottom: 1px solid var(--line);
}

@media (min-width: 734px) {
  .row {
    grid-template-columns: 180px minmax(0, 1fr);
  }
}

.row__when {
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.row__title {
  font-size: var(--fs-body-l);
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: -0.012em;
}

.row__org {
  color: var(--fg-2);
  font-weight: 400;
}

.row__text {
  margin-top: 6px;
  color: var(--fg-2);
}

.row__sub {
  display: grid;
  gap: 16px;
  margin-top: 18px;
  list-style: none;
}

@media (min-width: 1069px) {
  .row__sub {
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 20px 28px;
  }
}

.row__sub li {
  padding-inline-start: 16px;
  border-inline-start: 2px solid var(--line);
}

.row__sub h4 {
  font-size: var(--fs-body);
  font-weight: 600;
}

.row__sub h4 span {
  display: block;
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 400;
}

.row__sub p {
  margin-top: 6px;
  color: var(--fg-2);
  font-size: var(--fs-small);
}

/* A row of actions under an entry: links and plain-text buttons. */
.item-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 20px;
  margin-top: 14px;
  font-size: var(--fs-small);
}

.item-actions button {
  padding: 0;
  border: 0;
  background: none;
  color: var(--link);
  cursor: pointer;
}

.item-actions button:hover {
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

/* "Experiments and results" and similar: a pill that opens the detail
   panel below it; the chevron turns when it is open. */
.item-actions .expand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px 8px 16px;
  border-radius: 980px;
  background: color-mix(in srgb, var(--link) 12%, transparent);
  color: var(--link);
  font-weight: 600;
  transition: background-color 0.3s var(--ease);
}

.item-actions .expand:hover {
  background: color-mix(in srgb, var(--link) 20%, transparent);
  text-decoration: none;
}

.expand::after {
  content: "";
  width: 0.55em;
  height: 0.55em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 8'%3E%3Cpath d='M1.2 1.2 7 6.8l5.8-5.6' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center / contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 8'%3E%3Cpath d='M1.2 1.2 7 6.8l5.8-5.6' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center / contain;
  transition: rotate 0.4s var(--ease);
}

.expand[aria-expanded="true"]::after {
  rotate: 180deg;
}

.expand-panel {
  margin-top: 16px;
  padding: clamp(20px, 2.6vw, 32px);
  border-radius: var(--r-md);
  background: var(--tile);
}

.section--alt .expand-panel {
  background: var(--tile-2);
}

.expand-panel > .link-more,
.expand-panel > .item-actions {
  margin-top: 18px;
}

.expand-panel .chart {
  padding: 0;
  background: none;
}

/* Experiments inside a panel: one block per study. */

.study__num {
  margin-inline-end: 8px;
  color: var(--fg-2);
}

.study__how {
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.study__how {
  margin-top: 6px;
}

[hidden] {
  display: none !important;
}

/* App icons with light and dark versions follow the site theme, including the
   theme button. The hidden one is lazy, so it never downloads. */
.icon-dark,
[data-theme-now="dark"] .icon-light {
  display: none;
}

[data-theme-now="dark"] .icon-dark {
  display: block;
}

/* ==========================================================================
   Product and project pages
   Patterns borrowed from Apple's product pages: a product hero, device frames,
   "Get the highlights", "Take a closer look", icon features, stat bands,
   "Get to know" card rails with detail sheets, flows, specs. Each page sets
   --tint (its accent) on <body>; everything falls back to the site accent.
   ========================================================================== */

/* ---------------------------------------------------------------- icons (assets/img/icons.svg, Framework7 Icons) */

.ico {
  width: 24px;
  height: 24px;
  flex: none;
  fill: currentColor;
  vertical-align: middle;
}

/* ---------------------------------------------------------------- placeholders
   Stand-ins for images and films still to come. Each says what belongs there
   and at what size; PLACEHOLDERS.md lists them all. Swap the <div> for an
   <img> (or <video>) with the same aspect ratio. */

.ph {
  --ph-tint: var(--tint, var(--accent));
  position: relative;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 10px;
  width: 100%;
  height: 100%;
  min-height: 120px;
  padding: 24px;
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 20% 0%, color-mix(in srgb, var(--ph-tint) 16%, transparent), transparent 60%),
    radial-gradient(90% 80% at 100% 100%, color-mix(in srgb, var(--ph-tint) 10%, transparent), transparent 55%),
    var(--bg-3);
  color: var(--fg-2);
  text-align: center;
}

.ph::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: 1.5px dashed color-mix(in srgb, var(--fg) 18%, transparent);
  border-radius: max(6px, calc(var(--r-md) - 10px));
  pointer-events: none;
}

.ph .ico {
  width: 32px;
  height: 32px;
  color: var(--ph-tint);
}

.ph__what {
  max-width: 28em;
  font-size: var(--fs-small);
  line-height: 1.4;
  font-weight: 600;
  color: var(--fg);
}

.ph__size {
  font-family: var(--mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.02em;
  color: var(--fg-2);
  text-transform: uppercase;
}

.device--phone .ph {
  padding: 18px 12px;
}

.device--phone .ph::before {
  inset: 8px;
  border-radius: 12% / 5.5%;
}

.device--phone .ph__what {
  font-size: var(--fs-micro);
}

/* In a small phone the label shrinks, and then only the icon remains (the
   full description stays in aria-label and PLACEHOLDERS.md). */
.device--phone .device__screen {
  container-type: inline-size;
}

.device--phone .ph {
  overflow: hidden;
  overflow-wrap: anywhere;
}

@container (max-width: 150px) {
  .device--phone .ph__size {
    display: none;
  }

  .device--phone .ph__what {
    font-size: var(--fs-micro);
  }
}

@container (max-width: 110px) {
  .device--phone .ph__what {
    display: none;
  }
}

/* The phone in a .duo covers the window's lower corner, so the window's
   placeholder centers its label in the part left showing. */
.duo > .device--window .ph {
  padding-inline-end: 20%;
}

/* ---------------------------------------------------------------- device frames */

.device {
  position: relative;
  margin: 0;
}

/* A phone: Apple's iPhone Pro bezel (assets/img/frames, 978 × 2000), silver
   in light mode and black in dark, laid over the screen. Put an <img> (or
   .ph) inside .device__screen; the screen is the bezel's opening, 874 × 1900
   at (52, 50), which is a 460 × 1000 ratio, so iPhone 17 Pro screenshots
   (1206 × 2622) fit exactly. The corners clip a little inside the opening's
   (15.6% / 7.2%), so no sliver of page shows past the bezel. */
.device--phone {
  --phone-frame: url("/assets/img/frames/iphone-pro-silver.webp");
  width: 100%;
  aspect-ratio: 978 / 2000;
  filter: drop-shadow(0 28px 30px rgb(0 0 0 / 0.26));
}

[data-theme-now="dark"] .device--phone {
  --phone-frame: url("/assets/img/frames/iphone-pro-black.webp");
}

.device--phone .device__screen {
  position: absolute;
  inset: 2.5% 5.317%;
  overflow: hidden;
  border-radius: 14.5% / 6.67%;
  background: #000;
}

.device--phone .device__screen > img,
.device--phone .device__screen > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The bezel, with its Dynamic Island, over the screen. */
.device--phone::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--phone-frame) center / 100% 100% no-repeat;
  pointer-events: none;
}

/* iPhone Duo, open (2000 × 1453) or .device--closed (1435 × 2000): silver
   in light mode and dark blue in dark, like the phone. The <img> inside is
   the screenshot already cut to the bezel's opening at the frame's own size
   (the screens are not plain rounded rectangles: the cover screen has a
   camera hole and larger corners on the hinge side), with the bezel on top. */
.device--duo {
  --duo-frame: url("/assets/img/frames/iphone-duo-light-open.webp");
  aspect-ratio: 2000 / 1453;
  filter: drop-shadow(0 28px 30px rgb(0 0 0 / 0.26));
}

.device--duo.device--closed {
  --duo-frame: url("/assets/img/frames/iphone-duo-light-closed.webp");
  aspect-ratio: 1435 / 2000;
}

[data-theme-now="dark"] .device--duo {
  --duo-frame: url("/assets/img/frames/iphone-duo-dark-open.webp");
}

[data-theme-now="dark"] .device--duo.device--closed {
  --duo-frame: url("/assets/img/frames/iphone-duo-dark-closed.webp");
}

.device--duo > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.device--duo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--duo-frame) center / 100% 100% no-repeat;
  pointer-events: none;
}

/* Rows of Duos at one height: each grows in proportion to its width over
   height. On phones the open ones take a row each and the closed ones pair up. */
.duo-gallery {
  display: grid;
  gap: clamp(24px, 3.4vw, 48px);
}

.duo-gallery__row {
  display: flex;
  align-items: flex-start;
  gap: clamp(16px, 2.6vw, 36px);
}

.duo-gallery__row > .device--duo {
  flex: 1.3765 1 0;
  min-width: 0;
}

.duo-gallery__row > .device--duo.device--closed {
  flex-grow: 0.7175;
}

@media (max-width: 733px) {
  .duo-gallery__row {
    flex-wrap: wrap;
  }

  .duo-gallery__row > .device--duo:not(.device--closed) {
    flex-basis: 100%;
    order: 1;
  }

  .duo-gallery__row > .device--duo.device--closed {
    flex: 1 1 0;
  }
}

/* A tablet: Apple's 13-inch iPad Pro bezel (2000 × 1533), silver in light
   mode and space black in dark, landscape unless .device--portrait. Same
   markup as the phone. The opening is 1834 × 1375 at (83, 79), a 4:3 ratio,
   so 13-inch iPad Pro screenshots (2752 × 2064) fit exactly. */
.device--tablet {
  --tablet-frame: url("/assets/img/frames/ipad-pro-13-silver-landscape.webp");
  width: 100%;
  aspect-ratio: 2000 / 1533;
  filter: drop-shadow(0 28px 30px rgb(0 0 0 / 0.26));
}

[data-theme-now="dark"] .device--tablet {
  --tablet-frame: url("/assets/img/frames/ipad-pro-13-space-black-landscape.webp");
}

.device--tablet.device--portrait {
  --tablet-frame: url("/assets/img/frames/ipad-pro-13-silver.webp");
  aspect-ratio: 1533 / 2000;
}

[data-theme-now="dark"] .device--tablet.device--portrait {
  --tablet-frame: url("/assets/img/frames/ipad-pro-13-space-black.webp");
}

.device--tablet .device__screen {
  position: absolute;
  inset: 5.153% 4.15%;
  overflow: hidden;
  border-radius: 2.1% / 2.8%;
  background: #000;
}

.device--tablet.device--portrait .device__screen {
  inset: 4.15% 5.153%;
  border-radius: 2.8% / 2.1%;
}

.device--tablet .device__screen > img,
.device--tablet .device__screen > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.device--tablet::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--tablet-frame) center / 100% 100% no-repeat;
  pointer-events: none;
}

/* A desktop window with traffic lights, for Blender add-ons and web tools. */
.device--window {
  overflow: hidden;
  border-radius: 14px;
  background: var(--tile-2);
  box-shadow:
    0 0 0 1px var(--line-soft),
    0 40px 80px -36px rgb(0 0 0 / 0.45);
}

.device--window .device__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 30px;
  padding-inline: 12px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--bg-2);
  color: var(--fg-2);
  font-size: var(--fs-micro);
}

.device--window .device__bar::before {
  content: "";
  width: 52px;
  height: 12px;
  background:
    radial-gradient(circle at 6px 6px, #ff5f57 5.5px, transparent 6px),
    radial-gradient(circle at 26px 6px, #febc2e 5.5px, transparent 6px),
    radial-gradient(circle at 46px 6px, #28c840 5.5px, transparent 6px);
}

.device--window .device__screen {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--bg-3);
}

.device--window .device__screen > img,
.device--window .device__screen > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.device--window .ph {
  border-radius: 0;
}

/* Three phones, the middle one in front. */
.phones {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: min(100%, 860px);
  margin-inline: auto;
}

.phones > .device {
  width: 31%;
}

.phones > .device:nth-child(2) {
  z-index: 1;
  width: 36%;
  margin-inline: -4%;
}

.phones > .device:not(:nth-child(2)) {
  margin-bottom: 4%;
  opacity: 0.96;
}

/* A window with a phone resting on its lower corner. The phone hangs below
   the window into the duo's own bottom padding, so a hero that clips its
   overflow never cuts the phone's lower corners. */
.duo {
  position: relative;
  width: min(100%, 980px);
  margin-inline: auto;
  padding-inline-end: 9%;
  padding-bottom: 4%;
}

.duo > .device--phone {
  position: absolute;
  inset-inline-end: 0;
  bottom: 0;
  width: 24%;
}

/* ---------------------------------------------------------------- product hero */

.phero {
  padding-top: clamp(48px, 7vw, 96px);
  text-align: center;
  overflow: hidden;
}

.phero__icon {
  display: block;
  width: clamp(88px, 10vw, 128px);
  height: clamp(88px, 10vw, 128px);
  margin: 0 auto clamp(18px, 2.4vw, 28px);
}

.phero__icon img {
  width: 100%;
  height: 100%;
  border-radius: 23.5%;
  filter: drop-shadow(0 10px 24px rgb(0 0 0 / 0.18));
}

.phero__name {
  font-size: var(--fs-lead);
  font-weight: 600;
  letter-spacing: -0.014em;
}

.phero__title {
  max-width: 16ch;
  margin: 10px auto 0;
}

.phero__lead {
  max-width: 34em;
  margin: clamp(16px, 2vw, 24px) auto 0;
  color: var(--fg-2);
}

.phero__cta {
  margin-top: clamp(24px, 3vw, 36px);
}

.phero__media {
  margin-top: clamp(40px, 6vw, 80px);
}

.phero__note {
  margin-top: 14px;
  color: var(--fg-2);
  font-size: var(--fs-small);
}

/* ---------------------------------------------------------------- headline + statement blocks */

.lede {
  max-width: 30em;
}

.lede--center {
  margin-inline: auto;
  text-align: center;
}

.lede .t-two-tone {
  margin-top: 20px;
}

/* ---------------------------------------------------------------- stat band */

.statband {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(28px, 4vw, 44px) clamp(20px, 3vw, 40px);
}

@media (min-width: 834px) {
  .statband {
    grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr));
  }
}

.statband__item {
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.statband__kicker {
  display: block;
  color: var(--fg-2);
  font-size: var(--fs-small);
}

.statband__num {
  display: block;
  margin-top: 4px;
  color: var(--tint, var(--fg));
  font-size: var(--fs-h1);
  line-height: 1;
  font-weight: 600;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

.statband__num small {
  font-size: 0.42em;
  letter-spacing: -0.01em;
}

.statband__label {
  display: block;
  margin-top: 10px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.35;
}

/* ---------------------------------------------------------------- Get the highlights */

.hl-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px 32px;
  margin-bottom: clamp(28px, 3.6vw, 48px);
}

.hl {
  --hl-dur: 6s;
  position: relative;
}

.hl__track {
  display: flex;
  gap: clamp(14px, 1.6vw, 24px);
  padding: 0 max(var(--g), calc((100vw - var(--w-wide)) / 2));
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: max(var(--g), calc((100vw - var(--w-wide)) / 2));
  scrollbar-width: none;
  list-style: none;
}

.hl__track::-webkit-scrollbar {
  display: none;
}

.hl__slide {
  position: relative;
  display: flex;
  flex: none;
  flex-direction: column;
  width: min(86vw, var(--w-wide));
  aspect-ratio: 16 / 9.2;
  overflow: hidden;
  border-radius: var(--r-xl);
  background: var(--tile);
  scroll-snap-align: center;
}

/* On a gray band the slides take the page color: white, or black in dark mode. */
.section--alt .hl__slide {
  background: var(--bg);
}

.theme-dark .hl__slide {
  background: #000;
}

.hl__cap {
  position: relative;
  z-index: 1;
  max-width: 24em;
  padding: clamp(24px, 3.2vw, 44px) clamp(24px, 3.4vw, 48px) 0;
  color: var(--fg-2);
  font-size: var(--fs-statement);
  line-height: 1.18;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.hl__cap strong {
  color: var(--fg);
  font-weight: 600;
}

/* Media sits whole inside the slide, never cut off by its edge: a box that
   is rounded on top and sliced at the bottom reads as broken. */
.hl__media {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: clamp(16px, 2.4vw, 32px) clamp(24px, 4vw, 64px) clamp(24px, 3vw, 44px);
}

.hl__media > .device--phone {
  width: auto;
  height: 100%;
}

.hl__media > .device--window {
  width: auto;
  max-width: min(100%, 760px);
  height: 100%;
  max-height: 100%;
  aspect-ratio: 16 / 10.5;
}

.hl__media > .device--window .device__screen {
  height: calc(100% - 30px);
  aspect-ratio: auto;
}

/* A full-bleed picture: its box covers the whole slide, so the picture is
   placed the same whether or not the box has a filter (a filter makes the
   box the picture's frame of reference; see .hl--mono-sides). */
.hl__media--fill {
  position: absolute;
  inset: 0;
  padding: 0;
}

.hl__media--fill > img,
.hl__media--fill > video,
.hl__media--fill > .ph {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The picture on the slide in view drifts slowly closer while its dot
   fills, and eases back once the slide moves on. */
@media (prefers-reduced-motion: no-preference) {
  .hl__media--fill > img,
  .hl__media--fill > .loop video {
    transition: scale 0.8s var(--ease);
  }

  .hl__slide[aria-hidden="false"] .hl__media--fill > img,
  .hl__slide[aria-hidden="false"] .hl__media--fill > .loop video {
    scale: 1.08;
    transition: scale var(--hl-dur) linear;
  }
}

/* .hl--mono-sides (Research): the slides either side of the one in view
   are in black and white, and a slide eases into color as it arrives. */
.hl--mono-sides .hl__media {
  transition: filter 0.6s var(--ease);
}

.hl--mono-sides .hl__slide[aria-hidden="true"] .hl__media {
  filter: grayscale(1);
}

.hl__media--fill ~ .hl__cap,
.hl__slide--fill .hl__cap {
  color: rgb(255 255 255 / 0.72);
  text-shadow: 0 1px 18px rgb(0 0 0 / 0.35);
}

.hl__slide--fill .hl__cap strong {
  color: #fff;
}

@media (max-width: 733px) {
  .hl__slide {
    aspect-ratio: 3 / 4.2;
  }

  .hl__media > .device--window {
    width: 100%;
    height: auto;
  }

  .hl__media > .device--window .device__screen {
    height: auto;
    aspect-ratio: 16 / 10;
  }
}

.hl__nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: clamp(20px, 2.6vw, 32px);
}

.hl__dots {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 52px;
  padding: 0 22px;
  border-radius: 980px;
  background: var(--glass);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  box-shadow: inset 0 0 0 1px var(--line-soft);
}

.hl__dot {
  position: relative;
  width: 8px;
  height: 8px;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: 980px;
  background: var(--fg-3);
  cursor: pointer;
  transition: width 0.5s var(--ease), background-color 0.3s var(--ease);
}

.hl__dot:hover {
  background: var(--fg-2);
}

.hl__dot.is-current {
  width: 48px;
  background: color-mix(in srgb, var(--fg) 22%, transparent);
}

.hl__dot.is-current::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--fg);
  transform-origin: left center;
  animation: hl-fill var(--hl-dur) linear forwards;
}

.hl__dot.is-current:dir(rtl)::after {
  transform-origin: right center;
}

.hl.is-paused .hl__dot.is-current::after {
  animation-play-state: paused;
}

.hl.is-static .hl__dot.is-current::after {
  animation: none;
}

/* Under reduced motion the slides never advance on their own, so there is
   nothing to play or pause. */
.hl.is-static .hl__play {
  display: none;
}

@keyframes hl-fill {
  from {
    transform: scaleX(0);
  }

  to {
    transform: scaleX(1);
  }
}

.hl__play {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--glass);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  color: var(--fg);
  cursor: pointer;
}

.hl__play svg {
  width: 16px;
  height: 16px;
  fill: currentColor;
}

.hl__play .i-play,
.hl.is-stopped .hl__play .i-pause {
  display: none;
}

.hl.is-stopped .hl__play .i-play {
  display: block;
}

/* ---------------------------------------------------------------- Take a closer look */

.closer {
  display: grid;
  gap: clamp(24px, 3vw, 40px);
  align-items: center;
}

@media (min-width: 834px) {
  .closer {
    grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.6fr);
  }
}

.closer__list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}

.closer__item {
  max-width: 100%;
  border-radius: var(--r-lg);
  background: var(--bg-3);
  transition: background-color 0.4s var(--ease);
}

.theme-dark .closer__item,
.section--alt .closer__item {
  background: var(--tile-2);
}

.closer__btn {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  padding: 10px 22px 10px 12px;
  border: 0;
  background: none;
  color: var(--fg);
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: -0.016em;
  text-align: start;
  cursor: pointer;
}

.closer__plus {
  display: grid;
  flex: none;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--fg);
  color: var(--bg);
  transition: rotate 0.5s var(--ease), opacity 0.3s var(--ease);
}

.closer__plus .ico {
  width: 18px;
  height: 18px;
}

.closer__item.is-open .closer__plus {
  rotate: 45deg;
  opacity: 0;
  width: 0;
  margin-inline-end: -12px;
}

.closer__text {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 0.5s var(--ease);
}

.js .closer__item:not(.is-open) .closer__text {
  grid-template-rows: 0fr;
}

.closer__text > div {
  overflow: hidden;
  transition: visibility 0s;
}

/* Closed text is hidden from screen readers too, once it has collapsed. */
.js .closer__item:not(.is-open) .closer__text > div {
  visibility: hidden;
  transition: visibility 0s 0.5s;
}

.closer__text p {
  max-width: 26em;
  padding: 0 24px 22px;
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.42;
}

.closer__text strong {
  color: var(--fg);
}

.closer__stage {
  display: grid;
  min-height: 0;
}

.closer__media {
  grid-area: 1 / 1;
  display: grid;
  place-items: center;
  transition: opacity 0.6s var(--ease), scale 0.8s var(--ease);
}

.js .closer__media:not(.is-on) {
  opacity: 0;
  scale: 0.985;
  pointer-events: none;
  visibility: hidden;
}

.closer__media > .device--phone {
  width: min(100%, 340px);
}

.closer__media > img,
.closer__media > .ph,
.closer__media > svg {
  width: 100%;
  border-radius: var(--r-lg);
}

.closer__media > .ph {
  aspect-ratio: 4 / 3;
}

@media (max-width: 833px) {
  .closer__stage {
    order: -1;
  }
}

/* ---------------------------------------------------------------- media with a segmented switch */

.segmedia {
  text-align: center;
}

.segmedia__stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.segmedia__item {
  grid-area: 1 / 1;
  transition: opacity 0.5s var(--ease);
}

.js .segmedia__item:not(.is-on) {
  opacity: 0;
  visibility: hidden;
}

.segmedia__item > img,
.segmedia__item > .ph,
.segmedia__item > svg {
  width: 100%;
  border-radius: var(--r-xl);
}

.segmedia__cap {
  min-height: 3em;
  max-width: 36em;
  margin: 18px auto 0;
  color: var(--fg-2);
}

.segmedia__cap strong {
  color: var(--fg);
}

/* ---------------------------------------------------------------- icon features */

.fgrid {
  display: grid;
  gap: clamp(32px, 4vw, 48px) clamp(24px, 3vw, 48px);
  list-style: none;
}

@media (min-width: 600px) {
  .fgrid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1000px) {
  .fgrid {
    grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
  }
}

.fgrid__item .ico {
  width: 40px;
  height: 40px;
  margin-bottom: 14px;
  color: var(--tint, var(--accent));
}

.fgrid__item p {
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.47;
}

.fgrid__item strong {
  color: var(--fg);
  font-weight: 600;
}

/* ---------------------------------------------------------------- Get to know: tall cards with a + sheet */

.gtk .rail__track {
  grid-auto-columns: min(78vw, 372px);
}

.rail__item.gtk__card {
  position: relative;
  aspect-ratio: 372 / 600;
  background: var(--tile);
  isolation: isolate;
}

.theme-dark .rail__item.gtk__card {
  background: var(--tile-2);
}

.gtk__card .gtk__text {
  position: relative;
  z-index: 1;
  padding: 28px 28px 0;
}

.gtk__title {
  margin-top: 8px;
  font-size: var(--fs-title);
  line-height: 1.16;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.gtk__card--icon .gtk__text {
  padding-top: 32px;
}

.gtk__card--icon .ico {
  width: 44px;
  height: 44px;
  margin-bottom: 20px;
  color: var(--tint, var(--accent));
}

.rail__item.gtk__card--icon {
  aspect-ratio: auto;
  min-height: 250px;
  padding-bottom: 72px;
}

.gtk__card--icon .gtk__body {
  margin-top: 10px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.45;
}

.gtk__more {
  position: absolute;
  z-index: 2;
  inset-inline-end: 20px;
  bottom: 20px;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--bg);
  cursor: pointer;
}

/* As on the project cards, only the disc grows, so the icon stays crisp. */
.gtk__more::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 50%;
  background: var(--fg);
  transition: scale 0.35s var(--ease-spring), background-color 0.3s var(--ease);
}

.gtk__more:hover::before {
  scale: 1.1;
}

.gtk__more .ico {
  width: 20px;
  height: 20px;
}

/* The detail sheet opened by a + button. */
.sheet {
  width: min(880px, calc(100% - 2 * var(--g)));
  max-height: min(86vh, 900px);
  margin: auto;
  padding: 0;
  border: 0;
  border-radius: var(--r-xl);
  background: var(--bg);
  color: var(--fg);
  box-shadow: 0 30px 90px rgb(0 0 0 / 0.35);
  overflow: auto;
}

.sheet::backdrop {
  background: rgb(0 0 0 / 0.5);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
}

.sheet[open] {
  animation: sheet-in 0.5s var(--ease-out);
}

@keyframes sheet-in {
  from {
    opacity: 0;
    translate: 0 40px;
  }
}

.sheet__inner {
  padding: clamp(40px, 6vw, 72px) clamp(24px, 6vw, 80px) clamp(40px, 5vw, 64px);
}

.sheet__inner > * + * {
  margin-top: 18px;
}

.sheet__inner p {
  color: var(--fg-2);
  font-size: var(--fs-body-l);
  line-height: 1.42;
}

.sheet__inner strong {
  color: var(--fg);
}

.sheet__inner .ph,
.sheet__inner img {
  margin-top: 28px;
  border-radius: var(--r-lg);
}

.sheet__close {
  position: sticky;
  top: 16px;
  float: inline-end;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  margin: 16px 16px 0 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--bg-3);
  color: var(--fg);
  cursor: pointer;
}

.sheet__close:dir(rtl) {
  margin: 16px 0 0 16px;
}

.sheet__close .ico {
  width: 18px;
  height: 18px;
  rotate: 45deg;
}

/* The paper reader: a tall sheet holding the browser's own PDF viewer. */
.sheet.reader {
  width: min(1100px, calc(100% - 2 * var(--g)));
  height: min(92vh, 1400px);
  max-height: none;
  overflow: hidden;
}

.reader[open] {
  display: flex;
  flex-direction: column;
}

.reader__bar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 12px 12px 24px;
  border-bottom: 1px solid var(--line-soft);
}

.reader__bar:dir(rtl) {
  padding: 12px 24px 12px 12px;
}

.reader__title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-size: var(--fs-small);
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.reader__dl {
  font-size: var(--fs-small);
  white-space: nowrap;
}

.reader .sheet__close {
  position: static;
  float: none;
  flex: none;
  margin: 0;
}

.reader__frame {
  flex: 1;
  width: 100%;
  border: 0;
  background: var(--bg-2);
}

/* ---------------------------------------------------------------- how it works: a flow of steps */

.flow {
  --flow-gap: clamp(16px, 2vw, 28px);
  display: grid;
  gap: var(--flow-gap);
  counter-reset: flow;
  list-style: none;
}

@media (min-width: 834px) {
  .flow {
    grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr));
  }
}

.flow__step {
  position: relative;
  counter-increment: flow;
}

.flow__icon {
  position: relative;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  margin-bottom: 18px;
  border-radius: var(--r-md);
  background: var(--tile-2);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  color: var(--tint, var(--accent));
}

.section--alt .flow__icon {
  background: var(--bg);
}

.flow__icon .ico {
  width: 28px;
  height: 28px;
}

/* A hairline links each step to the next, ending in a small arrowhead. */
@media (min-width: 834px) {
  .flow__step:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 28px;
    inset-inline-start: 68px;
    inset-inline-end: calc(-1 * var(--flow-gap) + 8px);
    height: 1px;
    background: linear-gradient(90deg, var(--line), var(--line) calc(100% - 6px), transparent);
  }

  .flow__step:not(:last-child)::before {
    content: "";
    position: absolute;
    top: 25px;
    inset-inline-end: calc(-1 * var(--flow-gap) + 8px);
    width: 7px;
    height: 7px;
    border-top: 1px solid var(--fg-3);
    border-inline-end: 1px solid var(--fg-3);
    rotate: 45deg;
  }

  .flow__step:dir(rtl):not(:last-child)::before {
    rotate: -45deg;
  }
}

.flow__num {
  display: block;
  margin-bottom: 6px;
  color: var(--fg-2);
  font-size: var(--fs-micro);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.flow__num::before {
  content: counter(flow, decimal-leading-zero);
}

.flow__title {
  font-size: var(--fs-body-l);
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.012em;
}

.flow__text {
  margin-top: 6px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.47;
}

/* ---------------------------------------------------------------- specs */

.specs {
  border-top: 1px solid var(--line);
}

.specs__row {
  display: grid;
  gap: 6px 32px;
  padding: 22px 0;
  border-bottom: 1px solid var(--line);
}

@media (min-width: 734px) {
  .specs__row {
    grid-template-columns: minmax(160px, 0.36fr) 1fr;
  }
}

.specs__row dt {
  font-size: var(--fs-body);
  font-weight: 600;
}

.specs__row dd {
  min-width: 0;
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.47;
  overflow-wrap: anywhere;
}

.specs__row dd strong {
  color: var(--fg);
  font-weight: 600;
}

.specs__row dd ul {
  list-style: none;
}

.specs__row dd li + li {
  margin-top: 4px;
}

/* Big numbers beside a detailed list (camera-spec style). */
.bigspecs {
  display: grid;
  gap: 32px clamp(32px, 6vw, 80px);
}

@media (min-width: 834px) {
  .bigspecs {
    grid-template-columns: minmax(200px, 0.5fr) 1fr;
  }
}

.bigspecs__nums > div {
  padding: 18px 0 24px;
  border-top: 1px solid var(--line);
}

.bigspecs__nums small {
  display: block;
  color: var(--fg-2);
  font-size: var(--fs-micro);
}

.bigspecs__nums b {
  display: block;
  font-size: var(--fs-h2);
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -0.03em;
}

.bigspecs__nums span {
  display: block;
  color: var(--fg-2);
  font-size: var(--fs-small);
}

.bigspecs__list {
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.bigspecs__list h3 {
  font-size: var(--fs-body);
  font-weight: 600;
}

.bigspecs__list p {
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.47;
}

.bigspecs__list p + h3 {
  margin-top: 22px;
}

/* ---------------------------------------------------------------- code, maths and wire formats */

.monocard {
  padding: clamp(24px, 3vw, 36px);
  border-radius: var(--r-lg);
  background: var(--tile);
  font-family: var(--mono);
  font-size: var(--fs-small);
  line-height: 1.7;
  overflow-x: auto;
  white-space: pre;
  color: var(--fg);
}

.section--alt .monocard {
  background: var(--tile-2);
}

@media (max-width: 733px) {
  .monocard {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }
}

.monocard .c {
  color: var(--fg-2);
}

.monocard .k {
  color: var(--tint, var(--accent-text));
}

/* A binary frame drawn as labelled byte boxes. */
.frame {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  font-family: var(--mono);
  font-size: var(--fs-micro);
}

.frame__part {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 18px;
  min-width: 120px;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--tile-2);
  box-shadow: inset 0 0 0 1px var(--line-soft);
}

.frame__part b {
  font-family: var(--font);
  font-size: var(--fs-small);
  font-weight: 600;
}

.frame__part span {
  color: var(--fg-2);
}

.frame__part--wide {
  flex: 1;
  min-width: 220px;
  background: color-mix(in srgb, var(--tint, var(--accent)) 10%, var(--tile-2));
}

/* Layered architecture: rows of packages from the editor down to the renderer. */
.arch {
  display: grid;
  gap: 10px;
}

.arch__tier {
  display: grid;
  gap: 10px;
}

@media (min-width: 734px) {
  .arch__tier {
    grid-template-columns: 150px 1fr;
    align-items: stretch;
  }
}

.arch__label {
  align-self: center;
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
}

.arch__boxes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
}

.arch__box {
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--tile-2);
  box-shadow: inset 0 0 0 1px var(--line-soft);
}

.section--alt .arch__box {
  background: var(--bg);
}

.arch__box code {
  display: block;
  font-family: var(--mono);
  font-size: var(--fs-micro);
  color: var(--tint, var(--accent-text));
}

.arch__box span {
  display: block;
  margin-top: 4px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.4;
}

/* A small file tree in a card. */
.tree {
  padding: clamp(20px, 2.6vw, 28px);
  border-radius: var(--r-lg);
  background: var(--tile-2);
  font-family: var(--mono);
  font-size: var(--fs-small);
  line-height: 1.8;
  white-space: pre;
  overflow-x: auto;
  box-shadow: inset 0 0 0 1px var(--line-soft);
}

.tree b {
  color: var(--tint, var(--accent-text));
  font-weight: 500;
}

/* ---------------------------------------------------------------- lineup (Artifacts) */

.lineup-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: clamp(28px, 3.6vw, 44px);
}

.lineup-head .seg {
  margin-top: 0;
}

.lineup .rail__track {
  grid-auto-columns: min(82vw, 392px);
}

.rail__item.lcard {
  background: var(--tile-2);
  scroll-snap-align: start;
}

.lcard[hidden] {
  display: none !important;
}

.lcard__media {
  position: relative;
  display: grid;
  place-items: center;
  height: 300px;
  padding: 24px;
  overflow: hidden;
  background: linear-gradient(180deg, color-mix(in srgb, var(--card-tint, var(--accent)) 10%, var(--tile-2)), var(--tile-2));
}

.lcard__media .device--phone {
  width: 116px;
}

.lcard__media .device--window {
  width: 100%;
}

.lcard__media > img.lcard__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
}

.lcard__bigicon {
  display: block;
  width: 128px;
  height: 128px;
}

.rail__item .lcard__bigicon img,
.rail__item .lcard__icon img {
  width: 100%;
  height: 100%;
  aspect-ratio: 1;
  border-radius: 23.5%;
  filter: drop-shadow(0 12px 26px rgb(0 0 0 / 0.22));
}

.lcard__icon {
  flex: none;
  width: 44px;
  height: 44px;
}

.rail__item .lcard__icon img {
  filter: drop-shadow(0 2px 6px rgb(0 0 0 / 0.14));
}

.lcard__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 6px;
  padding: 24px 28px 28px;
}

.lcard__top {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 6px;
}

.lcard__kind {
  color: var(--fg-2);
  font-size: var(--fs-micro);
  font-weight: 600;
}

.lcard__new {
  display: block;
  color: var(--accent-text);
  font-size: var(--fs-micro);
  font-weight: 600;
}

.lcard__name {
  font-size: var(--fs-title);
  line-height: 1.12;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.lcard__tag {
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.4;
}

.lcard__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 22px;
  margin-top: auto;
  padding-top: 22px;
}

/* ---------------------------------------------------------------- more artifacts / next */

.more__title {
  margin-bottom: clamp(24px, 3vw, 36px);
}

.next-card {
  display: grid;
  align-items: center;
  gap: 24px;
  padding: clamp(28px, 4vw, 48px);
  border-radius: var(--r-xl);
  background: var(--tile);
  color: var(--fg);
  transition: background-color 0.4s var(--ease);
}

@media (min-width: 734px) {
  .next-card {
    grid-template-columns: auto 1fr auto;
  }
}

.next-card:hover {
  text-decoration: none;
  background: var(--bg-3);
}

.section--alt .next-card {
  background: var(--bg);
}

.section--alt .next-card:hover {
  background: var(--bg-3);
}

.next-card img {
  width: 88px;
  height: 88px;
  border-radius: 23.5%;
  filter: drop-shadow(0 6px 16px rgb(0 0 0 / 0.16));
}

/* A hairline keeps a picture on white from melting into a white card. */
.next-card__thumb {
  position: relative;
  justify-self: start;
}

.next-card__thumb::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--r-md);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  pointer-events: none;
}

.next-card .next-card__thumb img {
  width: 168px;
  height: 118px;
  object-fit: cover;
  border-radius: var(--r-md);
  filter: none;
}

.next-card__label {
  display: block;
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
}

.next-card__name {
  display: block;
  margin-top: 4px;
  font-size: var(--fs-h3);
  line-height: 1.1;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.next-card__go {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--fg);
  color: var(--bg);
  transition: translate 0.4s var(--ease);
}

.next-card:hover .next-card__go {
  translate: 4px 0;
}

.next-card__go:dir(rtl) .ico {
  scale: -1 1;
}

/* ---------------------------------------------------------------- local nav: product icon and pill */

.lnav__title img {
  width: 26px;
  height: 26px;
  margin-inline-end: 10px;
  border-radius: 23.5%;
  vertical-align: -6px;
}

.lnav__inner .btn + .btn {
  margin-inline-start: -10px;
}

/* ---------------------------------------------------------------- project pages (Design) */

.project-hero {
  padding-top: clamp(48px, 7vw, 96px);
}

.project-hero .t-display {
  margin-top: 8px;
}

.project-hero .t-lead {
  max-width: 32em;
  margin-top: 18px;
}

.project-hero__media {
  margin-top: clamp(32px, 5vw, 64px);
}

.project-hero__media img,
.project-hero__media .ph {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--r-xl);
}

.project-hero__media .ph {
  aspect-ratio: 16 / 9;
}

.tools-used {
  display: flex;
  flex-wrap: wrap;
  gap: 18px 26px;
}

.tools-used li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-body);
}

.tools-used img {
  width: 32px;
  height: 32px;
  object-fit: contain;
}

.gallery {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(12px, 1.6vw, 20px);
}

@media (min-width: 734px) {
  .gallery {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  .gallery > .g-6 { grid-column: span 6; }
  .gallery > .g-4 { grid-column: span 4; }
  .gallery > .g-3 { grid-column: span 3; }
  .gallery > .g-2 { grid-column: span 2; }
}

.gallery figure {
  margin: 0;
}

.gallery .ph,
.gallery img,
.gallery video {
  width: 100%;
  height: 100%;
  border-radius: var(--r-lg);
  object-fit: cover;
}

/* A captioned figure keeps its caption inside: the media takes whatever
   height the row leaves above it. */
.gallery figure:has(figcaption) {
  display: flex;
  flex-direction: column;
}

.gallery figure:has(figcaption) > :is(.ph, img, video) {
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
}

.gallery figcaption {
  margin-top: 12px;
  color: var(--fg-2);
  font-size: var(--fs-small);
}

/* Reference board: the references a project was built from, shown whole
   (never cropped) in columns, each credited where its author is known. */
.refs {
  columns: 2;
  column-gap: clamp(12px, 1.6vw, 20px);
}

@media (min-width: 734px) {
  .refs {
    columns: 4;
  }
}

.refs figure {
  margin: 0 0 clamp(12px, 1.6vw, 20px);
  break-inside: avoid;
}

.refs img {
  width: 100%;
  height: auto;
  border-radius: var(--r-md);
}

.refs figcaption {
  margin-top: 8px;
  color: var(--fg-2);
  font-size: var(--fs-small);
}

/* ---------------------------------------------------------------- page tint and small product pieces */

.tinted {
  --tint: var(--tint-l);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tinted {
    --tint: var(--tint-d);
  }
}

:root[data-theme="dark"] .tinted,
.tinted .theme-dark {
  --tint: var(--tint-d);
}

.lnav__title {
  display: inline-flex;
  align-items: center;
  min-width: 0;
}

/* On a narrow screen a long project name ends in an ellipsis rather than
   pushing the buttons off the edge. */
.lnav__title > span {
  overflow: hidden;
  text-overflow: ellipsis;
}

.lnav__inner > .btn {
  flex-shrink: 0;
}

/* Four app icon appearances in a 2 × 2 grid. */
.icon-quad {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 3vw, 36px);
  width: min(100%, 420px);
  margin-inline: auto;
}

.icon-quad img {
  width: 100%;
  border-radius: 23.5%;
  filter: drop-shadow(0 8px 18px rgb(0 0 0 / 0.16));
}

.hl__media > .tree {
  align-self: center;
  margin-bottom: 6%;
}

/* AMVR view sets: one tile per camera. */
.views-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: clamp(10px, 1.4vw, 16px);
  max-width: calc(var(--n) * 170px);
  margin-inline: auto;
}

.view-tile {
  margin: 0;
  padding: 18px 12px 14px;
  border-radius: var(--r-md);
  background: var(--tile-2);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  color: var(--tint, var(--fg));
}

.view-tile svg {
  display: block;
  width: 100%;
  max-width: 120px;
  margin-inline: auto;
}

.view-tile figcaption {
  margin-top: 8px;
  color: var(--fg-2);
  font-size: var(--fs-micro);
  font-weight: 600;
}

/* Line diagrams drawn in currentColor. */
.diagram {
  width: 100%;
  max-width: 460px;
  color: var(--fg);
}

.closer__media > .diagram {
  max-width: 460px;
  padding: clamp(16px, 3vw, 32px);
  border-radius: var(--r-lg);
  background: var(--tile-2);
}

@media (min-width: 834px) {
  .flow__step.is-row-end::after,
  .flow__step.is-row-end::before {
    display: none;
  }
}

/* ---------------------------------------------------------------- research list variants
   .rlist--feature: each entry as a large picture beside its text, sides
   alternating; .rlist--cards: entries as tiles with an icon. Panels keep
   their full width underneath. */

/* A highlight slide whose film fills it. */
.hl__media--fill > .loop {
  position: absolute;
  inset: 0;
}

.hl__media--fill > .loop video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hl__slide--fill::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  z-index: 1;
  height: 55%;
  background: linear-gradient(rgb(0 0 0 / 0.62), transparent);
  pointer-events: none;
}

.hl__slide--fill .hl__cap {
  z-index: 2;
}

/* ---------------------------------------------------------------- interaction experiments page */

.xp-trio .fig {
  color: inherit;
}

.xp-trio .fig:hover {
  text-decoration: none;
}

.xp-trio .fig__media img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: scale 0.8s var(--ease-out);
  will-change: scale;
}

.xp-trio .fig:hover .fig__media img {
  scale: 1.03;
}

.xp-trio .fig__cap {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--fg);
}

.xp-title .study__num {
  display: block;
  margin-bottom: 8px;
  color: var(--fg-2);
  font-size: var(--fs-eyebrow);
  letter-spacing: -0.012em;
}

.xp-feature {
  margin-top: clamp(32px, 4vw, 56px);
}

.xp-feature .feature__media .fig__media img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.xp-feature .chart {
  margin-top: 24px;
}

.xp-result {
  margin-top: clamp(48px, 6vw, 80px);
}

.xp-lead {
  max-width: var(--w-text);
  margin: clamp(20px, 3vw, 32px) 0 clamp(32px, 4vw, 48px);
  color: var(--fg-2);
  font-size: var(--fs-body-l);
  line-height: 1.47;
}

.next-card__go--back .ico {
  scale: -1 1;
}

.next-card__go--back:dir(rtl) .ico {
  scale: 1 1;
}

/* ---------------------------------------------------------------- project cards (Design)
   Tall cards in a rail, after Apple's "Get to know" cards: the picture fills
   the card, the year and kind of work sit above the name, and the whole card
   opens the project's page. --wc-pos picks the part of a wide picture the
   card shows. On a light picture the text turns dark (.wcard--light). A
   product shot on a plain background sits whole at the foot of the card
   instead (.wcard--inset), on --wc-bg, --wc-w wide. */

.works .rail__track {
  grid-auto-columns: min(78vw, 372px);
}

.rail__item.wcard {
  position: relative;
  display: block;
  aspect-ratio: 372 / 680;
  border-radius: var(--r-lg);
  background: var(--wc-bg, var(--tile-2));
  color: #fff;
  isolation: isolate;
}

.rail__item.wcard--light {
  background: var(--wc-bg, #f5f5f7);
  color: #1d1d1f;
}

.wcard__link {
  position: absolute;
  inset: 0;
  display: block;
  border-radius: inherit;
  color: inherit;
  text-decoration: none;
}

.wcard__link:hover {
  text-decoration: none;
}

.wcard__link:focus-visible {
  outline-offset: -4px;
  border-radius: inherit;
}

.rail__item.wcard .wcard__img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
  object-position: var(--wc-pos, 50% 50%);
  transition: scale 0.7s var(--ease);
  will-change: scale;
}

.rail__item.wcard--inset .wcard__img {
  inset: auto auto var(--wc-b, 0) 50%;
  width: var(--wc-w, 100%);
  max-width: none;
  height: auto;
  translate: -50% 0;
}

.wcard__link:hover .wcard__img {
  scale: 1.035;
}

/* A soft shade behind light text, so it reads on any picture. */
.wcard:not(.wcard--light, .wcard--plain) .wcard__link::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  z-index: -1;
  height: 46%;
  border-radius: inherit;
  background: linear-gradient(180deg, rgb(0 0 0 / 0.5), rgb(0 0 0 / 0));
  pointer-events: none;
}

.wcard__text {
  padding: 30px 30px 0;
}

.wcard__eyebrow {
  font-size: var(--fs-small);
  line-height: 1.3;
  font-weight: 600;
  opacity: 0.86;
}

.wcard__title {
  margin-top: 6px;
  font-size: var(--fs-title);
  line-height: 1.14;
  font-weight: 600;
  letter-spacing: -0.016em;
}

/* Only the disc grows on hover. Scaling the whole button would scale the
   icon's raster too, which thins and blurs its stroke mid-animation. */
.wcard__plus {
  position: absolute;
  inset-inline-end: 20px;
  bottom: 20px;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  color: #1d1d1f;
  isolation: isolate;
}

.wcard__plus::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.92);
  transition: scale 0.35s var(--ease-spring);
}

.wcard--light .wcard__plus {
  color: #fff;
}

.wcard--light .wcard__plus::before {
  background: #1d1d1f;
}

.wcard__link:hover .wcard__plus::before {
  scale: 1.12;
}

.wcard__plus .ico {
  width: 18px;
  height: 18px;
}

/* A line under the title, for cards that say more than their name. */
.wcard__note {
  max-width: 30em;
  margin-top: 12px;
  font-size: var(--fs-body);
  line-height: 1.4;
  opacity: 0.86;
}

/* A card with no page or picture (.wcard--plain): text and a large icon on
   the tile colour. */
.rail__item.wcard--plain {
  background: var(--tile);
  color: var(--fg);
}

.section--alt .rail__item.wcard--plain {
  background: var(--tile-2);
}

.wcard__ico {
  position: absolute;
  inset-inline-start: 30px;
  bottom: 30px;
  width: 72px;
  height: 72px;
  color: var(--accent);
}

/* One wide card on its own (.wcard--wide), text over the top of a photo. */
.wcard--wide {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--tile-2);
  color: #fff;
  isolation: isolate;
}

.wcard--wide .wcard__img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--wc-pos, 50% 50%);
  transition: scale 0.7s var(--ease);
  will-change: scale;
}

.wcard.wcard--wide .wcard__link::before {
  height: 62%;
  background: linear-gradient(180deg, rgb(0 0 0 / 0.6), rgb(0 0 0 / 0));
}

.wcard--wide .wcard__text {
  padding: clamp(28px, 4vw, 48px);
}

.wcard--wide .wcard__title {
  font-size: var(--fs-subhead);
  line-height: 1.08;
  letter-spacing: -0.02em;
}

@media (max-width: 733px) {
  .wcard--wide {
    aspect-ratio: 4 / 5;
  }
}

/* Shorter cards, for a row of smaller projects. */
.works--short .rail__item.wcard {
  aspect-ratio: 372 / 440;
}

/* ---------------------------------------------------------------- curved panorama (Bangudae XR)
   The Bangudae page opens on the cliff panorama, edge to edge, bent into a
   curved cinema screen: edges tallest, middle shortest. site.js draws it on
   a canvas, column by column, so the edges stay smooth; the <img> is the
   flat picture shown until then, or without script.

   Arriving from a Bangudae card (Research, Home), a second canvas laid over
   the page picks up the card where it was, zoomed in on the carved panel,
   and in one move grows it to full width, pulls back to the whole cliff,
   squares its corners and bends it. */

/* The first screen below the menus, with the panorama in its middle. */
.pano-stage {
  display: grid;
  align-content: center;
  min-height: calc(100svh - var(--nav-h) - var(--lnav-h));
}

@media (max-width: 733px) {
  .pano-stage {
    min-height: 0;
    padding-block: 40px;
  }
}

.pano {
  position: relative;
  aspect-ratio: 3600 / 1107;
}

.pano img,
.pano canvas {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.pano canvas {
  position: absolute;
  inset: 0;
}

.pano.is-drawn img,
.pano.is-flying canvas {
  visibility: hidden;
}

/* The landing point of the move, so it shows even while the rest of the
   page waits for its translation. */
.i18n-wait :is(.pano, .pano-flight) {
  visibility: visible;
}

/* Above the page, below the sticky menus (90 and 100). Named for the page
   transition, so it stays out of the cross-fade: fully drawn from the first
   frame, over the card it replaces, while the pages fade around it. */
.pano-flight {
  position: fixed;
  inset: 0;
  z-index: 80;
  width: 100%;
  height: 100%;
  pointer-events: none;
  view-transition-name: pano-flight;
}

::view-transition-group(pano-flight),
::view-transition-new(pano-flight) {
  animation: none;
}

/* The cards it starts from show the carved panel, zoomed in. */
.promo__pano {
  display: block;
  width: min(100%, 1040px);
  margin-bottom: clamp(32px, 4vw, 56px);
  overflow: hidden;
  border-radius: var(--r-lg);
}

.promo__pano img {
  width: 100%;
  aspect-ratio: 16 / 7;
  object-fit: cover;
}

/* A slow, slight drift in on hover: on a picture this wide, the usual zoom
   moves too far, too fast. */
.promo__pano img,
.wcard--wide .wcard__img {
  transition: scale 1.4s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: scale;
}

.promo__pano:hover img,
.wcard--wide .wcard__link:hover .wcard__img {
  scale: 1.02;
}

/* ---------------------------------------------------------------- software logos (Design)
   White line logos with their names, in a quiet row under the Design hero.
   The logos are white, so this only sits on dark pages. */

.toolkit {
  padding-block: clamp(48px, 6vw, 80px) clamp(32px, 5vw, 64px);
  text-align: center;
}

.toolkit__title {
  margin-bottom: clamp(24px, 3vw, 36px);
  color: var(--fg-2);
}

.toolkit__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 44px 12px;
  max-width: 960px;
  margin-inline: auto;
  list-style: none;
}

.toolkit__list li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 148px;
}

.toolkit__list img {
  width: 108px;
  height: 108px;
  object-fit: contain;
  transition: transform 0.45s var(--ease);
}

.toolkit__list li:hover img {
  transform: translateY(-3px);
}

.toolkit__list span {
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.3;
}

@media (max-width: 733px) {
  .toolkit__list {
    gap: 28px 4px;
  }

  .toolkit__list li {
    width: 104px;
  }

  .toolkit__list img {
    width: 76px;
    height: 76px;
  }

  .toolkit__list span {
    font-size: var(--fs-micro);
  }
}

/* ---------------------------------------------------------------- app bar (Artifacts)
   A row of app icons with names, like a store's product strip. It scrolls
   sideways when the icons don't fit; chevrons appear at whichever end has more. */

.appbar {
  position: relative;
  padding-bottom: clamp(48px, 6vw, 80px);
  /* The shrunken row is laid out twice as wide (see .is-stuck); clipping
     sideways keeps that from widening the page. */
  overflow-x: clip;
}

/* At the end of a section the section's own padding already gives the gap. */
.section > .appbar:last-child {
  padding-bottom: 0;
}

/* The Artifacts page keeps its bar under the menu. Once stuck it shrinks to
   a row of small icons on frosted glass; the shrink is a transform, so the
   page below never jumps. */
.appbar--sticky {
  position: sticky;
  top: var(--nav-h);
  z-index: 40;
  padding-block: 20px 22px;
}

.appbar--sticky::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  z-index: -1;
  height: var(--appbar-h);
  border-bottom: 1px solid var(--line-soft);
  background: var(--glass);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}

/* On an app page the bar comes before the local nav: once shrunk it stays
   under the menu and the local nav sticks beneath it. Both move with the
   global nav when it tucks away, using the same timing (see .has-lnav .lnav). */
.has-lnav:has(.appbar--sticky) .lnav {
  top: calc(var(--nav-h) + var(--appbar-h));
}

.has-lnav .appbar--sticky {
  z-index: 80;
  transition: transform 0.6s var(--ease-out);
}

.gnav-hidden:not(.nav-open) .appbar--sticky {
  transition: transform 0.45s var(--ease);
  transform: translateY(calc(-1 * var(--nav-h)));
}

.appbar--sticky .appbar__track {
  transform-origin: 50% 0;
  transition: transform 0.45s var(--ease);
}

.appbar--sticky .appbar__name {
  transition: opacity 0.25s var(--ease);
}

.appbar--sticky.is-stuck {
  pointer-events: none;
}

.appbar--sticky.is-stuck::before {
  opacity: 1;
}

/* Twice as wide before halving, so the small row fits every icon even where
   the full-size row has to scroll (phones). */
.appbar--sticky.is-stuck .appbar__track {
  width: 200%;
  margin-inline: -50%;
  overflow: hidden;
  transform: translateY(-11px) scale(0.5);
}

.appbar--sticky.is-stuck :is(.appbar__name, .appbar__kind, .appbar__paddle) {
  opacity: 0;
}

.appbar--sticky.is-stuck .appbar__item {
  pointer-events: auto;
}

/* Above a local nav (app pages) the shrink follows the scroll instead of
   snapping: the icons scale down and the glass behind them shortens at the
   rate the page moves, so the bar's lower edge stays on the local nav until
   both stick. site.js sets --shrink (0 to 1) and --strip (the glass height). */
.appbar--linked {
  pointer-events: none;
}

.appbar--linked :is(.appbar__item, .appbar__paddle) {
  pointer-events: auto;
}

.appbar--sticky.appbar--linked::before {
  height: var(--strip, var(--appbar-h));
}

.appbar--sticky.appbar--linked .appbar__track {
  --s: calc(1 - var(--shrink, 0) / 2);
  width: calc(100% / var(--s));
  margin-inline: calc(50% - 50% / var(--s));
  transform: translateY(calc(var(--shrink, 0) * -11px)) scale(var(--s));
  transition: none;
}

/* Pointing at (or opening) one app turns the others transparent: their clear
   icons fade in where the app has them, and the rest fade to grey. */
.appbar__icon--img {
  position: relative;
}

.appbar__icon--img > img {
  transition: opacity 0.35s var(--ease), filter 0.35s var(--ease);
}

.appbar__icon > .appbar__clear {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.appbar:has(.appbar__item:hover, .appbar__item:focus-visible, .appbar__item[aria-current]) .appbar__item:not(:hover, :focus-visible, [aria-current]) .appbar__icon:has(.appbar__clear) > img:not(.appbar__clear) {
  opacity: 0;
}

.appbar:has(.appbar__item:hover, .appbar__item:focus-visible, .appbar__item[aria-current]) .appbar__item:not(:hover, :focus-visible, [aria-current]) .appbar__clear {
  opacity: 1;
}

.appbar:has(.appbar__item:hover, .appbar__item:focus-visible, .appbar__item[aria-current]) .appbar__item:not(:hover, :focus-visible, [aria-current]) .appbar__icon:not(:has(.appbar__clear)) > img {
  opacity: 0.45;
  filter: grayscale(1);
}

.appbar__track {
  display: flex;
  gap: clamp(12px, 2.4vw, 32px);
  padding: 4px max(var(--g), calc((100vw - var(--w-main)) / 2)) 8px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scroll-padding-inline: max(var(--g), calc((100vw - var(--w-main)) / 2));
  scrollbar-width: none;
  list-style: none;
}

.appbar__track::-webkit-scrollbar {
  display: none;
}

.appbar__track > li {
  flex: none;
  scroll-snap-align: start;
}

/* Centred while the icons fit; once they overflow, the auto margins collapse
   and the row scrolls from its start as usual. */
.appbar__track > li:first-child {
  margin-inline-start: auto;
}

.appbar__track > li:last-child {
  margin-inline-end: auto;
}

.appbar__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 100px;
  color: var(--fg);
  text-align: center;
}

.appbar__item:hover {
  text-decoration: none;
}

.appbar__icon {
  display: grid;
  place-items: center;
  width: 80px;
  height: 80px;
  margin-bottom: 14px;
  border-radius: 22.5%;
  background: linear-gradient(180deg, var(--tile-2), var(--bg-2));
  box-shadow: inset 0 0 0 1px var(--line-soft), 0 1px 3px rgb(0 0 0 / 0.06);
  color: var(--fg-2);
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease);
}

.appbar__icon svg {
  width: 42px;
  height: 42px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.appbar__icon--img {
  background: none;
  box-shadow: none;
  filter: drop-shadow(0 2px 6px rgb(0 0 0 / 0.12));
}

.appbar__icon img {
  width: 100%;
  height: 100%;
  border-radius: 23.5%;
}

.appbar__item:hover .appbar__icon {
  transform: translateY(-3px);
  box-shadow: inset 0 0 0 1px var(--line-soft), 0 8px 18px rgb(0 0 0 / 0.1);
}

.appbar__item:hover .appbar__icon--img {
  box-shadow: none;
  filter: drop-shadow(0 8px 14px rgb(0 0 0 / 0.18));
}

.appbar__name {
  position: relative;
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
  white-space: nowrap;
  transition: color 0.3s var(--ease);
}

/* The open app: its name darkens and an underline grows in beneath it, so
   neighbouring names never shift. */
.appbar__name::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -6px;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
  transform: scaleX(0);
  transition: transform 0.5s var(--ease);
}

.appbar__item:hover .appbar__name,
.appbar__item[aria-current] .appbar__name {
  color: var(--fg);
}

.appbar__item[aria-current] .appbar__name::after {
  transform: scaleX(1);
}

/* What kind of artifact it is (iOS app, add-on, web), shown while pointed at.
   Its line is always reserved, so nothing below moves. */
.appbar__kind {
  margin-top: 12px;
  color: var(--fg-2);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

.appbar:not(.is-stuck) .appbar__item:is(:hover, :focus-visible) .appbar__kind {
  opacity: 1;
  transform: none;
}

.appbar__paddle {
  position: absolute;
  top: 0;
  display: grid;
  place-items: center;
  width: max(var(--g), 48px);
  height: 92px;
  padding: 0;
  border: 0;
  color: var(--fg);
  cursor: pointer;
  transition: opacity 0.3s var(--ease);
}

.appbar__paddle--prev {
  inset-inline-start: 0;
  background: linear-gradient(to right, var(--bg) 55%, transparent);
}

.appbar__paddle--next {
  inset-inline-end: 0;
  background: linear-gradient(to left, var(--bg) 55%, transparent);
}

.appbar__paddle--prev:dir(rtl) {
  background: linear-gradient(to left, var(--bg) 55%, transparent);
}

.appbar__paddle--next:dir(rtl) {
  background: linear-gradient(to right, var(--bg) 55%, transparent);
}

.appbar__paddle:disabled {
  opacity: 0;
  pointer-events: none;
}

.appbar__paddle svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.appbar__paddle:dir(rtl) svg {
  scale: -1 1;
}

@media (max-width: 733px) {
  .appbar__item {
    min-width: 80px;
  }

  .appbar__icon {
    width: 64px;
    height: 64px;
  }

  .appbar__icon svg {
    width: 34px;
    height: 34px;
  }

  .appbar__name {
    font-size: var(--fs-micro);
  }

  .appbar__paddle {
    height: 74px;
  }
}

/* ---------------------------------------------------------------- footnotes & footer */

.footnotes {
  padding: 24px 0 18px;
  border-bottom: 1px solid var(--line);
  color: var(--fg-2);
  font-size: var(--fs-micro);
  line-height: 1.5;
}

.footnotes ol {
  display: grid;
  gap: 8px;
  padding-inline-start: 1.4em;
}

.footnotes li::marker {
  font-variant-numeric: tabular-nums;
}

.footnotes a {
  color: var(--link);
}

.gfooter {
  background: var(--bg-2);
  color: var(--fg-2);
  font-size: var(--fs-micro);
  line-height: 1.34;
}

.gfooter__inner {
  width: min(var(--w-main), calc(100% - 2 * var(--g)));
  margin-inline: auto;
  padding: 18px 0 28px;
}

.gfooter__dir {
  display: grid;
  gap: 24px;
  padding: 26px 0 30px;
  border-bottom: 1px solid var(--line);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 734px) {
  .gfooter__dir {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

.gfooter__col h3 {
  margin-bottom: 10px;
  color: var(--fg);
  font-size: var(--fs-micro);
  font-weight: 600;
}

.gfooter__col ul {
  display: grid;
  gap: 8px;
  list-style: none;
}

.gfooter__col a {
  color: var(--fg-2);
}

.gfooter__col a:hover {
  color: var(--fg);
}

.gfooter__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 8px 24px;
  padding-top: 16px;
}

.gfooter__legal a {
  color: var(--fg-2);
}

.gfooter__legal nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0 16px;
}

/* ---------------------------------------------------------------- misc components */

.callout-note {
  padding: 22px 24px;
  border-radius: var(--r-md);
  background: var(--tile);
  color: var(--fg-2);
}

.callout-note strong {
  color: var(--fg);
}

.icon-list {
  display: grid;
  gap: 18px;
  list-style: none;
}

.icon-list li {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 14px;
  align-items: start;
}

.icon-list svg {
  width: 26px;
  height: 26px;
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.email-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px 18px;
}

.email-link {
  font-size: var(--fs-statement);
  font-weight: 600;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}

.portrait {
  overflow: hidden;
  border-radius: var(--r-lg);
}

.portrait img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 62% 30%;
}

/* ---------------------------------------------------------------- award */

.award {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: var(--fg);
}

a.award:hover {
  text-decoration: none;
}

.award__laurel {
  flex: none;
  width: 22px;
  height: 40px;
  fill: currentColor;
}

.award__laurel--r {
  transform: scaleX(-1);
}

.award__text {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  line-height: 1.2;
}

.award__title {
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: -0.012em;
}

.award__sub {
  max-width: 24ch;
  color: var(--fg-2);
  font-size: var(--fs-micro);
  letter-spacing: -0.006em;
}

.hero .award {
  margin-top: 30px;
}

/* Design principles: three short statements in tiles. */
.principles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.6vw, 20px);
}

.principles > * {
  padding: clamp(26px, 3vw, 38px);
  border-radius: var(--r-lg);
  background: var(--tile-2);
}

.principles h3 {
  font-size: var(--fs-lead);
  line-height: 1.2;
  letter-spacing: -0.012em;
}

.principles p {
  margin-top: 10px;
  color: var(--fg-2);
}

@media (max-width: 833px) {
  .principles {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------- research page
   Three lists: publications, industry projects and personal projects. Each
   entry shows its main point; the panel under it holds the depth (studies,
   results, figures and links). */

.rhead {
  margin-bottom: clamp(20px, 3vw, 32px);
}

.rhead p {
  max-width: 40em;
  margin-top: 10px;
  color: var(--fg-2);
  font-size: var(--fs-body-l);
  line-height: 1.45;
}

.entry {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0 clamp(24px, 4vw, 56px);
  padding-block: clamp(26px, 3.4vw, 38px);
  border-bottom: 1px solid var(--line);
}

.entry > .expand-panel {
  grid-column: 1 / -1;
  margin-top: 22px;
}

.entry .item-actions {
  margin-top: 16px;
}

/* A film inside an experiment's panel stays at a readable size. */
.panel-video {
  max-width: 720px;
  margin-top: 14px;
  border-radius: var(--r-sm);
}

.points {
  display: grid;
  gap: 12px;
  padding-inline-start: 1.1em;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.points strong {
  color: var(--fg);
}

.tools-nudge {
  margin-top: clamp(28px, 4vw, 40px);
  margin-bottom: clamp(28px, 3.6vw, 44px);
  color: var(--fg-2);
  font-size: var(--fs-body-l);
  line-height: 1.45;
}

.tools-nudge .link-more {
  margin-inline-start: 4px;
}

/* ---------------------------------------------------------------- home
   Who and what first, then a short reel of the work with subtitles, then six
   projects (two with something to try), the 3D work and a way to get in touch.
   Real media carries the page; motion stays with video, reveals and hover. */

/* Intro: the name as a two-tone headline, the one-line pitch, the proof. */
.intro {
  padding-top: clamp(48px, 7vw, 104px);
}

.intro__title {
  display: flex;
  flex-direction: column;
  font-size: var(--fs-display);
  line-height: 0.98;
  font-weight: 600;
  letter-spacing: -0.042em;
}

.intro__role {
  color: var(--fg-3);
}

.intro__cols {
  display: grid;
  gap: 20px clamp(32px, 6vw, 96px);
  margin-top: clamp(28px, 3.6vw, 44px);
}

@media (min-width: 834px) {
  .intro__cols {
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    align-items: end;
  }
}

.intro__lead {
  max-width: 22em;
  font-size: var(--fs-statement);
  line-height: 1.26;
  font-weight: 500;
  letter-spacing: -0.022em;
}

.intro__aside {
  max-width: 30em;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.intro__aside p + p {
  margin-top: 10px;
}

.intro__cta {
  margin-top: clamp(28px, 3.4vw, 40px);
}

/* Highlights under the pitch: four facts, quietly set. */
.intro__wins {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 28px clamp(20px, 3vw, 40px);
  margin-top: clamp(48px, 6vw, 88px);
  list-style: none;
}

@media (min-width: 1069px) {
  .intro__wins {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Reel: shots cross-fade on a stage, each with a subtitle; the bar below
   shows progress and jumps between shots. site.js drives it. */
.reel {
  margin: clamp(40px, 5.6vw, 72px) auto 0;
}

.reel__stage {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-xl);
  background: #000;
  color: #fff;
  isolation: isolate;
}

@media (max-width: 733px) {
  .reel__stage {
    aspect-ratio: 4 / 5;
    border-radius: var(--r-lg);
  }
}

.reel__poster,
.reel__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.reel__layer {
  opacity: 0;
  transition: opacity 0.9s var(--ease);
}

.reel__layer.is-on {
  opacity: 1;
}

/* Stills drift slowly while they are on screen. */
.reel__layer--still.is-on {
  animation: reel-drift var(--dur, 5s) linear both;
}

@keyframes reel-drift {
  from {
    scale: 1.02;
  }

  to {
    scale: 1.1;
  }
}

.reel.is-paused .reel__layer--still {
  animation-play-state: paused;
}

/* Shade under the subtitles so they read over any shot. */
.reel__stage::after {
  content: "";
  position: absolute;
  inset: 48% 0 0;
  z-index: 1;
  background: linear-gradient(to top, rgb(0 0 0 / 0.62), rgb(0 0 0 / 0));
  pointer-events: none;
}

.reel__end {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-content: center;
  gap: 8px;
  padding: 24px;
  background: #000;
  text-align: center;
  opacity: 0;
  transition: opacity 0.9s var(--ease);
}

.reel__end.is-on {
  opacity: 1;
}

.reel__end-name {
  font-size: var(--fs-h1);
  line-height: 1;
  font-weight: 600;
  letter-spacing: -0.04em;
}

.reel__end-role {
  color: rgb(255 255 255 / 0.62);
  font-size: var(--fs-eyebrow);
}

.reel__line {
  position: absolute;
  inset-inline: 0;
  bottom: clamp(22px, 3.8vw, 52px);
  z-index: 2;
  width: min(88%, 30em);
  margin-inline: auto;
  font-size: var(--fs-lead);
  line-height: 1.34;
  font-weight: 500;
  letter-spacing: -0.014em;
  text-align: center;
  text-wrap: balance;
  text-shadow: 0 1px 18px rgb(0 0 0 / 0.5);
  transition: opacity 0.45s var(--ease), translate 0.7s var(--ease-out);
}

.reel__line.is-out {
  opacity: 0;
  translate: 0 8px;
}

/* The shot's project, top left. */
.reel__now {
  position: absolute;
  top: clamp(14px, 2vw, 22px);
  inset-inline-start: clamp(14px, 2vw, 22px);
  z-index: 2;
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 980px;
  background: rgb(0 0 0 / 0.36);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  font-size: var(--fs-micro);
  font-weight: 600;
  line-height: 1.25;
  transition: opacity 0.45s var(--ease);
}

.reel__count {
  color: rgb(255 255 255 / 0.6);
  font-variant-numeric: tabular-nums;
}

.reel__now:has(.reel__label:empty),
.reel.is-end .reel__now {
  opacity: 0;
}

.reel .loop__toggle {
  z-index: 3;
}

.reel.is-paused .loop__toggle .i-play {
  display: block;
}

.reel.is-paused .loop__toggle .i-pause {
  display: none;
}

html:not(.js) .reel .loop__toggle {
  display: none;
}

/* Progress: one segment per shot. */
.reel__bar {
  display: flex;
  gap: 6px;
  margin-top: 10px;
}

.reel__seg {
  flex: 1;
  min-width: 0;
  padding: 10px 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.reel__seg > span {
  position: relative;
  display: block;
  height: 3px;
  overflow: hidden;
  border-radius: 2px;
  background: var(--bg-3);
  transition: background-color 0.3s var(--ease);
}

.reel__seg > span::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--fg);
  transform: scaleX(var(--p, 0));
  transform-origin: 0 50%;
}

.reel__seg:dir(rtl) > span::after {
  transform-origin: 100% 50%;
}

.reel__seg:hover > span {
  background: var(--line);
}

.reel__seg:focus-visible {
  outline-offset: 0;
}

/* The script under the reel is for screen readers (and the subtitles). */
.reel__script {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Section titles */
.sect-title {
  font-size: var(--fs-h2);
  line-height: 1.02;
  letter-spacing: -0.04em;
}

/* ---------------------------------------------------------------- promos (home)
   Selected work in the manner of Apple's home page: full-width tiles with a
   title, one line, actions and a large picture, then pairs. Thin gaps
   separate them; .theme-dark makes a tile dark, .promo--paper warm. */

.promos {
  display: grid;
  gap: 12px;
  padding: clamp(56px, 7vw, 96px) 12px 0;
}

.promo-pair {
  display: grid;
  gap: 12px;
}

@media (min-width: 834px) {
  .promo-pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.promo {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: clamp(560px, 52vw, 700px);
  padding: clamp(44px, 5vw, 60px) var(--g) 0;
  overflow: hidden;
  background: var(--bg-2);
  color: var(--fg);
  text-align: center;
}

.promo.theme-dark {
  background: #000;
}

.promo--paper {
  background: #f4ecdf;
  color: #2a211a;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .promo--paper {
    background: #211a13;
    color: #f4ecdf;
  }
}

:root[data-theme="dark"] .promo--paper {
  background: #211a13;
  color: #f4ecdf;
}

.promo--half {
  min-height: clamp(520px, 44vw, 640px);
}

.promo__eyebrow {
  margin-bottom: 6px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.promo__eyebrow--new {
  color: var(--accent-text);
}

.promo__award {
  margin-bottom: 14px;
}

.promo__title {
  font-size: var(--fs-h2);
  line-height: 1.07;
  font-weight: 600;
  letter-spacing: -0.024em;
}

.promo--half .promo__title {
  font-size: var(--fs-subhead);
}

.promo__sub {
  max-width: 26em;
  margin-top: 8px;
  font-size: var(--fs-lead);
  line-height: 1.22;
  letter-spacing: -0.014em;
}

.promo--half .promo__sub {
  font-size: var(--fs-eyebrow);
}

.promo__cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px 14px;
  margin-top: 20px;
}

.promo__cta .btn--secondary {
  background: transparent;
}

/* The picture sits at the foot of the tile and may run off its edge. */
.promo__media {
  display: flex;
  flex: 1;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  margin-top: clamp(28px, 4vw, 48px);
}

.promo .phones {
  width: min(100%, 640px);
  margin-bottom: clamp(32px, 4vw, 56px);
}

.promo__media--photo {
  margin-inline: calc(-1 * var(--g));
  width: calc(100% + 2 * var(--g));
}

.promo__media--photo img {
  width: 100%;
  height: clamp(240px, 26vw, 360px);
  object-fit: cover;
}

.promo__views {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  width: min(100%, 460px);
  margin-bottom: clamp(32px, 4vw, 48px);
}

.promo__views .view-tile {
  padding: 10px;
  border-radius: 14px;
  background: var(--bg);
  color: var(--accent);
}

.promo__views svg {
  display: block;
  width: 100%;
}

@media (max-width: 733px) {
  .promo,
  .promo--half {
    min-height: 0;
  }
}

/* What I do: each area under its icon. */
.skill__ico {
  width: 36px;
  height: 36px;
  margin-bottom: 14px;
  color: var(--accent);
}

/* What I do: four areas, each with its tools */
.skills {
  padding-top: clamp(88px, 11vw, 152px);
}

.skills__grid {
  display: grid;
  gap: 36px clamp(24px, 3vw, 40px);
  margin-top: clamp(32px, 4.4vw, 56px);
  list-style: none;
}

@media (min-width: 734px) {
  .skills__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1069px) {
  .skills__grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.skill,
.win {
  padding-top: 22px;
  border-top: 1px solid var(--line);
}

.skill__title {
  font-size: var(--fs-title-s);
  line-height: 1.2;
  letter-spacing: -0.016em;
}

.skill__text {
  margin-top: 10px;
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.5;
}

.skill__tools {
  margin-top: 14px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.win__big {
  font-size: var(--fs-h3);
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -0.032em;
  font-variant-numeric: tabular-nums;
}

.win__text {
  max-width: 22em;
  margin-top: 8px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.45;
}

/* Selected publications */
.pubs {
  padding-block: clamp(88px, 11vw, 152px);
}

.pubs__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px 32px;
  margin-bottom: clamp(24px, 3vw, 40px);
}

.pubs__head .link-more {
  font-size: var(--fs-body);
}

.pubs__list {
  list-style: none;
  border-top: 1px solid var(--line);
}

.pub {
  display: grid;
  gap: 8px 40px;
  padding: 24px 0;
  border-bottom: 1px solid var(--line);
}

@media (min-width: 834px) {
  .pub {
    grid-template-columns: 200px minmax(0, 1fr);
  }

  .pub__meta {
    flex-direction: column;
    grid-row: span 2;
  }
}

.pub__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.45;
}

.pub__title {
  font-size: var(--fs-lead);
  line-height: 1.3;
  letter-spacing: -0.016em;
}

.pub__title a {
  color: var(--fg);
}

.pub__title a:hover {
  color: var(--link);
}

.pub__authors {
  color: var(--fg-2);
  font-size: var(--fs-small);
}

.pub__authors b {
  color: var(--fg);
  font-weight: 600;
}

/* Design and 3D: a dark band with a gallery */
.craft {
  padding-block: clamp(80px, 10vw, 136px);
}

.craft .shead {
  margin-bottom: clamp(28px, 4vw, 44px);
}

.craft__label {
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
}

.craft__title {
  max-width: 18ch;
  margin-top: 12px;
  font-size: var(--fs-h2);
  line-height: 1.04;
  letter-spacing: -0.034em;
}

.rail__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  color: inherit;
}

.rail__link:hover {
  text-decoration: none;
}

.rail__link:hover .rail__title {
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

/* About and contact */
.closing {
  padding-block: clamp(96px, 12vw, 168px);
}

.closing__grid {
  display: grid;
  gap: clamp(28px, 5vw, 80px);
  align-items: center;
}

@media (min-width: 734px) {
  .closing__grid {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.5fr);
  }
}

.closing__portrait {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
}

.closing__portrait img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 12%;
}

@media (max-width: 733px) {
  .closing__portrait {
    width: min(240px, 64%);
  }
}

.closing__title {
  font-size: var(--fs-h2);
  line-height: 1.02;
  letter-spacing: -0.04em;
}

.closing__copy > * + * {
  margin-top: 16px;
}

.closing__copy > p:not(.links-inline) {
  max-width: 34em;
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.5;
}

.closing__copy > .closing__title + p {
  margin-top: 22px;
}

.closing__email {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
}

.closing__copy > .closing__email {
  margin-top: 28px;
}

.closing__copy > .closing__links {
  margin-top: 22px;
}

/* Arabic and Chinese: more leading; Arabic letterforms also run small beside
   Latin at the same size, so body text steps up a little. */
:is(:lang(ar), :lang(zh)) :is(.intro__lead, .intro__aside, .promo__sub, .skill__text, .win__text, .closing__copy p, .pub__title) {
  line-height: 1.75;
}

:lang(ar) :is(.intro__title, .sect-title, .promo__title, .craft__title, .closing__title) {
  line-height: 1.3;
}

:lang(zh) :is(.intro__title, .sect-title, .promo__title, .craft__title, .closing__title) {
  line-height: 1.22;
}

:lang(ar) .intro__role,
:lang(zh) .intro__role {
  font-size: 0.62em;
  margin-top: 0.3em;
}

:lang(ar) :is(.skill__text, .closing__copy > p:not(.links-inline)) {
  font-size: var(--fs-body-l);
}

:lang(ar) :is(.intro__aside, .win__text) {
  font-size: var(--fs-body);
}

:lang(ar) .reel__line {
  font-size: var(--fs-lead);
}

@media (min-width: 834px) {
  .gnav:lang(ar) .gnav__list a {
    font-size: var(--fs-small);
  }
}

/* ---------------------------------------------------------------- motion
   One vocabulary for the whole site:
   - entrances decelerate slowly (--ease-out) over about a second
   - state changes (hover, toggles, controls) use --ease over 0.3–0.6s
   - only transform and opacity animate, except chart bars and disclosures
   The inline script in each <head> adds .js before first paint, so start states
   never flash, and site.js removes each element's delay once it has arrived.
   Everything here is skipped under prefers-reduced-motion. */

/* Scroll reveal: fade and rise. */
.js [data-reveal]:not(.is-done) {
  transition:
    opacity 1s var(--ease-out) var(--rd, 0ms),
    transform 1.3s var(--ease-out) var(--rd, 0ms);
}

.js [data-reveal]:not(.in) {
  opacity: 0;
  transform: translate3d(0, 48px, 0);
}

.js [data-reveal="fade"]:not(.in) {
  transform: none;
}

.js [data-reveal="scale"]:not(.in) {
  transform: translate3d(0, 40px, 0) scale(0.94);
}

/* Media inside a revealing block settles from a gentle zoom. */
.js [data-reveal]:not(.is-done) :is(.tile__media, .fig__media, .window__media, .rail__item) > :is(img, video) {
  transition:
    transform 1.9s var(--ease-out) var(--rd, 0ms),
    opacity 0.8s var(--ease) var(--rd, 0ms);
}

.js [data-reveal]:not(.in) :is(.tile__media, .fig__media, .window__media, .rail__item) > :is(img, video) {
  transform: scale(1.1);
}

/* Lists and grids cascade: the container fades while its items rise in turn. */
.js [data-reveal]:is(.rows, .facts, .steps, .findings, .chips, .icon-list, .principles):not(.in),
.js .rail[data-reveal]:not(.in) {
  transform: none;
}

.js [data-reveal]:not(.is-done) :is(.rows > li, .facts > *, .steps > *, .findings > *, .chips > li, .icon-list > li, .principles > *, .rail__track > li) {
  transition:
    opacity 0.9s var(--ease-out) calc(var(--rd, 0ms) + var(--ci, 0) * 70ms),
    transform 1.2s var(--ease-out) calc(var(--rd, 0ms) + var(--ci, 0) * 70ms);
}

.js [data-reveal]:not(.in) :is(.rows > li, .facts > *, .steps > *, .findings > *, .chips > li, .icon-list > li, .principles > *, .rail__track > li) {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
}

/* Two-tone paragraphs: the text arrives, then its key phrases light up in turn. */
.js .t-two-tone[data-reveal] strong {
  transition: color 1.2s var(--ease) calc(var(--rd, 0ms) + 380ms + var(--ci, 0) * 220ms);
}

.js .t-two-tone[data-reveal]:not(.in) strong {
  color: var(--fg-3);
}

/* Lazy images fade in once loaded instead of popping. */
.js main img[loading="lazy"] {
  transition: opacity 0.8s var(--ease), transform 1.1s var(--ease-out);
}

.js main img.is-loading {
  opacity: 0;
}

/* Hero: headline elements rise out of a soft blur; the hero figure floats up after. */
.js .hero :is(.hero__eyebrow, .hero__title, .hero__lead, .cta-row, .award),
.js .page-hero .container > * {
  animation: hero-in 1.3s var(--ease-out) both;
}

.js .hero .hero__title,
.js .page-hero .container > :nth-child(2) {
  animation-delay: 0.08s;
}

.js .hero .hero__lead,
.js .page-hero .container > :nth-child(3) {
  animation-delay: 0.18s;
}

.js .hero :is(.cta-row, .award),
.js .page-hero .container > :nth-child(n + 4) {
  animation-delay: 0.28s;
}

.js .hero > :is(.fig, .container-wide) {
  animation: stage-in 1.6s var(--ease-out) 0.28s both;
}

.js .hero > :is(.fig, .container-wide) :is(.fig__media, .white-stage) > :is(img, video) {
  animation: settle 2.4s var(--ease-out) 0.28s both;
}

@keyframes hero-in {
  from {
    opacity: 0;
    translate: 0 24px;
    filter: blur(6px);
  }

  to {
    opacity: 1;
    translate: 0 0;
    filter: none;
  }
}

@keyframes stage-in {
  from {
    opacity: 0;
    translate: 0 64px;
    scale: 0.96;
  }
}

@keyframes settle {
  from {
    scale: 1.12;
  }
}

/* Scroll-linked motion runs on the compositor where supported; elsewhere the
   page is simply static. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 734px) {
    /* Large figures drift a little slower than the page. */
    .parallax > :is(img, video) {
      scale: 1.12;
      animation: drift linear both;
      animation-timeline: view();
      animation-range: cover;
    }
  }
}

@keyframes drift {
  from {
    translate: 0 -5%;
  }

  to {
    translate: 0 5%;
  }
}

/* Page to page: a quick cross-fade (supporting browsers only). */
@view-transition {
  navigation: auto;
}

::view-transition-old(root) {
  animation: vt-out 0.28s var(--ease) both;
}

::view-transition-new(root) {
  animation: vt-in 0.5s var(--ease-out) both;
}

@keyframes vt-out {
  to {
    opacity: 0;
  }
}

@keyframes vt-in {
  from {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }

  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }

  .js [data-reveal]:not(.in),
  .js [data-reveal]:not(.in) :is(.rows > li, .facts > *, .steps > *, .findings > *, .chips > li, .icon-list > li, .principles > *, .rail__track > li),
  .js [data-reveal]:not(.in) :is(.tile__media, .fig__media, .window__media, .rail__item) > :is(img, video) {
    opacity: 1;
    transform: none;
  }

  .js .bars:not(.in) .bar__fill {
    width: var(--v);
  }

  .js .bars:not(.in) .bar__value,
  .js main img.is-loading {
    opacity: 1;
  }

  .js .t-two-tone[data-reveal]:not(.in) strong {
    color: var(--fg);
  }
}

/* ---------------------------------------------------------------- print */

@media print {
  .gnav,
  .lnav,
  .gfooter__dir,
  .loop__toggle,
  .rail__controls {
    display: none !important;
  }

  /* Printing (or "Save as PDF") leaves the pictures and films out. */
  img,
  video,
  canvas,
  picture {
    visibility: hidden !important;
  }

  [data-reveal],
  [data-reveal] * {
    opacity: 1 !important;
    transform: none !important;
  }

  .bar__fill {
    width: var(--v) !important;
  }
}

/* ---------------------------------------------------------------- publications as paper stacks (Research)
   Each paper is a small stack of its pages. On hover the front page comes
   forward and the two behind it fan out to either side. Papers without a PDF yet show a typeset
   title page (.paper__cover) over blank sheets. */

/* The papers sit in a rail that scrolls sideways. The track leaves room
   above and to the sides for the hover fan. */
.papers-rail .rail__track.papers {
  grid-auto-columns: min(68vw, 300px);
  gap: clamp(36px, 4.4vw, 60px);
  padding-top: 36px;
  padding-bottom: 12px;
}

.papers-rail {
  margin-top: clamp(8px, 1.5vw, 16px);
}

/* The thesis, as one line under the papers. */
.pubs-thesis {
  margin-top: clamp(40px, 5vw, 64px);
  padding-top: clamp(24px, 3vw, 32px);
  border-top: 1px solid var(--line);
  color: var(--fg-2);
  font-size: var(--fs-body);
  line-height: 1.5;
}

.pubs-thesis__meta {
  display: block;
  margin-bottom: 4px;
  font-size: var(--fs-small);
  font-weight: 600;
}

.pubs-thesis__title {
  display: block;
  color: var(--fg);
  font-weight: 600;
}

.pubs-thesis b {
  font-weight: inherit;
}

.pubs-thesis .link-more {
  margin-inline-start: 6px;
  white-space: nowrap;
}

.paper {
  position: relative;
  display: flex;
  flex-direction: column;
}

.paper:hover,
.paper:focus-within {
  z-index: 1;
}

.paper__stack {
  position: relative;
  display: block;
  aspect-ratio: 210 / 297;
  margin: 6px 10px 32px;
}

.paper__page {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 4px;
  background: #fff;
  box-shadow: 0 0 0 0.5px rgb(0 0 0 / 0.12), 0 6px 20px rgb(0 0 0 / 0.14);
  transition: transform 0.7s var(--ease-out), opacity 0.7s var(--ease-out);
}

/* Counted from the front, so a two-page paper (no third sheet) works too. */
.paper__page:nth-last-child(2) {
  transform: translate(4px, 3px) rotate(2.5deg);
}

.paper__page:nth-last-child(3) {
  transform: translate(-5px, 5px) rotate(-4deg);
}

@media (hover: hover) {
  .paper:hover .paper__page:last-child {
    transform: translateY(-3%) scale(1.05);
  }

  .paper:hover .paper__page:nth-last-child(2) {
    transform: translate(-11%, 2%) rotate(-5deg);
  }

  .paper:hover .paper__page:nth-last-child(3) {
    transform: translate(11%, 2%) rotate(5deg);
  }
}

/* A title page drawn in HTML, with grey bars standing in for the text. */

.paper__meta {
  color: var(--fg-2);
  font-size: var(--fs-small);
  font-weight: 600;
}

.paper__title {
  margin-top: 8px;
  font-size: var(--fs-lead);
  line-height: 1.22;
  font-weight: 600;
  letter-spacing: -0.016em;
}

.paper__authors {
  margin-top: 8px;
  color: var(--fg-2);
  font-size: var(--fs-small);
  line-height: 1.4;
}

.paper__authors b {
  color: var(--fg);
  font-weight: 600;
}

.paper__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin-top: auto;
  padding-top: 20px;
  font-size: var(--fs-small);
}

.paper__dl {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.paper__dl .ico {
  width: 17px;
  height: 17px;
}

/* Cite copies the paper's BibTeX (hidden <pre> beside it); a button that
   looks like the links next to it. */
.paper__cite {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
}

.paper__cite.is-copied {
  color: var(--fg-2);
}
