/* The six product pages and their demos, on the tokens site.css defines.
   Nothing here names a colour, a curve or a duration of its own. */

/* ── Hero ─────────────────────────────────────────────────────────────── */

.product-hero {
  padding-top: calc(var(--header-h) + clamp(32px, 6vw, 88px));
  padding-bottom: clamp(48px, 8vw, 120px);
}
.product-hero__grid { display: grid; gap: clamp(40px, 6vw, 56px); align-items: center; }
.product-hero__copy { display: flex; flex-direction: column; gap: 22px; max-width: 640px; }
.product-hero__title {
  font-size: clamp(40px, 5.6vw, 80px);
  line-height: 1;
  letter-spacing: -.022em;
}
.product-hero--stacked .product-hero__copy { margin-bottom: clamp(40px, 6vw, 64px); }
/* Where the hero stacks, as on a phone, its first screen says what the page
   sells, what it costs and how to start, before any demo. A wide screen keeps
   the prototype's hero, with the price at the page's close. */
.product-hero__price { font-family: var(--font-display); font-size: 26px; line-height: 1.1; }
@media (min-width: 960px) {
  .product-hero__price, .product-hero__buy { display: none; }
}
/* Side by side the copy starts at the top and stays beside a tall demo as it
   scrolls. Centred against the kids page's phone and its 23 worlds, the
   headline began below the first screen and jumped further down when the
   demo grew. */
@media (min-width: 960px) {
  .product-hero__grid { grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 26px; align-items: start; }
  .product-hero__copy { grid-column: 1 / span 6; position: sticky; top: calc(var(--header-h) + 24px); }
  .product-hero__grid > :last-child { grid-column: 7 / span 6; }
}

.product-sample { font-size: 13px; line-height: 1.6; color: var(--muted); max-width: 420px; }
.product-link {
  align-self: flex-start;
  font-size: 14px;
  font-weight: 600;
  border-bottom: 1px solid currentColor;
  padding-block: 10px 2px;
}

/* ── The phone every demo sits in ─────────────────────────────────────── */

.phone {
  padding: 10px;
  border-radius: 40px;
  background: var(--phone);
  box-shadow: var(--shadow-lift);
}
.phone__screen {
  position: relative;
  overflow: hidden;
  border-radius: 30px;
  background: var(--surface);
  outline: 1px solid var(--imgline);
  outline-offset: -1px;
}

/* ── Points, steps and split sections ─────────────────────────────────── */

.product-section {
  padding-block: clamp(48px, 8vw, 110px);
  border-top: 1px solid var(--line);
}
.product-points {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
  counter-reset: point;
}
/* A flex item is not a list item, so the list keeps its own count. */
.product-points > li {
  counter-increment: point;
  display: flex;
  gap: 16px;
  padding: 22px 22px 22px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
  line-height: 1.65;
}
.product-points > li::before {
  content: counter(point, lower-roman);
  flex: 0 0 1.6em;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 20px;
  line-height: 1.2;
  color: var(--accent);
}
@media (min-width: 720px) {
  .product-points { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 26px; }
  .product-points--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .product-points--single { grid-template-columns: minmax(0, 1fr); }
}
.product-points__title { font-size: 22px; margin-bottom: 18px; }

.product-split { display: grid; gap: 32px; }
.product-split__head { display: flex; flex-direction: column; gap: 18px; max-width: 560px; margin-bottom: clamp(28px, 4vw, 44px); }
.product-split .product-split__head { margin-bottom: 0; }
.product-split__title { font-size: clamp(32px, 3.9vw, 56px); line-height: 1.04; letter-spacing: -.02em; }
@media (min-width: 960px) {
  .product-split { grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 26px; align-items: start; }
  .product-split > :first-child { grid-column: 1 / span 5; }
  .product-split > :last-child { grid-column: 7 / span 6; }
}

