/* Nibsy website. Tokens come from tokens.css (generated from
   packages/design-tokens); nothing here invents a colour, a radius or a
   duration. Layouts are fluid between breakpoints so in-between widths
   (960, 1146) hold up, not only the breakpoint values themselves.
   Pages link tokens.css first; an @import here would cost a round trip. */
@font-face {
  font-family: "Nunito";
  font-weight: 800;
  font-display: swap;
  src: url("/site/fonts/nunito-800.woff?v=caf59ee79945") format("woff");
}
@font-face {
  font-family: "DM Sans";
  font-weight: 400;
  font-display: swap;
  src: url("/site/fonts/dm-sans-400.woff?v=95f559bfda75") format("woff");
}
@font-face {
  font-family: "DM Sans";
  font-weight: 600;
  font-display: swap;
  src: url("/site/fonts/dm-sans-600.woff?v=6b28b9b732f1") format("woff");
}
/* The note styles, loaded only where a card is drawn or a sample shown. */
@font-face {
  font-family: "Kalam";
  font-display: swap;
  src: url("/site/fonts/kalam.woff?v=c5daa2618101") format("woff");
}
@font-face {
  font-family: "Patrick Hand";
  font-display: swap;
  src: url("/site/fonts/patrick-hand.woff?v=b5696fd25688") format("woff");
}

:root {
  --gutter: 16px;
  --content: 1200px;
  --header: 64px;
  --paper-shadow: 0 1px 2px #30455b1f, 0 10px 28px -6px #30455b2e;
  --lift-shadow: 0 2px 4px #30455b24, 0 18px 36px -8px #30455b38;
  --ease: cubic-bezier(0.33, 0.02, 0.2, 1);
  --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
  color-scheme: light;
}
@media (min-width: 600px) {
  :root {
    --gutter: 24px;
  }
}
@media (min-width: 960px) {
  :root {
    --gutter: 40px;
    --header: 80px;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header) + var(--space-md));
}
body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font:
    400 var(--type-body) / var(--leading-body) "DM Sans",
    system-ui,
    sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}
img,
canvas,
svg {
  display: block;
  max-width: 100%;
}
img {
  height: auto;
}
a {
  color: var(--blue);
  text-underline-offset: 3px;
}
h1,
h2,
h3 {
  font-family: "Nunito", system-ui, sans-serif;
  font-weight: 800;
  color: var(--ink);
  margin: 0;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
p {
  margin: 0;
  text-wrap: pretty;
}
:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.skip-link {
  position: absolute;
  left: var(--space-md);
  top: -100px;
  z-index: 100;
  background: var(--blue);
  color: var(--paper);
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius-pill);
}
.skip-link:focus {
  top: var(--space-sm);
}

.wrap {
  width: min(var(--content), 100% - 2 * var(--gutter));
  margin-inline: auto;
}

/* ---- Buttons --------------------------------------------------------- */
.button {
  --button-bg: transparent;
  --button-fg: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  min-height: 48px;
  padding: 0 var(--space-lg);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--button-bg);
  color: var(--button-fg);
  font:
    600 var(--type-body) / 1 "DM Sans",
    system-ui,
    sans-serif;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    transform var(--motion-fast) var(--ease),
    background-color var(--motion-fast) var(--ease),
    border-color var(--motion-fast) var(--ease),
    box-shadow var(--motion-fast) var(--ease);
}
.button:hover {
  border-color: var(--ink);
}
.button:active {
  transform: scale(0.98);
}
.button.primary {
  --button-bg: var(--blue);
  --button-fg: var(--paper);
  border-color: var(--blue);
}
.button.primary:hover {
  box-shadow: 0 6px 18px -6px #345b8799;
}
.button.quiet {
  border-color: transparent;
  min-height: 44px;
  padding: 0 var(--space-md);
  color: var(--blue);
}
.button.quiet:hover {
  background: #345b870f;
}
.button.icon {
  width: 44px;
  padding: 0;
}
.button:disabled {
  opacity: 0.4;
  cursor: default;
  transform: none;
}
.button.small {
  min-height: 44px;
  padding: 0 var(--space-md-plus);
  font-size: var(--type-label);
}
.text-link {
  font-weight: 600;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: 44px;
}
.text-link:hover {
  text-decoration: underline;
}

/* ---- Header ---------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--cream);
  border-bottom: 1px solid transparent;
  transition: border-color var(--motion-fast) var(--ease);
}
.site-header.scrolled {
  border-bottom-color: var(--line);
}
.site-header .wrap {
  height: var(--header);
  display: flex;
  align-items: center;
  gap: var(--space-md);
}
/* The lockup as the app draws it (packages/design-tokens lockup): the
   mascot cropped to its optical bounds, then the wordmark, sized from one
   number, the bird's height. The wordmark file keeps a safety margin around
   its bounds (WORDMARK_PAD in scripts/site-assets.mjs); the negative margins
   take it back out, so the gap is the app's. */
