/* Hatch — the landing page.
   One family, ink on shell, the little guy's room colour as the ground it lives on.
   Light theme only, on purpose: every colour is set here, nothing follows the system. */

:root {
  /* The brand: ink on shell, and four soft accents used one at a time. */
  --shell: #F2EEE5;          /* the ground: the sheet, the header, the footer */
  --ink: #201E19;
  --sprout: #D6E89C;         /* the accent: the legendary chip, the app icon */
  --aqua: #81DCD4;
  --peach: #F3B89D;
  --lilac: #C7BAE8;

  --linen: #E7DFD2;          /* the waiting room, and what a missing picture keeps */
  --paper: var(--shell);     /* the sheet the posters are printed on */
  --stock: #FBF9F4;          /* label stock: a passport's label, the box label */
  --ink2: #4A453F;           /* body copy; labels on the room */
  --ink3: #6E6960;           /* labels on shell and stock only (fails AA on linen) */
  --rule: rgb(32 30 25 / .12);
  --room: var(--linen);      /* the creature's room colour, set by page.js at the reveal */

  /* Two voices, the brand's pair: the rounded one speaks (headlines, reading, buttons), the mono one
     states facts (labels, numbers, the chip, tags). Neither crosses over. */
  --font: ui-rounded, "SF Pro Rounded", "Nunito", system-ui, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  /* Never less than the safe area: a phone on its side keeps the island and the corners out of the margin.
     Both sides take the larger inset, so every block still starts on one margin line. */
  --gutter: max(clamp(16px, 4.4vw, 64px), env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px));
  --max: 1280px;
  /* The margin line: every block starts on it, at every width. % resolves where it's used. */
  --edge: max(var(--gutter), calc((100% - var(--max)) / 2));
  --peek: 32px;              /* how much of the paper sheet shows under the hero */
  --r-card: 28px;
  --r-tile: 24px;

  /* The app's springs: pop (0.3, 0.58), enter (0.55, 0.86), press (0.2, 1.0). */
  --pop: 300ms cubic-bezier(.34, 1.56, .64, 1);
  --enter: 560ms cubic-bezier(.22, 1, .36, 1);
  --press: 180ms ease-out;
}

/* ---------- Base ---------- */

*, *::before, *::after { box-sizing: border-box; }
html {
  background: var(--linen);
  color: var(--ink);
  font-family: var(--font);
  -webkit-text-size-adjust: 100%;
  scrollbar-gutter: stable;
  transition: background-color 1.1s ease;
}
html.revealed { background: var(--room); }
/* Past the hero the page is shell to the end, and so is what shows when a phone overscrolls the bottom. */
html.revealed:has(.bar[data-ground="paper"]) { background: var(--shell); }
html.locked, html.locked body { overflow: hidden; overscroll-behavior: none; }
body {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
h1, h2, p, figure, ol, ul, table { margin: 0; }
ol, ul { padding: 0; list-style: none; }
img, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
::selection { background: var(--sprout); color: var(--ink); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
[hidden] { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- Type: two voices, size and tone ---------- */

/* The fact voice: every label, number and unit, in mono caps. */
.caps {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .08em;
  line-height: 1.35;
  text-transform: uppercase;
  color: var(--ink3);
}
h2 {
  font-size: clamp(36px, 4.6vw, 64px);
  font-weight: 900;
  letter-spacing: -.03em;
  line-height: 1;
  text-wrap: balance;
}
.lead {
  font-size: clamp(17px, 1.4vw, 20px);
  line-height: 1.45;
  color: var(--ink2);
  max-width: 34ch;
  text-wrap: pretty;
}
/* The logo: the hatchling peeking out of its egg, and the word. One drawing (index.html's symbols),
   always in ink, sized by its height. */
.wordmark { display: inline-flex; color: var(--ink); text-decoration: none; }
.logo { display: block; height: 34px; width: auto; aspect-ratio: 765 / 259; fill: currentColor; overflow: visible; }

/* ---------- Controls: an ink pill, and words with no box ---------- */

.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 52px;
  padding: 0 24px 1px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--shell);
  font-size: 17px;
  font-weight: 800;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--pop), box-shadow 200ms ease-out;
}
.pill:hover { transform: translateY(-2px); box-shadow: 0 12px 20px -12px rgb(32 30 25 / .55); }
.pill:active { transform: translateY(1px) scale(.96); box-shadow: none; transition-duration: 120ms; }
.pill:focus-visible { outline-offset: 4px; }
.pill--sm { height: 40px; padding: 0 18px 1px; font-size: 15px; }
.pill--lg { height: 60px; padding: 0 32px 1px; font-size: 19px; }