.product-parts { display: grid; gap: 32px 26px; }
.product-part { display: flex; flex-direction: column; gap: 10px; max-width: 520px; }
.product-part__title { font-size: clamp(24px, 2.4vw, 32px); line-height: 1.1; }
.product-part__body { font-size: 15px; line-height: 1.7; color: var(--ink2); }
@media (min-width: 720px) {
  .product-parts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .product-parts--single { grid-template-columns: minmax(0, 1fr); }
}
@media (min-width: 1100px) {
  .product-parts { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .product-parts--single { grid-template-columns: minmax(0, 1fr); }
}

.product-upgrade, .product-value { font-size: 15px; line-height: 1.7; color: var(--ink); max-width: 560px; }
.product-alone { display: flex; flex-direction: column; gap: 14px; margin-top: clamp(32px, 5vw, 56px); max-width: 640px; }

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

/* ── How every page ends ──────────────────────────────────────────────── */

.product-close { padding-block: clamp(64px, 10vw, 140px); border-top: 1px solid var(--line); background: var(--bg2); }
.product-close__inner { display: flex; flex-direction: column; align-items: center; gap: 20px; text-align: center; }
.product-close__title { max-width: 18ch; font-size: clamp(36px, 5vw, 72px); line-height: 1; letter-spacing: -.02em; }
.product-close__price { display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 6px 14px; margin-top: 8px; }
.product-close__label { font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--muted); }
.product-close__figure { font-family: var(--font-display); font-size: clamp(30px, 3.4vw, 44px); line-height: 1.1; }
.product-close__figure .proposed { font-family: var(--font-body); font-size: 12px; color: var(--muted); vertical-align: middle; }
.product-close__note { max-width: 520px; font-size: 14px; line-height: 1.6; color: var(--ink2); }
.product-close__small { font-size: 13px; color: var(--muted); }
.product-close__all { font-size: 13px; color: var(--muted); border-bottom: 1px solid var(--line); padding-block: 12px 2px; }

/* ── Kids: the live world ─────────────────────────────────────────────── */

.world-demo { display: grid; gap: 28px; justify-items: center; }
.world-demo__stage { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.world-demo__greeted { display: flex; flex-direction: column; align-items: center; gap: 12px; max-width: 320px; text-align: center; }
.world-demo__greeted[hidden] { display: none; }
.world-demo__greeted-line { font-size: 14px; line-height: 1.6; color: var(--ink2); }
.world-demo__phone { width: min(300px, 78vw); }
.world-stack { aspect-ratio: 1 / 2; background: var(--bg2); }
.world-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-ui) var(--ease-out);
}
.world-frame.is-shown { opacity: 1; pointer-events: auto; }
.world-frame.is-front { z-index: 1; }
.world-demo__side { display: flex; flex-direction: column; gap: 18px; width: 100%; min-width: 0; }
/* Neither box narrows below its own example, "për shembull 5" and "на пример
   Леон" being the longest: side by side where both fit, one above the other
   where they do not. Fixed at 1.5 to 1, the age box narrowed to about 108
   pixels on a wide screen and cut its number off in every language. */
.world-demo__form { display: grid; grid-template-columns: repeat(auto-fit, minmax(10em, 1fr)); gap: 12px; align-items: end; }
.world-demo__field { display: flex; flex-direction: column; gap: 8px; min-width: 0; font-size: 13px; font-weight: 600; }
.world-demo__show { grid-column: 1 / -1; justify-self: start; min-height: 46px; }
.world-demo__error { grid-column: 1 / -1; min-height: 1.4em; font-size: 13px; color: var(--accent); }
.world-demo__kept { grid-column: 1 / -1; }
.world-demo__field input, .seat-finder__input {
  min-height: 48px;
  padding: 0 14px;
  border: 0;
  border-radius: 12px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1.5px var(--ink);
  color: var(--ink);
  font: inherit;
  font-size: 16px;
  font-weight: 400;
}
/* The seat finder's own example name, "на пример Мила Петровска", is the
   longest placeholder either input shows and clipped against the phone
   mockup's fixed, narrow width at the input's own 16px (kept there to stop
   iOS zooming in on focus); shrinking only the placeholder's size leaves
   that font-size untouched while giving the example room to fit. */