.brand {
  --bird: 42px;
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}
.brand-bird {
  display: block;
  width: calc(var(--bird) * 1065 / 1226);
  height: var(--bird);
}
.brand-bird img {
  display: block;
  width: 100%;
  height: 100%;
}
.brand-word {
  display: block;
  /* 101 / 42 of the bird, plus the file's margin (40 / 2356.94 each side). */
  width: calc(var(--bird) * 2.48638);
  margin: calc(var(--bird) * -0.040814);
  margin-left: calc(var(--bird) * 0.12585);
}
.lockup {
  min-height: 44px;
  margin-right: auto;
  border-radius: var(--radius-sm);
}
@media (min-width: 600px) {
  .lockup {
    --bird: 46px;
  }
}
@media (min-width: 960px) {
  .lockup {
    --bird: 54px;
  }
}
/* The bird arrives with two small hops and settles, as on the app's welcome
   (BirdIntro): on the first page of a visit (js/hello.mjs marks it before
   the first paint), never with reduced motion. */
.hello .lockup .brand-bird,
.closing-bird.play {
  animation: bird-along 740ms both;
}
.hello .lockup .brand-bird img,
.closing-bird.play img {
  animation: bird-hops 740ms both;
}
@keyframes bird-along {
  0% {
    transform: translateX(calc(var(--bird) * -1));
    animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
  }
  51.4% {
    transform: translateX(calc(var(--bird) * -0.47));
    animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
  }
  100% {
    transform: none;
  }
}
@keyframes bird-hops {
  0%,
  51.4% {
    transform: none;
    animation-timing-function: cubic-bezier(0.5, 1, 0.89, 1);
  }
  25.7% {
    transform: translateY(calc(var(--bird) * -0.224));
    animation-timing-function: cubic-bezier(0.11, 0, 0.5, 0);
  }
  75.7% {
    transform: translateY(calc(var(--bird) * -0.168));
    animation-timing-function: cubic-bezier(0.11, 0, 0.5, 0);
  }
  100% {
    transform: none;
  }
}
/* A pointer resting on the lockup gets one small hop. */
@keyframes bird-hop {
  50% {
    transform: translateY(calc(var(--bird) * -0.14));
    animation-timing-function: cubic-bezier(0.11, 0, 0.5, 0);
  }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  :root:not(.hello) .lockup:hover .brand-bird img {
    animation: bird-hop var(--motion-standard) cubic-bezier(0.5, 1, 0.89, 1);
  }
}
.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}
.site-nav a:not(.button) {
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
  font-size: var(--type-label);
  padding: 0 var(--space-sm-plus);
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-pill);
}
.site-nav a:not(.button):hover,
.site-nav a[aria-current="page"] {
  color: var(--blue);
}
.site-nav .button {
  margin-left: var(--space-sm);
}
.menu-toggle {
  display: none;
}
@media (max-width: 759px) {
  .menu-toggle {
    display: inline-flex;
  }
  .site-nav {
    position: absolute;
    top: var(--header);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--space-sm) var(--gutter) var(--space-lg);
    background: var(--cream);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 18px 30px -24px #30455b55;
    visibility: hidden;
    opacity: 0;
    transform: translateY(-8px);
    transition:
      opacity var(--motion-fast) var(--ease),
      transform var(--motion-fast) var(--ease),
      visibility 0s linear var(--motion-fast);
  }
  .menu-open .site-nav {
    visibility: visible;
    opacity: 1;
    transform: none;
    transition:
      opacity var(--motion-fast) var(--ease),
      transform var(--motion-fast) var(--ease);
  }
  .site-nav a:not(.button) {
    font-size: var(--type-body);
    padding: 0;
    min-height: 52px;
    border-bottom: 1px solid #c8cfc480;
    border-radius: 0;
  }
  .site-nav .button {
    margin: var(--space-md) 0 0;
  }
}
.menu-toggle span,
.menu-toggle span::before,
.menu-toggle span::after {
  display: block;
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: var(--ink);
  position: relative;
  transition:
    transform var(--motion-fast) var(--ease),
    background-color var(--motion-fast) var(--ease);
}
.menu-toggle span::before,
.menu-toggle span::after {
  content: "";
  position: absolute;
  left: 0;
}
.menu-toggle span::before {
  top: -6px;
}
.menu-toggle span::after {
  top: 6px;
}
.menu-open .menu-toggle span {
  background: transparent;
}
.menu-open .menu-toggle span::before {
  transform: translateY(6px) rotate(45deg);
}
.menu-open .menu-toggle span::after {
  transform: translateY(-6px) rotate(-45deg);
}

/* ---- Type for marketing pages ----------------------------------------
   The web's wide screens need a display size above the app's 34px; these
   scale fluidly from the app's own sizes on a phone. */
