/* ---- Tokens ---- */
:root {
  --bg: #0c0c0b;
  --bg-raised: #151513;
  --text: #f1efe9;
  --text-muted: #8f8c83;
  --border: #29271f;
  --accent: #d9a24b;
  --font-display: "Space Grotesk", "Helvetica Neue", Arial, sans-serif;
  --font-body: "neue-haas-grotesk-text", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Geist Mono", "SF Mono", Consolas, monospace;
  --content-width: 46rem;
  --page-width: 72rem;
  --space-1: 0.5rem;
  --space-2: 1rem;
  --space-3: 1.5rem;
  --space-4: 2.5rem;
  --space-5: 4rem;
  --space-6: 6rem;
}

/* ---- Reset ---- */
* {
  box-sizing: border-box;
}

html {
  color-scheme: dark;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* The image plugin wraps pictures in <picture>; let the <img> lay out as if it weren't there. */
picture {
  display: contents;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
}

h1, h2, h3 {
  font-family: var(--font-display);
  line-height: 1.15;
  margin: 0;
}

p {
  margin: 0 0 var(--space-3);
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.skip-link a {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--accent);
  color: #0c0c0b;
  padding: var(--space-1) var(--space-2);
  z-index: 100;
}
.skip-link a:focus {
  left: var(--space-2);
  top: var(--space-2);
}

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ---- Header ---- */
.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: var(--page-width);
  margin: 0 auto;
  padding: var(--space-3) var(--space-3);
}

.site-header__mark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  text-decoration: none;
  letter-spacing: -0.01em;
}

.site-header__nav {
  display: flex;
  gap: var(--space-3);
}

.site-header__nav a {
  text-decoration: none;
  color: var(--text-muted);
  font-size: 0.95rem;
  transition: color 0.15s ease;
}

.site-header__nav a:hover {
  color: var(--text);
}

/* ---- Footer ---- */
.site-footer {
  border-top: 1px solid var(--border);
  margin-top: var(--space-6);
}

.site-footer__row {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: var(--space-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
  font-size: 0.9rem;
}

.site-footer__brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
}

.site-footer__mark {
  width: 2.5rem;
  height: 2.5rem;
}

.site-footer__row a {
  color: var(--accent);
  text-decoration: none;
}

.site-footer__row a:hover {
  color: var(--text);
}

/* ---- Home: intro ---- */
.home-intro {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr) minmax(0, 1.55fr) minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
  padding: var(--space-4) var(--space-3) var(--space-5);
}

.home-intro__name {
  font-size: clamp(2.25rem, 3.6vw, 3.4rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
}

.home-intro__name a {
  text-decoration: none;
}

.home-intro__nav {
  display: flex;
  flex-direction: column;
  padding-top: 0.35rem;
}

.home-intro__nav a,
.home-intro__email {
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.15s ease;
}

.home-intro__nav a:hover,
.home-intro__email:hover {
  color: var(--text);
}

.home-intro__about {
  padding-top: 0.35rem;
}

.home-intro__about h2 {
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.6;
}

.home-intro__about p {
  color: var(--text-muted);
  max-width: 32rem;
  margin-bottom: var(--space-3);
}

.home-intro__more {
  font-weight: 500;
  text-decoration: none;
}

.home-intro__more:hover {
  color: var(--accent);
}

.home-intro__email {
  justify-self: end;
  padding-top: 0.35rem;
}

@media (max-width: 64rem) {
  .home-intro {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
    row-gap: var(--space-3);
  }

  .home-intro__name {
    grid-column: 1 / -1;
  }

  .home-intro__email {
    justify-self: start;
    grid-column: 1 / -1;
  }
}

@media (max-width: 40rem) {
  .home-intro {
    grid-template-columns: 1fr;
  }
}

/* ---- Home: work rail ---- */
.home-work {
  padding-bottom: var(--space-4);
}

.home-rail {
  display: flex;
  gap: var(--space-3);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: var(--space-3);
  padding: 0 var(--space-3) var(--space-2);
  scrollbar-width: none;
  cursor: grab;
}

.home-rail::-webkit-scrollbar {
  display: none;
}

.home-rail.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none;
}

.home-rail.is-dragging a {
  pointer-events: none;
}

.rail-card {
  flex: 0 0 clamp(17rem, 25vw, 25rem);
  scroll-snap-align: start;
}

.rail-card a {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  text-decoration: none;
}

.rail-card__label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 1.05rem;
  font-weight: 500;
}

.rail-card__dot {
  width: 1rem;
  height: 1rem;
  border: 1.5px solid currentColor;
  border-radius: 50%;
  flex-shrink: 0;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.rail-card a:hover .rail-card__dot,
.rail-card a:focus-visible .rail-card__dot {
  background: var(--accent);
  border-color: var(--accent);
}

.rail-card__media {
  position: relative;
  display: block;
  aspect-ratio: 7 / 10;
  border-radius: 0.5rem;
  overflow: hidden;
  background: var(--bg-raised);
}

.rail-card__media > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s ease;
  -webkit-user-drag: none;
  user-select: none;
}

.rail-card a:hover .rail-card__media > img {
  transform: scale(1.03);
}

.rail-card__badge {
  position: absolute;
  top: 0;
  right: 7%;
  width: 16%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: var(--bg);
}

.rail-card__badge img {
  width: 42%;
  height: 42%;
}

@media (max-width: 40rem) {
  .rail-card {
    flex-basis: 78vw;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rail-card__media > img {
    transition: none;
  }

  .rail-card a:hover .rail-card__media > img {
    transform: none;
  }
}

/* ---- Project (case study) ----
   One horizontal track on wide screens: a full-screen hero, the overview,
   the write-up in blocks (grouped by main.js), then the next project. Phones
   and no-JS get the same content stacked. */
.project {
  overflow-x: clip;
  --pad-y: clamp(4.5rem, 11svh, 7rem);
  --gap: clamp(3rem, 6vw, 6rem);
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  position: relative;
}

.project-close {
  position: fixed;
  top: var(--space-3);
  right: var(--space-3);
  z-index: 20;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.95rem;
  border-radius: 999px;
  background: rgb(12 12 11 / 0.55);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  font-size: 0.9rem;
  color: var(--text);
  text-decoration: none;
  transition: background 220ms, color 220ms;
}

.project-close:hover,
.project-close:focus-visible {
  background: var(--text);
  color: var(--bg);
}

/* Hero */
.project-hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
}

.project-hero__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  view-transition-name: project-hero;
}

.project-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgb(12 12 11 / 0.85), rgb(12 12 11 / 0.2) 45%, transparent 70%);
}

.project-hero__text {
  position: absolute;
  left: var(--space-4);
  right: var(--space-4);
  bottom: var(--space-5);
  z-index: 1;
}

.project-hero__eyebrow {
  margin: 0 0 var(--space-2);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text);
  opacity: 0.8;
  text-wrap: balance;
}

.project-hero__title {
  max-width: 14ch;
  margin: 0;
  font-size: clamp(3rem, 8vw, 8rem);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 0.95;
  text-wrap: balance;
}

.project-hero__hint {
  position: absolute;
  right: var(--space-4);
  bottom: var(--space-5);
  z-index: 1;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.project-hero__hint span {
  display: inline-block;
  margin-left: 0.4rem;
}

/* Overview */
.project-intro {
  padding: var(--space-5) var(--space-3);
}

.project-intro__summary {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 2.2vw, 2rem);
  line-height: 1.25;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}

.project-meta {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-3) var(--space-2);
  margin: var(--space-4) 0 0;
}

.project-meta dt {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.project-meta dd {
  margin: 0.2rem 0 0;
  font-size: 0.95rem;
}

.project-press {
  margin-top: var(--space-4);
}

.project-press h2 {
  margin: 0 0 var(--space-1);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.project-press ul {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.95rem;
}

.project-press a {
  color: var(--text);
  text-decoration-color: var(--accent);
  text-underline-offset: 0.2em;
}

.project-press .handle {
  color: var(--text-muted);
}

.project-video {
  display: block;
  width: 100%;
  height: auto;
}

/* At a glance */
.project-glance {
  padding: var(--space-5) var(--space-3) 0;
}

.project-glance__label {
  margin: 0 0 var(--space-2);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.project-glance__lead {
  max-width: 38rem;
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.6;
}

.project-glance__lead span {
  display: block;
  margin-bottom: 0.25rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.project-glance__stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-3);
  margin: var(--space-4) 0 0;
}

/* Value above its label, though the label comes first in the markup. */
.project-glance__stats div {
  display: flex;
  flex-direction: column-reverse;
  justify-content: flex-end;
  gap: 0.4rem;
}

.project-glance__stats dd {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 4.5vw, 4.25rem);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1;
}

.project-glance__stats dt {
  max-width: 16rem;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--text-muted);
}

.project-glance__role {
  margin: var(--space-4) 0 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Write-up blocks */
.project-body {
  padding: 0 var(--space-3);
}

.project-text h2 {
  margin: var(--space-4) 0 var(--space-2);
  font-size: 1.6rem;
  font-weight: 500;
  letter-spacing: -0.02em;
}

.project-text > :first-child {
  margin-top: 0;
}

.project-text p,
.project-text li {
  font-size: 1rem;
  line-height: 1.7;
  color: var(--text);
}

.project-text p {
  margin: 0 0 var(--space-2);
}

.project-text ul,
.project-text ol {
  margin: 0 0 var(--space-2);
  padding-left: 1.2em;
}

.project-text li {
  margin-bottom: var(--space-1);
}

.project-text .project-inline {
  display: block;
  width: 100%;
  height: auto;
  margin: var(--space-2) 0;
  border-radius: 4px;
}

.project-text li::marker {
  color: var(--accent);
}

.project-figure {
  margin: var(--space-3) 0;
}

.project-figure figcaption {
  margin-bottom: var(--space-1);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.project-figure img,
.project-figure video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
}

/* Colour cards (markup lives in the markdown) */
.case-study__colors {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
}

.case-study__color-card {
  overflow: hidden;
  border-radius: 10px;
  background: var(--bg-raised);
}

.case-study__color-swatch {
  height: 6rem;
}

/* Cards copy their hex on click: they lift a little to say so. */
.case-study__color-card[role="button"] {
  cursor: copy;
  transition: translate 220ms var(--ease-out), box-shadow 220ms var(--ease-out);
}

.case-study__color-card[role="button"]:hover,
.case-study__color-card[role="button"]:focus-visible {
  translate: 0 -3px;
  box-shadow: 0 10px 24px rgb(0 0 0 / 0.35);
  outline: none;
}

.case-study__color-card[role="button"]:focus-visible {
  box-shadow: 0 0 0 2px var(--accent), 0 10px 24px rgb(0 0 0 / 0.35);
}

.case-study__color-card[role="button"]:active {
  translate: 0 -1px;
}

.case-study__color-card.is-copied .case-study__color-hex {
  color: var(--accent);
}

.case-study__color-info {
  display: grid;
  gap: 0.5rem;
  padding: 0.85rem 0.9rem 1rem;
  line-height: 1.35;
}

.case-study__color-info p {
  margin: 0;
}

.case-study__color-name {
  font-size: 0.9rem;
  font-weight: 600;
}

.case-study__color-hex {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--text-muted);
}

.case-study__color-usage {
  font-size: 0.75rem;
  color: var(--text-muted);
}

/* Next project */
.project-end {
  display: grid;
  gap: var(--space-3);
  justify-items: start;
  padding: var(--space-5) var(--space-3) var(--space-6);
}