.world-demo__field input::placeholder, .seat-finder__input::placeholder { color: var(--muted); font-size: 14px; }
.world-picker {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter);
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
  scrollbar-width: none;
}
.world-picker::-webkit-scrollbar { display: none; }
.world-pick {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 104px;
  padding: 12px 8px;
  border: 0;
  border-radius: 18px;
  background: transparent;
  text-align: center;
  cursor: pointer;
  scroll-snap-align: start;
  -webkit-tap-highlight-color: transparent;
  transition-property: background-color, transform;
  transition-duration: var(--dur-hover), var(--dur-press);
  transition-timing-function: ease, var(--ease-out);
}
.world-pick:active { transform: scale(.96); }
.world-pick[aria-pressed="true"] { background: var(--surface); box-shadow: 0 0 0 1px var(--line); }
.world-pick[aria-busy="true"] .world-pick__art { opacity: .5; }
@media (hover: hover) and (pointer: fine) {
  .world-pick:hover { background: var(--surface); }
}
.world-pick__art {
  width: 56px;
  height: 56px;
  border-radius: 14px;
  background: var(--bg2);
  object-fit: contain;
  padding: 6px;
  transition: opacity var(--dur-ui) var(--ease-out);
}
.world-pick__name { min-width: 0; font-family: var(--font-display); font-size: 16px; line-height: 1.15; overflow-wrap: anywhere; }
@media (min-width: 960px) {
  /* The picker takes its own row under the phone and the form. Two to a row
     beside the phone left a name about 85 pixels, which broke the longer
     ones mid word (диносауру, сите) once the composed themes joined the
     worlds. */
  .world-demo {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas: "stage form" "picker picker";
    align-items: start; justify-items: stretch; gap: 32px;
  }
  .world-demo__stage { grid-area: stage; }
  .world-demo__side { display: contents; }
  .world-demo__form { grid-area: form; }
  .world-demo__side > :not(.world-demo__form):not(.world-picker) { grid-column: 1 / -1; }
  .world-picker {
    grid-area: picker;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    overflow: visible;
    margin-inline: 0;
    padding-inline: 0;
  }
  .world-pick { flex-direction: row; width: auto; padding: 8px 10px; text-align: left; gap: 12px; }
  .world-pick__art { width: 44px; height: 44px; }
}

/* ── Seating: the hall and the finder ─────────────────────────────────── */

.seat-demo { display: grid; gap: 32px; align-items: start; }
.seat-plan { border-radius: 22px; background: var(--surface); box-shadow: var(--shadow-lift); overflow: hidden; }
.seat-plan__bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 16px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}
.seat-plan__bar span { color: var(--muted); }
.seat-plan__body { display: grid; gap: 16px; padding: 16px; }
.seat-plan__waiting { border-radius: 16px; background: var(--bg2); padding: 14px; }
.seat-plan__label {
  display: flex;
  justify-content: space-between;
  margin-bottom: 12px;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}