.display {
  font-size: clamp(40px, 3.6vw + 22px, 74px);
  line-height: 1.04;
  letter-spacing: -0.02em;
}
.section-title {
  font-size: clamp(28px, 1.8vw + 20px, 46px);
  line-height: 1.1;
}
.lede {
  font-size: clamp(17px, 0.4vw + 15px, 20px);
  line-height: 1.55;
  color: var(--muted);
  max-width: 34em;
}
.eyebrow {
  font-size: var(--type-label);
  font-weight: 600;
  color: var(--blue);
  margin-bottom: var(--space-sm-plus);
}
.script {
  font-family: "Patrick Hand", "Kalam", cursive;
  font-weight: 400;
  color: var(--blue);
}

section {
  padding-block: clamp(64px, 6vw + 32px, 128px);
}

/* ---- Hero ------------------------------------------------------------- */
.hero {
  padding-block: clamp(32px, 4vw + 12px, 88px) clamp(48px, 5vw + 24px, 112px);
}
.hero .wrap {
  display: grid;
  gap: clamp(32px, 4vw, 64px);
  align-items: center;
}
.hero-copy {
  display: grid;
  gap: var(--space-lg);
  justify-items: start;
}
/* The page's opening: the headline, the line under it and the actions rise
   into place one after another, once, as the bird hops in. */
@media (prefers-reduced-motion: no-preference) {
  .hero-copy > * {
    animation: rise var(--motion-slow) var(--ease-out) both;
  }
  .hero-copy > :nth-child(2) {
    animation-delay: 70ms;
  }
  .hero-copy > :nth-child(3) {
    animation-delay: 140ms;
  }
}
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm) var(--space-md);
  margin-top: var(--space-sm);
}
.hero-card {
  justify-self: center;
  width: min(100%, 640px);
}
@media (min-width: 960px) {
  .hero .wrap {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  }
  .hero-card {
    justify-self: end;
  }
}
/* Before launch (coming-soon.html): the bird stands in for the card. */
.soon-bird {
  justify-self: center;
  width: clamp(160px, 18vw + 80px, 320px);
}
.soon-bird img {
  display: block;
  width: 100%;
  height: auto;
}
@media (min-width: 960px) {
  .soon-bird {
    justify-self: center;
  }
}

/* ---- The turnable card ------------------------------------------------ */
/* A closed card is shown larger than one page of the open spread, as a real
   card held up would be; opening it draws back to fit both pages. The stage
   is tall enough for the closed card, so nothing below moves as it turns. */
.bifold {
  --turn: var(--motion-slow);
  --closed-scale: 1.45;
  display: grid;
  gap: var(--space-sm);
  width: 100%;
}
@media (min-width: 960px) {
  .bifold {
    --closed-scale: 1.3;
  }
}
.bifold-stage {
  position: relative;
  perspective: 2400px;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  cursor: grab;
  border-radius: var(--radius-md);
}
.bifold-stage::before {
  content: "";
  display: block;
  padding-top: calc(70% * var(--closed-scale) + var(--space-lg));
}
.bifold-stage:active {
  cursor: grabbing;
}
.book {
  --cover-angle: 0deg;
  --page-angle: 0deg;
  --shift: -25%;
  --k: var(--closed-scale);
  position: absolute;
  left: 0;
  top: 50%;
  width: 100%;
  aspect-ratio: 1200 / 840;
  transform-style: preserve-3d;
  transform: translateY(-50%) translateX(calc(var(--shift) * var(--k)))
    scale(var(--k));
  transition:
    transform var(--turn) var(--ease),
    opacity 90ms linear;
}
.book[data-view="inside"] {
  --k: 1;
}
.leaf {
  position: absolute;
  inset: 0 0 0 50%;
  transform-style: preserve-3d;
  transform-origin: left center;
  transition: transform var(--turn) var(--ease);
}
.cover-leaf {
  transform: translateZ(1px) rotateY(var(--cover-angle));
}
.page-leaf {
  transform: rotateY(var(--page-angle));
}
.book.still,
.book.still .leaf {
  transition: none;
}
.book.fading {
  opacity: 0;
}
.face {
  position: absolute;
  inset: 0;
  background: var(--paper);
  border-radius: 2px;
  box-shadow: var(--paper-shadow);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
}
.face.reverse {
  transform: rotateY(180deg);
}
.face.away {
  visibility: hidden;
}
.book[data-view="inside"] .face {
  box-shadow:
    inset 8px 0 14px -10px #30455b33,
    var(--paper-shadow);
}
.book[data-view="inside"] .face.reverse {
  box-shadow:
    inset -8px 0 14px -10px #30455b33,
    var(--paper-shadow);
}
.face canvas {
  width: 100%;
  height: 100%;
  /* WebKit composites a canvas on its own layer and doesn't apply the
     face's backface-visibility to it: without this the reverse of each leaf
     shows through, mirrored. */
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  opacity: 0;
  transition: opacity var(--motion-standard) var(--ease);
}
.bifold.drawn .face canvas {
  opacity: 1;
}
.bifold-controls {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  align-items: center;
  gap: var(--space-sm);
  max-width: 360px;
  width: 100%;
  justify-self: center;
}
.bifold-status {
  text-align: center;
  font-size: var(--type-label);
  color: var(--muted);
}
.bifold-controls [data-step="1"] {
  min-width: 140px;
}