/* The secondary: the brand's outline pill, its words in the fact voice. Hover fills it with a breath of ink. */
.pill--line {
  padding: 0 24px;
  background: transparent;
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px currentColor;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  transition: transform var(--pop), background-color 200ms ease-out;
}
.pill--line:hover { background: rgb(32 30 25 / .07); box-shadow: inset 0 0 0 1.5px currentColor; }
.pill--line:active { box-shadow: inset 0 0 0 1.5px currentColor; }

/* The rarity chip, exactly the app's: five pips and a word. Ink from Rare up, sprout from Legendary. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 11px 0 10px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px rgb(32 30 25 / .2);
  color: var(--ink);
  white-space: nowrap;
  vertical-align: middle;
}
.chip b { font-family: var(--mono); font-size: 11px; font-weight: 600; letter-spacing: .1em; line-height: 1; text-transform: uppercase; }
.pips { display: inline-flex; gap: 2px; }
.pips i { width: 5px; height: 5px; border-radius: 50%; background: rgb(32 30 25 / .18); }
.chip[data-stars="1"] i:nth-child(-n+1),
.chip[data-stars="2"] i:nth-child(-n+2),
.chip[data-stars="3"] i:nth-child(-n+3),
.chip[data-stars="4"] i:nth-child(-n+4),
.chip[data-stars="5"] i { background: currentColor; }
.chip:is([data-r="rare"], [data-r="veryRare"]) { background: var(--ink); color: var(--shell); box-shadow: none; }
.chip:is([data-r="rare"], [data-r="veryRare"]) i { background: rgb(242 238 229 / .3); }
.chip:is([data-r="legendary"], [data-r="oneOfOne"]) { background: var(--sprout); color: var(--ink); box-shadow: none; }
.chip:is([data-r="legendary"], [data-r="oneOfOne"]) i { background: rgb(32 30 25 / .3); }

/* The knock dots: a capsule grows for each knock. */
.dots { display: inline-flex; align-items: center; gap: 5px; }
.dots i { width: 8px; height: 8px; border-radius: 4px; background: rgb(32 30 25 / .16); transition: width var(--pop), background-color 200ms ease-out; }
.dots i.on { width: 18px; background: var(--ink); }

/* ---------- The stage and the arrival ---------- */

#stage {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
  touch-action: none;               /* while the egg waits, a swipe is a knock */
}
/* After: the page scrolls, taps reach the little guys. And the stage takes the large viewport, so Safari's
   toolbar folding away on the first scroll doesn't resize it: no lens jump, no new drawing buffer. */
html.revealed #stage { touch-action: pan-y; bottom: auto; height: 100vh; height: 100lvh; }
/* No WebGL, or the engine never came: there's nothing to draw, so nothing to take the taps. */
html.no-stage #stage { display: none; }

.skip {
  position: fixed;
  top: 16px;
  left: max(var(--gutter), calc((100vw - var(--max)) / 2));
  z-index: 40;
  padding: 10px 16px 11px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--shell);
  font-size: 15px;
  font-weight: 800;
  text-decoration: none;
}
.skip:not(:focus) {
  width: 1px; height: 1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

.arrival {
  position: fixed;
  left: 0;
  right: 0;
  padding: 0 var(--edge);
  bottom: calc(48px + env(safe-area-inset-bottom));
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 400ms ease-out, transform var(--enter);
}
.arrival.on { opacity: 1; transform: none; }
.arrival-line {
  min-height: 1.05em;
  font-size: clamp(34px, 3.8vw, 52px);
  font-weight: 900;
  letter-spacing: -.026em;
  line-height: 1.05;
  max-width: 16ch;
}
.arrival-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 12px; }
/* The arrival room is dim (about #A3A8B0 before the first knock): ink2 measures 4:1 there, ink 7:1. */
.arrival .caps { color: var(--ink); }
.arrival .dots i:not(.on) { background: rgb(32 30 25 / .22); }
.arrival-note { margin-top: 12px; font-size: 17px; color: var(--ink); max-width: 32ch; }
.arrival-note:empty, #arrival-caps:empty { display: none; }   /* an empty caps span would still take the gap */

/* Over the egg; the engine may move it with --egg-x, --egg-y and --egg-h. The defaults are the egg as
   world.js frames it ('egg'), measured at 1440, 1024, 800 and 390: centred 42% down, 45vh tall, and
   89vw where a portrait phone's width decides. The focus ring is egg-shaped (the app's egg is .72 wide). */