.seat-plan__label b { letter-spacing: 0; color: var(--ink); font-variant-numeric: tabular-nums; }
.seat-plan__chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.seat-chip {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 0 14px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.seat-chip.is-seated { opacity: 0; }
.seat-hall { display: block; width: 100%; height: auto; border-radius: 16px; background: var(--bg2); }
.seat-hall__head { fill: var(--line); }
.seat-hall__head-label { fill: var(--ink2); font-family: var(--font-body); font-size: 13px; }
.seat-table__top { fill: var(--surface); stroke: var(--line); stroke-width: 1.5; }
.seat-table__lit {
  fill: var(--accent-soft);
  stroke: var(--accent);
  stroke-width: 3;
  opacity: 0;
  transition: opacity var(--dur-ui) var(--ease-out);
}
.seat-table.is-lit .seat-table__lit { opacity: 1; }
.seat-table__label { fill: var(--ink); font-family: var(--font-body); font-size: 20px; font-weight: 700; }
.seat-table__count { fill: var(--muted); font-family: var(--font-body); font-size: 12px; font-variant-numeric: tabular-nums; }
.seat-chair { fill: var(--line); }
.seat-guest { fill: var(--accent); opacity: 0; transform-box: fill-box; transform-origin: center; }
.seat-guest.is-seated { opacity: 1; }
.seat-guest.is-before { fill: var(--ink2); }
.seat-demo__side { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.seat-demo__phone { width: min(300px, 100%); }
.seat-demo__after { display: flex; flex-direction: column; align-items: center; gap: 12px; max-width: 300px; text-align: center; font-size: 14px; color: var(--ink2); }
.seat-demo__after[hidden] { display: none; }
.seat-finder { display: flex; flex-direction: column; gap: 10px; min-height: 560px; padding: 40px 16px 18px; }
.seat-finder__title { font-family: var(--font-display); font-size: 22px; line-height: 1.15; }
.seat-finder__find { min-height: 44px; }
.seat-finder__label { font-size: 13px; font-weight: 600; }
.seat-finder__hint { font-size: 12px; color: var(--muted); }
.seat-finder__answer { min-height: 1.6em; font-size: 15px; font-weight: 600; }
.seat-finder__choices { display: flex; flex-wrap: wrap; gap: 6px; }
.seat-choice {
  min-height: 36px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: var(--bg2);
  font-size: 12px;
  cursor: pointer;
  transition: transform var(--dur-press) var(--ease-out);
}
.seat-choice:active { transform: scale(.96); }
.seat-hall--mini { margin-top: auto; }
.seat-hall--mini .seat-table__label { font-size: 26px; }
.seat-hall--mini .seat-hall__head-label { display: none; }
.seat-finder__note { font-size: 11px; text-align: center; color: var(--muted); }
@media (min-width: 720px) {
  .seat-plan__body { grid-template-columns: 190px minmax(0, 1fr); align-items: start; }
  .seat-plan__chips { flex-direction: column; align-items: stretch; }
  .seat-chip { justify-content: center; }
}
@media (min-width: 1100px) {
  .seat-demo { grid-template-columns: minmax(0, 1fr) 300px; gap: 40px; }
}

/* ── Photos: one guest found in three photos ──────────────────────────── */

.faces-demo { margin: 0; display: flex; flex-direction: column; gap: 18px; }
.faces-demo__photos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(8px, 1.4vw, 18px); margin: 0; padding: 0; list-style: none; }
.face-photo {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: var(--radius-photo);
  outline: 1px solid var(--imgline);
  outline-offset: -1px;
}
.face-photo img { width: 100%; height: 100%; object-fit: cover; }
/* Where her face is in each photo, measured on the square picture as a share
   of its width and height, and how wide the ring around it is. These three
   photos are the same p-mila-toast/-sparkler/-arch crops home.css's own
   .face-ring uses for its face-match section, so the fractions and the 26%
   ring width are copied from there rather than re-measured. */
.face-photo--toast { --face-x: 43%; --face-y: 43%; --face-size: 26%; --i: 0; }
.face-photo--sparkler { --face-x: 46%; --face-y: 43%; --face-size: 26%; --i: 1; }
.face-photo--friends { --face-x: 49%; --face-y: 42%; --face-size: 26%; --i: 2; }
.face-ring {
  position: absolute;
  left: var(--face-x);
  top: var(--face-y);
  width: var(--face-size);
  aspect-ratio: 1;
  border-radius: 50%;
  translate: -50% -50%;
  box-shadow: 0 0 0 2px var(--on-photo), 0 0 0 4px var(--accent);
  opacity: 0;
}
.faces-demo__say { position: relative; min-height: 1.6em; font-family: var(--font-display); font-size: clamp(20px, 2vw, 26px); }
.faces-demo__before, .faces-demo__after { display: block; }
.faces-demo__after { position: absolute; inset: 0; opacity: 0; }
.faces-demo__caption { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; }
.faces-demo__sent {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 34px;
  padding: 0 14px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font-size: 12px;
  font-weight: 600;
  opacity: 0;
}
.faces-demo__sent::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.faces-demo__example { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.faces-demo.is-playing .face-ring {
  animation: face-ring-settle var(--dur-reveal) var(--ease-out) calc(300ms + var(--i) * 450ms) both;
}
/* She is named first, the rings settle one photo at a time, and only then
   does the line say where she was found and her photos go out. */
.faces-demo.is-playing .faces-demo__before { animation: face-say-out var(--dur-ui) var(--ease-out) 1.6s both; }
.faces-demo.is-playing .faces-demo__after { animation: face-found var(--dur-reveal) var(--ease-out) 1.7s both; }
.faces-demo.is-playing .faces-demo__sent { animation: face-found var(--dur-reveal) var(--ease-out) 2.3s both; }
@keyframes face-say-out { to { opacity: 0; } }
@keyframes face-ring-settle { from { opacity: 0; transform: scale(1.6); } to { opacity: 1; transform: none; } }
@keyframes face-found { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ── Digital: the real invitation ─────────────────────────────────────── */

.invite-demo { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 16px; }
.invite-demo__phone { width: min(320px, 82vw); }
.invite-demo__screen { aspect-ratio: 9 / 19.5; background: var(--paper); }
.invite-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  opacity: 0;
  transition: opacity var(--dur-ui) var(--ease-out);
}
.invite-frame.is-shown { opacity: 1; }
.invite-demo .product-sample { text-align: center; }

/* ── Printed: the envelope, papers and designs ────────────────────────── */

.envelope-demo .ev-frame { max-width: 520px; margin-inline: auto; box-shadow: var(--shadow-lift); }
.envelope-demo__next {
  position: absolute;
  z-index: 10;
  left: 50%;
  bottom: 18px;
  translate: -50% 0;
  min-height: 40px;
  font-size: 12px;
  /* Dark glass, since it sits on a cream envelope and white satin rather than
     on the home hero's dark photo, where the white glass it wore read as
     near-white words on near-white paper. */
  color: var(--on-photo);
  background: color-mix(in oklab, var(--night) 62%, transparent);
  --chip-line: var(--on-photo-line);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
@media (hover: hover) and (pointer: fine) {
  .envelope-demo__next:hover { background: color-mix(in oklab, var(--night) 74%, transparent); }
}

.paper-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; margin: 0; padding: 0; list-style: none; }
@media (min-width: 720px) { .paper-row { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.paper { display: flex; flex-direction: column; gap: 12px; }
.paper__face {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius-photo);
  outline: 1px solid var(--imgline);
  outline-offset: -1px;
}
.paper__face img { width: 100%; height: 100%; object-fit: cover; }
/* A band of light crosses the paper under the pointer, as it would when the
   sheet is tilted toward a lamp. */
.paper__face::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 38%, color-mix(in oklab, var(--on-photo) 45%, transparent) 50%, transparent 62%);
  transform: translateX(-100%);
  pointer-events: none;
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .paper:hover .paper__face::after { transform: translateX(100%); transition: transform var(--dur-reveal) var(--ease-in-out); }
}

/* The printed page's own matching-set proof: five real pieces of one suite,
   side by side. A place card is printed landscape and the rest portrait, so
   unlike design-tile's uniform 640/900 crop these keep each piece's own
   shape rather than cropping a wide card down to a tall frame. */
.matching-set-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; margin: 0 0 28px; padding: 0; list-style: none; }
@media (min-width: 720px) { .matching-set-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.matching-set-tile { display: flex; flex-direction: column; justify-content: flex-end; gap: 10px; }
.matching-set-photo { display: block; }
.matching-set-photo img { width: 100%; height: auto; border-radius: var(--radius-photo); outline: 1px solid var(--imgline); outline-offset: -1px; }
.matching-set-label { font-size: 13px; color: var(--muted); }

.design-strip {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(140px, 1fr);
  gap: 18px;
  margin: 0 calc(var(--gutter) * -1);
  padding: 0 var(--gutter) 24px;
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter);
  scrollbar-width: none;
}
.design-strip::-webkit-scrollbar { display: none; }
/* Seven columns of at least 140 pixels overflowed the page between 960 and
   about 1230 wide, which made a phone showing the desktop site zoom the whole
   page out. They share the width instead, which is what they already did
   wherever they fitted. */
