/* FitForge case study
   Hero section — Figma node 2101:3473.

   The hero is a 1601 x 1739 composition. Everything inside it is positioned as a
   percentage of that box so the whole thing scales with the viewport instead of
   needing a breakpoint per element. `--u` is one design pixel — a length, since
   CSS can't divide two lengths into a ratio — so a Figma value of 64px is
   written `calc(64 * var(--u))`. It's only needed for the handful of values that
   can't be expressed as a percentage: corner radii, shadows, type. */

:root {
  /* Figma variables */
  --ff-black: #000000;
  --ff-white: #ffffff;
  --ff-grey: #cedcc9;
  --ff-light-grey: #edf2dc;
  --ff-dark-green: #0f1d15;
  --ff-primary-green: #042f18;
  --ff-green-light: #1d4320;
  --ff-dirty-white: #fbffef;
  --ff-lime: #dbf963;

  --font-ui: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

  /* Liquid Glass / Frost - Regular */
  --glass-frost: 6px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--ff-black);
  color: var(--ff-white);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
}

img { display: block; }


/* --------------------------------------------------------------- Glass ---- */

/* Shared by the hero's "Run prototype" button (2101:10606) and the user
   stories arrows (2102:10732) — both are the same rgba(0,0,0,0.2) surface at
   Liquid Glass / Frost - Regular. */
.glass {
  border: 0;
  font-family: inherit;
  color: var(--ff-white);
  cursor: pointer;
  background: rgba(0, 0, 0, 0.2);
  -webkit-backdrop-filter: blur(var(--glass-frost)) saturate(140%);
  backdrop-filter: blur(var(--glass-frost)) saturate(140%);
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, 0.35),
    inset 0 0 0 1px rgba(255, 255, 255, 0.14),
    0 8px 32px rgba(0, 0, 0, 0.35);
  transition: background 200ms ease, box-shadow 200ms ease, transform 200ms ease;
}

.glass:hover {
  background: rgba(255, 255, 255, 0.14);
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, 0.5),
    inset 0 0 0 1px rgba(255, 255, 255, 0.22),
    0 10px 36px rgba(0, 0, 0, 0.4);
}

.glass:focus-visible {
  outline: 2px solid var(--ff-lime);
  outline-offset: 3px;
}

/* Past the design width the page would just keep growing, so the reading column
   is capped and centred against the black backdrop. The cap lives on a grid
   column rather than on `main` itself so the sections that run edge to edge can
   opt out with `grid-column: full`. Measuring in `vw` would have done the same
   job but counts a classic scrollbar's width, which pushes those sections a few
   pixels wider than the page and knocks their gutters out of line with it. */
main {
  display: grid;
  grid-template-columns:
    [full-start] minmax(0, 1fr)
    [content-start] minmax(0, 1800px) [content-end]
    minmax(0, 1fr) [full-end];
}

main > * { grid-column: content; }


/* ---------------------------------------------------------------- Hero ---- */

.hero-wrap {
  container-type: inline-size;
}

.hero {
  --u: calc(100cqw / 1601);
  position: relative;
  width: 100%;
  aspect-ratio: 1601 / 1739;
  overflow: hidden;
  background: var(--ff-black);
  isolation: isolate;
}

/* -- background ------------------------------------------------------------ */

.hero__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Product photography, bled off the top and bottom of the section. */
.hero__photo {
  position: absolute;
  left: 10.1187%;      /* 162 / 1601 */
  top: -21.0466%;      /* -366 / 1739 */
  width: 77.1393%;     /* 1235 / 1601 */
  height: 126.1644%;   /* 2194 / 1739 */
}

.hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Black falloff on both vertical edges so the photo dissolves into the page.
   The conclusion panel crops the same photograph and takes the same falloff. */
.hero__photo-fade,
.conclusion__photo-fade {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgb(0, 0, 0) 2.4292%, rgba(0, 0, 0, 0) 16.113%),
    linear-gradient(270deg, rgb(0, 0, 0) 0.60728%, rgba(0, 0, 0, 0) 13.522%);
}

/* Splash screen background blur. */
.hero__glow {
  position: absolute;
  left: -51.9051%;     /* -831 / 1601 */
  top: 7.4756%;        /* 130 / 1739 */
  width: 174.3048%;    /* 2790.62 / 1601 */
  height: 133.1225%;   /* 2315 / 1739 */
  max-width: none;
}

/* Rectangle 1436 (2105:10846) — the glow runs past the right edge of the photo's
   own falloff, so this carries it the rest of the way into the page's black.
   Last of the background layers, as in the design. */
.hero__edge-fade {
  position: absolute;
  right: 0;
  top: 0;
  width: 17.8014%;     /* 285 / 1601 */
  height: 96.0322%;    /* 1670 / 1739 */
  background: linear-gradient(to left, rgb(0, 0, 0) 0%, rgba(0, 0, 0, 0) 100%);
}

/* -- brand ----------------------------------------------------------------- */

.hero__logo {
  position: absolute;
  left: 36.8520%;      /* 590 / 1601 */
  top: 10.7533%;       /* 187 / 1739 */
  width: 26.2336%;     /* 420 / 1601 */
  height: auto;
  z-index: 2;
}

.hero__tagline {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 19.5514%;       /* 340 / 1739 */
  width: 19.8001%;     /* 317 / 1601 */
  margin: 0;
  z-index: 2;
  font-size: clamp(15px, calc(20 * var(--u)), 20px);
  font-weight: 300;
  font-style: italic;
  line-height: normal;
  text-align: center;
  color: var(--ff-grey);
  text-wrap: balance;
}