.knock {
  position: fixed;
  left: var(--egg-x, 50%);
  top: var(--egg-y, 42%);
  z-index: 5;
  height: var(--egg-h, min(45vh, 89vw));
  aspect-ratio: .72;
  transform: translate(-50%, -50%);
  border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
  pointer-events: none;
}
.knock:focus-visible { outline-offset: 12px; }

/* ---------- The header: the wordmark and the primary ---------- */

.bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: calc(72px + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) var(--edge) 0;
  transition: background-color 200ms ease-out, box-shadow 200ms ease-out;
}
/* The bar takes the ground under it (page.js): clear on the hero, shell from the sheet on. */
.bar[data-ground="paper"] { background: rgb(242 238 229 / .96); box-shadow: inset 0 -1px 0 var(--rule); }
/* The logo prints at the second knock, like a label printer: the egg, then a letter at a time. */
.bar .wordmark { clip-path: inset(0 100% 0 0); transition: clip-path 700ms steps(6, jump-end); }
html:is(.printed, .revealed) .bar .wordmark { clip-path: inset(0 -4px 0 0); }
.bar-cta { opacity: 0; transform: translateY(-8px); visibility: hidden; }
html.revealed .bar-cta {
  opacity: 1; transform: none; visibility: visible;
  transition: opacity 400ms ease-out 420ms, transform var(--enter) 420ms, visibility 0s 420ms, box-shadow 200ms ease-out;
}
html.revealed .bar-cta:hover { transform: translateY(-2px); transition: transform var(--pop), box-shadow 200ms ease-out; }
html.revealed .bar-cta:active { transform: translateY(1px) scale(.96); }

/* ---------- The hero: the caption on the little guy's room ---------- */

.hero {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: flex-end;
  height: 100vh;
  height: 100svh;
  min-height: 560px;
  padding: 0 var(--edge) calc(var(--peek) + 64px);
  pointer-events: none;             /* taps fall through to the stage */
}
.hero-cap { pointer-events: auto; max-width: 600px; }
.hero-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
/* The caption lies over the sill's floor, which keeps only half the room's glow: ink2 measured 3.9–4.4:1
   there (day, golden, night), ink 7.2:1 and up. So the caption is all ink; size carries the hierarchy. */
.hero .caps { color: var(--ink); }
.hero h1 {
  margin-top: 16px;
  font-size: clamp(48px, 6.4vw, 92px);
  font-weight: 900;
  letter-spacing: -.034em;
  line-height: .98;
  outline: none;
}
.hero-desc { margin-top: 12px; font-size: clamp(17px, 1.4vw, 20px); color: var(--ink); max-width: 32ch; }
.actions { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 32px; }
.show-status {
  position: absolute;
  left: 0;
  top: calc(100% + 12px);
  opacity: 0;
  transition: opacity 200ms ease-out;
}
.show-status.on { opacity: 1; }
.show-url { color: var(--ink); text-transform: none; letter-spacing: 0; user-select: all; overflow-wrap: anywhere; }
/* The field the old copy path selects from: pinned and invisible, 16px so iOS doesn't zoom to it. */
.copy-field { position: fixed; top: 0; left: 0; width: 1px; height: 1px; padding: 0; border: 0; opacity: 0; font-size: 16px; pointer-events: none; }

/* Opened without its number (the engine and the genome both failed to load): only the words that don't need one. */
html.no-number :is(.hero-meta, [data-show], .carton-base [data-f="today"]) { display: none; }

/* One entrance, once: the caption, then the header's primary, then the sheet rises into view. */
[data-enter] { opacity: 0; transform: translateY(16px); }
html.revealed [data-enter] {
  opacity: 1;
  transform: none;
  transition: opacity 480ms ease-out, transform var(--enter);
  transition-delay: calc(var(--d, 0) * 90ms);
}

/* ---------- The sheet: the posters, printed on paper ---------- */

/* main sits over the fixed stage; where it's clear (the hero, the sill's window) a tap goes through to the
   little guys. Only what's printed takes the pointer: the sheet's sections and the hero's caption. */
main { position: relative; z-index: 1; pointer-events: none; }
main > .sheet > * { pointer-events: auto; }
main > .sheet > .sill { pointer-events: none; }
.sill > .sill-head, .sill .sun { pointer-events: auto; }
/* The sheet has no ground of its own: its window onto the sill (.portal) paints it, every pixel but itself,
   so the stage behind the page shows through the window and nowhere else. What's printed on it keeps a
   ground of its own too, the same shell, so every word has a ground a contrast check can find. */