@media (min-width: 960px) { .design-strip { grid-auto-columns: minmax(0, 1fr); overflow: visible; margin-inline: 0; padding-inline: 0; } }
/* Narrower, the designs wrap into rows rather than scroll, so every one of
   them shows without a sideways drag. */
@media (max-width: 959px) {
  .design-strip {
    grid-auto-flow: row;
    grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    gap: 12px;
    margin-inline: 0;
    padding: 0 0 24px;
    overflow: visible;
  }
}

/* ── Designs page ─────────────────────────────────────────────────────── */

/* The families wrap rather than scroll, because a scrolling row hid the last
   two on a phone with nothing to say they were there. */
.design-tabs { display: flex; flex-wrap: wrap; gap: 8px; }
.design-tab { flex: 0 0 auto; --chip-line: var(--line); }
.design-families { display: flex; flex-direction: column; }
.design-band {
  display: block;
  margin-bottom: 28px;
  padding: 18px 22px;
  border-radius: 16px;
  background: var(--accent-soft);
  font-size: 15px;
  font-weight: 600;
}
.design-family { padding-block: clamp(40px, 6vw, 72px); border-top: 1px solid var(--line); scroll-margin-top: calc(var(--header-h) + 12px); }
.design-family__head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 8px 24px; margin-bottom: 28px; }
.design-family__name { font-size: clamp(30px, 3.4vw, 48px); line-height: 1.05; letter-spacing: -.02em; }
.design-family__line { font-size: 14px; color: var(--muted); max-width: 520px; }
.design-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(150px, 42vw), 1fr));
  gap: clamp(14px, 2vw, 26px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.design-tile { scroll-snap-align: start; }
.design-tile-open { display: block; width: 100%; padding: 0; border: 0; background: none; text-align: inherit; cursor: pointer; }
.design-tile img, .design-viewer-img, .design-tile .card-composed, .design-viewer .card-composed {
  width: 100%;
  height: auto;
  aspect-ratio: 640 / 900;
  object-fit: cover;
  object-position: top;
  border-radius: 3px;
  box-shadow: var(--shadow-menu);
}
/* Inside the viewer a composed card sizes like design-viewer-img, contained
   rather than cropped, since object-fit does nothing on a figure. A figure
   whose only children are absolutely positioned (the bg image and the text
   layer) has no in-flow content of its own, so aspect-ratio cannot derive
   its size from two max- constraints the way it derives design-viewer-img's
   from that <img>'s intrinsic picture; height is given as a definite value,
   the smaller of the two caps design-viewer-img itself is held to, for
   aspect-ratio to size the auto width from. */
.design-viewer .card-composed {
  width: auto;
  height: min(
    calc(min(70vh, 100vw - 2 * var(--gutter)) * 900 / 640),
    calc(100dvh - 2 * var(--gutter))
  );
  box-shadow: none;
}

/* designs.js's own viewer: a design opened full size. Dark regardless of the
   page's own theme, the way a slide viewer is, so the picture reads the same
   whoever is looking at it. */
.design-viewer {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  place-items: center;
  padding: var(--gutter);
  background: rgb(10 10 10 / 0.92);
}
.design-viewer-img {
  width: auto;
  max-width: min(70vh, 100%);
  max-height: calc(100dvh - 2 * var(--gutter));
  aspect-ratio: auto;
  object-fit: contain;
  -webkit-user-select: none;
  user-select: none;
}
.design-viewer-step--back { left: max(16px, env(safe-area-inset-left)); }
.design-viewer-step--next { right: max(16px, env(safe-area-inset-right)); }
.design-viewer-step { top: 50%; translate: 0 -50%; }
.design-viewer-close {
  top: max(16px, env(safe-area-inset-top));
  right: max(16px, env(safe-area-inset-right));
}
.design-viewer-close, .design-viewer-step {
  position: fixed;
  z-index: 81;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--on-photo-glass);
  color: var(--on-photo);
  box-shadow: inset 0 0 0 1px var(--on-photo-line);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  cursor: pointer;
  transition: transform var(--dur-press) var(--ease-out);
}
.design-viewer-close:active, .design-viewer-step:active { transform: scale(.96); }
@media (prefers-reduced-motion: no-preference) {
  .design-viewer { animation: design-viewer-in 200ms var(--ease-out) both; }
}
@keyframes design-viewer-in { from { opacity: 0; } }