/* ---- How it works ------------------------------------------------------ */
.how {
  background: var(--paper);
  border-block: 1px solid #c8cfc480;
}
.how-head {
  display: grid;
  gap: var(--space-md);
  max-width: 40em;
  margin-bottom: clamp(40px, 3vw + 24px, 72px);
}
.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(40px, 4vw, 56px);
}
@media (min-width: 960px) {
  .steps {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(24px, 3vw, 48px);
  }
}
.step {
  display: grid;
  grid-template-rows: auto auto auto;
  align-content: start;
  gap: var(--space-md);
}
.step-visual {
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-md);
  background: var(--cream);
  display: grid;
  place-items: center;
  overflow: hidden;
  position: relative;
}
.step-number {
  font:
    800 var(--type-label) / 1 "Nunito",
    sans-serif;
  color: var(--blue);
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
}
.step-number::before {
  content: "";
  width: 24px;
  height: 2px;
  background: var(--peach);
  border-radius: 2px;
}
.step h3 {
  font-size: var(--type-title);
  line-height: var(--leading-title);
}
.step p {
  color: var(--muted);
  max-width: 30em;
}
/* The steps play the app's welcome scenes (WelcomeScenes.tsx), each once
   when it comes into view. The CSS below is each scene's last frame, so with
   reduced motion, or before the script runs, a step shows where it ends.
   `.armed` holds a scene's first frame until it is seen; `.play` runs it. */
.step-visual {
  container-type: inline-size;
}
/* Step 1, cards worth keeping: three real covers, squared up in a deck,
   deal out into a fan. */
.fan {
  position: relative;
  width: 50%;
  aspect-ratio: 1 / 1;
}
.fan img {
  position: absolute;
  width: 54%;
  aspect-ratio: 5 / 7;
  object-fit: cover;
  left: 23%;
  top: 6%;
  border-radius: 2px;
  box-shadow: var(--paper-shadow);
  transform: translate(var(--x, 0), var(--y, 0)) rotate(var(--tilt));
}
.fan img:nth-child(1) {
  --x: -46%;
  --tilt: -9deg;
}
.fan img:nth-child(3) {
  --x: 46%;
  --tilt: 9deg;
  --delay: 126ms;
}
.fan img:nth-child(2) {
  z-index: 1;
  --y: -3%;
  --tilt: -2deg;
  --delay: 252ms;
}
.scene.armed .fan img {
  transform: translate(0, var(--y, 0)) rotate(calc(var(--tilt) * 0.2));
}
.scene.play .fan img {
  transition: transform 504ms var(--ease-out) var(--delay, 0ms);
}
/* Step 2, say it your way: the card opens, and the message writes itself
   inside. Sizes are in container units, so the scene scales with its step. */
.write-scene {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}
.ws-card {
  flex-shrink: 0;
  width: 40cqw;
  aspect-ratio: 5 / 7;
  background: var(--paper);
  border-radius: 2px;
  box-shadow: var(--paper-shadow);
  --lean: perspective(900px) rotateX(8deg);
}
.ws-cover {
  position: relative;
  z-index: 1;
  margin-right: -3.2cqw;
  overflow: hidden;
  transform: var(--lean) rotate(-6deg);
}
.ws-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ws-note {
  display: flex;
  flex-direction: column;
  gap: 1.6cqw;
  padding: 4cqw;
  font-family: "Kalam", cursive;
  font-size: max(11px, 3.1cqw);
  line-height: 1.4;
  color: var(--ink);
  text-align: left;
  transform: var(--lean) rotate(3deg);
}
/* The rest of the message keeps its place while it's written, so the lines
   never reflow as letters arrive. */
.ws-rest {
  color: transparent;
}
.scene.armed .ws-cover {
  transform: var(--lean) translateX(50%);
}
.scene.armed .ws-note {
  opacity: 0;
  transform: var(--lean) translateX(-50%) rotate(3deg);
}
.scene.armed .ws-from,
.scene.writing .ws-from {
  visibility: hidden;
}
.scene.play .ws-card {
  transition:
    transform var(--motion-slow) var(--ease-out),
    opacity var(--motion-slow) var(--ease-out);
}
/* Step 3, send it with a link, seen from the other end: the envelope lands,
   the bird's seal lifts, the flap opens and the card rises out. Nothing fades
   in, so nothing shows through anything else. Geometry is the app's, in
   container units: the envelope is 48 wide and 0.68 of that tall; above it is
   room for the open flap and the card. */