.sheet > :not(.sill), .sill-head, .sun { background: var(--paper); }
.sheet {
  position: relative;
  isolation: isolate;
  overflow: clip;
  margin-top: calc(-1 * var(--peek));
  padding: 80px 0;
  border-radius: var(--r-card) var(--r-card) 0 0;   /* the footer carries on from its bottom edge */
  transform: translateY(calc(var(--peek) + 48px));
}
html.revealed .sheet { transform: none; transition: transform 800ms cubic-bezier(.22, 1, .36, 1) 300ms; }

.wrap { padding: 0 var(--edge); }
.poster { padding: 80px 0; }

/* A poster: copy on one side, its one object on the other; the object alternates. */
.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 96px; align-items: center; }
.split--flip .obj { order: -1; }
.copy > h2 + .lead { margin-top: 24px; }
.copy > .lead + * { margin-top: 32px; }

/* Entrances on the way down: each block once, never again. */
html.revealed [data-reveal] { opacity: 0; transform: translateY(24px); }
html.revealed [data-reveal].in { opacity: 1; transform: none; transition: opacity 480ms ease-out, transform var(--enter); }

/* 2 — One of a million: the spec sheet. The label says what, the right column says it. */
.million { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 96px; align-items: start; }
.million > h2 { grid-column: 1; }
.million > .lead { grid-column: 2; padding-top: 4px; }
.lineup { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 32px 24px; margin-top: 64px; }
/* A passport each: the little guy in its own room on top, its papers on label stock below.
   Sized by its own width (cqi), so a passport reads the same four to a row or two. */