.project-next {
  display: grid;
  gap: 0.35rem;
  width: min(30rem, 100%);
  color: var(--text);
  text-decoration: none;
}

.project-next__label {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.project-next__media {
  display: block;
  aspect-ratio: 4 / 3;
  margin: var(--space-1) 0;
  overflow: hidden;
  border-radius: 6px;
}

.project-next__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: scale 700ms var(--ease-expo);
}

.project-next:hover .project-next__media img,
.project-next:focus-visible .project-next__media img {
  scale: 1.05;
}

.project-next__title {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 3vw, 2.6rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

.project-next__client {
  font-size: 0.9rem;
  color: var(--text-muted);
}

.project-end__home {
  color: var(--text-muted);
  font-size: 0.9rem;
  text-underline-offset: 0.2em;
}

.project-end__home:hover {
  color: var(--text);
}

/* Progress along the bottom edge */
/* Pictures fill their box with their average colour until they arrive. */
img[style*="--ph"] {
  background-color: var(--ph);
}

img[style*="--ph"].is-settled {
  background-color: transparent;
}

/* Then they develop out of it: a soft blur, close to that colour, that sharpens. */
[data-project] img.is-arriving {
  clip-path: inset(0 round 4px);
  animation: picture-develop 700ms cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes picture-develop {
  from {
    filter: blur(24px) saturate(0.8);
  }
}

.project-progress {
  position: fixed;
  left: var(--space-3);
  right: var(--space-3);
  bottom: var(--space-2);
  z-index: 20;
  height: 3px;
  border-radius: 3px;
  background: rgb(241 239 233 / 0.12);
  overflow: hidden;
}

.project-progress span {
  display: block;
  height: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}

/* Chapter marks: a tick on the progress bar where each chapter starts. */
.project-marks {
  position: fixed;
  left: var(--space-3);
  right: var(--space-3);
  bottom: var(--space-2);
  z-index: 21;
  height: 3px;
  pointer-events: none;
}

.project-marks__mark {
  position: absolute;
  top: 50%;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  background: none;
  translate: -50% -50%;
  cursor: pointer;
  pointer-events: auto;
}

.project-marks__mark::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2px;
  height: 9px;
  border-radius: 2px;
  background: rgb(241 239 233 / 0.45);
  translate: -50% -50%;
  transition: height 200ms ease, background-color 200ms ease;
}

.project-marks__mark.is-reached::before {
  background: var(--accent);
}

.project-marks__mark:hover::before,
.project-marks__mark:focus-visible::before {
  height: 15px;
  background: var(--text);
}

.project-marks__mark:focus-visible {
  outline: none;
}

.project-marks__label {
  position: absolute;
  bottom: calc(100% + 0.25rem);
  left: 50%;
  padding: 0.35rem 0.6rem;
  border-radius: 999px;
  background: rgb(8 8 7 / 0.88);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  translate: -50% 0.25rem;
  transition: opacity 180ms ease, translate 180ms ease;
  pointer-events: none;
}

.project-marks__mark.is-start .project-marks__label {
  left: 0;
  translate: 0 0.25rem;
}

.project-marks__mark.is-end .project-marks__label {
  left: auto;
  right: 0;
  translate: 0 0.25rem;
}

.project-marks__mark:hover .project-marks__label,
.project-marks__mark:focus-visible .project-marks__label {
  opacity: 1;
  translate: -50% 0;
}

.project-marks__mark.is-start:hover .project-marks__label,
.project-marks__mark.is-start:focus-visible .project-marks__label,
.project-marks__mark.is-end:hover .project-marks__label,
.project-marks__mark.is-end:focus-visible .project-marks__label {
  translate: 0 0;
}

/* About: blocks written straight into about.njk */
.project-quote {
  max-width: 16ch;
  margin: var(--space-4) 0;
  font-family: var(--font-display);
  font-size: clamp(2rem, 4.2vw, 3.75rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.05;
  text-wrap: balance;
}

.project-quote__swatch {
  color: #ffb705;
}

.project-facts,
.project-roles {
  margin: 0;
  padding: 0;
  list-style: none;
}

.project-facts li {
  display: flex;
  gap: 0.75rem;
  margin: 0;
  padding: 0.45rem 0;
}

/* Emoji vary in width; a fixed column keeps the facts starting in one line. */
.project-facts li > [aria-hidden] {
  flex: none;
  width: 1.4em;
  text-align: center;
}

.project-roles li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 var(--space-2);
  margin: 0 0 var(--space-2);
}

.project-roles__role {
  font-weight: 500;
}

.project-roles__org {
  grid-column: 1;
  color: var(--text-muted);
}

.project-roles__dates {
  grid-column: 2;
  grid-row: 1;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-muted);
}

.project-board a {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 4px;
}

.project-board img {
  transition: scale 700ms var(--ease-expo);
}

.project-board__link {
  position: absolute;
  right: var(--space-2);
  bottom: var(--space-2);
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  background: rgb(12 12 11 / 0.7);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  font-size: 0.85rem;
  color: var(--text);
}

.project-board a:hover img,
.project-board a:focus-visible img {
  scale: 1.04;
}

/* Photos sit edge to edge; only the strip's outer corners are rounded. */
.project-gallery {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  margin: var(--space-3) 0;
  padding: 0;
  overflow: hidden;
  border-radius: 4px;
  list-style: none;
}

.project-gallery img {
  display: block;
  width: 100%;
  /* Without this the image's own height attribute wins over the 2:3 frame. */
  height: auto;
  aspect-ratio: 2 / 3;
  object-fit: cover;
}

/* Phones: an odd photo out would leave a hole beside it, so the last one
   spans both columns in a landscape frame. */
@media (max-width: 47.99rem) {
  .project-gallery li:last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }

  .project-gallery li:last-child:nth-child(odd) img {
    aspect-ratio: 4 / 3;
  }
}

.project-contact {
  gap: var(--space-1);
}

.project-contact__title {
  margin: 0 0 var(--space-2);
  font-size: clamp(2.5rem, 6vw, 5.5rem);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1;
}

.project-contact__link {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 2vw, 1.6rem);
  color: var(--text);
  text-decoration-color: var(--accent);
  text-underline-offset: 0.2em;
}

.project-contact .project-end__home {
  margin-top: var(--space-3);
}

/* Work: a mosaic hero and one card per project */
.project-hero__mosaic {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
  background: var(--bg);
}

.project-hero__mosaic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.45;
  filter: grayscale(0.5);
}

.project-card {
  display: grid;
  gap: 0.4rem;
  align-content: start;
  color: var(--text);
  text-decoration: none;
}

.project-card__media {
  display: block;
  aspect-ratio: 4 / 3;
  margin-bottom: var(--space-1);
  overflow: hidden;
  border-radius: 6px;
  background: var(--bg-raised);
}

.project-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: scale 700ms var(--ease-expo);
}

.project-card:hover .project-card__media img,
.project-card:focus-visible .project-card__media img {
  scale: 1.05;
}

.project-card__meta {
  display: flex;
  gap: 0.75rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.project-card__meta span:first-child {
  color: var(--accent);
}

.project-card__title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.4vw, 2.1rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.project-card__summary {
  max-width: 34rem;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--text-muted);
}

.project--work .project-body {
  display: grid;
  gap: var(--space-5);
  padding-block: var(--space-5);
}