/* The envelope demo's replay chip sits over the artwork rather than beside
   it, so it is drawn smaller than the chip's own 44 pixel floor. A phone set
   to show the desktop site is still steered with a thumb at any width, so
   its floor follows the pointer rather than the viewport alone. */
@media (max-width: 699px), (hover: none) and (pointer: coarse) {
  .envelope-demo__next { min-height: 44px; font-size: 14px; }
}

/* ── On a phone ───────────────────────────────────────────────────────── */
/* The floor site.css sets for a phone, 14 pixel text, 16 pixel copy and 44
   pixel controls, applied to the product pages' own pieces, and each demo
   laid out so it can be worked with one thumb on one screen. */
@media (max-width: 699px) {
  .product-points > li, .product-part__body, .product-upgrade, .product-value { font-size: 16px; }
  .product-sample, .product-close__small, .world-demo__field, .world-demo__error,
  .seat-plan__bar, .seat-finder__label, .seat-finder__hint, .seat-finder__note,
  .faces-demo__sent, .faces-demo__example { font-size: 14px; }
  .product-close__label { font-size: 14px; letter-spacing: .14em; }
  .product-close__all, .product-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding-block: 0;
    border-bottom: 0;
    font-size: 14px;
    text-decoration: underline;
    text-underline-offset: 4px;
  }

  /* The kids demo reads top to bottom as the thumb works it: the name, the
     world that greets it, then the other worlds. The phone is sized from the
     screen's height, so the boxes and the whole phone fit on one screen. */
  .world-demo__side { display: contents; }
  .world-demo__form { order: 1; width: 100%; }
  .world-demo__stage { order: 2; }
  /* The age field keeps the form's narrower column (world-demo__form's 1fr
     against the name's 1.5fr), which leaves it too little room for a full
     example phrase at the input's own 16px: Albanian's "për shembull 5" ran
     past its edge. Only the hint shrinks, so a typed age stays full size. */
  .world-demo__field--age input::placeholder { font-size: 13px; }
  /* All ten worlds show at once, two to a row, as the wide picker lays them
     out. A scrolling row showed three and hid seven. */
  .world-picker {
    order: 3;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px;
    width: 100%;
    overflow: visible;
    margin-inline: 0;
    padding-inline: 0;
  }
  .world-pick { flex-direction: row; width: auto; padding: 8px; text-align: left; gap: 8px; }
  .world-pick__art { width: 40px; height: 40px; flex-shrink: 0; }
  /* Half a phone leaves a name about 100 pixels, which a thirteen letter
     word such as Роденденскиот fills only at this size. */
  .world-pick__name { font-size: 14px; }
  .world-demo__side > .product-sample { order: 4; }
  .world-demo__phone { width: min(300px, 78vw, calc((100svh - var(--header-h) - 250px) / 2)); }

  /* The guest's phone comes first, straight under the headline, because
     typing a name into it is the demo. The host's plan follows. */
  .seat-demo__side { order: -1; }
  .seat-finder { min-height: min(560px, calc(100svh - var(--header-h) - 40px)); }
  .seat-plan__label { font-size: 14px; letter-spacing: .1em; }
  .seat-chip { font-size: 14px; }
  .seat-choice { min-height: 44px; padding: 0 14px; font-size: 14px; }
  /* The hall is drawn on a 520 unit wide board and shown at about 330
     pixels, so its lettering is set larger here to read at 14 pixels. */
  .seat-hall__head-label { font-size: 22px; }
  .seat-table__label { font-size: 26px; }
  .seat-table__count { font-size: 22px; transform: translateY(8px); }
  .seat-hall--mini .seat-table__label { font-size: 30px; }

  /* One photo across the screen and two under it, so the ring on her face
     is large enough to see. */
  .faces-demo__photos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .face-photo:first-child { grid-column: 1 / -1; }
}

/* ── Reduced motion ───────────────────────────────────────────────────── */
/* Each demo's finished still: the rings on her face, the hall full, the
   frames shown without a fade. */
@media (prefers-reduced-motion: reduce) {
  .faces-demo .face-ring, .faces-demo .faces-demo__after, .faces-demo .faces-demo__sent,
  .faces-demo.is-playing .face-ring, .faces-demo.is-playing .faces-demo__after, .faces-demo.is-playing .faces-demo__sent { opacity: 1; animation: none; }
  .faces-demo .faces-demo__before, .faces-demo.is-playing .faces-demo__before { opacity: 0; animation: none; }
  .world-frame, .invite-frame, .seat-table__lit, .world-pick__art { transition: none; }
}