.lineup li {
  position: relative;
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  border-radius: var(--r-tile);
  background: var(--stock);
  overflow: hidden;
  box-shadow:
    0 0 0 1px rgb(32 30 25 / .05),
    0 2px 3px rgb(32 30 25 / .06),
    0 22px 36px -22px rgb(32 30 25 / .34);
}
/* The ring goes round the whole passport: on the room alone it would be cut off by the card. */
.lineup li:has(.look:focus-visible) { outline: 2px solid var(--ink); outline-offset: 4px; }
/* The room: its own lit floor, a shadow on it, and the little guy (a turntable sprite). */
.look {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  padding: 0;
  border: 0;
  overflow: hidden;
  background: var(--tint, var(--linen));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.look:focus-visible { outline: none; }
.look-logo { position: absolute; top: 7cqi; left: 7cqi; height: clamp(13px, 6.4cqi, 18px); pointer-events: none; }
.look-room, .look-guy { position: absolute; inset: 0; background-size: cover; background-position: center; }
.look-guy {
  /* Twelve frames side by side: eleven head turns and a happy face. --f picks one. */
  background-size: 1200% 100%;
  background-position: calc(var(--f, 3) * 100% / 11) 0;
  transform-origin: 50% 82%;
  will-change: transform;
}
.look-shadow {
  position: absolute;
  left: 27%;
  width: 46%;
  top: 76%;
  height: 8%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(40 24 18 / .34), rgb(40 24 18 / .12) 60%, transparent);
  transform-origin: 50% 50%;
}
/* The papers: the name big, the number and the chip, what it's made of, its barcode. */
.pass { display: flex; flex-direction: column; flex: 1; padding: clamp(12px, 7cqi, 20px) clamp(12px, 7cqi, 20px) clamp(14px, 7.5cqi, 22px); }
.pass-name { font-size: clamp(22px, 12cqi, 34px); font-weight: 900; letter-spacing: -.03em; line-height: 1; overflow-wrap: anywhere; }
.pass-id { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin-top: clamp(8px, 4.5cqi, 12px); }
.pass-id > .caps { color: var(--ink); }
/* Where "Legendary" wouldn't fit beside its number, every chip goes under its number, so a row matches. */
@container (max-width: 289px) { .pass-id { flex-direction: column; align-items: flex-start; } }
.pass-traits { margin-top: clamp(10px, 5cqi, 14px); color: var(--ink3); text-wrap: balance; }
.pass-code { height: clamp(18px, 8.5cqi, 24px); margin-top: auto; padding-top: clamp(12px, 6cqi, 18px); box-sizing: content-box; }
.pass-code i { margin-right: 1px; }
.specs { grid-column: 1; display: flex; flex-wrap: wrap; gap: 24px 48px; margin-top: 64px; }
.specs div { display: flex; flex-direction: column-reverse; gap: 4px; }
.specs dd { margin: 0; font-family: var(--mono); font-size: clamp(40px, 4vw, 56px); font-weight: 500; letter-spacing: -.04em; line-height: 1; }
.odds { grid-column: 2; margin-top: 64px; width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.odds th { padding: 0 16px 12px 0; text-align: left; font-weight: 800; }
.odds th:last-child, .odds td:last-child { padding-right: 0; text-align: right; white-space: nowrap; }
.odds td:last-child { font-family: var(--mono); font-size: 14px; font-weight: 500; }
.odds td { padding: 12px 16px 12px 0; border-top: 1px solid var(--rule); vertical-align: middle; font-size: 15px; font-weight: 800; line-height: 1.3; }
.odds td:nth-child(2) { color: var(--ink2); font-weight: 600; }
.odds .one td { padding-bottom: 0; }
.odds .one td:nth-child(2) { color: var(--ink); font-weight: 800; }

/* Posters in the brand's colours: a sheet of sprout or of ink on the shell wall, its edge on the margin
   line, its words on its own inner line. Its columns keep the page's gap, so its right column starts on
   the same line as every other section's. A poster's footer is a ruled row of facts, like the printed ones. */
.panel { position: relative; overflow: hidden; border-radius: var(--r-card); padding: clamp(28px, 5.6vw, 80px); }
.panel-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 32px;
  margin-top: clamp(48px, 6vw, 80px);
  padding-top: 20px;
  border-top: 1px solid var(--line);
}
.panel--sprout { --line: rgb(32 30 25 / .22); background: var(--sprout); }
.panel--sprout .caps { color: var(--ink2); }          /* ink3 is 4.1:1 on sprout; ink2 is 7.2 */
.panel--sprout .dots i:not(.on) { background: rgb(32 30 25 / .2); }
.panel--ink { --line: rgb(242 238 229 / .16); background: var(--ink); color: var(--shell); }
.panel--ink .caps { color: #A8A296; }                 /* 6.6:1 on ink */
.panel--ink .lead { color: #D3CDC2; }                 /* 10.5:1 */
.panel--ink :focus-visible { outline-color: var(--shell); }
.panel--ink .pill--line { color: var(--shell); }
.panel--ink .pill--line:hover { background: rgb(242 238 229 / .1); }
.panel--ink .show-url { color: var(--shell); }
.panel--ink ::selection { background: var(--sprout); color: var(--ink); }

/* 3 — One a day: tomorrow's egg is the object, standing in the window's light on the poster, and the
   countdown is its caption, as big as a label can be. The only centred text on the page: a caption under
   its object. */
.tomorrow { display: flex; flex-direction: column; align-items: center; }
.tomorrow-stage { position: relative; width: min(100%, 520px); aspect-ratio: 1; margin: -40px 0 -4px; }
.tomorrow-stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.tomorrow-knock { position: absolute; inset: 10% 24% 8%; border-radius: 50% 50% 46% 46% / 58% 58% 42% 42%; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.tomorrow-knock:focus-visible { outline-offset: 6px; }
.tomorrow.no-egg .tomorrow-stage { display: none; }
.clock { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.clock-num {
  display: flex;
  font-family: var(--mono);
  font-size: clamp(44px, 5.4vw, 80px);
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: 1;
  white-space: nowrap;
}
/* Each figure on its own wheel: the slot clips, the old figure rolls up out of it and the next rolls in. */
.clock-num .fig { position: relative; display: inline-block; width: .57em; height: 1.04em; overflow: hidden; letter-spacing: 0; }
.clock-num .fig i { position: absolute; inset: 0; display: flex; justify-content: center; font-style: normal; }
.clock-num .colon { display: inline-flex; justify-content: center; width: .46em; letter-spacing: 0; transform: translateY(-.05em); }
/* What the egg says when it's knocked: the speaking voice, under the copy, gone after a few seconds. */
.egg-say {
  min-height: 1.3em;
  margin-top: 24px;
  font-size: clamp(22px, 2vw, 28px);
  font-weight: 900;
  letter-spacing: -.02em;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 300ms ease-out, transform var(--pop);
}
.egg-say.on { opacity: 1; transform: none; }
.panel--sprout .dots i { transition: width var(--pop), background-color 200ms ease-out; }
.clock-foot { display: flex; align-items: center; gap: 12px; }

/* 4 — The sill, live, through a window cut in the page. The window is the one thing on the sheet that
   isn't paper: its own shadow, a sheet-sized spread of shell, is the sheet's ground. Its cut edge catches
   a little shade along the top, the way a hole in card does. */
.sill-head > .sill-lead { grid-column: 2; padding-top: 4px; }
.portal-wrap { margin-top: 56px; pointer-events: none; }
.portal {
  position: relative;
  z-index: -1;
  aspect-ratio: 16 / 7;
  border-radius: var(--r-card);
  box-shadow: 0 0 0 9999px var(--paper);
}
.portal::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 4px 10px -2px rgb(32 30 25 / .28), inset 0 0 0 1px rgb(32 30 25 / .1);
}
.portal-still { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
html.portal-live .portal-still { visibility: hidden; }
html.no-stage .sun { display: none; }     /* without the stage, the window keeps its still and there's no sun to move */

/* The sun: a day strip in the brand's accents (lilac night, peach dawn and dusk, aqua midday), a disc you
   drag along it, the hour it is in the fact voice, and a mark at the real now. */
.sun { display: grid; grid-template-columns: minmax(200px, auto) minmax(0, 1fr) auto; align-items: center; gap: 16px 40px; margin-top: 24px; }
.sun-read { display: flex; flex-direction: column; gap: 6px; }
.sun-time { font-family: var(--mono); font-size: clamp(32px, 3vw, 44px); font-weight: 500; letter-spacing: -.04em; line-height: 1; }
.sun-read .caps { color: var(--ink2); }
.sun-dial { position: relative; padding: 30px 0 4px; }
.sun-range {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 12px;
  margin: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--lilac) 0 21%, var(--peach) 27%, #CDEFEA 37%, var(--aqua) 50%, #CDEFEA 63%,
    #F8DCC0 71%, var(--peach) 80%, var(--lilac) 87% 100%);
  box-shadow: inset 0 0 0 1px rgb(32 30 25 / .12);
  cursor: grab;
  touch-action: pan-y;
}
.sun-range:active { cursor: grabbing; }
.sun-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--sun-fill, var(--shell));
  box-shadow: inset 0 0 0 2px var(--ink), 0 6px 12px -6px rgb(32 30 25 / .6);
  transition: transform var(--pop);
}
.sun-range::-moz-range-thumb {
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: var(--sun-fill, var(--shell));
  box-shadow: inset 0 0 0 2px var(--ink), 0 6px 12px -6px rgb(32 30 25 / .6);
}
.sun-range:active::-webkit-slider-thumb { transform: scale(1.12); }
.sun-range:focus-visible { outline-offset: 6px; }
.sun-now { position: absolute; top: 0; left: calc(16px + (100% - 32px) * var(--now, .5)); transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 3px; pointer-events: none; }
.sun-now::after { content: ""; width: 1.5px; height: 8px; background: var(--ink); }
.sun-now .caps { font-size: 10px; color: var(--ink); }
.sun-ticks { display: flex; justify-content: space-between; margin-top: 12px; padding: 0 8px; font-size: 10px; }
.sun-back { justify-self: end; }

/* 5 — Gifts: one still life on the paper. The keepsake at the back, two snacks in front of it.
   The renders carry their own faint contact shadows; nothing is added. */
.promise { font-size: clamp(17px, 1.4vw, 20px); font-weight: 900; color: var(--ink); }
/* The loop is rendered on the page's own shell; its edges are feathered anyway, so a step of colour from
   the video's encoding never draws a box. */
.gift-film {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  background: var(--paper);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent), linear-gradient(transparent, #000 10%, #000 90%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent), linear-gradient(transparent, #000 10%, #000 90%, transparent);
  mask-composite: intersect;
}

/* 6 — The film, on the ink poster: a graphite phone with a lit rim (an ink phone would vanish into the ink),
   its shadow falling down-right into the poster. */
.phone {
  position: relative;
  width: min(100%, 340px);
  margin: 0 auto;
  padding: 10px;
  border-radius: 48px;
  background: var(--ink);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .16),
    inset 1px 0 0 rgb(255 255 255 / .06),
    inset 0 -2px 0 rgb(0 0 0 / .5),
    0 2px 2px rgb(32 30 25 / .16),
    12px 28px 48px -20px rgb(32 30 25 / .45);
}
.phone::before {                     /* the island */
  content: "";
  position: absolute;
  top: 22px;
  left: 50%;
  z-index: 1;
  width: 30%;
  height: 24px;
  transform: translateX(-50%);
  border-radius: 12px;
  background: #0E0D10;
}
.phone::after {                      /* the side button */
  content: "";
  position: absolute;
  top: 24%;
  right: -3px;
  width: 3px;
  height: 11%;
  border-radius: 0 2px 2px 0;
  background: #34312C;
}
.phone video { width: 100%; aspect-ratio: 9 / 16; object-fit: cover; border-radius: 38px; background: var(--linen); }
.panel--ink .phone {
  background: #36332D;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .28),
    inset 0 0 0 1px rgb(255 255 255 / .1),
    inset 0 -2px 0 rgb(0 0 0 / .45),
    12px 28px 48px -20px rgb(0 0 0 / .7);
}
.panel--ink .phone::after { background: #4A463F; }
.panel--ink .copy { align-self: start; }

/* The mark, poster-sized, peeking up out of the bottom edge: shell cap and shell, an aqua face, eyes in
   the ink. It rises once the poster is in view and its cap lifts; then its eyes follow you about. */
.peek {
  position: absolute;
  right: clamp(24px, 7%, 96px);
  bottom: 0;
  width: clamp(150px, 27%, 330px);
  height: auto;
  overflow: visible;
  transform: translateY(58%);
  pointer-events: none;
}
.peek-shell { fill: var(--shell); }
.peek-face { fill: var(--aqua); }
.peek-eyes path { fill: var(--ink); transform-box: fill-box; transform-origin: 50% 55%; transition: transform 90ms ease-in; }
.peek-eyes.shut path { transform: scaleY(.12); }
.peek.up { transform: translateY(40%); transition: transform 900ms cubic-bezier(.34, 1.3, .64, 1) 150ms; }
/* The cap is a lid: hinged at its lower left, it lifts a little more once it's up. */
.peek-cap { transform-box: fill-box; transform-origin: 12% 100%; transition: transform 700ms cubic-bezier(.34, 1.56, .64, 1) 750ms; }
.peek.up .peek-cap { transform: translateY(-10px) rotate(-7deg); }

/* The whole screen is the film's pause button. Paused by hand, a label-stock disc with an ink play
   mark floats over it, with one contact shadow; playing, the screen is clear. */
.film-toggle {
  position: absolute;
  inset: 10px;
  display: grid;
  place-items: center;
  border-radius: 38px;
}
.film-toggle:focus-visible { outline-offset: 14px; }   /* outside the ink bezel, where an ink ring shows */
.film-toggle::before,
.film-toggle::after {
  content: "";
  grid-area: 1 / 1;
  opacity: 0;
  transform: scale(.8);
  transition: opacity 200ms ease-out, transform var(--pop);
}
.film-toggle::before {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--stock);
  box-shadow: inset 0 -2px 0 rgb(32 30 25 / .08), 0 10px 18px -10px rgb(32 30 25 / .5);
}
.film-toggle::after {
  width: 22px;
  height: 26px;
  margin-left: 5px;                  /* the triangle's weight sits left of its box: nudge it to the eye's centre */
  background: var(--ink);
  clip-path: path("M0 3.5Q0 0 3 1.73L19.76 11.68Q22 13 19.76 14.32L3 24.27Q0 26 0 22.5Z");   /* rounded corners */
}
.phone.paused .film-toggle::before,
.phone.paused .film-toggle::after { opacity: 1; transform: none; }

