:root {
  --page: #ffffff;
  --card: #f6f6f6;
  --ink: #161514;
  --muted: #71706f;
  --tertiary: #afafaf;
  --pad: 64px;
  --content-width: 1280px;
  --content-gutter: 40px;
  --navigation-icon-size: 12px;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  color: var(--ink);
  background: var(--page);
  font-synthesis: none;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html {
  background: var(--page);
  scroll-behavior: smooth;
  /* iOS enlarges some blocks of text in landscape (the FAQ footnote) unless told not to */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
body { margin: 0; min-width: 320px; background: var(--page); color: var(--ink); -webkit-font-smoothing: antialiased; }
/* sticky footer: main absorbs any spare viewport height so short pages (legal, about) don't leave a gap under the footer */
body { display: flex; flex-direction: column; min-height: 100vh; min-height: 100svh; }
body > main { flex: 1 0 auto; }
/* keeps content clear of the notch / Dynamic Island if the page is ever laid out under it
   (viewport-fit=cover); without it, as now, browsers inset the page themselves and these are 0.
   Landscape phones get their layouts by orientation, not by reaching min-width: 769px */
body { padding-inline: env(safe-area-inset-left) env(safe-area-inset-right); }
a { color: inherit; }
img { display: block; max-width: 100%; }
/* AVIF/WebP wrappers from the build: the img lays out as if picture weren't there */
picture { display: contents; }
/* otherwise the empty source takes the img's grid cell in centred card layouts */
picture source { display: none; }
button { font: inherit; }

.nav {
  position: sticky;
  top: 0;
  z-index: 1000;
  width: 100%;
  background: #ffffff;
  color: var(--ink);
  transition: background-color .3s ease, color .3s ease, box-shadow .3s ease;
}

.home-page .nav {
  position: fixed;
  /* fixed, so outside the body's safe-area padding: pin to the viewport edge and pad it here */
  left: 0;
  padding-inline: env(safe-area-inset-left) env(safe-area-inset-right);
  background: transparent;
}

.home-page .nav.is-scrolled,
.home-page .nav:has(.device-menu.open),
.home-page .nav:has(.nav-hamburger.active) {
  background: #ffffff;
}

.nav-inner {
  position: relative;
  display: flex;
  min-height: 72px;
  align-items: center;
  justify-content: space-between;
}

.content-frame {
  width: min(100%, var(--content-width));
  margin-inline: auto;
  padding-inline: var(--content-gutter);
}

.nav-logo {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
  color: inherit;
  font-size: 20px;
  text-decoration: none;
}

.nav-logo-icon {
  width: 15px;
  width: 1cap;
  height: 15px;
  height: 1cap;
  flex: 0 0 15px;
  flex-basis: 1cap;
  border-radius: 1px;
  background: var(--ink);
}

.nav-logo-text {
  color: inherit;
  font-size: inherit;
  font-weight: 600;
  white-space: nowrap;
}

.nav-links {
  position: absolute;
  left: 50%;
  display: flex;
  align-items: center;
  gap: 24px;
  transform: translateX(-50%);
}

.nav-devices-trigger,
.nav-placeholder {
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}

.nav-page-link { text-decoration: none; }
.nav-page-link:hover { opacity: .65; }

.nav-devices-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  transition: opacity .2s ease;
}

.nav-devices-trigger:hover { opacity: .65; }

.nav-chevron,
.device-menu-arrow {
  display: block;
  flex: 0 0 auto;
  background: currentColor;
  -webkit-mask-position: center;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-position: center;
  mask-repeat: no-repeat;
  mask-size: contain;
}

.nav-chevron {
  width: 12px;
  height: 12px;
  -webkit-mask-image: url("icons/chevron.svg?v=a94ea67ea9");
  mask-image: url("icons/chevron.svg?v=a94ea67ea9");
  transition: transform .25s ease;
}

.nav-devices-trigger.active .nav-chevron { transform: rotate(180deg); }

.device-menu {
  --device-menu-left: var(--pad);
  --device-menu-right: var(--pad);
  --device-menu-height: 0px;
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  background: #f6f6f6;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-4px);
  transition: height .25s ease-out, opacity .15s ease-out, transform .15s ease-out, visibility .15s;
}

.device-menu.open {
  height: var(--device-menu-height);
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
  /* visible straight away (it only lingers when closing), so ArrowDown can focus the first row */
  transition: height .25s ease-out, opacity .15s ease-out, transform .15s ease-out, visibility 0s;
}

.device-menu-list {
  width: 100%;
  padding: 40px var(--device-menu-right) 40px var(--device-menu-left);
}

.device-menu-groups {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 80px;
}

.device-menu-group { min-width: 0; }

.device-menu-group-label {
  margin: 0 0 16px;
  color: var(--muted);
  font-size: 14px;
  font-weight: 600;
  line-height: 24px;
  opacity: 0;
  transform: translateY(-4px);
}

.device-menu.open .device-menu-group-label {
  animation: device-menu-row-reveal .4s ease-out 40ms both;
}

.device-menu-group-rows { display: grid; }

.device-menu-row {
  display: grid;
  min-height: 48px;
  padding: 12px 0;
  /* the last track is wider than the arrow, so the description always wraps well short of it */
  grid-template-columns: 164px minmax(0, 1fr) 48px;
  align-items: start;
  gap: 4px;
  color: var(--ink);
  font-size: 14px;
  line-height: 24px;
  text-decoration: none;
  opacity: 0;
  transform: translateY(-4px);
}

.device-menu.open .device-menu-row {
  animation: device-menu-row-reveal .4s ease-out var(--device-row-delay) both;
}

@keyframes device-menu-row-reveal {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

.device-menu-name { font-size: 14px; font-weight: 600; }

.device-menu-meta {
  color: var(--muted);
  text-align: left;
}

.device-menu-arrow {
  width: var(--navigation-icon-size);
  height: var(--navigation-icon-size);
  margin-top: 6px;
  justify-self: end;
  -webkit-mask-image: url("icons/arrow-right.svg?v=8487f9bdde");
  mask-image: url("icons/arrow-right.svg?v=8487f9bdde");
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity .15s ease-out, transform .15s ease-out;
}

.device-menu-row:hover .device-menu-arrow,
.device-menu-row:focus-visible .device-menu-arrow {
  opacity: 1;
  transform: translateX(0);
}

.nav-signup {
  display: inline-flex;
  min-height: 38px;
  margin-left: auto;
  padding: 0 16px;
  border-radius: 999px;
  align-items: center;
  justify-content: center;
  background: var(--ink);
  color: #ffffff;
  border: 0;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.nav-signup:hover { opacity: .86; }
.nav-signup:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }

/* Loops newsletter form: a card over the dimmed page on desktop, full screen on phones; any click
   outside the form closes it. The padding follows the site gutter (32px on phones), and the auto
   margins centre the form while letting a taller one scroll from its top */
.subscribe-modal {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: grid;
  overflow-y: auto;
  padding: var(--content-gutter);
  background: var(--page);
  opacity: 0;
  visibility: hidden;
  /* lets taps through while it fades out, so the page underneath responds straight away */
  pointer-events: none;
  transition: opacity .25s ease, visibility 0s linear .25s;
}

.subscribe-modal.open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity .25s ease;
}

.subscribe-modal .newsletter-form-container {
  width: min(100%, 420px);
  margin: auto;
  transform: translateY(8px);
  transition: transform .25s ease;
}

.subscribe-modal.open .newsletter-form-container { transform: none; }

/* the mobile menu's close X, in the card's top-right corner, for people who don't know clicking
   outside the form closes it */
.subscribe-modal .newsletter-form-container { position: relative; }

.subscribe-close {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}

.subscribe-close span {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 2px;
  margin: -1px 0 0 -10px;
  border-radius: 2px;
  background: currentColor;
  transform: rotate(45deg);
}

.subscribe-close span + span { transform: rotate(-45deg); }

/* phones only: the nav bar copy at the top of the full-screen form */
.subscribe-header { display: none; }
.subscribe-modal:focus { outline: none; }
.subscribe-close:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.subscribe-title {
  margin: 0;
  font-size: 20px;
  font-weight: 550;
  line-height: 1.1;
  letter-spacing: -.02em;
}

.subscribe-description {
  margin: 16px 0 0;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.55;
}

.newsletter-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 46px;
}