.send-scene {
  position: relative;
  width: 48cqw;
  height: 32.64cqw;
  translate: 0 15.7cqw;
  filter: drop-shadow(0 1.4cqw 2cqw #30455b29);
}
.send-scene > span {
  position: absolute;
  display: block;
}
.env-back,
.env-pocket {
  inset: 0;
  border-radius: 3px;
}
.env-back {
  background: var(--peach);
}
.env-flap-open {
  left: 0;
  bottom: 100%;
  width: 100%;
  height: 62%;
  background: color-mix(in srgb, var(--peach) 55%, var(--paper));
  clip-path: polygon(0 100%, 100% 100%, 50% 0);
  transform-origin: bottom;
}
.env-slot {
  left: 0;
  right: 0;
  top: -31.44cqw;
  bottom: 0;
  overflow: hidden;
}
.env-slot img {
  position: absolute;
  left: 20%;
  top: 35.36cqw;
  width: 60%;
  aspect-ratio: 5 / 7;
  object-fit: cover;
  border-radius: 2px;
  box-shadow: var(--paper-shadow);
  transform: translateY(calc(-35.36cqw + 4px)) rotate(-3deg);
}
.env-pocket {
  background: color-mix(in srgb, var(--peach) 70%, var(--paper));
  clip-path: polygon(0 0, 50% 58%, 100% 0, 100% 100%, 0 100%);
}
.env-flap-closed {
  left: 0;
  top: 0;
  width: 100%;
  height: 70%;
  background: color-mix(in srgb, var(--peach) 92%, var(--ink));
  clip-path: polygon(0 0, 100% 0, 50% 94.29%);
  transform-origin: top;
  transform: scaleY(0);
}
.send-scene .env-seal {
  left: 50%;
  top: 66%;
  width: 9cqw;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--paper);
  display: grid;
  place-items: center;
  opacity: 0;
  transform: translate(-50%, calc(-62.5% - 4.2cqw));
}
.env-seal img {
  width: 56%;
  height: auto;
}
.scene.armed .env-flap-open {
  transform: scaleY(0);
}
.scene.armed .env-slot img {
  transform: none;
}
.scene.armed .env-flap-closed {
  transform: none;
}
.scene.armed .env-seal {
  opacity: 1;
  transform: translate(-50%, -62.5%);
}
/* One timeline, eased in and out as the app's is: the landing takes the
   first third, the seal and flaps pass quickly through the middle, and the
   card rises through the second half. */
.scene.play .send-scene {
  animation: env-land 1680ms both;
}
.scene.play .env-seal {
  animation: env-seal 1680ms both;
}
.scene.play .env-flap-closed {
  animation: env-flap-closed 1680ms linear both;
}
.scene.play .env-flap-open {
  animation: env-flap-open 1680ms linear both;
}
.scene.play .env-slot img {
  animation: env-card 1680ms both;
}
@keyframes env-land {
  0% {
    rotate: 0deg;
    animation-timing-function: ease-in;
  }
  24.1% {
    rotate: -3deg;
  }
  30.4% {
    rotate: 2deg;
  }
  34.2%,
  100% {
    rotate: 0deg;
  }
}
@keyframes env-seal {
  0%,
  35.6% {
    opacity: 1;
    transform: translate(-50%, -62.5%);
  }
  42.2%,
  100% {
    opacity: 0;
    transform: translate(-50%, calc(-62.5% - 4.2cqw));
  }
}
@keyframes env-flap-closed {
  0%,
  42.2% {
    transform: none;
  }
  47.2%,
  100% {
    transform: scaleY(0);
  }
}
@keyframes env-flap-open {
  0%,
  47.2% {
    transform: scaleY(0);
  }
  51.4%,
  100% {
    transform: none;
  }
}
@keyframes env-card {
  0%,
  52.1% {
    transform: none;
    animation-timing-function: var(--ease-out);
  }
  100% {
    transform: translateY(calc(-35.36cqw + 4px)) rotate(-3deg);
  }
}