/* -- app screen previews --------------------------------------------------- */

.hero__screens {
  position: absolute;
  left: -0.0931%;      /* -1.49 / 1601 */
  top: 27.0845%;       /* 471 / 1739 */
  width: 100.0930%;    /* 1602.49 / 1601 */
  aspect-ratio: 1602.49 / 1222.346;
  /* Above the cap: the cluster reaches past 92% of the hero, so its tail spills
     over the light band rather than being cut off at the fold. */
  z-index: 3;
}

.screen {
  position: absolute;
  width: 37.1638%;     /* 595.549 / 1602.49 */
  aspect-ratio: 595.549 / 919.005;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Document order is the stacking order from the design: splash at the back,
   order builder in front. */
.screen--splash        { left: 27.5777%; top: 0; }             /* 441.93 / 1602.49 */
.screen--item-details  { left: 62.8352%; top: 12.4474%; }      /* 1006.94 / 1602.49, 152.15 / 1222.346 */
.screen--order-builder { left: 0;        top: 24.8161%; }      /* 303.34 / 1222.346 */

/* Three nested wrappers so the entrance, the float loop and the fixed tilt each
   own a transform and never overwrite one another. */
.screen__enter,
.screen__float {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.screen__card {
  width: 65.4183%;     /* 389.596 / 595.549 */
  aspect-ratio: 389.596 / 847.032;
  transform: rotate(-15deg);
  /* The exports carry the phone frame's rounded corners in their own alpha, so
     a square box round them throws shadow past the art at all four corners. It
     is the wireframe cards' 65.91px radius on a frame scaled to 94.11%. Written
     horizontal / vertical, since a single percentage would read off each axis
     and bend the corner into an ellipse. */
  border-radius: 15.923% / 7.323%;   /* 62.03 / 389.596, 62.03 / 847.032 */
  /* Screen Shadow - Case Study */
  box-shadow: calc(40 * var(--u)) calc(30 * var(--u)) calc(74 * var(--u)) 0 rgba(15, 29, 21, 0.15);
}

.screen__card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Hidden until the entrance runs. Only when JS is around to start it. */
.js .screen__enter { opacity: 0; }

@keyframes screenEnter {
  from { opacity: 0; transform: translate3d(0, 7%, 0); }
  to   { opacity: 1; transform: none; }
}

/* Percentage translations are relative to the element's own height, so the
   float keeps the same visual amplitude at every scale. */
@keyframes screenFloat {
  0%   { transform: translate3d(0, 1.1%, 0); }
  50%  { transform: translate3d(0, -1.5%, 0); }
  100% { transform: translate3d(0, 1.1%, 0); }
}

.hero.is-ready .screen__enter {
  animation: screenEnter 1.1s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: var(--enter-delay);
}

/* Each loop starts once its own entrance has landed, and every screen runs a
   different duration so they drift apart instead of bobbing in unison. */
.hero.is-ready .screen__float {
  animation: screenFloat var(--float-duration) ease-in-out infinite;
  animation-delay: calc(var(--enter-delay) + 1.1s);
}

.screen--splash        { --enter-delay: 0.2s;  --float-duration: 7.2s; }
.screen--item-details  { --enter-delay: 0.38s; --float-duration: 8.6s; }
.screen--order-builder { --enter-delay: 0.56s; --float-duration: 6.4s; }

/* -- CTA ------------------------------------------------------------------- */

.hero__cta {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  /* Stays the topmost thing in the hero now that the screens have moved up. */
  z-index: 4;

  width: clamp(200px, 14.7408%, 236px);   /* 236 / 1601 */
  height: clamp(52px, calc(60 * var(--u)), 60px);
  padding: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;

  border-radius: 60px;
}

.hero__cta:active {
  transform: translate(-50%, -50%) scale(0.97);
}

.hero__cta-label {
  font-size: clamp(15px, calc(18 * var(--u)), 18px);
  font-weight: 500;
  line-height: normal;
  white-space: nowrap;
}

.hero__cta-icon {
  width: clamp(17px, calc(20 * var(--u)), 20px);
  height: clamp(17px, calc(20 * var(--u)), 20px);
  flex: none;
}

/* -- cap ------------------------------------------------------------------- */

.hero__cap {
  position: absolute;
  left: 0;
  top: 92.1794%;       /* 1603 / 1739 */
  width: 100%;
  height: 10.2933%;    /* 179 / 1739 */
  z-index: 2;
  background: var(--ff-light-grey);
  border-radius: calc(64 * var(--u)) calc(64 * var(--u)) 0 0;
}


/* ------------------------------- Role, Problem and User Research ---------- */

/* Figma node 2101:3784. Unlike the hero this is a reading section, so the
   layout is genuinely responsive rather than a scaled copy: proportions and
   spacing come from the design, type is clamped so it stays readable, and the
   column counts step down at the widths where a card would get too narrow. */

.brief {
  padding: 0 48px 60px;
  background: var(--ff-light-grey);
  color: var(--ff-dark-green);
}

.brief__container {
  max-width: 1505px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 72px;
}

/* -- roles and deliverables — 2101:3786 ------------------------------------ */

.roles {
  position: relative;
  display: flex;
  gap: 84px;
  align-items: flex-start;
  padding: 44px;
  border-radius: 32px;
  overflow: hidden;
  background: var(--ff-dark-green);
}

/* Fits without shrinking at the design width (3 x 404 + 2 x 84 < 1417) and
   shrinks proportionally below it. */
.roles__col {
  position: relative;
  flex: 0 1 404px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.roles__heading {
  margin: 0;
  font-size: clamp(26px, 2.25vw, 32px);
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: -0.04em;
  color: var(--ff-lime);
}

.roles__heading--spacer { visibility: hidden; }

.roles__list {
  margin: 0;
  font-size: clamp(17px, 1.4vw, 20px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--ff-white);
}

.roles__glow {
  position: absolute;
  right: -157px;       /* 1505 - 603 - 1058.681 */
  top: -576px;
  width: 1058.681px;
  height: 1221.588px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.roles__glow-rotor {
  position: relative;
  flex: none;
  width: 1077.767px;
  height: 873.148px;
  transform: rotate(-79.26deg);
}

.roles__glow img {
  position: absolute;
  left: 0;
  top: -12.24%;
  width: 109.17%;
  height: 112.24%;
  max-width: none;
}

/* -- heading + body pairs — 2101:3797 and 2101:3855 ------------------------ */

.prose-pair {
  display: grid;
  grid-template-columns: 682fr 680fr;
  gap: 84px;
  max-width: 1446px;
}

.prose-pair__col {
  display: flex;
  flex-direction: column;
  gap: 21px;
  padding-left: 32px;
}

.prose-pair__heading {
  margin: 0;
  font-size: clamp(32px, 3.4vw, 48px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.04em;
  color: var(--ff-green-light);
}

.prose-pair__heading--spacer { visibility: hidden; }

.prose-pair__body {
  margin: 0;
  font-size: clamp(16px, 1.4vw, 20px);
  font-weight: 300;
  line-height: normal;
  color: var(--ff-dark-green);
}

/* -- highlights — 2101:3849 ------------------------------------------------ */

.highlights {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 24px;
}

.highlight {
  position: relative;
  min-height: 238px;
  padding-top: 44px;
  border-radius: 28.169px;
  overflow: hidden;
  background: var(--ff-dark-green);
}

.highlight__glow {
  position: absolute;
  left: -106.98%;      /* -383 / 358 */
  top: -92px;
  width: 199.56%;      /* 714.436 / 358 */
  height: 578.798px;
  pointer-events: none;
}

.highlight__glow img {
  position: absolute;
  left: 0;
  top: -18.25%;
  width: 114.04%;
  height: 120.25%;
  max-width: none;
}

.highlight__content {
  position: relative;
  /* 255.282px in the design, where the longest label fits on two lines with
     0.06px to spare — rounded up so a hair of font rendering doesn't turn it
     into three. */
  width: 256px;
  max-width: calc(100% - 32px);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
}

.highlight__icon {
  width: 74px;
  height: 74px;
  flex: none;
}

.highlight__label {
  font-size: clamp(17px, 1.5vw, 21.127px);
  font-weight: 500;
  line-height: normal;
  text-align: center;
  color: var(--ff-white);
}

/* -- user research ---------------------------------------------------------- */

.research {
  display: flex;
  flex-direction: column;
  gap: 40px;
}

/* -- personas — 2101:3862 -------------------------------------------------- */

.personas {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 24px;
  align-items: start;
}

.persona {
  position: relative;
  border-radius: 28.498px;
  overflow: hidden;
  background: var(--ff-white);
  /* Drop shadow sits on the row in the design; per card is the same silhouette
     for a rounded rectangle, and far cheaper than filtering the whole grid. */
  box-shadow: 40px 30px 37px rgba(15, 29, 21, 0.15);
}

.persona__head {
  position: relative;
  height: 419.448px;
  background: var(--ff-dark-green);
}

.persona__glow {
  position: absolute;
  left: -75.12%;       /* -268.945 / 358 */
  top: -106.86px;
  width: 230.23%;      /* 824.24 / 358 */
  height: 704.1px;
  max-width: none;
  pointer-events: none;
}

/* Everything in the head is centred on the card, so it survives the card
   getting narrower than the 358px it was drawn at. */
.persona__type,
.persona__avatar,
.persona__scrim,
.persona__id {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

.persona__type {
  top: 48.09px;
  width: 62.69%;       /* 224.418 / 358 */
  margin: 0;
  font-size: 35.622px;
  font-weight: 700;
  line-height: 30.279px;
  letter-spacing: -0.07em;
  text-align: center;
  color: var(--ff-lime);
}

.persona__avatar {
  top: 138.93px;
  width: 106.866px;
  height: 106.866px;
  border-radius: 28.498px;
  overflow: hidden;
  background: var(--ff-light-grey);
}

/* Each photo carries its own crop from the design. */
.persona__avatar img {
  position: absolute;
  max-width: none;
  object-fit: cover;
}

.persona__avatar--alex img  { left: -69.44%; top: -3.33%;  width: 229.44%; height: 152.77%; }
.persona__avatar--sarah img { left: -12.5%;  top: -11.67%; width: 125%;    height: 122.5%; }
.persona__avatar--mike img  { left: -12.5%;  top: -11.67%; width: 125%;    height: 122.5%; }
.persona__avatar--bob img   { left: -0.83%;  top: 0;       width: 102.52%; height: 100%; }

/* Sinks the bottom of the photo into the head before the name sits on it. */
.persona__scrim {
  top: 219.97px;
  width: 169.204px;
  height: 40.075px;
  background: linear-gradient(180deg, rgba(1, 2, 1, 0) 0%, #010201 100%);
}

.persona__id {
  top: 260.04px;
  width: 258.259px;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7.124px;
  text-align: center;
}

.persona__name {
  margin: 0;
  font-size: 21.373px;
  font-weight: 500;
  line-height: normal;
  white-space: nowrap;
  color: var(--ff-white);
}

.persona__role {
  margin: 0;
  font-size: 14.249px;
  font-weight: 500;
  line-height: normal;
  /* The longest role runs wider than this box in the design too — it still
     fits the card, so let it sit on one line. */
  white-space: nowrap;
  color: var(--ff-grey);
}

/* Pulled up over the head so the card ends up exactly as tall as its content,
   the way the absolutely-placed panel does in the design. */
.persona__body {
  position: relative;
  margin-top: -66.791px;   /* 419.448 - 352.657 */
  padding: 28.498px 21.373px;
  border-radius: 28.498px;
  background: var(--ff-white);
  display: flex;
  flex-direction: column;
  gap: 14.249px;
}

.persona__field {
  display: flex;
  flex-direction: column;
  gap: 7.124px;
}

/* The design draws a hairline between fields with the gap on both sides. */
.persona__field + .persona__field {
  padding-top: 14.249px;
  /* 0.890547px in the design; browsers snap that to half a pixel, so ask for
     the hairline the rule is meant to be. */
  border-top: 1px solid var(--ff-grey);
}

.persona__label {
  margin: 0;
  font-size: 12.468px;
  font-weight: 600;
  line-height: normal;
  color: var(--ff-green-light);
}

.persona__value {
  margin: 0;
  font-size: 14.249px;
  font-weight: 400;
  line-height: normal;
  color: var(--ff-dark-green);
}

ul.persona__value {
  padding-left: 21.3735px;
  list-style: disc;
}

.persona__quote {
  width: 95.2%;        /* 300.114 / 315.254 */
  font-style: italic;
}


/* ------------------------------------------------- User Stories ---------- */

/* Figma node 2101:4063. The annotation turns the three persona groups into
   carousel slides with the app's dot controls underneath, so the stacked
   1497px section in the file collapses to one slide plus the dots. */

.stories {
  --stories-gutter: 80px;
  padding: 72px var(--stories-gutter);
  background: var(--ff-dark-green);
}

.stories__container {
  max-width: 1441px;
  margin: 0 auto;
}

/* The arrows live in the section's gutters, so the stage reaches back out over
   the padding and the viewport keeps the container's full width. */
.stories__stage {
  margin-inline: calc(-1 * var(--stories-gutter));
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) 56px;
  grid-template-areas:
    "prev viewport next"
    ".    dots     .";
  align-items: center;
  column-gap: 24px;
  row-gap: 48px;
}

.stories__viewport {
  grid-area: viewport;
  overflow: hidden;
}

.stories__track {
  /* Gutter between slides. It only shows mid-travel — with it at zero the
     outgoing slide's cards pass flush against the incoming slide's, which
     reads as one crowded column rather than two slides. The travel has to
     carry it: each step is one slide plus one gutter. */
  --slide-gap: 0px;
  display: flex;
  gap: var(--slide-gap);
  /* Equal heights across slides, so the dots don't jump between groups. */
  align-items: stretch;
  transform: translateX(calc((-100% - var(--slide-gap)) * var(--slide, 0)));
  transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
}

.story-group {
  flex: 0 0 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.story-group__heading {
  margin: 0;
  font-size: clamp(32px, 3.4vw, 48px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--ff-lime);
}

.story-group__heading span { color: var(--ff-white); }

.story-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  align-items: flex-start;
  gap: 24px;
}

/* 342px cards, four to a row. The design's row measures 1440px inside a 1441px
   container, so a scrollbar alone is enough to drop it to three — hence the
   smaller basis, which decides the wrap, with the width capped at the design's
   342px so a short last row stays ragged instead of stretching. */
.story {
  flex: 1 1 320px;
  max-width: 342px;
  min-width: 0;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 24px 24px 24px 16px;
  border-radius: 16px;
  background: var(--ff-white);
}

.story__mark {
  flex: none;
  display: block;
  width: 20.75px;
  height: 15.864px;
  margin-top: 2px;
}

.story__text {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  line-height: normal;
  color: var(--ff-black);
}

/* -- arrows — 2102:10732, "Icon Button - Secondary" ------------------------ */

.stories__arrow {
  width: 56px;
  height: 56px;
  padding: 16px;
  border-radius: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.stories__arrow--prev { grid-area: prev; }
.stories__arrow--next { grid-area: next; }

.stories__arrow:active { transform: scale(0.94); }

.stories__arrow svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
}

/* -- dot controls, lifted from the app's home carousel --------------------- */

.stories__dots {
  grid-area: dots;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
}

.stories__dot {
  /* The dot itself is 6px tall, as in the app; the padding is only there to
     give it a usable hit area. */
  width: 6px;
  height: 6px;
  padding: 0;
  border: 0;
  border-radius: 60px;
  background: var(--ff-grey);
  cursor: pointer;
  transition: width 300ms cubic-bezier(0.16, 1, 0.3, 1), background 300ms ease;
}

.stories__dot::before {
  content: "";
  position: absolute;
  inset: -12px -6px;
}

.stories__dot { position: relative; }

.stories__dot[aria-selected="true"] {
  width: 18px;
  background: var(--ff-lime);
}

.stories__dot:focus-visible {
  outline: 2px solid var(--ff-lime);
  outline-offset: 4px;
}

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


/* ------------------------------------------------- Wireframes ------------ */

/* Figma node 2101:4095. The three screens are process artifacts being shown
   rather than UI to operate — roughly 380 nodes each of greyscale placeholder
   chrome — so they're the frames' own 2x exports, the same way the hero uses
   exports for the app screens. */

.wireframes {
  padding: 72px 0;
  background: var(--ff-light-grey);
  display: flex;
  flex-direction: column;
  gap: 48px;
  /* Closes the light-grey band the way the hero's cap (2101:3473) opens it, on
     the same radius. The hero scales its 64px off the section width, which
     works out to 4vw — held at the 40px the cap drops to on a phone, and capped
     at the 72px it reaches once `main` stops growing at 1800. */
  border-radius: 0 0 clamp(40px, 4vw, 72px) clamp(40px, 4vw, 72px);
}

.wireframes__heading {
  margin: 0;
  padding-left: 120px;
  font-size: clamp(32px, 3.4vw, 48px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.04em;
  color: var(--ff-black);
}

.wireframes__grid {
  list-style: none;
  margin: 0;
  padding: 0 120px;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  align-items: flex-start;
  justify-content: center;
  gap: 73px 59px;
}

/* Three across measures 1360px inside a 1361px row, so — as with the user
   story cards — the wrap is decided off a smaller basis and the width capped
   at the design's 414px. */
.wireframe {
  flex: 1 1 380px;
  max-width: 414px;
  min-width: 0;
  aspect-ratio: 414 / 900.0895;
  border-radius: 65.91px;
  overflow: hidden;
  background: var(--ff-white);
  box-shadow: 40px 30px 37px rgba(15, 29, 21, 0.15);
}

.wireframe img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}


/* ------------------------------------------------- Branding -------------- */

/* Figma node 2101:4478. The file places all four blocks absolutely; they sit on
   two columns and two rows, so a grid gets the same result and survives a
   narrow screen. */

.branding {
  /* Asymmetric in the design — 80 left, 97 right — which puts the columns
     exactly where the file does at 1601. */
  padding: 134px 97px 130px 80px;
  background: var(--ff-black);
}

.branding__grid {
  max-width: 1424px;   /* 650 + 125 + 649 */
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 650fr) minmax(0, 649fr);
  column-gap: 125px;
  row-gap: 131px;
  align-items: start;
}

.branding__intro {
  display: flex;
  flex-direction: column;
  gap: 21px;
}

.branding__heading {
  margin: 0;
  font-size: clamp(32px, 3.4vw, 48px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.04em;
  color: var(--ff-white);
}

.branding__body {
  margin: 0;
  font-size: clamp(16px, 1.4vw, 20px);
  font-weight: 300;
  line-height: normal;
  color: var(--ff-dirty-white);
}

.branding__logo img {
  width: 100%;
  height: auto;
}

/* -- typeface specimen ----------------------------------------------------- */

.branding__typeface {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.branding__typeface-name {
  margin: 0;
  font-size: clamp(64px, 8vw, 120px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--ff-white);
}

.branding__specimen {
  margin: 0;
  max-width: 541px;
  font-size: clamp(24px, 3vw, 40px);
  font-weight: 300;
  line-height: normal;
  text-align: justify;
  /* The run of spaces before the numerals is part of the specimen. */
  white-space: pre-wrap;
  /* The alphabet is one unbreakable 27-character run, wider than the column.
     The design's text nodes break inside a word rather than overflow. */
  overflow-wrap: break-word;
  color: var(--ff-lime);
}

/* -- icon set -------------------------------------------------------------- */

.branding__icons {
  align-self: center;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  justify-content: center;
  gap: 67px 55px;
}

.brand-icon {
  width: 32px;
  height: 32px;
  flex: none;
  fill: none;
  stroke: currentColor;
  /* Overrides the heavier weight the chevron symbols carry for the carousel
     arrows, so the whole set reads at the one stroke. */
  stroke-width: 2;
  color: var(--ff-lime);
}


/* ------------------------------------------------- Colour palette -------- */

/* Figma node 2101:4547, annotated "Full width animated carousel loop." Eight
   400 x 480 swatches — 3200px of strip, wider than any viewport it will ever
   sit in. Rather than crop it, the section runs it as a marquee: app.js prints
   the set a second time and the track walks exactly one set's width, which
   lands the copy on the original's starting mark and hides the seam.

   Without JS there's no copy to loop against, so `is-looping` stays off and the
   strip is simply scrollable instead. */

/* One of the sections that ignores the content cap: the loop reads as a band
   running past the page rather than a component sitting on it. */
.colors {
  grid-column: full;
  --swatch-w: 400px;
  overflow: hidden;
  background: var(--ff-black);
}

.colors:not(.is-looping) {
  overflow-x: auto;
}

.colors__track {
  display: flex;
  width: max-content;
}

.colors.is-looping .colors__track {
  animation: colors-loop 48s linear infinite;
}

/* Hovering parks the strip, so a swatch can be read without chasing it. */
.colors.is-looping:hover .colors__track {
  animation-play-state: paused;
}

.colors__set {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
}

.colors__swatch {
  position: relative;
  flex: none;
  width: var(--swatch-w);
  aspect-ratio: 400 / 480;
  overflow: hidden;
  background: var(--swatch);
  color: var(--swatch-ink);
}

.colors__swatch--lime {
  --swatch: var(--ff-lime);
  --swatch-ink: var(--ff-dark-green);
  --swatch-sub: var(--ff-dark-green);
}

.colors__swatch--black {
  --swatch: var(--ff-black);
  --swatch-ink: var(--ff-white);
  --swatch-sub: var(--ff-light-grey);
}

.colors__swatch--dark-green {
  --swatch: var(--ff-dark-green);
  --swatch-ink: var(--ff-white);
  --swatch-sub: var(--ff-light-grey);
}

.colors__swatch--primary-green {
  --swatch: var(--ff-primary-green);
  --swatch-ink: var(--ff-white);
  --swatch-sub: var(--ff-light-grey);
}

.colors__swatch--light-green {
  --swatch: var(--ff-green-light);
  --swatch-ink: var(--ff-white);
  --swatch-sub: var(--ff-light-grey);
}

.colors__swatch--grey {
  --swatch: var(--ff-grey);
  --swatch-ink: var(--ff-black);
  --swatch-sub: var(--ff-green-light);
}

.colors__swatch--light-grey {
  --swatch: var(--ff-light-grey);
  --swatch-ink: var(--ff-black);
  --swatch-sub: var(--ff-green-light);
}

.colors__swatch--white {
  --swatch: var(--ff-white);
  --swatch-ink: var(--ff-black);
  --swatch-sub: var(--ff-green-light);
}

.colors__label {
  position: absolute;
  left: 50%;
  bottom: 32px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: center;
  font-size: clamp(16px, 1.4vw, 20px);
  line-height: normal;
  white-space: nowrap;
}

.colors__name {
  margin: 0;
  font-weight: 600;
}

.colors__hex {
  margin: 0;
  font-weight: 300;
  color: var(--swatch-sub);
}

@keyframes colors-loop {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}


/* ------------------------------------------------- Previews -------------- */

/* Figma node 2101:10714. The annotation makes the app row a full-width looping
   carousel: it scrolls on its own, and on hover it can be grabbed and dragged
   to review the screens, with a 'Drag' tooltip following the cursor. */

.previews {
  --screen-w: clamp(240px, 26vw, 402px);
  --screen-gap: clamp(24px, 4.8vw, 77px);
  /* Out of the content column: the annotated carousel is meant to run edge to
     edge, which it can't do inside a capped one. Same as the colour strip. */
  grid-column: full;
  padding-bottom: 77px;
  background: var(--ff-grey);
  color: var(--ff-black);
}

/* Full-bleed section, page-width column — the same one the conclusion's panel
   puts its text in, so the two gutters line up past `main`'s cap as well. */
.previews__heading {
  margin: 0 auto;
  max-width: 1800px;
  padding: 72px 120px 48px;
  font-size: clamp(32px, 3.4vw, 48px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.04em;
  color: var(--ff-black);
}

/* -- app carousel — 2101:4584 ---------------------------------------------- */

.previews__carousel {
  position: relative;
  overflow: hidden;
  padding-bottom: 77px;
  /* The affordance the tooltip describes. */
  cursor: grab;
  touch-action: pan-y;
}

.previews__carousel.is-dragging { cursor: grabbing; }

.previews__carousel:focus-visible {
  outline: 2px solid var(--ff-dark-green);
  outline-offset: -4px;
}

.previews__track {
  display: flex;
  gap: var(--screen-gap);
  width: max-content;
  /* Driven from JS so the auto-scroll and the drag share one offset. */
  transform: translate3d(calc(-1 * var(--shift, 0px)), 0, 0);
}

.previews__set {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: var(--screen-gap);
  flex: none;
}

.preview-screen {
  flex: none;
  width: var(--screen-w);
  aspect-ratio: 402 / 874;
  border-radius: calc(64 / 402 * var(--screen-w));
  overflow: hidden;
}

.preview-screen img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Otherwise the browser's own image drag fights the carousel's. */
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}

/* Follows the cursor while hovering the strip. */
.previews__tip {
  position: absolute;
  left: 0;
  top: 0;
  margin: 0;
  padding: 8px 16px;
  border-radius: 60px;
  background: var(--ff-dark-green);
  color: var(--ff-lime);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -150%);
  transition: opacity 160ms ease;
}

.previews__carousel.is-hovered .previews__tip { opacity: 1; }

/* -- admin dashboard — 2101:5675 ------------------------------------------- */

.previews__admin {
  display: flex;
  justify-content: center;
  padding: 0 24px;
}

/* The export carries the panel's rounded corners and its drop shadow in its own
   alpha — the 1852px panel sits in a 2000px canvas, the rest being the shadow
   falling down and to the right. So no surface, radius or shadow here: any of
   them would be a second copy of what the image already draws. The cap is the
   panel's 1440 scaled up by that margin, so the panel itself still lands at the
   width it had. */
.preview-dashboard {
  width: 100%;
  max-width: 1555px;   /* 1440 * 2000 / 1852 */
}

.preview-dashboard img {
  width: 100%;
  height: auto;
}


/* ------------------------------------------------- Conclusion ------------ */

/* Figma node 2101:6026. A 1601 x 646 section: 48px of the previews' grey, then
   a black panel that runs to the bottom of the page behind rounded top corners.
   The panel's height is the design's 598 once its own padding is counted, so
   nothing here needs a fixed height to hold the shape. */

.conclusion {
  /* Edge to edge for the same reason the previews strip above it is: the panel
     is the page's closing band, and a capped column would leave grey rails. */
  grid-column: full;
  padding-top: clamp(24px, 3vw, 48px);   /* 48 / 1601 */
  background: var(--ff-grey);
}

.conclusion__panel {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: var(--ff-black);
  /* The hero's cap radius, the one the wireframes band closes on. */
  border-radius: clamp(40px, 4vw, 72px) clamp(40px, 4vw, 72px) 0 0;
  padding-block:
    clamp(56px, 11.65vw, 186.5px)   /* 186.5 / 1601 */
    clamp(48px, 5.9vw, 94.5px);     /* 94.5 / 1601 */
}

/* The panel bleeds edge to edge, but its text belongs to the page, so it sits
   in the same column everything else does: capped at `main`'s width and on the
   120px gutter the wireframes and previews headings above it use. (The file
   draws this section at 112 — 8px off the rest of the page, which reads as a
   misalignment once the sections are stacked.) */
.conclusion__container {
  max-width: 1800px;
  margin-inline: auto;
  padding-inline: 120px;
}

/* -- background ------------------------------------------------------------ */

.conclusion__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

/* Bled off the top of the panel. The vertical offset is a share of the photo's
   own height rather than the panel's, so it keeps its crop while the panel
   grows taller on a narrow screen. */
.conclusion__photo {
  position: absolute;
  left: 54.5909%;      /* 874 / 1601 */
  top: 0;
  width: 77.1393%;     /* 1235 / 1601 */
  aspect-ratio: 1235 / 2194;
  transform: translateY(-24.6117%);   /* -539.98 / 2194 */
}

.conclusion__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* -- content --------------------------------------------------------------- */

.conclusion__content {
  position: relative;
  max-width: 872px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 32px;
}

.conclusion__heading-group {
  display: flex;
  flex-direction: column;
  gap: 21px;
}

.conclusion__heading {
  margin: 0;
  font-size: clamp(32px, 3.4vw, 48px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.04em;
  color: var(--ff-lime);
}

.conclusion__body {
  margin: 0;
  font-size: clamp(16px, 1.4vw, 20px);
  font-weight: 300;
  line-height: normal;
  color: var(--ff-light-grey);
}

/* -- CTA ------------------------------------------------------------------- */

/* The hero's button again (2105:10840), minus the hero's fluid scaling — here
   it sits in a reading column, so it stays at its design size. */
.conclusion__cta {
  flex: none;
  width: 236px;
  height: 60px;
  padding: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border-radius: 60px;
}

.conclusion__cta:active { transform: scale(0.97); }

.conclusion__cta-label {
  font-size: 18px;
  font-weight: 500;
  line-height: normal;
  white-space: nowrap;
}

.conclusion__cta-icon {
  width: 20px;
  height: 20px;
  flex: none;
}


/* ------------------------------------------------------------ Lightbox ---- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.lightbox[hidden] { display: none; }

.lightbox__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.72);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  animation: lightboxFade 220ms ease both;
}

.lightbox__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: min(480px, 100%);
  height: min(980px, 100%);
  animation: lightboxRise 280ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* No surface of its own: the prototype is transparent now, so the phone sits
   straight on the backdrop. A panel behind it would only be the light
   background back again, and its shadow would fall from an invisible box. */
.lightbox__stage {
  flex: 1;
  width: 100%;
  min-height: 0;
  overflow: hidden;
  background: transparent;
}

.lightbox__frame {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

.lightbox__close {
  align-self: flex-end;
  width: 44px;
  height: 44px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  /* Glass comes from .glass — same surface as the CTA it was opened from. */
  border-radius: 50%;
}

.lightbox__close svg { width: 20px; height: 20px; }

@keyframes lightboxFade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes lightboxRise {
  from { opacity: 0; transform: translateY(24px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

body.is-locked { overflow: hidden; }


/* ---------------------------------------------------------- Responsive ---- */

/* Four cards across only while each still has room to read; below that they
   step to two, then one. */
@media (max-width: 1352px) {
  .highlights,
  .personas {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 1040px) {
  .roles {
    flex-wrap: wrap;
    gap: 40px 84px;
  }

  .roles__col { flex: 1 1 300px; }

  .prose-pair {
    grid-template-columns: minmax(0, 1fr);
    gap: 48px;
  }

  /* With one column per row the invisible headings only add dead space. */
  .roles__heading--spacer,
  .prose-pair__heading--spacer { display: none; }
}

@media (max-width: 1040px) {
  .stories {
    --stories-gutter: 40px;
    padding: 56px var(--stories-gutter);
  }

  .wireframes { padding: 56px 0; }
  .wireframes__heading { padding-left: 40px; }
  .wireframes__grid { padding: 0 40px; gap: 56px 40px; }

  .previews { padding-bottom: 56px; }
  .previews__heading { padding: 56px 40px 40px; }
  .conclusion__container { padding-inline: 40px; }
  .previews__carousel { padding-bottom: 56px; }

  /* One column: intro, logo, typeface, icons, in that reading order. */
  .branding {
    padding: 72px 40px;
  }

  .branding__grid {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 64px;
  }

  .branding__icons {
    align-self: start;
    justify-content: flex-start;
    gap: 40px 48px;
  }
}

@media (max-width: 720px) {
  .brief {
    padding: 0 24px 48px;
  }

  .stories {
    --stories-gutter: 24px;
    padding: 48px var(--stories-gutter);
  }

  /* No gutters left to hold the arrows, so they drop onto the dots row
     rather than sitting over the cards. */
  .stories__stage {
    margin-inline: 0;
    grid-template-columns: auto auto auto;
    grid-template-areas:
      "viewport viewport viewport"
      "prev     dots     next";
    justify-content: center;
    column-gap: 20px;
    row-gap: 32px;
  }

  .story-group { gap: 24px; }

  /* A phone slide is only as wide as the card, so the seam between slides is
     right against the reading column — it needs a real gutter to travel past. */
  .stories__track { --slide-gap: 32px; }

  .wireframes {
    padding: 48px 0;
    gap: 32px;
  }

  .wireframes__heading { padding-left: 24px; }

  /* Three 900-tall screens in a column is three screenfuls; swiped it is one.
     The section has no gutter of its own down here, so the strip carries it. */
  .wireframes__grid {
    flex-wrap: nowrap;
    justify-content: flex-start;
    padding: 0 24px 40px;
    gap: 16px;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 24px;
    scrollbar-width: none;
  }

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

  .wireframe {
    flex: 0 0 min(78%, 320px);
    max-width: none;
    scroll-snap-align: start;
    border-radius: 44px;
    box-shadow: 0 20px 40px rgba(15, 29, 21, 0.18);
  }

  .branding {
    padding: 56px 24px;
  }

  .branding__grid { row-gap: 48px; }

  .branding__icons { gap: 32px; }

  .previews { padding-bottom: 40px; }
  .previews__heading { padding: 48px 24px 32px; }
  .conclusion__container { padding-inline: 24px; }
  .previews__carousel { padding-bottom: 40px; }
  .previews__admin { padding: 0 24px; }

  /* Three swatches to a phone screen rather than two-thirds of one. */
  .colors { --swatch-w: 240px; }

  .colors__label { bottom: 24px; }

  .conclusion__content { gap: 24px; }

  .conclusion__heading-group { gap: 16px; }

  /* At the design's crop the photo would be a sliver down the right edge of a
     much taller panel. Blown up and anchored right, it still reads as the haze
     the text sits on. */
  .conclusion__photo {
    left: auto;
    right: -34%;
    width: 150%;
    transform: translateY(-14%);
  }

  .brief__container { gap: 56px; }

  .roles {
    padding: 32px 24px;
    gap: 32px;
    border-radius: 24px;
  }

  .roles__col { flex: 1 1 100%; }

  .prose-pair__col { padding-left: 0; }

  /* Stacked, these four cards each cost most of a phone screen. Swiped, the
     row costs one card. The strip bleeds out through the section's 24px gutter
     so a card can run off the edge, then pads it back on so the first card
     still starts on the gutter and the snap lands there. */
  .highlights,
  .personas {
    display: flex;
    flex-wrap: nowrap;
    gap: 16px;
    margin-inline: -24px;
    padding-inline: 24px;
    overflow-x: auto;
    /* `visible` on one axis would compute to `auto` on the other and hand the
       strip a vertical scrollbar of its own. */
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 24px;
    scrollbar-width: none;
  }

  .highlights::-webkit-scrollbar,
  .personas::-webkit-scrollbar { display: none; }

  /* Short of the full width, so the next card peeks and the row reads as
     something to swipe. */
  .highlight,
  .persona {
    flex: 0 0 min(78%, 320px);
    width: auto;
    max-width: none;
    scroll-snap-align: start;
  }

  .persona { box-shadow: 0 20px 40px rgba(15, 29, 21, 0.18); }

  /* Room under the cards for that shadow, which the strip would otherwise
     clip at the card's own edge. */
  .personas { padding-bottom: 40px; }

  .persona__name,
  .persona__role { white-space: normal; }

  .research { gap: 32px; }
}


/* Below the desktop range the composition stops being a scaled-down copy. The
   section fills the screen and stacks: brand, tagline, CTA, then the phone
   cluster, blown up past the section edges so the screens still read at phone
   scale. Everything in the stack stays positioned — the background layer is
   absolute, so static children would paint underneath it. */
@media (max-width: 860px) {
  .hero {
    --u: 1px;
    aspect-ratio: auto;
    min-height: 100svh;
    display: flex;
    flex-direction: column;
  }

  .hero__photo {
    left: -30%;
    top: -8%;
    width: 160%;
    height: 108%;
  }

  .hero__glow {
    left: -90%;
    top: 0;
    width: 280%;
    height: auto;
  }

  .hero__logo {
    position: relative;
    left: auto;
    top: auto;
    order: 1;
    width: min(62%, 300px);
    margin: clamp(48px, 9vh, 88px) auto 0;
  }

  .hero__tagline {
    position: relative;
    left: auto;
    top: auto;
    transform: none;
    order: 2;
    width: min(80%, 320px);
    margin: 18px auto 0;
    font-size: 16px;
  }

  .hero__cta {
    position: relative;
    left: auto;
    top: auto;
    transform: none;
    /* Above the cluster on mobile — over a phone this small the button would
       cover the screen it is meant to advertise. */
    order: 3;
    margin: 28px auto 0;
    flex: none;
  }

  .hero__cta:active { transform: scale(0.97); }

  /* Pushed to the bottom of the section; the tail of the cluster runs over the
     cap, the same way it does on the desktop composition. */
  .hero__screens {
    position: relative;
    order: 4;
    left: -42.5%;
    top: auto;
    width: 185%;
    margin-top: auto;
  }

  .hero__cap {
    top: auto;
    bottom: 0;
    height: 72px;
    border-radius: 40px 40px 0 0;
  }

  .lightbox { padding: 12px; }
  .lightbox__panel { gap: 8px; }
  .lightbox__stage { border-radius: 20px; }
}


/* ----------------------------------------------------- Reduced motion ---- */

@media (prefers-reduced-motion: reduce) {
  .js .screen__enter { opacity: 1; }

  .hero.is-ready .screen__enter {
    animation: none;
    opacity: 1;
  }

  .hero.is-ready .screen__float { animation: none; }

  .lightbox__backdrop,
  .lightbox__panel { animation: none; }

  .hero__cta,
  .conclusion__cta { transition: none; }

  .stories__track,
  .stories__dot { transition: none; }

  /* The palette stops travelling and becomes a strip the reader moves through
     themselves; the loop's copy would only be the same eight swatches again. */
  .colors.is-looping { overflow-x: auto; }
  .colors.is-looping .colors__track { animation: none; }
  .colors__set--clone { display: none; }
}