/* Wide screens: lay the track out sideways. */
@media (min-width: 48rem) {
  .js .project-block:not(.is-in) {
    translate: 3rem 0;
  }

  .project {
    height: 100vh;
    height: 100svh;
    overflow: hidden;
  }

  .project-track {
    display: flex;
    gap: var(--gap);
    height: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .project-track::-webkit-scrollbar {
    display: none;
  }

  .project-track > * {
    flex: none;
  }

  .project-hero {
    width: 100vw;
    height: 100%;
  }

  .project-intro {
    align-self: center;
    width: min(40rem, 70vw);
    padding: 0;
  }

  .project-glance {
    align-self: center;
    width: min(52rem, 80vw);
    padding: 0;
  }

  .project-video {
    align-self: center;
    width: auto;
    height: calc(100% - 2 * var(--pad-y));
    border-radius: 4px;
  }

  .project-body {
    display: flex;
    align-items: center;
    gap: var(--gap);
    padding: var(--pad-y) 0;
  }

  .project-body > * {
    flex: none;
  }

  .project-text {
    width: 26rem;
  }

  /* The credit sits above the picture without changing its height, so
     every picture on the track lines up. */
  .project-figure {
    position: relative;
    margin: 0;
  }

  .project-figure figcaption {
    position: absolute;
    bottom: 100%;
    left: 0;
    white-space: nowrap;
  }

  .project-figure img,
  .project-figure video {
    width: auto;
    height: calc(100svh - 2 * var(--pad-y) - 2rem);
    max-width: 85vw;
    object-fit: contain;
    /* Pictures too wide for the height keep to the top line, under their credit. */
    object-position: top;
  }

  /* A board's link sits on its corner, so its box has to match the picture,
     not the screen height: it takes its width, and its height follows. */
  .project-board.project-figure img {
    width: min(85vw, (100svh - 2 * var(--pad-y) - 2rem) * 3072 / 1540);
    height: auto;
  }

  .case-study__colors {
    grid-template-columns: repeat(5, 9.5rem);
  }

  .project-quote {
    width: 16ch;
    margin: 0;
  }

  /* Galleries become one strip, each photo as tall as the other figures. */
  .project-gallery {
    display: flex;
    height: calc(100svh - 2 * var(--pad-y) - 2rem);
    margin: 0;
  }

  .project-gallery li {
    flex: none;
    height: 100%;
  }

  .project-gallery img {
    width: auto;
    height: 100%;
    aspect-ratio: auto;
  }

  /* On About every photo shares one 2:3 frame, so they're all the same
     width as well as height (taller shots are trimmed top and bottom). */
  .project--about .project-gallery img {
    aspect-ratio: 2 / 3;
  }

  .project-contact {
    width: min(36rem, 80vw);
  }

  /* Cards are as tall as the track allows, leaving room for their text. */
  .project--work .project-body {
    display: flex;
    gap: var(--gap);
    padding-block: var(--pad-y);
  }

  .project-card {
    width: calc((100svh - 2 * var(--pad-y) - 9rem) * 4 / 3);
    max-width: 80vw;
  }

  .project-end {
    align-self: center;
    padding: 0 var(--space-6) 0 0;
  }
}

/* Blocks slide in as they enter the frame: up on phones, from the right on the track. */
@media (prefers-reduced-motion: no-preference) {
  .js .project-block {
    transition: opacity 900ms var(--ease-out), translate 1100ms var(--ease-expo);
  }

  .js .project-block:not(.is-in) {
    opacity: 0;
    translate: 0 1.5rem;
  }

  .js .project-hero__text > *,
  .js .project-hero__hint {
    animation: project-rise 1000ms var(--ease-expo) backwards;
  }

  .js .project-hero__title {
    animation-delay: 120ms;
  }

  .js .project-hero__hint {
    animation-delay: 300ms;
  }

  .project-hero__hint span {
    animation: project-nudge 1.8s var(--ease-out) 1.4s infinite;
  }
}

@keyframes project-rise {
  from {
    opacity: 0;
    translate: 0 1.5rem;
  }
}

@keyframes project-nudge {
  50% {
    translate: 0.35rem 0;
  }
}

/* Editorial text (opt-in per page with textStyle: "editorial"): numbered
   sections, a lead line from each section's first sentence, and text that
   shares a top edge with the pictures. */
.project--editorial .project-text h2 {
  display: flex;
  gap: 0.75rem;
  margin: var(--space-5) 0 var(--space-2);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.project--editorial .project-text > h2:first-child {
  margin-top: 0;
}

@media (max-width: 47.99rem) {
  .project--editorial .project-text + .project-text {
    margin-top: var(--space-5);
  }
}

.project-text__number {
  color: var(--accent);
}

.project--editorial .project-text__lead {
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-size: clamp(1.45rem, 2vw, 1.85rem);
  line-height: 1.22;
  letter-spacing: -0.015em;
  color: var(--text);
  text-wrap: pretty;
}

.project--editorial .project-text__lead--long {
  font-size: clamp(1.2rem, 1.5vw, 1.4rem);
  line-height: 1.3;
}

.project--editorial .project-text p:not(.project-text__lead),
.project--editorial .project-text li {
  font-size: 1.0625rem;
  line-height: 1.65;
  color: color-mix(in srgb, var(--text) 78%, var(--text-muted));
}

@media (min-width: 48rem) {
  /* Every block starts on the same top line as the pictures (which leave
     2rem above them for their credit). */
  .project--editorial .project-body {
    align-items: flex-start;
  }

  .project--editorial .project-figure,
  .project--editorial .project-gallery,
  .project--editorial .project-colors,
  .project--editorial .project-quote {
    margin-top: 2rem;
  }

  .project--editorial .project-text {
    width: 30rem;
    margin-top: 2rem;
    padding-left: var(--space-3);
    border-left: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
  }

  /* A section sits close to the picture that follows it. */
  .project--editorial .project-text:has(+ .project-figure, + .project-gallery, + .project-row, + .project-stats) {
    margin-right: calc(var(--space-4) - var(--gap));
  }
}

/* Chapters: a divider panel that opens each group of sections, with the
   chapter number, its name and the sections inside it. */
.project-chapter {
  margin: var(--space-5) 0 var(--space-3);
}

.project-chapter__number {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(4.5rem, 9vw, 8rem);
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--accent);
}

.project-chapter__title {
  margin: var(--space-2) 0 0;
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.4vw, 3rem);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.project-chapter__toc {
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  line-height: 2;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Rows: related pictures side by side, each with its own credit. */
.project-row {
  display: grid;
  gap: var(--space-3);
  margin: var(--space-3) 0;
}

.project-row .project-figure {
  margin: 0;
}

/* Stats: headline numbers set as text, in place of a picture. */
.project-stats {
  margin: var(--space-3) 0;
  padding: var(--space-3);
  border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
  border-radius: 4px;
  background: var(--bg-raised);
}

.project-stats__label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.project-stats dl {
  margin: 0;
}

.project-stats dl > div {
  padding: var(--space-3) 0;
}

.project-stats dl > div + div {
  border-top: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
}

.project-stats dt {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 500;
}

.project-stats dt span {
  margin-left: 0.5rem;
  color: var(--text-muted);
}

.project-stats dd {
  margin: 0;
  color: var(--text-muted);
}

.project-stats .project-stats__value {
  margin: var(--space-1) 0;
  font-family: var(--font-display);
  font-size: clamp(4.5rem, 8vw, 7.5rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--accent);
}

/* Small headings inside a section that gathers several states. */
.project--editorial .project-text h3 {
  margin: var(--space-3) 0 var(--space-1);
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.project-intro__role {
  margin: var(--space-3) 0 0;
  font-size: 1.0625rem;
  line-height: 1.65;
  color: color-mix(in srgb, var(--text) 78%, var(--text-muted));
}

@media (min-width: 48rem) {
  .project-chapter {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-self: stretch;
    width: 24rem;
    margin: 0 var(--space-4);
  }

  .project-row {
    display: flex;
    gap: var(--space-3);
    margin: 2rem 0 0;
  }

  .project--editorial .project-row .project-figure {
    margin-top: 0;
  }

  /* Same height and top line as the pictures on the track. */
  .project-stats {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    box-sizing: border-box;
    width: 26rem;
    height: calc(100svh - 2 * var(--pad-y) - 2rem);
    margin: 2rem 0 0;
  }

  /* Pictures in a row keep the full track height, however wide that makes them. */
  .project-row .project-figure img,
  .project-row .project-figure video {
    max-width: none;
  }
}

/* Showcase (opt-in with textStyle: "showcase"): gallery pages where the
   pictures are the page. Text shrinks to slim panels between them, captions
   sit on the pictures, and any picture opens full screen. */
.project--showcase .project-text h2 {
  margin: 0 0 var(--space-2);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.project--showcase .project-text p,
.project--showcase .project-text li {
  font-size: 0.95rem;
  line-height: 1.6;
  color: color-mix(in srgb, var(--text) 72%, var(--text-muted));
}

.project--showcase .project-text .project-text__intro {
  font-family: var(--font-display);
  font-size: 1.35rem;
  line-height: 1.3;
  color: var(--text);
}

.project--showcase .project-body img,
.project--showcase .project-body video {
  cursor: zoom-in;
}

.project--showcase .project-gallery img {
  height: auto;
  aspect-ratio: 1 / 1;
}

.project--showcase .project-figure figcaption {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

@media (min-width: 48rem) {
  .project--showcase .project-body {
    align-items: stretch;
    gap: 0.75rem;
    padding: 0;
  }

  /* Every picture fills the full height of the screen, edge to edge. */
  .project--showcase .project-figure,
  .project--showcase .project-row,
  .project--showcase .project-gallery {
    height: 100svh;
    margin: 0;
  }

  .project--showcase .project-figure img,
  .project--showcase .project-figure video {
    height: 100svh;
    max-width: none;
    border-radius: 0;
  }

  .project--showcase .project-row {
    display: flex;
    gap: 0.75rem;
  }

  /* Captions sit in the picture's corner and appear on hover. */
  .project--showcase .project-figure figcaption {
    top: auto;
    bottom: var(--space-3);
    left: var(--space-3);
    margin: 0;
    padding: 0.45rem 0.7rem;
    border-radius: 999px;
    background: rgb(10 10 9 / 0.62);
    backdrop-filter: blur(8px);
    color: var(--text);
    opacity: 0;
    transition: opacity 300ms var(--ease-out);
  }

  .project--showcase .project-figure:hover figcaption,
  .project--showcase .project-figure:focus-within figcaption {
    opacity: 1;
  }

  /* A run of squares becomes a grid two rows deep. */
  .project--showcase .project-gallery {
    display: grid;
    grid-template-rows: repeat(2, 50svh);
    grid-auto-flow: column;
    grid-auto-columns: 50svh;
    gap: 0.75rem;
    border-radius: 0;
  }

  .project--showcase .project-gallery li {
    height: auto;
  }

  .project--showcase .project-gallery img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* Colours become full-height columns: the swatch fills the screen, its
     name and use sit underneath. */
  .project--showcase .project-colors {
    height: 100svh;
    margin: 0;
  }

  .project--showcase .case-study__colors {
    grid-template-columns: repeat(5, 13rem);
    gap: 0.75rem;
    height: 100%;
  }

  .project--showcase .case-study__color-card {
    display: flex;
    flex-direction: column;
    border-radius: 0;
  }

  .project--showcase .case-study__color-swatch {
    flex: 1;
    height: auto;
  }

  .project--showcase .case-study__color-info {
    box-sizing: border-box;
    flex: none;
    height: calc(8.5rem + var(--space-2) + 52px);
    align-content: start;
    padding: 1.1rem 1rem calc(var(--space-2) + 52px);
  }

  /* Text panels: narrow, anchored to the bottom of the screen. */
  .project--showcase .project-text {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    width: 22rem;
    margin: 0 var(--space-4);
    padding-bottom: var(--pad-y);
  }

  .project--showcase .project-close {
    padding: 0.5rem 0.9rem;
    border-radius: 999px;
    background: rgb(10 10 9 / 0.55);
    backdrop-filter: blur(8px);
  }
}

@media (hover: none) {
  .project--showcase .project-figure figcaption {
    opacity: 1;
  }
}

/* Ambient colour: the page takes on a dark tint of the picture in view. */
.project--showcase {
  background-color: var(--ambient, var(--bg));
  transition: background-color 900ms var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .project--showcase {
    transition: none;
  }
}

/* The full-screen viewer. */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  background: rgb(8 8 7 / 0.96);
}

.viewer[hidden] {
  display: none;
}

.viewer__stage img,
.viewer__stage video {
  display: block;
  max-width: 92vw;
  max-height: 84svh;
  object-fit: contain;
}

.viewer__caption,
.viewer__count {
  position: absolute;
  bottom: var(--space-3);
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.viewer__caption {
  left: var(--space-3);
  max-width: 60vw;
}

.viewer__count {
  right: var(--space-3);
}

.viewer button {
  position: absolute;
  padding: 0.6rem 0.9rem;
  border: 0;
  border-radius: 999px;
  background: rgb(255 255 255 / 0.08);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}

.viewer button:hover,
.viewer button:focus-visible {
  background: rgb(255 255 255 / 0.18);
}

.viewer__close {
  top: var(--space-3);
  right: var(--space-3);
}

.viewer__prev,
.viewer__next {
  top: 50%;
  translate: 0 -50%;
}

.viewer__prev {
  left: var(--space-3);
}

.viewer__next {
  right: var(--space-3);
}

@media (max-width: 47.99rem) {
  .viewer__prev,
  .viewer__next {
    display: none;
  }
}

/* Stepping through: the next picture slides in from the side it came from. */
.viewer__stage .is-from-right {
  animation: viewer-step 420ms cubic-bezier(0.16, 1, 0.3, 1) both;
  --from: 3rem;
}

.viewer__stage .is-from-left {
  animation: viewer-step 420ms cubic-bezier(0.16, 1, 0.3, 1) both;
  --from: -3rem;
}

@keyframes viewer-step {
  from {
    opacity: 0;
    translate: var(--from) 0;
  }
}

/* Opening and closing: the picture grows out of, and back into, the track. */
::view-transition-group(viewer-picture) {
  animation-duration: 520ms;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---- Page transitions ----
   An orbit tile (or the "next project" card) shares the name project-hero
   with the project page's hero image, so the browser grows one into the
   other when the page changes. Everything else cross-fades. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
}

::view-transition-group(project-hero),
::view-transition-group(contact-panel) {
  overflow: clip;
  animation-duration: 750ms;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

::view-transition-old(project-hero),
::view-transition-new(project-hero),
::view-transition-old(work-page),
::view-transition-new(work-page),
::view-transition-old(contact-panel),
::view-transition-new(contact-panel) {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The Work page's hero grows out of (and back into) its home corner. */
.project-hero__mosaic {
  view-transition-name: work-page;
}

::view-transition-group(work-page) {
  overflow: clip;
  animation-duration: 750ms;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 450ms;
}

/* ---- 404 ---- */
/* 404: the home page's frame (.orbit, its corner links) with the message
   where the logo would be. */
.not-found {
  display: grid;
  place-items: center;
  padding: var(--space-6) var(--space-3);
  text-align: center;
}

/* One cell for the nav and the message: the corner nav has no height of its
   own, and as a row it would push the message off centre. The photo stays out
   of the grid, so it measures from the whole frame, not the padded cell. */
.not-found > :not(.not-found__photo) {
  grid-area: 1 / 1;
}

.not-found__body {
  max-width: 30rem;
}

.not-found__label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.not-found__code {
  margin: var(--space-2) 0 var(--space-3);
  font-family: var(--font-display);
  font-size: clamp(6rem, 22vw, 14rem);
  font-weight: 500;
  letter-spacing: -0.05em;
  line-height: 0.85;
}

.not-found__message {
  margin: 0;
  color: var(--text-muted);
  text-wrap: balance;
}

.not-found__message a {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-underline-offset: 0.2em;
  transition: color 220ms;
}

.not-found__message a:hover,
.not-found__message a:focus-visible {
  color: var(--accent);
}

/* A keyboard shot or render from @oh.type (main.js picks one).
   Phones: it fills the screen, darkened at the top and foot so the corner
   links and the text that sits on it stay readable. */
.not-found__photo {
  position: absolute;
  inset: 0;
  z-index: 0;
  margin: 0;
}

.not-found__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The foot's shade is measured in rem, not %, so it always reaches the top
   of the text block, which is the same height on a short phone as a tall one. */
.not-found__photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgb(12 12 11 / 0.8), rgb(12 12 11 / 0.35) 6rem, transparent 12rem),
    linear-gradient(to top, rgb(12 12 11 / 0.92) 7rem, rgb(12 12 11 / 0.62) 20rem, transparent 28rem);
}

.not-found.has-photo {
  place-items: end start;
  padding: 0 var(--space-3) calc(var(--edge) + 4.5rem);
  text-align: left;
}

.not-found.has-photo .not-found__body {
  position: relative;
  z-index: 1;
}

/* Over a photo the corner links need full contrast, not the muted grey. */
.not-found.has-photo .orbit-corner {
  color: var(--text);
}

.not-found.has-photo .not-found__code {
  margin: var(--space-1) 0 var(--space-2);
  font-size: clamp(6rem, 30vw, 9rem);
}

.not-found.has-photo .not-found__message {
  color: rgb(241 239 233 / 0.82);
}

.not-found__credit {
  margin: var(--space-2) 0 0;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgb(241 239 233 / 0.6);
}

.not-found__credit a {
  color: var(--text);
  text-decoration: none;
}

.not-found__credit a:hover,
.not-found__credit a:focus-visible {
  color: var(--accent);
}

/* Wider screens: a portrait shot can't fill a landscape screen without
   cropping and blurring, so it takes over the right half, edge to edge, and
   the text sits on the dark left half, nothing over the picture. */
@media (min-width: 48rem) and (orientation: landscape) {
  .not-found__photo {
    inset: 0 0 0 auto;
    width: 50%;
  }

  /* Only the About and Email corners sit on the picture: a light shade at
     its top and foot keeps them readable. */
  .not-found__photo::after {
    background:
      linear-gradient(to bottom, rgb(12 12 11 / 0.6), transparent 18%),
      linear-gradient(to top, rgb(12 12 11 / 0.6), transparent 18%);
  }

  /* No orbit to make room for, so no minimum height: a phone held sideways
     keeps the frame to its screen rather than scrolling. */
  .not-found.has-photo {
    min-height: 0;
    place-items: center start;
    padding: 0 calc(50% + var(--space-5)) 0 clamp(var(--space-4), 8vw, 9rem);
  }

  /* Sized by height too, so the text fits between the corners on short screens. */
  .not-found.has-photo .not-found__code {
    font-size: clamp(4.5rem, min(15vw, 26svh), 15rem);
  }

  .not-found.has-photo .not-found__message {
    color: var(--text-muted);
  }
}

/* No orbit to wait for: the message rises and the corners follow straight away. */
@media (prefers-reduced-motion: no-preference) {
  .js .not-found__body {
    animation: project-rise 1000ms var(--ease-expo) backwards;
  }

  .js .not-found .orbit-corner {
    animation-delay: 250ms;
  }
}

/* ---- Orbit home ----
   The logo sits at the exact centre of a full-viewport stage, wrapped in a
   rotating text ring, and one image per project orbits it in 3D. main.js
   positions every .orbit-item each frame; without JavaScript the items stay
   hidden and the corner links and dial carry the page. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.orbit {
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --mark: clamp(7.5rem, 17vmin, 12rem);
  --edge: var(--space-3);
  position: relative;
  height: 100vh;
  height: 100svh;
  min-height: 32rem;
  overflow: hidden;
  isolation: isolate;
  background: var(--bg);
}

/* A phone held sideways is shorter than the minimum: keep the frame to the
   screen, so the dial and the bottom corners don't fall below the fold. The
   orbit centres in the band between the name and the dial, with a smaller
   logo, so the ring's lettering clears both. */
@media (orientation: landscape) and (max-height: 30rem) {
  .orbit {
    --mark: 6.5rem;
    min-height: 0;
  }

  .orbit .orbit-stage {
    top: 3.5rem;
    bottom: 7.5rem;
  }
}

/* Corners: a viewfinder frame, one link per corner. */
.orbit-corner {
  position: absolute;
  z-index: 3000;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
  transition: color 220ms var(--ease-out);
}

.orbit-corner::before {
  content: "";
  position: absolute;
  width: 0.9rem;
  height: 0.9rem;
  border: 0 solid currentColor;
  opacity: 0.6;
  transition: width 320ms var(--ease-expo), height 320ms var(--ease-expo), opacity 220ms;
}

.orbit-corner--tl { top: var(--edge); left: var(--edge); }
.orbit-corner--tr { top: var(--edge); right: var(--edge); flex-direction: row-reverse; }
.orbit-corner--bl { bottom: var(--edge); left: var(--edge); }
.orbit-corner--br { bottom: var(--edge); right: var(--edge); flex-direction: row-reverse; }

.orbit-corner--tl::before { top: 0; left: 0; border-top-width: 1.5px; border-left-width: 1.5px; }
.orbit-corner--tr::before { top: 0; right: 0; border-top-width: 1.5px; border-right-width: 1.5px; }
.orbit-corner--bl::before { bottom: 0; left: 0; border-bottom-width: 1.5px; border-left-width: 1.5px; }
.orbit-corner--br::before { bottom: 0; right: 0; border-bottom-width: 1.5px; border-right-width: 1.5px; }

/* Empty box the About page's portrait grows out of and shrinks back into. */
.orbit-corner__origin {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.orbit-corner__key {
  display: grid;
  place-items: center;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 4px;
  background: var(--bg-raised);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 400;
  color: var(--text-muted);
  transition: background 220ms, color 220ms;
}

.orbit-corner:hover,
.orbit-corner:focus-visible {
  color: var(--text);
}

.orbit-corner:hover::before,
.orbit-corner:focus-visible::before {
  width: 1.6rem;
  height: 1.6rem;
  opacity: 1;
  color: var(--accent);
}

.orbit-corner:hover .orbit-corner__key,
.orbit-corner:focus-visible .orbit-corner__key {
  background: var(--accent);
  color: var(--bg);
}

/* Stage */
.orbit-stage {
  position: absolute;
  inset: 0;
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}

.orbit-stage.is-dragging {
  cursor: grabbing;
}

.orbit-core {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1000;
  /* Lets the logo video's black background drop out (see .orbit-core__loop). */
  mix-blend-mode: screen;
  width: var(--mark);
  height: var(--mark);
  translate: -50% -50%;
  pointer-events: none;
}

.orbit-core__mark {
  position: absolute;
  inset: 0;
  background: var(--text);
  -webkit-mask: url(/assets/footer-mark.svg) center / contain no-repeat;
  mask: url(/assets/footer-mark.svg) center / contain no-repeat;
}

/* The 3D logo loop takes over from the flat mark when motion is allowed.
   It's a video on black, cropped close to the logo; screen blending makes
   the black drop out so the page and passing images show through. */
.orbit-core__loop {
  display: none;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 119.7%;
  pointer-events: none;
  max-width: none;
  height: auto;
  translate: -50% -50%;
}

@media (prefers-reduced-motion: no-preference) {
  .orbit-core__loop {
    display: block;
  }

  .orbit-core__mark {
    visibility: hidden;
  }
}

/* The ring is drawn above the cloud so it stays readable as images pass. */
.orbit-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2600;
  width: calc(var(--mark) * 1.8);
  height: calc(var(--mark) * 1.8);
  translate: -50% -50%;
  overflow: visible;
  transition: opacity 200ms var(--ease-out);
}

.orbit-ring.is-swapping {
  opacity: 0;
}

.orbit-ring text {
  fill: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 11px; /* rescaled by main.js to stay ~11px on screen */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: fill 300ms;
}

.orbit-stage.is-focused .orbit-ring text {
  fill: var(--text);
}

/* Items: size and transform are set by main.js */
.orbit-item {
  position: absolute;
  left: 0;
  top: 0;
  display: none;
  border-radius: 6px;
  overflow: hidden;
  background: var(--bg-raised);
  box-shadow: 0 1.25rem 2.5rem -1rem rgb(0 0 0 / 0.7);
  will-change: transform, opacity;
  transition: box-shadow 320ms var(--ease-out);
}

.js .orbit-item {
  display: block;
}

.orbit-item img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 320ms var(--ease-out), filter 320ms var(--ease-out);
}

.orbit-item--soon img {
  filter: grayscale(0.35) brightness(0.8);
}

.orbit-item__mark {
  position: absolute;
  inset: 28%;
  background: var(--text-muted);
  opacity: 0.3;
  -webkit-mask: url(/assets/footer-mark.svg) center / contain no-repeat;
  mask: url(/assets/footer-mark.svg) center / contain no-repeat;
  transition: opacity 320ms var(--ease-out);
}

/* Focus a project: its image stays lit, the rest step back. */
.orbit-stage.is-focused .orbit-item:not(.is-match) img {
  opacity: 0.18;
  filter: grayscale(1);
}

.orbit-stage.is-focused .orbit-item:not(.is-match) .orbit-item__mark {
  opacity: 0.08;
}

.orbit-item.is-match {
  box-shadow: 0 0 0 1.5px rgb(217 162 75 / 0.7), 0 1.5rem 3rem -1rem rgb(0 0 0 / 0.8);
}

/* Dial: a numbered scale along the bottom edge. */
.orbit-dial {
  position: absolute;
  left: 50%;
  bottom: var(--edge);
  z-index: 3000;
  translate: -50% 0;
}

.orbit-dial__label {
  margin: 0 0 0.35rem;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-align: center;
  text-transform: uppercase;
  color: var(--text-muted);
}

.orbit-dial__name {
  color: var(--text);
}

.orbit-dial__name:empty + .orbit-dial__sep {
  display: none;
}

.orbit-dial ol {
  display: flex;
  align-items: flex-end;
  margin: 0;
  padding: 0;
  list-style: none;
}

.orbit-dial a,
.orbit-dial li > span {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  text-decoration: none;
  cursor: default;
  transition: color 220ms var(--ease-out);
}

.orbit-dial a {
  cursor: pointer;
}

/* Tick above each number; it grows for the project in focus. */
.orbit-dial a::before,
.orbit-dial li > span::before {
  content: "";
  order: -1;
  width: 2px;
  height: 0.45rem;
  border-radius: 1px;
  background: currentColor;
  opacity: 0.5;
  transition: height 320ms var(--ease-expo), opacity 220ms, background 220ms;
}

.orbit-dial .is-soon {
  opacity: 0.4;
}

/* The project currently facing the viewer gets a small marker. */
.orbit-dial .is-front::before {
  height: 0.8rem;
  opacity: 1;
}

.orbit-dial a:hover,
.orbit-dial a:focus-visible,
.orbit-dial .is-active {
  color: var(--text);
}

.orbit-dial .is-active::before {
  height: 1.25rem;
  opacity: 1;
  background: var(--accent);
}

/* Name and role: one quiet line, top centre, in the voice of the dial and corners. */
.orbit-intro {
  position: absolute;
  top: calc(var(--edge) + 1.05rem);
  left: 50%;
  z-index: 3000;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin: 0;
  translate: -50% 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  pointer-events: none;
}

.orbit-intro__name,
.orbit-intro__role {
  margin: 0;
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  white-space: nowrap;
}

.orbit-intro__name {
  color: var(--text);
}

.orbit-intro__role {
  display: flex;
  align-items: center;
  gap: inherit;
  color: var(--text-muted);
}

/* A short rule between name and role. */
.orbit-intro__role::before {
  content: "";
  width: 1.5rem;
  height: 1px;
  background: currentColor;
  opacity: 0.6;
}

/* Phones: below the corner links, a little tighter. */
@media (max-width: 40rem) {
  .orbit-intro {
    top: calc(var(--edge) + 3.7rem);
    gap: 0.6rem;
    font-size: 0.66rem;
    letter-spacing: 0.12em;
  }

  .orbit-intro__role::before {
    width: 0.9rem;
  }
}

/* Dial row: the numbers, with what they are on the left and the one-time
   spin hint on the right, kept level with the numbers and out of the orbit. */
.orbit-dial__row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  column-gap: 1.25rem;
}

.orbit-dial__caption,
.orbit-dial__hint {
  margin: 0 0 0.35rem;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.orbit-dial__caption {
  justify-self: end;
}

.orbit-dial__hint {
  justify-self: start;
  color: var(--accent);
  transition: opacity 400ms var(--ease-out);
}

.orbit-dial__hint.is-done {
  opacity: 0;
}

/* Phones: no room either side, so both sit on one line under the numbers.
   Held sideways, the sides are where the bottom corners are. */
@media (max-width: 40rem), (orientation: landscape) and (max-height: 30rem) {
  .orbit-dial__row {
    grid-template-columns: auto auto;
    justify-content: center;
    column-gap: 0.9rem;
  }

  .orbit-dial__row ol {
    grid-column: 1 / -1;
    grid-row: 1;
  }

  .orbit-dial__caption,
  .orbit-dial__hint {
    grid-row: 2;
    margin: 0.5rem 0 0;
  }

  .orbit-dial__caption:has(+ ol + .orbit-dial__hint:not([hidden]))::after {
    content: " ·";
  }
}


/* Intro: the mark rises first, then main.js throws the images out. */
@media (prefers-reduced-motion: no-preference) {
  .js .orbit-core {
    opacity: 0;
    animation: orbit-mark-rise 1000ms var(--ease-expo) 150ms forwards;
  }

  .js .orbit-ring {
    animation: orbit-ring-in 1200ms var(--ease-expo) 900ms backwards, orbit-ring-spin 60s linear infinite;
  }

  .js .orbit-corner,
  .js .orbit-intro,
  .js .orbit-dial__row,
  .js .orbit-dial__label {
    opacity: 0;
    animation: orbit-fade 900ms var(--ease-out) 1300ms forwards;
  }
}

/* Contact panel (opened from the Email corner) */
.orbit-contact {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: var(--space-4);
  border: 0;
  background: var(--bg-raised);
  color: var(--text);
  view-transition-name: contact-panel;
}

.orbit-contact[open] {
  display: grid;
  align-items: end;
}

.orbit-contact::backdrop {
  background: transparent;
}

.orbit-contact__body {
  display: grid;
  gap: var(--space-2);
  justify-items: start;
  padding-bottom: var(--space-4);
}

.orbit-contact__label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.orbit-contact__email {
  max-width: 100%;
  font-family: var(--font-display);
  font-size: clamp(2rem, 7.5vw, 7rem);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1;
  overflow-wrap: anywhere;
  color: var(--text);
  text-decoration: none;
  transition: color 220ms;
}

.orbit-contact__email:hover,
.orbit-contact__email:focus-visible {
  color: var(--accent);
}

.orbit-contact__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-top: var(--space-2);
}

.orbit-contact__copy,
.orbit-contact__link {
  padding: 0.7rem 1.1rem;
  border: 0;
  border-radius: 999px;
  background: var(--bg);
  font: inherit;
  font-size: 0.95rem;
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
  transition: background 220ms, color 220ms;
}

.orbit-contact__copy:hover,
.orbit-contact__copy:focus-visible,
.orbit-contact__link:hover,
.orbit-contact__link:focus-visible {
  background: var(--text);
  color: var(--bg);
}

/* Back from a project: no intro, the page should already be there. */
.orbit.is-returning .orbit-core,
.orbit.is-returning .orbit-corner,
.orbit.is-returning .orbit-intro,
.orbit.is-returning .orbit-dial__row,
.orbit.is-returning .orbit-dial__label {
  opacity: 1;
  animation: none;
}

@media (prefers-reduced-motion: no-preference) {
  .orbit.is-returning .orbit-ring {
    animation: orbit-ring-spin 60s linear infinite;
  }
}

@keyframes orbit-mark-rise {
  from {
    opacity: 0;
    transform: translateY(2.5rem) scale(0.86);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes orbit-ring-in {
  from {
    opacity: 0;
    scale: 0.7;
  }
}

@keyframes orbit-ring-spin {
  to {
    rotate: 360deg;
  }
}

@keyframes orbit-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@media (max-width: 40rem) {
  .orbit {
    --edge: var(--space-1);
  }

  .orbit-corner {
    font-size: 0.9rem;
  }

  /* Sit the dial above the bottom corner links. */
  .orbit-dial {
    bottom: calc(var(--edge) + 3.25rem);
  }

  .orbit-dial a,
  .orbit-dial li > span {
    padding-inline: 0.3rem;
  }
}

/* ---- Plan demo (Customer Proposal) ----
   The proposal's plan section rebuilt in HTML, with tabs to switch programs
   (main.js). Sizes are in em, where 1em is 16px in the Figma file, so the
   whole section scales with its frame. Haven's typeface is used when it's
   installed; otherwise the body grotesk stands in. */
@font-face {
  font-family: "Haven Acid Grotesk";
  src: local("FFF Acid Grotesk Book"), local("FFFAcidGrotesk-Book");
  font-weight: 400;
}

@font-face {
  font-family: "Haven Acid Grotesk";
  src: local("FFF Acid Grotesk Medium"), local("FFFAcidGrotesk-Medium");
  font-weight: 500;
}

.plan-demo__tabs {
  display: flex;
  flex: none; /* never squeezed by a tall plan below */
  gap: var(--space-1);
  margin-bottom: var(--space-2);
  overflow-x: auto;
  scrollbar-width: none;
}

.plan-demo__tab {
  position: relative;
  flex: none;
  padding: 0.55rem 0.95rem;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--text) 18%, transparent);
  border-radius: 999px;
  background: none;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 200ms, border-color 200ms;
}

.plan-demo__tab:hover {
  color: var(--text);
}

.plan-demo__tab[aria-selected="true"] {
  border-color: var(--accent);
  color: var(--text);
}

/* While it plays itself, the open tab fills up until the next one. */
.plan-demo__tab::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}

.plan-demo.is-auto .plan-demo__tab[aria-selected="true"]::after {
  animation: plan-dwell 4200ms linear forwards;
}

@keyframes plan-dwell {
  to {
    transform: scaleX(1);
  }
}

.plan-demo__screen {
  position: relative;
  container-type: inline-size;
  overflow: hidden;
  border-radius: 4px;
  background: #fff;
  color: #050505;
}

.haven-plan,
.plan-sheet {
  font-family: "Haven Acid Grotesk", var(--font-body);
  font-size: calc(100cqw / 25.125); /* the 402px phone build */
  line-height: 1.4;
}

.haven-plan {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5em;
  padding: 2em 1em; /* 32 16 */
}

.haven-plan p,
.haven-plan h3,
.haven-plan ul,
.haven-plan dl,
.haven-plan dd,
.plan-sheet p,
.plan-sheet h4 {
  margin: 0;
}

/* Headings take Haven's typeface, not the site's display face. */
.haven-plan :is(h3, h4),
.plan-sheet h4,
.haven-battery :is(h3, h4) {
  font-family: inherit;
}

.haven-plan__eyebrow {
  font-size: 0.875em;
  font-weight: 500;
  line-height: 1.5;
  color: #545454;
  text-transform: uppercase;
}

.haven-plan__details .haven-plan__eyebrow,
.haven-plan__rebates .haven-plan__eyebrow {
  font-size: 1em;
  line-height: 1.0625;
}

.haven-plan__title {
  margin-top: 0.4em !important;
  font-size: 2.25em;
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.015em;
}

.haven-plan__offer {
  display: flex;
  align-items: flex-start;
  gap: 1.25em;
  margin-top: 1.25em;
}

.haven-plan__badge {
  flex: none;
  padding: 1em;
  border-radius: 0.5em;
  background: #ddff0e;
}

/* $ 20, number 48, /mo 24, all at 145% leading, as in Figma. */
.haven-plan__amount {
  display: flex;
  align-items: baseline;
  font-weight: 500;
  line-height: 1.45;
}

.haven-plan__amount sup {
  align-self: flex-start;
  margin-top: 0.8em; /* 16px down the number's line, as in Figma */
  font-size: 1.25em;
  line-height: 1.45;
  vertical-align: baseline;
}

.haven-plan__amount [data-price] {
  font-size: 3em;
}

.haven-plan__per {
  font-size: 1.5em;
}

.haven-plan__tax {
  color: #545454;
  font-size: 0.75em;
  text-align: center;
}

.haven-plan__terms {
  padding: 0.6em 0 0;
  list-style: none;
  font-size: 0.875em;
  line-height: 1.5;
}

.haven-plan__terms li > *,
.haven-plan__terms li:not(.haven-plan__fold)::before {
  display: block;
}

.haven-plan__terms li:not(.haven-plan__fold),
.haven-plan__terms li > span {
  position: relative;
  padding-left: 1em;
}

.haven-plan__terms li:not(.haven-plan__fold)::before,
.haven-plan__terms li > span::before {
  content: "•";
  position: absolute;
  left: 0.2em;
}

.haven-plan__side {
  display: grid;
}

.haven-plan__schedule > div {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1em;
  padding: 0.75em 0;
  border-bottom: 1px solid #d3d3d3;
  line-height: 1.6;
}

.haven-plan__schedule > div:first-child {
  padding-top: 0;
}

.haven-plan__schedule dd {
  padding-top: 0.25em;
  font-size: 0.9375em;
  font-weight: 500;
  line-height: 1.067;
  text-align: right;
}

.haven-plan__footnote {
  padding: 0.85em 0 1.5em;
  color: #545454;
  font-size: 0.75em;
}

.haven-plan__note {
  position: relative;
  padding: 1em 1.25em;
  border: 1px solid #efff8c;
  border-radius: 0.5em;
  background: #f6ffbf;
}

.haven-plan__pill {
  display: inline-flex;
  align-items: center;
  margin-bottom: 0.857em !important;
  padding: 0.286em 1.143em 0.286em 0.714em; /* 4 16 4 10 */
  border-radius: 1.5em;
  background: #ddff0e;
  font-size: 0.875em;
  font-weight: 500;
  line-height: 1.5;
}

.haven-plan__pill svg {
  width: 1.4em;
  height: 1.4em;
}

.haven-plan__note-text {
  max-width: 24em;
  padding-right: 3.5em;
  font-size: 0.9375em;
  font-weight: 500;
  line-height: 1.067;
}

.haven-plan__callout {
  margin-top: 0.9em;
  padding: 0.9em 1em;
  border-radius: 0.5em;
  background: #fff;
  font-size: 0.875em;
  font-weight: 500;
}

.haven-plan__callout svg {
  width: 2em;
  margin-right: 0.4em;
  vertical-align: -0.15em;
}

.haven-plan__callout-note {
  margin-top: 0.5em !important;
  color: #8a8a8a;
  font-size: 0.85em;
  font-weight: 400;
}

.haven-plan__more {
  margin-top: 0.9em;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.8125em;
  line-height: 1.35;
  cursor: pointer;
}

.haven-plan__coin {
  position: absolute;
  top: 0.75em;
  right: 1em;
  width: 3.75em;
}

/* ConnectedSolutions adds a rebate under the plan details. */
.haven-plan__rebates {
  margin-top: 1.5em;
  padding-top: 1.5em;
  border-top: 1px solid #cfcfcf;
}

.haven-plan__rebates-text {
  margin-top: 1.5em !important;
  font-size: 1.25em;
  line-height: 1.45;
}

.haven-plan__rebate {
  margin-top: 1.5em;
  padding: 1.5em;
  border-radius: 0.5em;
  background: #f6ffbf;
  box-shadow: inset 0 0 0 2px #ddff0e;
}

.haven-plan__rebate-title {
  font-size: 1.0625em;
  font-weight: 500;
  line-height: 1.06;
}

.haven-plan__rebate p + p {
  margin-top: 0.5em;
  color: #3f3f3f;
  font-size: 0.875em;
  line-height: 1.4;
}

.haven-plan__rebate-more {
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* The rest of the plan section, the same for every program. */
.haven-plan__details {
  padding-top: 1.75em;
  border-top: 1px solid #d3d3d3;
}

.haven-plan__toggle {
  display: flex;
  margin-top: 1.25em !important;
  padding: 0.25em;
  overflow: hidden;
  border-radius: 2em;
  background: #f5f5f5;
  box-shadow: inset 0 0 0 1px #e6e6e6;
  font-size: 0.8125em;
  line-height: 1.35;
  white-space: nowrap;
}

.haven-plan__toggle span {
  flex: 1;
  padding: 0.615em 1.846em; /* 8 24 */
  border-radius: 2em;
  text-align: center;
}

.haven-plan__toggle .is-active {
  background: #050505;
  color: #fff;
  font-weight: 500;
}

.haven-plan__card {
  display: flex;
  gap: 0.857em; /* 12 */
  margin-top: 1.25em;
  padding: 1.714em; /* 24 */
  border-radius: 1.43em;
  background: #f5f5f5;
  box-shadow: inset 0 0 0 1px #e6e6e6;
  font-size: 0.875em;
  line-height: 1.5;
}

.haven-plan__card svg {
  flex: none;
  width: 2.571em; /* 36 */
  height: 2.571em;
}

.haven-plan__card-title {
  margin-bottom: 0.5em !important;
  font-size: 1.714em; /* 24 */
  font-weight: 500;
  line-height: 1.3;
}

/* Switching programs: text that changes crossfades in place, and parts
   that come and go fold open and shut. */
.haven-plan__swap {
  position: relative;
  display: grid;
}

/* The outgoing text leaves the flow, so the block takes the height of
   what's showing. */
.haven-plan__swap > [data-for]:not(.is-on) {
  position: absolute;
  inset: 0 0 auto;
}

.haven-plan__swap > [data-for] {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(0.35em);
  visibility: hidden;
  transition: opacity 250ms, transform 400ms var(--ease-out), visibility 0s 400ms;
}

.haven-plan__swap > .is-on {
  opacity: 1;
  transform: none;
  visibility: visible;
  transition: opacity 350ms 120ms, transform 500ms 120ms var(--ease-out), visibility 0s;
}

.haven-plan__fold {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 450ms var(--ease-out), opacity 200ms;
}

.haven-plan__fold.is-on {
  grid-template-rows: 1fr;
  opacity: 1;
  transition: grid-template-rows 450ms var(--ease-out), opacity 350ms 150ms;
}

.haven-plan__fold > * {
  min-height: 0;
  overflow: hidden;
}

/* Learn more: the program explainer over a dimmed plan. */
.plan-sheet {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  padding: 1em;
  background: rgb(0 0 0 / 0.4);
  opacity: 0;
  transition: opacity 250ms;
}

.plan-sheet[hidden] {
  display: none;
}

.plan-sheet.is-open {
  opacity: 1;
}

.plan-sheet__dialog {
  position: relative;
  box-sizing: border-box;
  width: min(37.5em, 100%);
  max-height: 100%;
  padding: 2.5em 2em 2em;
  overflow-y: auto;
  border-radius: 0.75em;
  background: #fff;
  text-align: left;
  transform: translateY(1em) scale(0.98);
  transition: transform 350ms var(--ease-out);
}

.plan-sheet.is-open .plan-sheet__dialog {
  transform: none;
}

.plan-sheet .haven-plan__pill {
  display: flex;
  width: max-content;
  margin: 0 auto 1.75em !important;
}

.plan-sheet__close {
  position: absolute;
  top: 1em;
  right: 1em;
  display: grid;
  width: 2em;
  height: 2em;
  padding: 0.35em;
  border: 0;
  border-radius: 50%;
  background: #e6e6e6;
  color: #545454;
  cursor: pointer;
}

.plan-sheet h4 {
  margin-bottom: 0.4em;
  font-size: 1.25em;
  font-weight: 500;
}

.plan-sheet__body:not(.is-on) {
  display: none;
}

.plan-sheet__body p {
  font-size: 0.875em;
}

.plan-sheet__body p + p {
  margin-top: 1.1em;
}

.plan-sheet b {
  font-weight: 500;
}

/* How your battery works: Haven's own toggle switches the situation, its
   pill sliding to the chosen one while the copy and illustration crossfade. */
.battery-demo {
  container-type: inline-size;
}

.haven-battery {
  padding: 2em 1em;
  border-radius: 4px;
  background: #124137;
  color: #fff;
  font-family: "Haven Acid Grotesk", var(--font-body);
  font-size: calc(100cqw / 25.125); /* the 402px phone build */
  line-height: 1.4;
}

.haven-battery p,
.haven-battery h3,
.haven-battery h4 {
  margin: 0;
}

.haven-battery__eyebrow {
  color: #4ba996;
  font-size: 0.9375em;
  font-weight: 500;
  line-height: 1.0625;
  text-transform: uppercase;
}

.haven-battery__title {
  margin-top: 0.5em !important;
  font-size: 2.625em;
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.015em;
}

.haven-battery__intro {
  max-width: 34.5em;
  margin-top: 0.6em !important;
  color: #f5f5f5;
  font-size: 1.25em;
  line-height: 1.45;
}

.haven-battery__toggle {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: 2.25em; /* 36px buttons; 42px on desktop */
  margin-top: 1.75em;
  padding: 0.25em;
  border-radius: 1.875em;
  background: #1c584b;
  box-shadow: inset 0 0 0 1px #318272; /* an inside stroke, as in Figma */
}

/* The pill slides under whichever situation is chosen. */
.haven-battery__toggle::before {
  content: "";
  position: absolute;
  top: 0.25em;
  bottom: 0.25em;
  left: 0.25em;
  width: calc((100% - 0.5em) / 3);
  box-sizing: border-box;
  border: 1px solid #bde100;
  border-radius: 1.875em;
  background: #ddff0e;
  transform: translateX(calc(var(--tab, 0) * 100%));
  transition: transform 550ms var(--ease-expo);
}

.haven-battery__tab {
  position: relative;
  min-width: 0;
  padding: 0 0.5em;
  overflow: hidden;
  border: 0;
  background: none;
  color: #4ba996;
  font: inherit;
  font-size: 0.75em;
  line-height: 1.4;
  white-space: nowrap;
  text-overflow: ellipsis;
  cursor: pointer;
  transition: color 300ms;
}

.haven-battery__tab[aria-selected="true"] {
  color: #050505;
  font-size: 0.8125em;
  font-weight: 500;
  line-height: 1.35;
}

.haven-battery__tab:focus-visible {
  outline-offset: -2px;
}

.haven-battery__panel {
  display: grid;
  gap: 1.5em;
  margin-top: 1.25em;
  padding: 1.75em 1.5em;
  border-radius: 1.25em;
  background: #1c584b;
}

.haven-battery__panel h4 {
  color: #efff8c;
  font-size: 2.25em;
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.015em;
}

.haven-battery__panel h4 + p {
  margin-top: 0.6em;
  color: #f5f5f5;
  font-size: 1.125em;
  line-height: 1.45;
}

.haven-battery__note {
  display: flex;
  align-items: center;
  gap: 0.5715em; /* 8px */
  margin-top: 1.5em;
  padding: 0.857em; /* 12px */
  background: #318272;
  font-size: 0.875em;
  line-height: 1.4;
}

.haven-battery__note svg {
  flex: none;
  width: 1.7em;
  height: 1.7em;
}

.haven-battery__art {
  display: grid;
  justify-items: center;
}

/* Copy and line breaks that differ between the phone and desktop builds. */
.haven-copy--wide {
  display: none;
}

.battery-demo .haven-battery__art img {
  grid-area: 1 / 1;
  width: min(100%, 20em);
  height: auto;
  max-width: none;
  border-radius: 0;
  opacity: 0;
  transform: translateY(0.75em) scale(0.96);
  visibility: hidden;
  transition: opacity 300ms, transform 500ms var(--ease-out), visibility 0s 500ms;
}

.battery-demo .haven-battery__art img.is-on {
  opacity: 1;
  transform: none;
  visibility: visible;
  transition: opacity 450ms 150ms, transform 700ms 150ms var(--ease-expo), visibility 0s;
}

/* Wide screens: the desktop build, as tall as the pictures on the track.
   The section continues past the bottom edge, as it does on the page. */
@media (min-width: 48rem) {
  .plan-demo {
    --plan-h: calc(100svh - 2 * var(--pad-y) - 2rem);
    display: flex;
    flex-direction: column;
    width: min(calc(var(--plan-h) * 1.9), 85vw);
    max-height: var(--plan-h);
  }

  /* A plan taller than the track scrolls inside the frame, and fades at
     the bottom while there's more below. */
  .plan-demo__screen {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .plan-demo__scroll {
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }

  .plan-demo__scroll.is-clipped {
    -webkit-mask-image: linear-gradient(to bottom, #000 82%, transparent);
    mask-image: linear-gradient(to bottom, #000 82%, transparent);
  }

  .haven-plan__rebate-title {
    font-size: 1.1875em;
    line-height: 1.05;
  }

  .haven-plan,
  .plan-sheet {
    font-size: calc(100cqw / 84);
  }

  .haven-plan {
    grid-template-columns: 38.5em 37.5em;
    gap: 2.5em 0;
    padding: 3.5em 4em;
  }

  .haven-plan__title {
    font-size: 2.625em;
  }

  .haven-plan__eyebrow {
    font-size: 1em;
    line-height: 1.0625;
  }

  .haven-plan__schedule > div {
    align-items: center;
  }

  .haven-plan__schedule dd {
    padding-top: 0;
    font-size: 1em;
  }

  .haven-plan__note {
    padding: 1.25em;
  }

  .haven-plan__note-text {
    font-size: 1em;
    line-height: 1.4;
  }

  .haven-plan__more {
    text-decoration: underline;
    text-underline-offset: 0.2em;
  }

  .haven-plan__toggle {
    font-size: 0.875em;
  }

  .haven-plan__toggle span {
    padding: 0.6em 1.25em;
  }

  .haven-plan__offer {
    margin-top: 1.75em;
  }

  .haven-plan__details {
    grid-column: 1 / -1;
  }

  .haven-plan__toggle {
    width: max-content;
  }

  .haven-plan__toggle span {
    flex: none;
  }

  .plan-sheet__dialog {
    padding: 3em 3.25em;
  }

  .battery-demo {
    width: min(calc((100svh - 2 * var(--pad-y) - 2rem) * 1.9), 85vw);
  }

  .haven-battery {
    padding: 3em 4em;
    font-size: calc(100cqw / 84);
  }

  .haven-battery__title {
    font-size: 2.625em;
  }

  .haven-battery__eyebrow {
    font-size: 1em;
  }

  .haven-copy--wide {
    display: inline;
  }

  .haven-copy--narrow {
    display: none;
  }

  .haven-battery__toggle {
    grid-auto-rows: 2.625em;
    margin-top: 2em;
  }

  .haven-battery__tab,
  .haven-battery__tab[aria-selected="true"] {
    font-size: 0.875em;
  }

  .haven-battery__panel {
    grid-template-columns: minmax(0, 41.25em) 17.5em;
    justify-content: space-between;
    align-items: center;
    padding: 2.25em 3em 2.25em 2em;
  }

  .haven-battery__panel h4 {
    font-size: 2.625em;
  }

  .haven-battery__panel h4 + p {
    font-size: 1.25em;
  }

  .battery-demo .haven-battery__art img {
    width: 100%;
  }
}

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

/* Keycap press: pill buttons sit on a thin edge and travel down onto it
   when pressed, the way a key does. */
.project-close,
.viewer button,
.orbit-contact__copy,
.orbit-contact__link {
  box-shadow: 0 2px 0 rgb(0 0 0 / 0.35);
  transition: background 220ms, color 220ms, transform 90ms var(--ease-out), box-shadow 90ms var(--ease-out);
}

.project-close:active,
.viewer button:active,
.orbit-contact__copy:active,
.orbit-contact__link:active {
  transform: translateY(2px);
  box-shadow: 0 0 0 rgb(0 0 0 / 0.35);
}

/* The next-project card gives a little under the finger. */
.project-next {
  transition: transform 140ms var(--ease-out);
}

.project-next:active {
  transform: scale(0.985);
}

/* Mouse users can drag the case-study track; text keeps its own cursor. */
@media (min-width: 48rem) {
  .project-track {
    cursor: grab;
  }

  .project-track :is(.project-text, .plan-demo, .battery-demo) {
    cursor: auto;
  }

  .project-track.is-dragging,
  .project-track.is-dragging * {
    cursor: grabbing;
    user-select: none;
  }

  .project-track.is-dragging a,
  .project-track.is-dragging img {
    pointer-events: none;
  }
}

/* Phones: text scrolling under the progress bar fades out before it gets
   there, so the bar and its chapter ticks never strike through a line. */
@media (max-width: 47.99rem) {
  .project::after {
    content: "";
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 19;
    height: calc(var(--space-2) + 2.25rem);
    background: linear-gradient(to top, var(--ambient, var(--bg)) 40%, transparent);
    pointer-events: none;
  }
}

/* Phones: Close tucks up out of the way while scrolling down (see main.js). */
@media (max-width: 47.99rem) {
  .project-close {
    transition: background 220ms, color 220ms, transform 90ms var(--ease-out), box-shadow 90ms var(--ease-out), translate 300ms var(--ease-out), opacity 300ms var(--ease-out);
  }

  .project-close.is-tucked:not(:focus-visible) {
    translate: 0 calc(-100% - var(--space-3) - env(safe-area-inset-top, 0px));
    opacity: 0;
    pointer-events: none;
  }
}

/* Phones: a new section reads as one, not as the next paragraph. */
@media (max-width: 47.99rem) {
  .project-text:not(:first-child):has(> h2:first-child) {
    margin-top: var(--space-5);
  }
}

/* Phones: the details row in two columns, so values like "Product Designer" fit on one line. */
@media (max-width: 40rem) {
  .project-meta {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Very wide pictures on phones (main.js marks them): a readable height,
   bleeding to the screen edges, panned sideways. */
.project-strip__hint {
  display: none;
}

@media (max-width: 47.99rem) {
  .project-figure--strip .project-strip {
    margin-inline: calc(-1 * var(--space-3));
    padding-inline: var(--space-3);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .project-figure--strip .project-strip::-webkit-scrollbar {
    display: none;
  }

  .project-figure--strip img {
    width: auto;
    max-width: none;
    height: 15rem;
  }

  /* Collages need more height than a timeline to read; an annotated
     diagram can ask for more still (--pan-h). */
  .project-figure--strip .project-pan {
    height: var(--pan-h, 24rem);
  }

  .project-strip__hint {
    display: block;
    margin: var(--space-1) 0 0;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    transition: opacity 300ms var(--ease-out);
  }

  .project-figure--strip.is-panned .project-strip__hint {
    opacity: 0;
  }
}

/* Phones: the page scrolls down, not sideways, so the hint sits under the
   title (clear of it and of the bottom fade) and its arrow points down. */
@media (max-width: 47.99rem) {
  .project-hero__text {
    bottom: calc(var(--space-5) + 1.75rem);
  }

  .project-hero__hint {
    left: var(--space-4);
    right: auto;
    bottom: calc(var(--space-2) + 2.5rem);
    color: var(--text-muted);
  }

  .project-hero__hint span {
    rotate: 90deg;
  }
}

@media (max-width: 47.99rem) and (prefers-reduced-motion: no-preference) {
  .project-hero__hint span {
    animation-name: project-nudge-down;
  }
}

@keyframes project-nudge-down {
  50% {
    translate: 0 0.35rem;
  }
}

/* Phones: a smaller mark leaves the tiles more room before they fade near it. */
@media (max-width: 40rem) {
  .orbit {
    --mark: clamp(5.75rem, 26vmin, 7.5rem);
  }
}

/* Phones: the address scales to fit the width on one line. */
@media (max-width: 40rem) {
  .orbit-contact__email {
    font-size: min(2rem, calc((100vw - 4rem) / 11.5));
  }
}

/* ---- Prototype rebuilds ----
   The deck's interactive components (Energy Actions, Watt Check), rebuilt as
   live pieces from their Figma states. A stage keeps the component's
   proportions (--r); everything on it is placed in percentages, and text is
   sized against the stage's width. */
.proto__stage {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: var(--r);
  overflow: hidden;
  border-radius: 4px;
  container-type: inline-size;
}

.proto__stage picture,
.proto-marks picture,
.proto-outlet picture {
  display: block;
}

.project-figure .proto__stage img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 0;
}

/* Wide screens: as tall as the other pictures on the track, unless that
   would make it wider than 85vw. */
@media (min-width: 48rem) {
  .project-figure .proto__stage {
    width: min(85vw, (100svh - 2 * var(--pad-y) - 2rem) * var(--r));
    max-width: none;
  }

  .project-figure .proto__stage img {
    max-width: none;
    height: auto;
    object-fit: fill;
  }
}

.proto__stage :is(button, select):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Numbered findings: the deck's yellow bullets bounce in, one after another
   (800, 1000 and 1200ms, a bouncy 958ms spring). */
.proto-marks,
.proto-outlet {
  position: relative;
}

/* Wide screens size the picture by height, so the wrapper hugs its width.
   (On phones the picture takes the column's width; hugging it there would
   collapse a lazy picture to nothing before it loads.) */
@media (min-width: 48rem) {
  .proto-marks,
  .proto-outlet {
    width: fit-content;
    max-width: 100%;
  }
}

.proto-marks__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.proto-mark circle {
  fill: #ffb705;
}

.proto-mark text {
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 700;
  text-anchor: middle;
  dominant-baseline: central;
  fill: #000;
}

.proto-mark {
  transform-box: fill-box;
  transform-origin: center;
}

.js [data-proto="marks"]:not(.is-playing) .proto-mark {
  scale: 0;
}

.js [data-proto="marks"].is-playing .proto-mark {
  animation: proto-bounce 958ms calc(800ms + var(--i) * 200ms) both;
}

@keyframes proto-bounce {
  0% { scale: 0; animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1); }
  45% { scale: 1.18; animation-timing-function: ease-in-out; }
  68% { scale: 0.93; animation-timing-function: ease-in-out; }
  85% { scale: 1.04; animation-timing-function: ease-in-out; }
  100% { scale: 1; }
}

/* The challenge outlet: its two slots glance around like eyes (Device Icon:
   1s, then top left, top right, bottom right and forward, 200ms each). */
.proto-outlet__slot {
  position: absolute;
  left: var(--x);
  top: 48.28%;
  width: 4.573%;
  height: 10.37%;
  border-radius: 999px;
  background: #a09e9e;
}

/* Phones: the notes need more height than the column gives them, so the
   outlet keeps a readable height and pans sideways, like a wide picture. */
@media (max-width: 47.99rem) {
  .proto-pan {
    margin-inline: calc(-1 * var(--space-3));
    padding-inline: var(--space-3);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .proto-pan::-webkit-scrollbar {
    display: none;
  }

  .proto-pan .proto-outlet {
    width: fit-content;
  }

  .project-figure .proto-pan .proto-outlet img {
    width: auto;
    max-width: none;
    height: 36rem;
  }
}

.js .proto-outlet.is-playing .proto-outlet__slot {
  animation: proto-glance 5s infinite;
}

@keyframes proto-glance {
  0%, 20% { translate: 0 0; animation-timing-function: var(--ease-out); }
  24%, 34% { translate: -80% -23.7%; animation-timing-function: var(--ease-out); }
  38%, 48% { translate: 80% -23.7%; animation-timing-function: var(--ease-out); }
  52%, 62% { translate: 53.3% 23.7%; animation-timing-function: var(--ease-out); }
  66%, 100% { translate: 0 0; }
}

/* Convergence: tap the card and its bottom sheet rises (450ms ease-out);
   Close or Dismiss lowers it again. */
.proto-sheet {
  background: #000;
}

.proto-sheet__card {
  position: absolute;
  left: 9.33%;
  top: 35.45%;
  width: 81.25%;
  padding: 0;
  border: 0;
  border-radius: 3cqw;
  background: none;
  cursor: pointer;
}

/* The card's hover state is a grey tint. */
.proto-sheet__card:hover img {
  filter: brightness(0.84);
}

.proto-sheet__sheet {
  position: absolute;
  left: 5.6%;
  top: 2.98%;
  width: 88.81%;
  translate: 0 110%;
  transition: translate 450ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.proto-sheet.is-open .proto-sheet__sheet {
  translate: 0 0;
}

.proto-sheet__sheet button {
  position: absolute;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  transition: background-color 100ms;
}

.proto-sheet__sheet button:hover {
  background: rgb(0 0 0 / 0.08);
}

.proto-sheet__sheet button:active {
  background: rgb(0 0 0 / 0.16);
}

.proto-sheet__close {
  left: 87.6%;
  top: 1.85%;
  width: 8%;
  aspect-ratio: 1;
  border-radius: 50%;
}

.proto-sheet__try {
  left: 5.25%;
  top: 81.1%;
  width: 89.5%;
  height: 6.3%;
  border-radius: 2.6cqw;
}

.proto-sheet__dismiss {
  left: 25%;
  top: 90%;
  width: 50%;
  height: 4.4%;
  border-radius: 2.6cqw;
}

/* Outcome: hovering a slice pulls it out of the ring and shows its numbers
   (300ms ease-out); at rest the centre says who saw the action. */
.proto-donut {
  display: flex;
  flex-direction: column;
  background: #ffb705;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Arial, sans-serif;
}

.proto-donut__chart {
  position: relative;
  aspect-ratio: 1001 / 900;
}

.proto-donut__ring {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.proto-donut__slice {
  cursor: pointer;
  transition: translate 300ms var(--ease-out);
}

.proto-donut__slice.is-on {
  translate: var(--dx) var(--dy);
}

.proto-donut__tip {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: max-content;
  min-width: var(--w);
  margin: 0;
  padding: 1.6cqw;
  border-radius: 1.2cqw;
  background: #fff;
  box-shadow: 0 0.4cqw 1.6cqw rgb(2 25 64 / 0.12);
  font-size: max(11px, 1.7cqw);
  line-height: 1.41;
  letter-spacing: -0.02em;
  color: #021940;
  opacity: 0;
  translate: 0 0.6cqw;
  transition: opacity 300ms var(--ease-out), translate 300ms var(--ease-out);
  pointer-events: none;
}

.proto-donut__tip span {
  display: block;
  margin-bottom: 0.8cqw;
  font-size: max(10px, 1.4cqw);
  font-weight: 700;
  line-height: 1.14;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.proto-donut__tip.is-on {
  opacity: 1;
  translate: 0 0;
}

.proto-donut__legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 3cqw;
  margin-top: auto;
  padding: 0 4cqw 5cqw;
}

.proto-donut__legend button {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.3em 0.2em;
  border: 0;
  background: none;
  font: inherit;
  font-size: max(12px, 1.6cqw);
  color: #021940;
  cursor: pointer;
}

.proto-donut__legend button::before {
  content: "";
  width: 0.9em;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--c);
}

.proto-donut__legend button[aria-pressed="true"] {
  font-weight: 700;
}

/* Too narrow for the cards beside the ring: each takes the ring's centre. */
@container (max-width: 34rem) {
  .proto-donut__tip {
    left: 50%;
    top: 49.5%;
    min-width: 0;
    translate: -50% -46%;
  }

  .proto-donut__tip.is-on {
    translate: -50% -50%;
  }
}

/* Phone screens on black, as in the deck. */
.proto-phone {
  background: #000;
}

.proto-phone__screen {
  position: absolute;
  left: 8.33%;
  top: 4.23%;
  width: 83.33%;
  aspect-ratio: 375 / 812;
  overflow: hidden;
  border-radius: 6.6cqw;
}

/* Device selection: one device at a time; Continue enables once one is chosen
   (instant, as in the prototype). */
.proto-picker__state {
  position: absolute;
  inset: 0;
  visibility: hidden;
}

.proto-picker__state.is-on {
  visibility: visible;
}

.proto-picker__state:first-child {
  position: relative;
}

.proto-picker__tile {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  height: 12.68%;
  padding: 0;
  border: 0;
  border-radius: 2.67cqw;
  background: transparent;
  color: transparent;
  font-size: 0;
  cursor: pointer;
}

/* Results and recovery: four screens build in one after another (from 1s,
   200ms apart); hovering one dims it and names what it's made of. */
.proto-screens {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 2.5%;
  align-items: start;
  padding: 2.5%;
  background: #000;
}

.proto-screens__screen {
  position: relative;
  aspect-ratio: 375 / 812;
  overflow: hidden;
  border-radius: 2.3cqw;
  outline: none;
}

.proto-screens__screen:focus-visible {
  box-shadow: 0 0 0 2px var(--accent);
}

.project-figure .proto-screens .proto-screens__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
}

.proto-screens__layer:not([data-step="0"]) {
  opacity: 0;
}

/* Discovery to result: the rings rise and shrink into the header as the
   result settles in (895ms, gentle). */
.proto-screens__layer[data-step="0"],
.proto-screens__layer[data-step="1"] {
  transition: opacity 895ms cubic-bezier(0.22, 1, 0.36, 1), translate 895ms cubic-bezier(0.22, 1, 0.36, 1), scale 895ms cubic-bezier(0.22, 1, 0.36, 1);
}

.proto-screens__layer[data-step="1"] {
  translate: 0 4%;
}

[data-step-at="1"] .proto-screens__layer[data-step="0"],
[data-step-at="2"] .proto-screens__layer[data-step="0"] {
  opacity: 0;
  translate: 0 -34%;
  scale: 0.5;
}

[data-step-at="1"] .proto-screens__layer[data-step="1"],
[data-step-at="2"] .proto-screens__layer[data-step="1"] {
  opacity: 1;
  translate: 0 0;
}

/* Result to results: a 1s dissolve. */
.proto-screens__layer[data-step="2"] {
  transition: opacity 1000ms ease-in-out;
}

[data-step-at="2"] .proto-screens__layer[data-step="2"] {
  opacity: 1;
}

.proto-screens__layer[data-step="detail"] {
  transition: opacity 350ms ease-in-out;
}

.proto-screens__screen.is-detail .proto-screens__layer[data-step="detail"] {
  opacity: 1;
}

@media (max-width: 47.99rem) {
  .proto-screens {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    aspect-ratio: auto;
  }

  .proto-screens__screen {
    border-radius: 4.6cqw;
  }
}

/* The cost card: changing the time recalculates the yearly cost. Built in
   points on the card (1pt = 0.2365cqw of the stage). */
.proto-cost {
  --pt: 0.2365cqw;
  background: #313131;
}

.proto-cost__card {
  position: absolute;
  left: 10.25%;
  top: 26.2%;
  width: 79.24%;
  box-sizing: border-box;
  padding: calc(20 * var(--pt));
  border-radius: calc(12 * var(--pt));
  background: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Arial, sans-serif;
  color: #021940;
}

.proto-cost__card p {
  margin: 0;
}

.proto-cost__label {
  font-size: calc(14 * var(--pt));
  font-weight: 700;
  line-height: calc(16 * var(--pt));
  letter-spacing: -0.014em;
  text-transform: uppercase;
  color: #e42b14;
}

.proto-cost__amount {
  display: flex;
  align-items: flex-start;
  margin-top: calc(8 * var(--pt)) !important;
  font-family: "Circular Sense", "Circular Std", "Avenir Next", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  font-weight: 500;
  letter-spacing: -0.006em;
}

.proto-cost__unit {
  font-size: calc(22 * var(--pt));
  line-height: calc(24 * var(--pt));
}

.proto-cost__unit:last-child {
  align-self: flex-end;
  margin-left: calc(2 * var(--pt));
  padding-bottom: calc(3 * var(--pt));
}

[data-cost] {
  margin-left: calc(1 * var(--pt));
  font-size: calc(34 * var(--pt));
  line-height: calc(40 * var(--pt));
  font-variant-numeric: tabular-nums;
}

.proto-cost__basis {
  margin-top: calc(8 * var(--pt)) !important;
  font-size: calc(15 * var(--pt));
  font-weight: 600;
  line-height: calc(20 * var(--pt));
  letter-spacing: -0.016em;
  color: #707070;
}

.proto-cost__fields {
  display: flex;
  gap: calc(8 * var(--pt));
  margin-top: calc(8 * var(--pt));
}

.proto-cost__select {
  flex: 1;
  height: calc(48 * var(--pt));
  padding: 0 calc(36 * var(--pt)) 0 calc(12 * var(--pt));
  border: 0;
  border-radius: calc(12 * var(--pt));
  background: #f4f4f4 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 8'%3E%3Cpath d='M1 1l5.5 5.5L12 1' fill='none' stroke='%23021940' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right calc(12 * var(--pt)) center / calc(13 * var(--pt)) auto;
  font: inherit;
  font-size: calc(17 * var(--pt));
  letter-spacing: -0.024em;
  color: #021940;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.proto-cost__select--amount {
  flex: 0 0 calc(60 * var(--pt));
  padding-right: calc(24 * var(--pt));
  background-position: right calc(10 * var(--pt)) center;
}

/* The spark: the slide lights up once (after 1s, 500ms ease-out); a tap
   switches the light. */
.proto-spark {
  padding: 0;
  border: 0;
  background: #000;
  cursor: pointer;
  transition: background-color 500ms var(--ease-out);
}

.proto-spark.is-on {
  background: #fff1cd;
}

.proto-spark__ring {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--d);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--c);
  translate: -50% -50%;
  scale: 0.459;
  opacity: 0;
  transition: scale 500ms var(--ease-out), opacity 500ms var(--ease-out);
}

.proto-spark.is-on .proto-spark__ring {
  scale: 1;
  opacity: 1;
}

.project-figure .proto-spark .proto-spark__bulb {
  position: absolute;
  left: 27.75%;
  top: 27.75%;
  width: 44.5%;
  transition: opacity 500ms var(--ease-out);
}

.proto-spark__bulb--on,
.proto-spark.is-on .proto-spark__bulb:not(.proto-spark__bulb--on) {
  opacity: 0;
}

.proto-spark.is-on .proto-spark__bulb--on {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .proto__stage *,
  .proto__stage {
    transition-duration: 0ms !important;
  }

  .js .proto-outlet.is-playing .proto-outlet__slot,
  .js [data-proto="marks"].is-playing .proto-mark {
    animation: none;
  }

  .js [data-proto="marks"]:not(.is-playing) .proto-mark {
    scale: 1;
  }
}

/* Grid Design System principles: a picture of a page of text on wide
   screens; on phones the text itself, set like the board, so it can be read. */
.ds-principles {
  display: none;
}

@media (max-width: 47.99rem) {
  .ds-principles-figure > picture,
  .ds-principles-figure > img {
    display: none;
  }

  .ds-principles {
    display: block;
    padding: var(--space-4) var(--space-3) var(--space-3);
    border-radius: 4px;
    background: #efefe7;
    font-family: "Haven Acid Grotesk", var(--font-body);
    color: #0b0b0b;
  }

  .ds-principles .ds-principles__mark {
    width: auto;
    height: 2.25rem;
    margin-bottom: var(--space-3);
    border-radius: 0;
  }

  .ds-principles h3 {
    margin: 0 0 var(--space-2);
    font-family: inherit;
    font-size: 1.75rem;
    font-weight: 500;
    line-height: 1.05;
    letter-spacing: -0.03em;
  }

  .ds-principles p {
    margin: 0;
    font-size: 0.95rem;
    line-height: 1.45;
  }

  .ds-principles ul {
    margin: var(--space-3) 0 0;
    padding: 0;
    list-style: none;
  }

  .ds-principles li {
    display: grid;
    grid-template-columns: 2rem 1fr;
    gap: var(--space-1) 0.65rem;
    align-items: center;
    margin-top: var(--space-3);
  }

  .ds-principles li img {
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
  }

  .ds-principles h4 {
    margin: 0;
    font-family: inherit;
    font-size: 1.2rem;
    font-weight: 500;
    line-height: 1.15;
    letter-spacing: -0.015em;
  }

  .ds-principles li p {
    grid-column: 1 / -1;
  }
}