/* ---- Collection -------------------------------------------------------- */
.collection-head {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: var(--space-md) var(--space-lg);
  margin-bottom: var(--space-lg);
}
.collection-head > div {
  display: grid;
  gap: var(--space-sm-plus);
}
.chips {
  display: flex;
  gap: var(--space-sm);
  overflow-x: auto;
  scrollbar-width: none;
  padding: 2px var(--gutter) var(--space-xs);
  margin-inline: calc(-1 * var(--gutter));
  scroll-padding-inline: var(--gutter);
}
.chips::-webkit-scrollbar {
  display: none;
}
.chip {
  flex: none;
  min-height: 40px;
  padding: 0 var(--space-md);
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--line);
  background: transparent;
  color: var(--ink);
  font:
    600 var(--type-label) / 1 "DM Sans",
    sans-serif;
  cursor: pointer;
  transition:
    background-color var(--motion-fast) var(--ease),
    border-color var(--motion-fast) var(--ease),
    color var(--motion-fast) var(--ease);
}
/* 40px chips sit in a 44px row: the row is the target (UI-RULES H6). */
.chip-row {
  min-height: 44px;
}
.chip:hover {
  border-color: var(--ink);
}
.chip[aria-pressed="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(148px, 22vw, 220px);
  gap: clamp(16px, 2vw, 28px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding: var(--space-md) var(--gutter) var(--space-lg);
  margin-inline: calc(-1 * var(--gutter));
  scroll-padding-inline: var(--gutter);
}
.rail::-webkit-scrollbar {
  display: none;
}
.rail .cover-tile {
  scroll-snap-align: start;
}
.cover-tile {
  display: grid;
  gap: var(--space-sm-plus);
  text-decoration: none;
  color: var(--ink);
  border-radius: var(--radius-sm);
}
.cover-frame {
  display: block;
  aspect-ratio: 5 / 7;
  border-radius: 2px;
  overflow: hidden;
  background: var(--mist);
  box-shadow: var(--paper-shadow);
  transition:
    transform var(--motion-standard) var(--ease),
    box-shadow var(--motion-standard) var(--ease);
}
.cover-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.cover-tile:hover .cover-frame {
  transform: translateY(-4px);
  box-shadow: var(--lift-shadow);
}
.cover-name {
  font-weight: 600;
  font-size: var(--type-label);
  line-height: var(--leading-label);
}
.collection-foot {
  margin-top: var(--space-sm);
}

/* ---- Personal touches --------------------------------------------------- */
.personal .wrap {
  display: grid;
  gap: clamp(40px, 5vw, 80px);
  align-items: center;
}
@media (min-width: 960px) {
  .personal .wrap {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}
.personal-copy {
  display: grid;
  gap: var(--space-lg);
  justify-items: start;
}
.facts {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--space-md-plus);
}
.facts li {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: var(--space-sm-plus);
}
.facts li::before {
  content: "";
  width: 10px;
  height: 10px;
  margin: 8px 0 0 6px;
  border-radius: 50%;
  background: var(--peach);
}
.facts strong {
  display: block;
  font-weight: 600;
}
.facts span {
  color: var(--muted);
}
.handwriting-sheet {
  position: relative;
  background: var(--paper);
  aspect-ratio: 5 / 4;
  border-radius: 2px;
  box-shadow: var(--paper-shadow);
  padding: clamp(24px, 4vw, 48px);
  display: grid;
  align-content: center;
  gap: var(--space-md);
  transform: rotate(1.5deg);
  background-image: repeating-linear-gradient(
    to bottom,
    transparent 0 46px,
    #c8cfc466 46px 47px
  );
}
.handwriting-sheet p {
  font-family: "Kalam", cursive;
  font-size: clamp(22px, 2vw + 10px, 34px);
  line-height: 1.4;
  color: var(--ink);
}
.handwriting-sheet .signature {
  justify-self: end;
  color: var(--blue);
}
.handwriting-sheet .bird {
  position: absolute;
  width: clamp(64px, 8vw, 104px);
  right: clamp(-12px, -1vw, -4px);
  top: clamp(-40px, -3vw, -24px);
  transform: rotate(-4deg);
}

/* ---- Questions --------------------------------------------------------- */
.questions .wrap {
  display: grid;
  gap: var(--space-xl);
}
@media (min-width: 960px) {
  .questions .wrap {
    grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
    align-items: start;
  }
}
.faq {
  border-top: 1px solid var(--line);
}
.faq details {
  border-bottom: 1px solid var(--line);
}
.faq summary {
  list-style: none;
  cursor: pointer;
  min-height: 64px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  font-weight: 600;
  font-size: 17px;
}
.faq summary::-webkit-details-marker {
  display: none;
}
.faq summary::after {
  content: "";
  flex: none;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--blue);
  border-bottom: 2px solid var(--blue);
  transform: translateY(-3px) rotate(45deg);
  transition: transform var(--motion-fast) var(--ease);
}
.faq details[open] summary::after {
  transform: translateY(2px) rotate(-135deg);
}
.faq details p {
  padding: 0 0 var(--space-lg);
  color: var(--muted);
  max-width: 36em;
}

/* ---- Closing band ----------------------------------------------------- */
.closing {
  padding-block: clamp(56px, 5vw + 24px, 104px);
}
.closing .wrap {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: var(--space-lg);
}
.closing-bird {
  display: block;
  width: clamp(88px, 8vw, 120px);
  --bird: clamp(92px, 8.3vw, 125px);
}
.closing-bird img {
  display: block;
  width: 100%;
}
.closing-bird.armed {
  transform: translateX(calc(var(--bird) * -1));
}