/* ---------- The footer: a carton of your next six ---------- */

.carton { position: relative; z-index: 1; padding: 32px 0 calc(28px + env(safe-area-inset-bottom)); background: var(--shell); }
.carton-wrap { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: 48px; align-items: center; }
.carton-copy h2 { font-size: clamp(40px, 4.6vw, 72px); font-weight: 900; letter-spacing: -.032em; line-height: .98; text-wrap: balance; }
.carton-copy .lead { margin-top: 20px; max-width: 34ch; color: var(--ink); }
.carton-cta { margin-top: 32px; }
/* What the egg says back: a line in the brand's voice, under the copy, gone after a few seconds. */
.carton-say {
  min-height: 1.3em;
  margin-top: 24px;
  font-size: clamp(22px, 2vw, 28px);
  font-weight: 900;
  letter-spacing: -.02em;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 300ms ease-out, transform var(--pop);
}
.carton-say.on { opacity: 1; transform: none; }
.carton-stage { position: relative; aspect-ratio: 7 / 6; }
.carton-stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: manipulation; }
/* Before the carton is built (or where it can't be), the stage keeps its room; nothing jumps. */
.carton-keys { position: absolute; left: 0; right: 0; bottom: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.carton-keys button {
  position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.carton-keys button:focus-visible {
  position: static; width: auto; height: 36px; padding: 0 14px; clip: auto; overflow: visible;
  border-radius: 999px; background: var(--ink); color: var(--shell); font-weight: 800; font-size: 14px;
}
.carton.no-carton .carton-stage { display: none; }
.carton-base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 28px;
  margin-top: 40px;
  padding-top: 20px;
  border-top: 1px solid var(--rule);
}
.carton-base .wordmark { margin-right: auto; }
.carton-base .logo { height: 30px; }
.carton-base .caps { color: var(--ink2); }
.barcode { display: flex; height: 32px; }
.barcode i { flex: none; height: 100%; margin-right: 2px; background: var(--ink); }
.barcode i.gap { background: none; }

/* ---------- Widths ---------- */

@media (max-width: 1100px) {
  .lineup { gap: 24px 16px; }
  .split, .million { column-gap: 64px; }
}

@media (max-width: 900px) {
  .carton-wrap { grid-template-columns: minmax(0, 1fr); }
  .carton-stage { margin-top: 24px; aspect-ratio: 1; }
  .split { grid-template-columns: minmax(0, 1fr); }
  .split--flip .obj { order: 0; }
  .split .obj { margin-top: 48px; }
  /* The ink poster stacks phone first, then the words, with room below them for the mark to peek. */
  .panel--ink .split--flip .obj { order: -1; margin: 0 0 48px; }
  .panel--ink { padding-bottom: clamp(140px, 30vw, 220px); }
  .peek { width: clamp(120px, 30vw, 220px); }
  .million { grid-template-columns: minmax(0, 1fr); }
  .million > :is(h2, .lead, .lineup, .specs, .odds) { grid-column: 1; }
  .million > .lead { margin-top: 24px; padding-top: 0; }
  .lineup { margin-top: 48px; }
  .specs { margin-top: 48px; }
  .odds { margin-top: 48px; }
  .sill-head > .sill-lead { grid-column: 1; margin-top: 24px; padding-top: 0; }
  .portal { aspect-ratio: 4 / 3; }
  .sun { grid-template-columns: minmax(0, 1fr) auto; }
  .sun-dial { grid-column: 1 / -1; grid-row: 2; }
  .gifts { max-width: 560px; }
  .phone { margin-left: 0; }
}

@media (max-width: 600px) {
  :root { --peek: 24px; }
  .bar { height: calc(60px + env(safe-area-inset-top)); }
  .bar .logo { height: 28px; }
  .arrival { bottom: calc(32px + env(safe-area-inset-bottom)); }
  .hero { padding-bottom: calc(var(--peek) + 48px); }
  .hero h1 { margin-top: 12px; }
  .actions { margin-top: 24px; }
  .sheet { padding: 48px 0; }
  .poster { padding: 48px 0; }
  .lineup { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 12px; }
  .portal-wrap { margin-top: 40px; }
  .portal { aspect-ratio: 4 / 5; }
  .specs { gap: 24px 32px; }
  /* The table, two lines a row: the chip and the odds, then what to look for. */
  .odds thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .odds tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px 16px; padding: 12px 0; border-top: 1px solid var(--rule); }
  .odds td { display: block; padding: 0; border: 0; }
  .odds td:nth-child(2) { grid-column: 1 / -1; grid-row: 2; }
  .odds .one td { padding: 0; }
  .carton-base .wordmark { flex-basis: 100%; }
}