.newsletter-form-input,
.newsletter-form-button,
.newsletter-loading-button {
  width: 100%;
  min-height: 48px;
  border-radius: 999px;
  font: inherit;
}

.newsletter-form-input {
  padding: 0 22px;
  border: 1px solid #e2e2e2;
  background: #ffffff;
  color: var(--ink);
  font-size: 14px;
  transition: border-color .2s ease;
}

.newsletter-form-input::placeholder { color: var(--tertiary); }
.newsletter-form-input:focus { outline: none; border-color: var(--ink); }

.newsletter-form-button,
.newsletter-loading-button {
  display: flex;
  padding: 0 22px;
  border: 0;
  align-items: center;
  justify-content: center;
  background: var(--ink);
  color: #ffffff;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity .2s ease;
}

.newsletter-form-button:hover { opacity: .86; }
.newsletter-form-button:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }
.newsletter-form-button:disabled { opacity: .2; cursor: default; }
/* takes the Subscribe button's place while the signup sends, as plain text */
.newsletter-loading-button { background: transparent; color: var(--ink); cursor: default; }

.newsletter-error { margin-top: 16px; }

.newsletter-error-message {
  margin: 0;
  color: #b91c1c;
  font-size: 14px;
  line-height: 1.55;
}

/* after a signup the thank-you (a blue thumbs-up over a line in the title's type) takes the form's
   place and spacing; Loops' script shows it with display: flex */
.newsletter-form-container.is-subscribed .newsletter-form { display: none; }

.newsletter-success {
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin-top: 46px;
}

.newsletter-success img { width: 32px; height: 32px; }

.newsletter-success-message {
  margin: 0;
  color: var(--ink);
  font-size: 20px;
  font-weight: 550;
  line-height: 1.1;
  letter-spacing: -.02em;
  text-align: center;
}

.subscribe-legal {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin: 24px 0 0;
  font-size: 14px;
  line-height: 1.4;
}

.subscribe-legal a {
  color: var(--ink);
  text-decoration: none;
  transition: opacity .2s ease;
}

.subscribe-legal a:hover { opacity: .7; }
.subscribe-legal a:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* desktop: a white card over the dimmed page, scrolling within the window if it's taller */
@media (min-width: 769px) {
  /* the dim fades in while the card slides up from below the window, and both reverse on close.
     Scrolling waits until the card has landed (app.js adds .is-settled), since the off-screen card
     would otherwise flash a scrollbar while it moves */
  .subscribe-modal {
    opacity: 1;
    overflow-y: hidden;
    background: rgba(22, 21, 20, 0);
    transition: background-color .4s ease, visibility 0s linear .4s;
  }
  .subscribe-modal.open {
    background: rgba(22, 21, 20, .24);
    transition: background-color .4s ease;
  }
  .subscribe-modal.is-settled { overflow-y: auto; }
  .subscribe-modal .newsletter-form-container {
    width: min(100%, 552px);
    padding: 64px;
    border-radius: 14px;
    background: var(--page);
    box-shadow: 0 32px 80px rgba(22, 21, 20, .18), 0 2px 8px rgba(22, 21, 20, .08);
    transform: translateY(100vh);
    transition: transform .4s cubic-bezier(.32, 0, .67, 0);
  }
  .subscribe-modal.open .newsletter-form-container {
    transform: none;
    transition: transform .6s cubic-bezier(.32, .72, 0, 1);
  }
}

.subscribe-points {
  display: flex;
  flex-direction: column;
  gap: 24px;
  margin: 46px 0 0;
  padding: 0;
  list-style: none;
}