/* ---- Footer ----------------------------------------------------------- */
.site-footer {
  border-top: 1px solid var(--line);
  padding-block: var(--space-xl) var(--space-xxl);
  font-size: var(--type-label);
  color: var(--muted);
}
.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md) var(--space-xl);
  align-items: center;
  justify-content: space-between;
}
.site-footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-lg);
}
.site-footer a {
  color: var(--ink);
  text-decoration: none;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.site-footer a:hover {
  color: var(--blue);
}
.footer-legal {
  flex-basis: 100%;
  margin: 0;
}
.footer-brand {
  display: grid;
  gap: var(--space-xs);
}
.footer-brand .brand {
  --bird: 32px;
}

/* ---- Catalog page ------------------------------------------------------- */
.page-head {
  padding-block: clamp(24px, 3vw + 8px, 56px) var(--space-lg);
  display: grid;
  gap: var(--space-md);
}
.catalog-tools {
  display: grid;
  gap: var(--space-md);
  position: sticky;
  top: var(--header);
  z-index: 10;
  background: var(--cream);
  padding-block: var(--space-sm) var(--space-md);
}
@media (min-width: 960px) {
  .catalog-tools {
    grid-template-columns: minmax(0, 1fr) 280px;
    align-items: center;
  }
}
.search {
  position: relative;
}
.search input {
  width: 100%;
  min-height: 48px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--line);
  background: var(--field);
  padding: 0 var(--space-md) 0 44px;
  font:
    400 var(--type-body) / 1 "DM Sans",
    sans-serif;
  color: var(--ink);
}
.search input:focus {
  border-color: var(--blue);
  outline: none;
  box-shadow: 0 0 0 3px #345b8726;
}
.search svg {
  position: absolute;
  left: 16px;
  top: 50%;
  translate: 0 -50%;
  width: 18px;
  color: var(--muted);
  pointer-events: none;
}
.grid {
  display: grid;
  grid-template-columns: repeat(
    auto-fill,
    minmax(clamp(140px, 18vw, 210px), 1fr)
  );
  gap: clamp(24px, 2.4vw, 40px) clamp(16px, 2vw, 32px);
  padding-block: var(--space-md) var(--space-xxl);
}
.grid-empty {
  padding-block: var(--space-xxl);
  display: grid;
  justify-items: start;
  gap: var(--space-md);
}
.skeleton {
  aspect-ratio: 5 / 7;
  border-radius: 2px;
  background: linear-gradient(
      100deg,
      var(--mist) 40%,
      #f5f7f3 50%,
      var(--mist) 60%
    )
    0 0 / 300% 100%;
  animation: shimmer 1.4s linear infinite;
}
@keyframes shimmer {
  to {
    background-position: -150% 0;
  }
}
.load-error {
  display: grid;
  gap: var(--space-md);
  justify-items: start;
  padding-block: var(--space-xl);
}

/* ---- Card page ---------------------------------------------------------- */
.card-page {
  padding-block: clamp(16px, 2vw, 40px) clamp(48px, 5vw, 96px);
}
.card-page .wrap {
  display: grid;
  gap: clamp(24px, 3vw, 56px);
}
@media (min-width: 960px) {
  .card-page .wrap {
    grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
    align-items: center;
  }
}
.card-page .bifold {
  max-width: 720px;
  justify-self: center;
}
.card-info {
  display: grid;
  gap: var(--space-lg);
  justify-items: start;
  align-content: center;
}
.card-info .title-block {
  display: grid;
  gap: var(--space-sm);
}
.card-info h1 {
  font-size: clamp(28px, 1.6vw + 20px, 42px);
  line-height: 1.1;
}
.card-info .category {
  color: var(--muted);
  font-weight: 600;
  font-size: var(--type-label);
}
.inside-words {
  font-family: "Kalam", cursive;
  font-size: 22px;
  color: var(--blue);
}
.card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm) var(--space-md);
  align-items: center;
}
.price-note {
  color: var(--muted);
  font-size: var(--type-label);
}
.breadcrumb {
  font-size: var(--type-label);
}
.related {
  padding-block: var(--space-xl) clamp(64px, 6vw, 112px);
  border-top: 1px solid var(--line);
}
.related h2 {
  font-size: var(--type-title);
  margin-bottom: var(--space-sm);
}

/* ---- Not found ----------------------------------------------------------- */
.not-found {
  min-height: 60svh;
  display: grid;
  place-items: center;
  text-align: center;
}
.not-found .wrap {
  display: grid;
  justify-items: center;
  gap: var(--space-lg);
}
.not-found img {
  width: 120px;
}

/* ---- Account: sign in, create, reset, the account page --------------------
   One narrow column, the app's steps. Fields are the search field's
   material; the checklist and notice are the app's. */