/* ---------- Reduced motion: the same story, as fades ---------- */

@media (prefers-reduced-motion: reduce) {
  [data-enter], html.revealed [data-reveal], .arrival, .sheet, .bar-cta { transform: none !important; }
  .bar .wordmark { clip-path: none; opacity: 0; transition: opacity 300ms ease-out; }
  html:is(.printed, .revealed) .bar .wordmark { opacity: 1; }
  .pill:hover, .pill:active, html.revealed .bar-cta:hover { transform: none; }
  .dots i { transition: none; }
  .film-toggle::before, .film-toggle::after { transform: none; }
  .peek, .peek.up { transform: translateY(40%); transition: none; }
  .peek-cap, .peek.up .peek-cap { transition: none; }
}

/* ---------- Forced colours: what's drawn only in fills keeps a system colour ---------- */

@media (forced-colors: active) {
  /* The film's play mark: a disc and a triangle that a forced background would wipe out. */
  .film-toggle::before { forced-color-adjust: none; background: ButtonFace; border: 2px solid ButtonText; }
  .film-toggle::after { forced-color-adjust: none; background: ButtonText; }
  /* The knocks, the pips, the barcode: empty in GrayText, filled in the text colour. */
  .dots i, .arrival .dots i:not(.on), .chip i, .chip:is([data-r]) i { forced-color-adjust: none; background: GrayText; }
  .dots i.on,
  .chip[data-stars="1"] i:nth-child(-n+1),
  .chip[data-stars="2"] i:nth-child(-n+2),
  .chip[data-stars="3"] i:nth-child(-n+3),
  .chip[data-stars="4"] i:nth-child(-n+4),
  .chip[data-stars="5"] i { background: CanvasText; }
  .barcode i:not(.gap) { forced-color-adjust: none; background: CanvasText; }
}