.subscribe-points li {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

.subscribe-point-icon {
  width: 32px;
  height: 32px;
  background: var(--ink);
  -webkit-mask: var(--subscribe-icon) center / contain no-repeat;
  mask: var(--subscribe-icon) center / contain no-repeat;
}

.subscribe-points h3 {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.45;
}

.subscribe-points p {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.45;
}

.subscribe-disclaimer {
  margin: 24px 0 0;
  color: var(--tertiary);
  font-size: 12px;
  line-height: 1.5;
  text-align: center;
}

@media (max-width: 768px) {
  /* a copy of the nav bar (logo and the menu's X) stays pinned while the form scrolls under it, so
     the card's own X is hidden and the form starts below the bar */
  .subscribe-modal { padding-top: calc(64px + var(--content-gutter)); }
  .subscribe-header {
    position: fixed;
    top: 0;
    right: 0;
    left: 0;
    z-index: 1;
    display: block;
    background: var(--page);
  }
  .subscribe-header .subscribe-close { position: relative; top: auto; right: auto; }
  .newsletter-form-container > .subscribe-close { display: none; }
  /* 16px stops iOS zooming the page in when the field is focused */
  .newsletter-form-input { font-size: 16px; }
  /* the form only fades in on phones */
  .subscribe-modal .newsletter-form-container,
  .subscribe-modal.open .newsletter-form-container { transform: none; transition: none; }
}

@media (prefers-reduced-motion: reduce) {
  .subscribe-modal,
  .subscribe-modal .newsletter-form-container { transition: none; }
}

.nav-devices-trigger:focus-visible,
.device-menu-row:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

.nav-hamburger,
.nav-mobile-menu { display: none; }

.nav-hamburger {
  position: relative;
  z-index: 1001;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
  padding: 8px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}

.nav-hamburger span {
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform .25s ease, opacity .2s ease;
}

.nav-hamburger.active span:nth-child(1) { transform: rotate(45deg) translate(5px, 5px); }
.nav-hamburger.active span:nth-child(2) { opacity: 0; }
.nav-hamburger.active span:nth-child(3) { transform: rotate(-45deg) translate(5px, -5px); }

.site-shell {
  width: 100%;
  min-height: calc(100vh - 72px);
  min-height: calc(100svh - 72px);
  padding: 14px;
}

/* The scroll reveal: the hero pins while its card grows from a 48px square to full bleed, fading
   the render in as it opens. The stage is 100svh, the screen with a mobile toolbar showing, which
   holds still while the toolbar collapses: the text it anchors is always on screen, and nothing in
   the hero is laid out again mid-scroll (dvh would resize it, and the toolbar's animation resizes
   the viewport every frame). The card only ever moves by transform and opacity. Where the browser
   runs scroll-driven animations they drive it from keyframes app.js writes, so it keeps up with the
   scroll without waiting on the main thread; elsewhere app.js updates it each frame. */
.collection-hero-frame {
  width: 100%;
  height: 240vh;
  height: 240svh;
  background: #ffffff;
}

.collection-hero {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: #ffffff;
  color: var(--ink);
  --hero-reveal-progress: 0;
}

/* the card scales and the surface inside it scales back by the inverse, so the render keeps its
   size while the card's edges move; app.js sets both scales, these defaults (48px on a typical
   screen) only cover the first paint */
.collection-hero-reveal,
.collection-hero-surface {
  position: absolute;
  inset: 0;
  will-change: transform;
}

.collection-hero-reveal {
  --hero-reveal-scale-x: .0375;
  --hero-reveal-scale-y: .06;
  overflow: hidden;
  background: var(--card);
  transform: scale(var(--hero-reveal-scale-x), var(--hero-reveal-scale-y));
}

.collection-hero-reveal::after {
  position: absolute;
  inset: 0;
  z-index: 3;
  background: var(--card);
  content: "";
  opacity: clamp(0, calc(1 - (var(--hero-reveal-progress) * 4)), 1);
  pointer-events: none;
}

.collection-hero-surface {
  background: var(--card);
  transform: scale(calc(1 / var(--hero-reveal-scale-x)), calc(1 / var(--hero-reveal-scale-y)));
}

@media (max-width: 768px) {
  .collection-hero-reveal {
    --hero-reveal-scale-x: .128;
    --hero-reveal-scale-y: .06;
  }
}

/* scroll-driven: app.js adds hero-timeline once it has written the card's keyframes and the scroll
   offsets each part runs between */
.hero-timeline .collection-hero-reveal,
.hero-timeline .collection-hero-surface,
.hero-timeline .collection-hero-reveal::after,
.hero-timeline .collection-hero-image,
.hero-timeline .collection-hero-difference::after {
  animation-duration: auto;
  animation-timing-function: linear;
  animation-fill-mode: both;
  animation-timeline: scroll(root block);
  animation-range: var(--hero-reveal-start) var(--hero-reveal-end);
}

.hero-timeline .collection-hero-reveal { animation-name: hero-reveal-card; }
.hero-timeline .collection-hero-surface { animation-name: hero-reveal-surface; }

.hero-timeline .collection-hero-reveal::after {
  animation-name: hero-reveal-veil;
  animation-range: var(--hero-reveal-start) var(--hero-veil-end);
}

.hero-timeline .collection-hero-image {
  animation-name: hero-reveal-image;
  animation-range: var(--hero-image-start) var(--hero-image-end);
}

/* the word's light copy is clipped to the card's edges, so it shows nothing until they cross it */
.hero-timeline .collection-hero-difference::after {
  animation-name: hero-reveal-word;
  opacity: 1;
}

@keyframes hero-reveal-veil {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes hero-reveal-image {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* the open card, held once the reveal has finished so scrolling back up doesn't play it in reverse.
   Collapsed, the open hero also takes just one screen: a return to the home page in the same visit
   starts here (see the head script in build.js), and app.js switches to it once the card is open */
.hero-open .collection-hero-reveal,
.hero-open .collection-hero-surface {
  animation: none;
  transform: none;
  will-change: auto;
}

.hero-open .collection-hero-reveal::after { display: none; }

.hero-open .collection-hero-image {
  animation: none;
  opacity: 1;
}

.hero-open .collection-hero-difference::after {
  animation: none;
  clip-path: none;
  opacity: 1;
}

.hero-revealed .collection-hero-frame {
  height: 100vh;
  height: 100svh;
}

/* one screen tall in a one-screen frame, so there's nothing to pin; left sticky, Safari would take
   the open card's grey for a landscape phone's safe areas */
.hero-revealed .collection-hero { position: relative; }

.collection-hero-image {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(58vw, 760px);
  height: min(72vh, 52vw, 760px);
  height: min(72svh, 52vw, 760px);
  object-fit: contain;
  opacity: clamp(0, calc((var(--hero-reveal-progress) - .08) * 2.5), 1);
  transform: translate(-50%, -50%);
}

.collection-hero-content {
  position: absolute;
  bottom: var(--pad);
  left: var(--pad);
  z-index: 2;
  width: min(52vw, 760px);
}

.collection-hero-content .collection-hero-eyebrow {
  display: inline-flex;
  margin: 0 0 16px;
  align-items: center;
  gap: 8px;
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
}

.collection-hero-badge {
  padding: 1px 3px 1px 5px;
  border: 1.5px solid #292929;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 1px;
}

.collection-hero-eyebrow:link,
.collection-hero-eyebrow:visited {
  text-decoration: none;
}

.collection-hero-eyebrow:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }

.collection-hero-content h1 {
  margin: 0;
  font-size: clamp(40px, min(4vw, 6.5vh), 48px);
  font-weight: 550;
  line-height: 1.1;
  letter-spacing: -.055em;
}


/* Short desktop viewports (13"/14" laptops, non-maximised windows) */
@media (min-width: 769px) and (max-height: 900px) {
  .collection-hero-image { height: min(60vh, 640px); height: min(60svh, 640px); }
  .collection-hero-content { width: min(44vw, 640px); }
}

/* Tablet widths: the 40px headline is too wide to sit beside the phone, so keep the phone in the
   space between the nav (~88px) and the text block (~260px tall, 64px off the bottom, 24px gap).
   Below 700px tall (landscape phones) that space is too small, but the phone is then short and
   narrow enough to sit beside the text, so those keep the centred phone. */
@media (min-width: 769px) and (max-width: 1023px) and (min-height: 700px) {
  .collection-hero-image {
    top: calc(88px + (100vh - 436px) / 2);
    top: calc(88px + (100svh - 436px) / 2);
    height: min(72vh, 52vw, 760px, 100vh - 436px);
    height: min(72svh, 52vw, 760px, 100svh - 436px);
  }
}

/* Short landscape screens (landscape phones, short windows): the phone sits in the space right of
   the text (left edge var(--pad), as wide as its paragraph) and below the 72px nav; the card still
   grows from the centre and uncovers it. Keyed on orientation rather than width: Chrome on iOS
   gives a landscape phone a narrower viewport than Safari (its toolbar sits at the side), which
   would otherwise get the portrait phone layout. */
@media (orientation: landscape) and (max-height: 680px) {
  .collection-hero-image {
    top: calc(50% + 36px);
    left: calc((var(--pad) + min(44vw, 420px) + 100%) / 2);
    width: min(58vw, 760px);
    height: min(100vh - 120px, 640px);
    height: min(100svh - 120px, 640px);
  }
  .collection-hero-content {
    bottom: 40px;
    width: min(44vw, 420px);
  }
}


@media (min-width: 769px) {
  .collection-hero-heading-line {
    display: block;
    white-space: nowrap;
  }
}

.collection-hero-difference {
  position: relative;
  display: inline-block;
  padding-right: .04em;
  margin-right: -.04em;
  color: #c9c9c9;
}

.collection-hero-difference::after {
  position: absolute;
  inset: 0;
  color: #e0e1e2;
  content: attr(data-text);
  clip-path: inset(
    var(--difference-clip-top, 50%)
    var(--difference-clip-right, 50%)
    var(--difference-clip-bottom, 50%)
    var(--difference-clip-left, 50%)
  );
  mix-blend-mode: difference;
  opacity: 0;
  pointer-events: none;
}

.collection-hero-difference.has-reveal-overlap::after {
  opacity: 1;
}

.collection-hero-content p {
  max-width: 420px;
  margin: 16px 0 0;
  color: var(--muted);
  font-size: 16px;
  line-height: 1.55;
}

.collection-hero-cta {
  display: inline-flex;
  min-height: 48px;
  margin-top: 32px;
  padding: 0 22px;
  border-radius: 999px;
  align-items: center;
  justify-content: center;
  background: var(--ink);
  color: #ffffff;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition: opacity .2s ease;
}

.collection-hero-cta:hover { opacity: .86; }
.collection-hero-cta:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }

/* Short desktop viewports tighten the headline-to-paragraph gap; this sits after the base
   paragraph rule so it isn't overridden by it */
@media (min-width: 769px) and (max-height: 900px) {
  .collection-hero-content p { margin-top: 12px; }
}

/* Landscape phones: the hero text has under 240px between the nav and the bottom of the screen
   (after the base and short-window type rules it overrides) */
@media (orientation: landscape) and (max-height: 500px) {
  .collection-hero-image {
    left: calc((var(--content-gutter) + min(50vw, 420px) + 100%) / 2);
    height: calc(100svh - 104px);
  }
  .collection-hero-content {
    bottom: 20px;
    width: min(50vw, 420px);
  }
  .collection-hero-content .collection-hero-eyebrow { margin-bottom: 8px; }
  .collection-hero-content h1 { font-size: 28px; }
  .collection-hero-content p {
    margin-top: 8px;
    font-size: 14px;
    line-height: 1.45;
  }
  .collection-hero-cta { margin-top: 14px; }
}


.collection-grid {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.collection-card {
  display: block;
  width: 100%;
  margin: 0;
  min-width: 0;
  overflow: hidden;
  border-radius: 8px;
  background: var(--card);
  text-decoration: none;
}

.collection-card:focus-visible { outline: 2px solid #171717; outline-offset: 3px; }

.collection-art {
  aspect-ratio: 4 / 5;
  display: grid;
  min-height: 0;
  overflow: hidden;
  padding: 0;
  place-items: center;
}

.collection-feature-card {
  position: relative;
  display: flex;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  padding: clamp(20px, 2.2vw, 32px);
  background: #144d8d;
  color: #ffffff;
}

.grainient-container {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
}

.grainient-container canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Legal pages */
.legal-main { padding-bottom: 160px; }
.legal-hero-wrap { padding-top: 16px; padding-bottom: 16px; }
.legal-hero.collection-feature-card {
  height: min(28vw, 350px);
  min-height: 300px;
  aspect-ratio: auto;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
}
.legal-hero h1 {
  position: relative;
  z-index: 1;
  margin: 0;
  color: #ffffff;
  font-size: 34px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -.05em;
  text-align: center;
}
.legal-hero-logo {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 2;
  display: grid;
  width: 30px;
  height: 30px;
  place-items: center;
  overflow: hidden;
  border-radius: 2px;
}
.legal-hero-logo span {
  display: block;
  width: 30px;
  height: 30px;
  border-radius: inherit;
  background: #ffffff;
}
.legal-hero-logo:focus-visible { outline: 2px solid #ffffff; outline-offset: 2px; }
.legal-content {
  max-width: 780px;
  margin-top: 120px;
  margin-right: auto;
  margin-left: auto;
}
.legal-updated {
  margin: 0 0 72px;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.7;
}
.legal-license-note {
  display: grid;
  margin: 0 0 72px;
  padding: 24px;
  grid-template-columns: 18px minmax(0, 1fr);
  align-items: start;
  column-gap: 6px;
  border-radius: 8px;
  background: #f6f6f6;
}
.legal-license-note-icon {
  width: 18px;
  height: 18px;
}
.legal-license-note .license-note {
  margin: 0;
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.35;
}
.legal-license-note div > p:last-child {
  margin: 7px 0 0;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.5;
}
/* the section number sits in the same fixed column as the list numbers, so titles,
   paragraphs and list copy all start on one line */
.legal-content { --legal-title-offset: 19px; }
/* two-digit section numbers ("10.") need a wider column */
.legal-content.has-two-digit-sections { --legal-title-offset: 27px; }
.legal-section + .legal-section { margin-top: 36px; }
.legal-section h2 {
  display: grid;
  grid-template-columns: var(--legal-title-offset) minmax(0, 1fr);
  margin: 0 0 7px;
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0;
}
.legal-section-body {
  color: var(--muted);
  font-size: 14px;
  line-height: 1.75;
}
.legal-section-body p { margin: 0; }
.legal-section-body > p { padding-left: var(--legal-title-offset); }
.legal-section-body p + p,
.legal-section-body p + ul,
.legal-section-body ul + p { margin-top: 18px; }
.legal-section-body ul {
  display: flex;
  margin: 0;
  padding: 0;
  flex-direction: column;
  list-style: none;
}
.legal-section-body li {
  display: flex;
  align-items: baseline;
  color: var(--muted);
}
.legal-section-body li + li { margin-top: 10px; }
.legal-section-body .sup-number {
  min-width: calc(var(--legal-title-offset) - 8px);
  margin-right: 8px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 400;
  line-height: 1;
}
.legal-section-body .legal-list-copy { min-width: 0; }
.legal-section-body strong { color: var(--ink); font-weight: 400; }
.legal-section-body a { color: var(--ink); text-underline-offset: 3px; }
.legal-section-body a:hover { text-decoration-thickness: 2px; }

/* About page */
.about-main { padding-bottom: 160px; }
.about-content {
  margin-top: 120px;
  margin-right: auto;
  margin-left: auto;
}
.about-copy {
  max-width: 780px;
  margin-right: auto;
  margin-left: auto;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.75;
}
.about-title {
  margin: 0 0 24px;
  font-size: inherit;
  font-weight: 600;
  line-height: inherit;
}
.about-copy p { margin: 0; }
.about-copy p + p { margin-top: 24px; }
/* the painting has a white ground, so it sits on the page in the text column, at 500px beside phones */
.about-process {
  max-width: 780px;
  margin: 64px auto;
}
.about-process img {
  display: block;
  width: 100%;
  max-width: 500px;
  height: auto;
  margin-inline: auto;
}
.about-process figcaption {
  margin-top: 10px;
  text-align: right;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}
.about-signoff {
  max-width: 780px;
  margin: 64px auto 0;
  color: var(--ink);
  font-size: 14px;
  line-height: 1.75;
}
/* the nav logo's square (1cap of its 20px wordmark) as a tumbling cube; it comes to rest
   on the front face between loops, since the six turns add up to a full rotation */
.about-signoff-cube {
  --cube: 15px;
  position: relative;
  font-size: 20px;
  width: var(--cube);
  height: var(--cube);
  transform-style: preserve-3d;
  animation: about-signoff-cube 3.7s cubic-bezier(.25, .46, .45, .94) infinite;
}
@supports (width: 1cap) {
  .about-signoff-cube { --cube: 1cap; }
}
.about-signoff-cube span {
  position: absolute;
  inset: 0;
  border-radius: 1px;
}
.about-signoff-cube span:nth-child(1) { transform: translateZ(calc(var(--cube) / 2)); background: #161514; }
.about-signoff-cube span:nth-child(2) { transform: rotateY(90deg) translateZ(calc(var(--cube) / 2)); background: #868585; }
.about-signoff-cube span:nth-child(3) { transform: rotateY(180deg) translateZ(calc(var(--cube) / 2)); background: #3b3a39; }
.about-signoff-cube span:nth-child(4) { transform: rotateY(-90deg) translateZ(calc(var(--cube) / 2)); background: #ababab; }
.about-signoff-cube span:nth-child(5) { transform: rotateX(-90deg) translateZ(calc(var(--cube) / 2)) rotate(180deg); background: #61605f; }
.about-signoff-cube span:nth-child(6) { transform: rotateX(90deg) translateZ(calc(var(--cube) / 2)); background: #d0d0d0; }
@keyframes about-signoff-cube {
  0% { transform: perspective(calc(var(--cube) * 10)) rotateZ(0deg) rotateY(0deg) rotateX(0deg); }
  13.514% { transform: perspective(calc(var(--cube) * 10)) rotateZ(90deg) rotateY(0deg) rotateX(0deg); }
  27.027% { transform: perspective(calc(var(--cube) * 10)) rotateZ(90deg) rotateY(0deg) rotateX(-90deg); }
  40.541% { transform: perspective(calc(var(--cube) * 10)) rotateZ(90deg) rotateY(90deg) rotateX(-90deg); }
  54.054% { transform: perspective(calc(var(--cube) * 10)) rotateZ(180deg) rotateY(90deg) rotateX(-90deg); }
  86.486% { transform: perspective(calc(var(--cube) * 10)) rotateZ(180deg) rotateY(-180deg) rotateX(-90deg); }
  100% { transform: perspective(calc(var(--cube) * 10)) rotateZ(180deg) rotateY(-180deg) rotateX(-180deg); }
}

/* a share of the card rather than a fixed padding, so the render scales with the card,
   up to its size on a 24" iMac (2240px wide); wider screens only add space around it */
.collection-art img {
  width: 66%;
  height: 66%;
  max-width: 480px;
  max-height: 600px;
  min-width: 0;
  min-height: 0;
  object-fit: contain;
}

.collection-context {
  padding: 20px;
  background: var(--card);
}

.collection-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.collection-heading h2 {
  margin: 0;
  font-size: 14px;
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: -.015em;
}

.collection-heading span,
.collection-context p {
  color: var(--muted);
  font-size: 14px;
  line-height: 1.45;
}

.collection-context p { margin: 5px 0 0; }

.collection-heading .collection-file-count {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  min-width: 40px;
  padding: 4px 8px;
  border-radius: 999px;
  background: #eaeaea;
  color: var(--muted);
  font-size: 12px;
  font-weight: 400;
  line-height: 16px;
  letter-spacing: .048px;
  white-space: nowrap;
}

.detail-shell {
  width: min(100%, var(--content-width));
  margin-inline: auto;
  padding-block: var(--pad);
  padding-inline: var(--content-gutter);
}

.detail-layout {
  display: flex;
  gap: clamp(40px, 5vw, 72px);
  align-items: start;
}

.detail-gallery {
  display: grid;
  flex: 1 1 0;
  width: 0;
  max-width: 750px;
  min-width: 0;
  gap: 14px;
}

.detail-image-wrap {
  width: 100%;
  max-width: 750px;
  aspect-ratio: 3 / 4;
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  place-items: center;
  overflow: hidden;
  padding: 120px;
  border-radius: 8px;
  background: var(--card);
}

/* colour changes stack the incoming render over the outgoing one; <picture> is display: contents,
   so the stacking and fade sit on the img. The renders are transparent, so fading both at once would
   let the card show through mid-way: the outgoing one holds until the incoming one has fully covered
   it, then fades out underneath (which only touches the soft shadow edges) */
.detail-image-wrap img,
.detail-mobile-hero img,
.mobile-thumbnail img {
  z-index: 1;
  grid-area: 1 / 1;
  transition: opacity .45s ease;
}
:is(.detail-image-wrap, .detail-mobile-hero, .mobile-thumbnail) > picture.is-entering img { opacity: 0; }
/* z-index keeps it underneath: once its opacity drops below 1 it would otherwise be painted above
   the now fully opaque incoming render */
:is(.detail-image-wrap, .detail-mobile-hero, .mobile-thumbnail) > picture.is-leaving img {
  z-index: 0;
  opacity: 0;
  transition: opacity .3s ease .45s;
}

.detail-image-wrap img {
  min-width: 0;
  min-height: 0;
  width: 100%;
  height: 100%;
  max-width: 620px;
  max-height: 820px;
  object-fit: contain;
}

.detail-mobile-stage { display: none; }

.detail-context {
  position: sticky;
  top: calc(72px + var(--pad));
  display: flex;
  min-height: calc(100vh - 72px - (var(--pad) * 2));
  min-height: calc(100svh - 72px - (var(--pad) * 2));
  flex: 0 0 480px;
  flex-direction: column;
  width: 480px;
  max-width: 100%;
  padding-top: 4px;
}

.detail-context h1 {
  max-width: 560px;
  margin: 0;
  font-size: 34px;
  line-height: 1.08;
  letter-spacing: -.045em;
  font-weight: 600;
}

.product-meta {
  display: flex;
  align-items: baseline;
  margin: 18px 0 0;
  font-size: 14px;
  color: var(--muted);
}

.color-picker {
  margin-top: 34px;
}

.color-picker > p {
  margin: 0;
  font-size: 14px;
  color: var(--muted);
}

.color-picker > p strong { color: var(--ink); }

.color-options {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.color-swatch {
  appearance: none;
  display: grid;
  width: 32px;
  height: 32px;
  padding: 4px;
  border: 3px solid transparent;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  place-items: center;
}

.color-swatch > span {
  display: block;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--swatch);
}

.color-swatch.is-selected {
  border-color: var(--swatch);
}

.color-swatch:focus-visible {
  outline: 2px solid #171717;
  outline-offset: 3px;
}

.color-swatch:disabled {
  opacity: .35;
  cursor: not-allowed;
}

.detail-description {
  margin: 44px 0 0;
  max-width: 39rem;
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink);
  letter-spacing: -.01em;
}

.buy-button {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  min-height: 48px;
  margin-top: 24px;
  padding: 0 22px;
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: #ffffff;
  font-weight: 600;
  font-size: 14px;
  text-decoration: none;
  cursor: pointer;
}

.buy-button span:last-child { color: #ffffff; font-weight: 600; }
.buy-button:hover { opacity: .86; }

.license-note {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 10pt 0 0;
  color: var(--muted);
  font-size: 14px;
  font-weight: 400;
}

.license-note img {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-top: 44px;
  border-radius: 8px;
}

.feature-item {
  min-width: 0;
  padding: 24px;
  border-radius: inherit;
  background: #f6f6f6;
  text-align: left;
}

.feature-item .feature-icon {
  display: block;
  width: 18px;
  height: 18px;
  background: var(--ink);
  -webkit-mask: var(--feature-icon) center / contain no-repeat;
  mask: var(--feature-icon) center / contain no-repeat;
}

.feature-item h2 {
  margin: 15px 0 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.35;
}

.feature-item p {
  margin: 7px 0 0;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.5;
}

/* FAQ */
.faq-section {
  padding-block: 200px;
}

.faq-header { margin: 0 auto 32px; text-align: left; }
.faq-header h2 {
  margin: 0;
  font-size: 34px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.03em;
}
.faq-list { display: flex; flex-direction: column; width: 100%; }
@media (min-width: 810px) {
  .faq-section {
    display: grid;
    grid-template-columns: 1fr 2fr;
    column-gap: 50px;
    row-gap: 48px;
    align-items: start;
  }
  .faq-header { grid-column: 1; margin: 0; }
  .faq-list { grid-column: 2; margin: 0; }
}
.faq-item {
  overflow: hidden;
}
.faq-item h3 { margin: 0; }
.faq-question {
  display: flex;
  width: 100%;
  padding: 32px 0;
  border: 0;
  align-items: flex-start;
  justify-content: space-between;
  background: transparent;
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  text-align: left;
  cursor: pointer;
  touch-action: manipulation;
}
.faq-item:first-child .faq-question { padding-top: 0; }
.faq-question:focus-visible { outline: 2px solid var(--ink); outline-offset: 5px; }
.faq-icon {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--navigation-icon-size);
  height: var(--navigation-icon-size);
  margin-left: 20px;
  margin-top: calc((1.4em - var(--navigation-icon-size)) / 2);
}
.faq-icon span {
  position: absolute;
  width: 100%;
  height: 1.5px;
  background: currentColor;
  transition: transform .4s cubic-bezier(.32, .72, 0, 1);
}
.faq-icon span:last-child { transform: rotate(90deg); }
.faq-item.open .faq-icon span { transform: rotate(180deg); }
/* Only the grid row animates. The answer's bottom spacing is clipped content rather
   than transitioned padding, so each frame of the expand is one layout change. */
.faq-answer {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .5s cubic-bezier(.32, .72, 0, 1);
}
.faq-answer-inner {
  min-height: 0;
  margin: 0;
  overflow: hidden;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.6;
  opacity: 0;
  transition: opacity .35s ease;
}
.faq-list .faq-answer-inner::after { display: block; height: 32px; content: ''; }
.faq-item.open .faq-answer { grid-template-rows: 1fr; }
.faq-item.open .faq-answer-inner { opacity: 1; }
.faq-help { margin: 0; padding-top: 32px; color: var(--muted); font-size: 14px; line-height: 1.6; }
.faq-help a { color: var(--ink); text-underline-offset: 3px; }
.faq-help a:hover { text-decoration-thickness: 2px; }

/* Footer */
.site-footer { background: #000; color: #fff; }
.site-footer-inner { padding-top: 64px; padding-bottom: 64px; }
.footer-bottom { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); align-items: stretch; gap: 100px; }
.footer-brand { display: flex; flex-direction: column; justify-content: space-between; align-items: flex-start; gap: 32px; }
.footer-disclosure-text { display: flex; flex: 1; max-width: 760px; flex-direction: column; align-items: flex-start; gap: 24px; color: var(--tertiary); font-size: 14px; line-height: 24px; }
.footer-copyright { margin: 0; color: var(--tertiary); font-size: 12px; line-height: 1.6; }
.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 40px;
}
.footer-legal a,
.footer-collections a,
.footer-logo { color: inherit; text-decoration: none; }
.footer-legal a,
.footer-legal button { color: #fff; font-size: inherit; font-weight: 400; }
.footer-legal button { padding: 0; border: 0; background: none; font-family: inherit; line-height: inherit; cursor: pointer; }
.footer-legal a:hover,
.footer-legal button:hover,
.footer-collections a:hover,
.footer-logo:hover { opacity: .68; }
.footer-statement {
  width: 100%;
  margin: 0;
  color: inherit;
  font-size: inherit;
  line-height: inherit;
}
.footer-logo {
  display: inline-flex;
  width: max-content;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
  font-size: 20px;
  font-weight: 600;
}
.footer-logo-mark {
  width: 15px;
  width: 1cap;
  height: 15px;
  height: 1cap;
  flex: 0 0 15px;
  flex-basis: 1cap;
  border-radius: 1px;
  background: #fff;
}
.footer-collections { display: flex; flex-wrap: wrap; gap: 12px 40px; }
.footer-collections a { color: #fff; font-size: inherit; line-height: inherit; }

/* Landscape tablets keep the desktop split: the context panel stays fixed
   while only the gallery column contracts. */
@media (min-width: 1024px) and (max-width: 1279px) and (min-height: 600px) and (orientation: landscape) {
  .detail-shell { padding-block: 32px; }
  .detail-layout {
    gap: 32px;
  }
  .detail-image-wrap { padding: 72px; }
}

/* Portrait tablets and smaller screens stack before the two panes can meet. */
@media (max-width: 1023px),
(min-width: 1024px) and (max-width: 1279px) and (orientation: portrait),
(min-width: 1024px) and (max-width: 1279px) and (max-height: 599px) {
  .site-shell { padding: 24px; }
  .detail-shell { padding-top: 0; overflow-x: clip; }
  .detail-layout {
    --detail-nav-height: 72px;
    --stage-card-peek: 180px;
    --stage-card-radius: 28px;
    flex-direction: column;
    gap: 0;
  }
  /* As on the homepage, the nav floats transparent over the hero until scrolled. */
  .detail-page .nav {
    position: fixed;
    left: 0;
    padding-inline: env(safe-area-inset-left) env(safe-area-inset-right);
    background: transparent;
  }
  .detail-page .nav.is-scrolled,
  .detail-page .nav:has(.device-menu.open),
  .detail-page .nav:has(.nav-hamburger.active) {
    background: #ffffff;
  }
  /* The hero and thumbnails stay pinned behind the nav while the info card
     scrolls up over them, leaving the card's top peeking out on load. */
  .detail-mobile-stage {
    position: sticky;
    top: 0;
    z-index: 0;
    display: flex;
    flex-direction: column;
    width: calc(100% + (var(--content-gutter) * 2));
    height: calc(100vh - var(--stage-card-peek));
    height: min(calc(100svh - var(--stage-card-peek)), calc(150vw + var(--detail-nav-height)));
    min-height: 424px;
    margin: 0 calc(-1 * var(--content-gutter));
    padding-top: var(--detail-nav-height);
    padding-bottom: calc(var(--stage-card-radius) + 20px);
    overflow: clip;
    background: var(--card);
  }
  .detail-mobile-hero {
    display: grid;
    flex: 1 1 0;
    min-height: 0;
    width: 100%;
    margin: 0;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    place-items: center;
    overflow: hidden;
    padding: 36px;
    touch-action: pan-y;
    will-change: transform;
  }
  .detail-mobile-hero img {
    min-width: 0;
    min-height: 0;
    width: 100%;
    /* the hero padding is the margin on phones; the cap only bites past ~430px wide */
    max-width: max(75%, 360px);
    height: 100%;
    object-fit: contain;
  }
  .mobile-thumbnails-container {
    flex: 0 0 auto;
    width: 100%;
    overflow-x: auto;
    padding: 0 0 4px;
    text-align: left;
    scroll-behavior: smooth;
    scrollbar-width: none;
  }
  .mobile-thumbnails-container::-webkit-scrollbar { display: none; }
  .mobile-thumbnails-track {
    display: inline-flex;
    gap: 14px;
    padding: 2px var(--content-gutter);
  }
  .mobile-thumbnail {
    appearance: none;
    /* one cell, so a colour change can stack the incoming render over the outgoing one */
    display: grid;
    grid-template: minmax(0, 1fr) / minmax(0, 1fr);
    width: 56px;
    height: 70px;
    flex: 0 0 auto;
    overflow: hidden;
    padding: 10px;
    border: 0;
    border-radius: 8px;
    background: var(--page);
    opacity: .4;
    cursor: pointer;
    transition: opacity .2s ease, transform .2s ease;
  }
  .mobile-thumbnail.is-active {
    opacity: 1;
    transform: translateY(-2px);
  }
  .mobile-thumbnail:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
  }
  .mobile-thumbnail img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
  .detail-gallery { display: none; }
  .detail-context {
    position: relative;
    top: auto;
    z-index: 1;
    order: 1;
    min-height: 0;
    flex-basis: auto;
    width: calc(100% + (var(--content-gutter) * 2));
    max-width: none;
    margin: calc(-1 * var(--stage-card-radius)) calc(-1 * var(--content-gutter)) 0;
    padding: 40px var(--content-gutter) 0;
    border-radius: var(--stage-card-radius) var(--stage-card-radius) 0 0;
    background: var(--page);
  }
  .collection-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Short landscape screens (landscape phones): stacked, the stage leaves a ~90px render and pushes
   the info card below the screen, so split like desktop instead. The stage stays pinned on the
   left at full height and the info column scrolls on the right; no card overlap or peek. */
@media (orientation: landscape) and (max-width: 1279px) and (max-height: 599px) {
  /* Safari fills a landscape phone's safe areas with the colour of sticky and fixed elements at
     the screen's edges (whatever they paint, children included), so the pinned stage's grey
     tinted only its side. The grey is painted instead by the layout behind the stage, over the
     same column: the stage stays clear, the sides stay white, and it looks the same */
  .detail-layout {
    position: relative;
    isolation: isolate;
    flex-direction: row;
  }
  .detail-layout::before {
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(-1 * var(--content-gutter));
    z-index: -1;
    width: calc(50% + var(--content-gutter));
    background: var(--card);
    content: "";
  }
  .detail-mobile-stage {
    flex: 0 0 calc(50% + var(--content-gutter));
    width: auto;
    /* the thumbnail strip is wider than the column; let it scroll instead of widening the stage */
    min-width: 0;
    /* as tall as what's on screen (dvh), so the render and thumbnails fill it whether or not the
       toolbar shows */
    background: none;
    height: 100vh;
    height: 100dvh;
    min-height: 0;
    margin: 0 0 0 calc(-1 * var(--content-gutter));
    padding-bottom: 16px;
  }
  .detail-mobile-hero { padding: 20px; }
  /* replace the 60% tablet cap (min-width: 769px, later in this file): this stage is short, not
     tall. Tall renders are bound by height; 85% keeps wide ones (MacBook) off the column edges */
  .detail-mobile-stage .detail-mobile-hero img { max-width: 85%; max-height: 100%; }
  .mobile-thumbnails-track { gap: 10px; }
  .mobile-thumbnail { width: 44px; height: 56px; padding: 8px; }
  .detail-context {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    margin: 0;
    padding: calc(var(--detail-nav-height) + 24px) 0 0 32px;
    border-radius: 0;
  }
}

/* portrait phones; a phone on its side keeps the short landscape hero */
@media (max-width: 768px) and (orientation: portrait), (max-width: 768px) and (min-height: 681px) {
  /* the render fills the space between the 64px nav and the text, 24px clear of each, up to 48% of
     the screen: app.js measures where the text starts (it wraps differently on each phone), and
     until then this assumes a ~330px text block */
  .collection-hero-image {
    top: calc((64px + var(--hero-text-top, 100vh - 330px)) / 2);
    top: calc((64px + var(--hero-text-top, 100svh - 330px)) / 2);
    width: 88vw;
    height: min(48vh, var(--hero-text-top, 100vh - 330px) - 112px);
    height: min(48svh, var(--hero-text-top, 100svh - 330px) - 112px);
  }
  .collection-hero-content {
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    padding: 32px;
  }
  .collection-hero-content h1 { font-size: 34px; }
  .collection-hero-content .collection-hero-eyebrow { margin-bottom: 12px; }
  .collection-hero-content p { margin-top: 12px; font-size: 15px; }
  .collection-hero-cta { margin-top: 24px; }
}

@media (max-width: 768px) {
  :root { --content-gutter: 32px; }
  .collection-grid { grid-template-columns: 1fr; }
  .collection-art {
    aspect-ratio: 5 / 6;
    padding: 0;
  }
  .collection-art img { width: 60%; height: 60%; }
  .collection-feature-card {
    aspect-ratio: .708 / 1;
    padding: 14px;
  }
  .nav-inner { min-height: 64px; }
  .detail-shell { padding: 0 32px 100px; }
  .site-shell { padding: 14px; }
  .collection-context { padding: 18px; }
  .detail-layout { --detail-nav-height: 64px; }
  .detail-description { margin-top: 36px; }
  .feature-grid { grid-template-columns: 1fr; }
  .faq-section { padding-block: 100px; }
  .faq-question { padding: 24px 0; }
  .faq-list .faq-answer-inner::after { height: 24px; }
  .site-footer-inner { padding-block: 48px; }
  .footer-bottom { grid-template-columns: minmax(0, 1fr); }
  .footer-brand { grid-row: 2; gap: 20px; }
  .footer-legal, .footer-collections { gap: 12px 24px; }
  .legal-main { padding-bottom: 100px; }
  .legal-hero-wrap.content-frame { width: 100%; padding: 0; }
  .legal-hero.collection-feature-card {
    height: 510px;
    min-height: 0;
    aspect-ratio: auto;
    border-radius: 0;
  }
  .legal-hero-logo {
    top: 32px;
    left: 32px;
  }
  .legal-hero h1 { max-width: 86%; }
  .legal-content { margin-top: 80px; }
  .legal-updated, .legal-license-note { margin-bottom: 56px; }
  .about-main { padding-bottom: 100px; }
  .about-content { margin-top: 80px; }
  .about-process { margin: 48px auto; }
  .about-process img { max-width: none; }
  .about-process figcaption { margin-top: 8px; }
  .about-signoff { margin-top: 48px; }
}

/* The centred links (~554px) only clear the logo and Subscribe button with a 24px gap from 880px,
   and still look cramped on landscape phones (up to 956px), so use the tablet breakpoint */
@media (max-width: 1023px) {
  .nav-links { display: none; }
  .device-menu { display: none; }
  .nav-signup { display: none; }
  .nav-hamburger { display: flex; }
  .nav-mobile-menu {
    position: fixed;
    inset: 0;
    z-index: 999;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    visibility: hidden;
    transform: translateY(-100%);
    background: #ffffff;
    color: var(--ink);
    padding: 120px max(32px, env(safe-area-inset-right)) 0 max(32px, env(safe-area-inset-left));
    pointer-events: none;
    transition: transform .6s cubic-bezier(.85, 0, .15, 1), visibility .6s;
  }
  .nav-mobile-menu.open {
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
  }
  .nav-mobile-inner {
    display: flex;
    width: 100%;
    min-height: calc(100vh - 120px);
    min-height: calc(100svh - 120px);
    margin: 0;
    padding: 0;
    flex-direction: column;
    gap: 40px;
    text-align: left;
  }
  .nav-mobile-links {
    display: flex;
    flex-direction: column;
    gap: 20px;
  }
  .nav-mobile-links > a,
  .nav-mobile-device-toggle {
    color: var(--ink);
    font-size: 34px;
    font-weight: 600;
    line-height: 1.6;
    letter-spacing: -.035em;
    text-decoration: none;
    transition: opacity .3s ease;
  }
  .nav-mobile-links a:hover { opacity: .7; }
  .nav-mobile-links:has(.nav-mobile-devices.open) > a { color: #afafaf; }
  /* full width of the menu's padding, in the menu links' type; fades in with the footer */
  .nav-mobile-subscribe {
    display: flex;
    width: 100%;
    padding: 6px 22px;
    border: 0;
    border-radius: 999px;
    align-items: center;
    justify-content: center;
    background: var(--ink);
    color: #ffffff;
    font-size: 34px;
    font-weight: 600;
    line-height: 1.6;
    letter-spacing: -.035em;
    cursor: pointer;
  }
  .nav-mobile-subscribe:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }
  .nav-mobile-device-toggle { padding: 0; }
  .nav-mobile-device-toggle .faq-icon { width: 36px; height: 36px; padding: 8px; margin-top: calc((1.6em - 36px) / 2); }
  .nav-mobile-device-toggle .faq-icon span { width: 20px; height: 2px; border-radius: 2px; }
  .nav-mobile-collections { display: flex; flex-direction: column; gap: 20px; padding-left: 20px; font-size: 24px; }
  .nav-mobile-collections a:first-child { margin-top: 24px; }
  .nav-mobile-collections a:last-child { margin-bottom: 4px; }
  .nav-mobile-collections a { color: var(--ink); font-size: inherit; font-weight: 600; line-height: 1.4; text-decoration: none; }
  .nav-mobile-collections { transition: opacity .4s cubic-bezier(.32, .72, 0, 1); }
  .blur-reveal-word {
    display: inline-block;
    filter: blur(12px);
    opacity: 0;
    transform: translateY(20px);
    transition: filter .8s cubic-bezier(.25, .4, .25, 1), opacity .8s cubic-bezier(.25, .4, .25, 1), transform .8s cubic-bezier(.25, .4, .25, 1);
    will-change: filter, opacity, transform;
  }
  .blur-reveal.visible .blur-reveal-word {
    filter: blur(0);
    opacity: 1;
    transform: translateY(0);
  }
  .nav-mobile-footer {
    margin: auto 0 0;
    padding: 0 0 40px;
    color: var(--tertiary);
    font-size: 12px;
    line-height: 1.4;
    opacity: 0;
    transform: translateY(100px);
    transition: opacity 1s ease, transform 1s ease;
  }
  .nav-mobile-footer.visible {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Collection opening (src/page-transition.js): tapping a home card grows the card into the
   collection page's hero while its render flies to its place, after samgros.com's project cards.
   The card's caption rides along its bottom edge and gives way to the thumbnail strip; the rest of
   the home page fades out at once, and the collection page fades and rises in behind the card as it
   lands. Going back runs it in reverse, with the grid fading in where it was left. The morph uses
   the portfolio gallery's 0.6s curve. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition { pointer-events: none; }
  ::view-transition-group(collection-box),
  ::view-transition-group(collection-render),
  ::view-transition-group(collection-caption) {
    animation-duration: .6s;
    animation-timing-function: cubic-bezier(.16, 1, .3, 1);
  }
  /* flat grey once the render and caption are lifted out, so stretching it doesn't show */
  ::view-transition-old(collection-box),
  ::view-transition-new(collection-box) { height: 100%; }
  ::view-transition-old(collection-render),
  ::view-transition-new(collection-render) { height: 100%; }
  /* a larger render still loading: the card's carries on alone, then fades out under it */
  :root.morph-render-pending::view-transition-old(collection-render) { animation: none; mix-blend-mode: normal; }
  :root.morph-render-pending::view-transition-new(collection-render) { animation: none; opacity: 0; }
  :root.morph-render-arrived::view-transition-old(collection-render) { animation: .25s ease both collection-fade-out; mix-blend-mode: normal; }
  :root.morph-render-arrived::view-transition-new(collection-render) { animation: none; mix-blend-mode: normal; }
  /* the caption and the thumbnail strip keep their own size, the outgoing one leaving quickly and
     the incoming one arriving as the card settles */
  ::view-transition-old(collection-caption),
  ::view-transition-new(collection-caption) { width: auto; height: auto; mix-blend-mode: normal; }
  ::view-transition-old(collection-caption) { animation: .15s ease-in both collection-fade-out; }
  ::view-transition-new(collection-caption) { animation: .3s ease-out .3s both collection-fade-in; }
  /* page-transition.js moves the box, render and caption with a transform alone, which Safari can
     run off the main thread; the name only, so the crossfades inside keep the group's .6s */
  :root.morph-composited::view-transition-group(collection-box),
  :root.morph-composited::view-transition-group(collection-render),
  :root.morph-composited::view-transition-group(collection-caption) {
    animation-name: none;
    transform-origin: 0 0;
  }
  ::view-transition-group(collection-nav) { animation-duration: .3s; }
  /* the outgoing page is gone before the incoming one starts, so the full-screen plus-lighter blend
     the browser crossfades with would only cost Safari a full-screen composite every frame */
  ::view-transition-old(root),
  ::view-transition-new(root),
  ::view-transition-old(collection-details),
  ::view-transition-new(collection-details) { mix-blend-mode: normal; }
  /* the phone details card has a layer of its own (page-transition.js) but moves with the page */
  ::view-transition-old(root),
  ::view-transition-old(collection-details) { animation: .14s ease-in both collection-fade-out; }
  ::view-transition-new(root),
  ::view-transition-new(collection-details) {
    animation: .26s ease-out .3s both collection-fade-in, .32s cubic-bezier(.32, .72, .5, 1) .2s both collection-rise;
  }
  :root.morph-back::view-transition-new(root) { animation: .3s ease-out .2s both collection-fade-in; }
}

@keyframes collection-fade-in { from { opacity: 0; } }
@keyframes collection-fade-out { to { opacity: 0; } }
@keyframes collection-rise { from { transform: translateY(12px); } }

/* Scroll reveal, matching the Hilium landing page */
.reveal {
  opacity: 0;
  transform: translateY(100px);
  transition: opacity 1s ease var(--reveal-delay, 0s), transform 1s ease var(--reveal-delay, 0s);
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

/* `scale` rather than `transform`, so the hover composes with the reveal */
@media (hover: hover) and (pointer: fine) {
  .collection-art { transition: transform .6s cubic-bezier(.22, 1, .36, 1); }
  .collection-card:hover .collection-art { transform: scale(1.01); }
  /* on the question rather than the item, whose opacity belongs to the reveal */
  .faq-list .faq-question { transition: opacity .2s ease; }
  .faq-list .faq-question:hover { opacity: .65; }
}

@media (min-width: 769px) {
  .detail-shell { padding-bottom: 200px; }
  /* On tablets the stacked hero is far taller than on phones, so the render is
     capped to a share of it instead of filling it edge to edge. */
  .detail-mobile-hero img {
    max-width: 60%;
    max-height: 60%;
  }
  .legal-hero .legal-hero-logo {
    top: 32px;
    left: 32px;
  }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; animation-delay: 0ms !important; }
  .collection-hero-frame { height: 100vh; height: 100svh; }
  .collection-hero { height: 100%; }
  .collection-hero-reveal,
  .collection-hero-surface { transform: none; }
  .collection-hero-reveal::after { display: none; }
  .collection-hero-image,
  .collection-hero-content { opacity: 1; }
  .about-signoff-cube { animation: none; }
  .reveal { opacity: 1; transform: none; }
  .collection-card:hover .collection-art { transform: none; }
}

/* Landscape phones share the portrait phones' spacing: the nav, the hero text and the product page
   sit on one 32px gutter, and the home grid keeps its 14px frame. Last in the file, as it
   overrides the stacked-layout and tablet rules above. */
@media (orientation: landscape) and (max-height: 500px) {
  :root { --content-gutter: 32px; }
  .site-shell { padding: 14px; }
  .collection-hero-content {
    bottom: var(--content-gutter);
    left: var(--content-gutter);
  }
}