.account-page {
  padding-block: var(--space-xl) var(--space-xxl);
  min-height: 70svh;
}
.account-column {
  max-width: 440px;
  margin-inline: auto;
}
.account-step {
  display: grid;
  gap: var(--space-md);
}
.account-step.enter {
  animation: step-in var(--motion-standard) var(--ease-out) both;
}
@keyframes fade-in {
  from {
    opacity: 0;
  }
}
@keyframes step-in {
  from {
    opacity: 0;
    transform: translateX(16px);
  }
}
.account-bird {
  width: 44px;
}
.account-step h1 {
  font-size: clamp(28px, 1.2vw + 22px, 36px);
  line-height: 1.15;
}
.account-step h1:focus {
  outline: none;
}
.account-step form {
  display: grid;
  gap: var(--space-md);
}
.account-step .button.wide {
  width: 100%;
  margin-top: var(--space-xs);
}
.field {
  display: grid;
  gap: var(--space-sm);
}
.field label {
  font-size: var(--type-label);
  font-weight: 600;
  color: var(--ink);
}
.input {
  width: 100%;
  min-height: 48px;
  border-radius: var(--radius-md);
  border: 1.5px solid var(--line);
  background: var(--field);
  padding: 0 var(--space-md);
  font:
    400 var(--type-body) / 1 "DM Sans",
    sans-serif;
  color: var(--ink);
}
.input:focus {
  border-color: var(--blue);
  outline: none;
  box-shadow: 0 0 0 3px #345b8726;
}
.input-with-action {
  position: relative;
}
.input-with-action .input {
  padding-right: 72px;
}
.reveal {
  position: absolute;
  right: var(--space-xs);
  top: 50%;
  translate: 0 -50%;
  min-height: 40px;
  padding: 0 var(--space-sm-plus);
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--blue);
  font:
    600 var(--type-label) / 1 "DM Sans",
    sans-serif;
  cursor: pointer;
}
.reveal:hover {
  background: #345b870f;
}
.checklist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-xs);
  font-size: var(--type-label);
  color: var(--muted);
}
.checklist li {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}
.checklist .tick {
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  transition:
    background-color var(--motion-fast) var(--ease),
    border-color var(--motion-fast) var(--ease);
}
.checklist .met {
  color: var(--ink);
}
.checklist .met .tick {
  background: var(--blue);
  border-color: var(--blue);
}
.checklist .met .tick::after {
  content: "";
  width: 8px;
  height: 4px;
  border: solid var(--paper);
  border-width: 0 0 2px 2px;
  rotate: -45deg;
  translate: 0 -1px;
}
.form-note:empty {
  display: none;
}
.form-note {
  padding: var(--space-sm-plus) var(--space-md);
  border-radius: var(--radius-md);
  background: var(--mist);
  font-size: var(--type-label);
  line-height: var(--leading-label);
}
.form-note.error {
  background: #eebaaa59;
  color: var(--ink);
}
.account-links {
  display: grid;
  justify-items: start;
}
.account-links .text-link,
.account-section .text-link,
.account-foot .text-link {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--blue);
  cursor: pointer;
}
.notice-panel {
  display: grid;
  gap: var(--space-sm-plus);
  padding: var(--space-md-plus);
  border-radius: var(--radius-lg);
  background: var(--paper);
  box-shadow: var(--paper-shadow);
  font-size: var(--type-label);
  line-height: var(--leading-label);
}
.notice-panel h2 {
  font-size: var(--type-title);
}
.fine-print {
  font-size: var(--type-label);
  line-height: var(--leading-label);
  color: var(--muted);
}
.check-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm-plus);
  min-height: 44px;
  font-weight: 600;
  cursor: pointer;
}
.check-row input {
  width: 22px;
  height: 22px;
  margin: 0;
  accent-color: var(--blue);
}
.account-section {
  display: grid;
  gap: var(--space-sm);
  /* Not a page section: none of the page-level section padding. */
  padding: var(--space-md) 0 0;
  border-top: 1px solid var(--line);
  justify-items: start;
}
.account-section h2 {
  font-size: var(--type-title);
  line-height: var(--leading-title);
}
.account-name .button.wide {
  width: auto;
  justify-self: start;
}
.account-row {
  display: grid;
  gap: var(--space-xs);
}
.row-label {
  font-weight: 600;
}
.row-detail,
.row-help {
  color: var(--muted);
  font-size: var(--type-label);
  line-height: var(--leading-label);
}
.account-row .button {
  justify-self: start;
  margin-top: var(--space-sm);
}
.account-foot {
  display: grid;
  gap: var(--space-sm-plus);
  justify-items: start;
  padding-top: var(--space-lg);
  border-top: 1px solid var(--line);
}
.confirm {
  max-width: min(400px, 100% - 2 * var(--gutter));
  border: 0;
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  background: var(--paper);
  color: var(--ink);
  box-shadow: var(--lift-shadow);
}
.confirm::backdrop {
  background: #30455b59;
}
.confirm h2 {
  font-size: var(--type-title);
  margin-bottom: var(--space-sm);
}
.confirm-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}

/* ---- Privacy notice --------------------------------------------------------- */
.legal-page {
  padding-block: var(--space-xl) var(--space-xxl);
  min-height: 70svh;
}
.legal {
  max-width: 40em;
  display: grid;
  gap: var(--space-md);
}
.legal h2 {
  font-size: var(--type-title);
  line-height: var(--leading-title);
  margin-top: var(--space-lg);
}
.legal ul {
  margin: 0;
  padding-left: 1.25em;
  display: grid;
  gap: var(--space-sm);
}
.legal p {
  margin: 0;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
  }
  .skeleton {
    animation: none;
  }
  .account-step.enter {
    animation: fade-in var(--motion-fast) linear both;
  }
  .cover-tile:hover .cover-frame {
    transform: none;
  }
}
