/* ==========================================================================
   Tokens: mirror the "BOTM mock tokens" variable collection in Figma.
   ========================================================================== */
:root {
  --color-bg-page: #FBF7F4;
  --color-bg-surface: #EFE9E2;
  --color-text-primary: #020202;
  --color-text-secondary: #4A4642;
  --color-text-link: #074974;
  --color-brand-primary: #0A68A6;
  --color-brand-primary-hover: #074974;
  --color-brand-deep: #0E3964;
  --color-control-field: #FFFFFF;
  --color-control-border: #7A7F85;
  --color-control-disabled-bg: #DCDEE0;
  --color-control-disabled-text: #4A4F55;
  --color-art-pink: #F68FBD;
  --color-art-pink-light: #F9BDD7;
  --color-art-pink-line: #E37FAE;

  --radius-card: 24px;
  --radius-control: 4px;

  --font-serif: "Newsreader", Georgia, "Times New Roman", serif;
  --font-sans: "DM Sans", Helvetica, Arial, sans-serif;

  --gutter: 16px;
}

/* ==========================================================================
   Base
   ========================================================================== */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--color-bg-page);
  color: var(--color-text-primary);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.5;
  overflow-x: clip;
}

h1, h2, p { margin: 0; }

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.display {
  font-family: var(--font-serif);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.01em;
}
.display em { font-style: italic; }

/* Buttons. Figma: Button/Primary, Button/Disabled, Button/Primary – focus */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 11px 60px;
  border: 0;
  border-radius: var(--radius-control);
  font: 500 1.0625rem/1.3 var(--font-sans);
  text-decoration: none;
  cursor: pointer;
}
.btn--primary {
  background: var(--color-brand-primary);
  color: #FFFFFF;
}
.btn--primary:hover { background: var(--color-brand-primary-hover); }

:focus-visible {
  outline: 2px solid var(--color-brand-primary);
  outline-offset: 3px;
}

/* ==========================================================================
   Intro and footer (mock framing, not part of the Figma sections)
   ========================================================================== */
.intro {
  min-height: 85svh;
  display: grid;
  align-content: center;
  gap: 16px;
  max-width: 720px;
  margin-inline: auto;
  padding: 64px var(--gutter);
}
.intro__badge {
  justify-self: start;
  padding: 4px 10px;
  border: 1px solid var(--color-control-border);
  border-radius: 999px;
  font-size: 0.875rem;
  font-weight: 500;
}
.intro__title {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: clamp(2.25rem, 5vw, 3.5rem);
  line-height: 1.05;
}
.intro__lede,
.intro__hint { color: var(--color-text-secondary); }

/* Motion status: one message is visible, chosen by the same conditions that
   turn the motion on. Hidden messages use display:none, so screen readers
   only hear the visible one. */
.motion-status {
  padding: 12px 16px;
  border-left: 3px solid var(--color-brand-primary);
  background: var(--color-bg-surface);
  font-size: 0.9375rem;
}
.motion-status__msg { display: none; }
.motion-status__msg--unsupported { display: inline; }
@supports (animation-timeline: view()) {
  .motion-status__msg--unsupported { display: none; }
  @media (prefers-reduced-motion: reduce) {
    .motion-status__msg--reduced { display: inline; }
  }
  @media (prefers-reduced-motion: no-preference) and (max-width: 1099px) {
    .motion-status__msg--narrow { display: inline; }
  }
  @media (prefers-reduced-motion: no-preference) and (min-width: 1100px) {
    .motion-status__msg--full { display: inline; }
  }
}

/* Tall enough that the page can scroll past the selections section far
   enough for its covers to finish rising. */
.footer {
  min-height: 60svh;
  display: grid;
  align-content: center;
  padding: 64px var(--gutter);
  text-align: center;
  color: var(--color-text-secondary);
}
.footer p { max-width: 640px; margin-inline: auto; }

/* ==========================================================================
   Section 1 · Gift hero
   --------------------------------------------------------------------------
   The default rules are the END state (Figma 1B): full-bleed card, square
   corners, boxes advanced one slot. Browsers without scroll-driven
   animations, and people who prefer reduced motion, get this static layout.
   The motion block further down animates FROM the start state (Figma 1A).
   ========================================================================== */
.gift {
  /* Desktop card at rest is 1036px of a 1440px frame: 0.72 of full width. */
  --rest-scale: 0.72;
  padding-block: 96px;
}

.gift__stage {
  display: grid;
  overflow: clip;
}

/* Background layer. Laid out at its full-bleed size; at rest it is scaled down. */
.gift__card {
  grid-area: 1 / 1;
  position: relative;
  width: 100%;
  aspect-ratio: 1440 / 678;          /* Figma 1B card: 1440 × 678 */
  background: var(--color-bg-surface);
}

.gift__panel {
  position: absolute;
  inset: 0 auto 0 0;
  width: 48.94%;                     /* 507 / 1036 */
  overflow: hidden;
  background: var(--color-art-pink);
}
.gift__floor {
  position: absolute;
  inset: 20.49% 0 0 0;               /* horizon at 100 / 488 */
  background: var(--color-art-pink-light);
}
.gift__wall {
  position: absolute;
  top: 0;
  left: var(--x);
  width: 0.6%;
  height: 20.49%;
  background: var(--color-art-pink-line);
}

/* The carousel. Each box sits in a slot on a line toward one vanishing
   point (V); every slot is 0.75× the one in front. Scaling the whole row
   by 1 / 0.75 around V moves every box exactly one slot forward. */
.gift__row {
  position: absolute;
  inset: 0;
  transform-origin: 120.316% 9.016%; /* V = (610, 44) in the 507 × 488 panel */
  transform: scale(1.3333);          /* end state: advanced one slot */
}
.gift__box {
  position: absolute;
  overflow: visible;
}
/* Slots 1–7 (Figma 1A box positions, as % of the panel). */
.gift__box:nth-child(1) { left: 9.862%;   top: 61.475%; width: 31.558%; height: 45.902%; }
.gift__box:nth-child(2) { left: 37.475%;  top: 48.361%; width: 23.669%; height: 34.426%; }
.gift__box:nth-child(3) { left: 58.185%;  top: 38.525%; width: 17.751%; height: 25.82%;  }
.gift__box:nth-child(4) { left: 73.718%;  top: 31.148%; width: 13.314%; height: 19.365%; }
.gift__box:nth-child(5) { left: 85.367%;  top: 25.615%; width: 9.985%;  height: 14.524%; }
.gift__box:nth-child(6) { left: 94.104%;  top: 21.465%; width: 7.489%;  height: 10.893%; }
.gift__box:nth-child(7) { left: 100.657%; top: 18.353%; width: 5.617%;  height: 8.17%;   }

/* Rounded corners without animating border-radius: four page-colored
   corner pieces with a quarter-circle cut out. Scaling a piece toward its
   outer corner shrinks the visible radius to 0. Size = 24px / 0.72, so
   the corners read as 24px while the card is at rest. */
.gift__corner {
  --r: calc(var(--radius-card) / 0.72);
  position: absolute;
  width: var(--r);
  height: var(--r);
  transform: scale(0);               /* end state: square corners */
}
.gift__corner--tl { top: 0;    left: 0;  transform-origin: 0 0;
  background: radial-gradient(circle at 100% 100%, transparent calc(var(--r) - 0.5px), var(--color-bg-page) var(--r)); }
.gift__corner--tr { top: 0;    right: 0; transform-origin: 100% 0;
  background: radial-gradient(circle at 0 100%,    transparent calc(var(--r) - 0.5px), var(--color-bg-page) var(--r)); }
.gift__corner--bl { bottom: 0; left: 0;  transform-origin: 0 100%;
  background: radial-gradient(circle at 100% 0,    transparent calc(var(--r) - 0.5px), var(--color-bg-page) var(--r)); }
.gift__corner--br { bottom: 0; right: 0; transform-origin: 100% 100%;
  background: radial-gradient(circle at 0 0,       transparent calc(var(--r) - 0.5px), var(--color-bg-page) var(--r)); }

/* Copy layer. Positioned in the stage, not in the card, so it never moves. */
.gift__copy {
  grid-area: 1 / 1;
  align-self: center;
  justify-self: start;
  position: relative;                /* paints above the card */
  margin-left: 53.33%;               /* Figma: x 768 of 1440 */
  width: 29.2%;                      /* Figma: 420 of 1440 */
  display: grid;
  justify-items: start;
  gap: 16px;
}
.gift__copy .display { font-size: clamp(2.25rem, 3.6vw, 3.5rem); }   /* 52px at 1440 */
.gift__sub {
  font-family: var(--font-serif);
  font-size: 1.1875rem;              /* 19px */
  line-height: 1.4;
  margin-bottom: 8px;
}

/* --- Below 1100px: stacked card, no grow, simpler motion ---------------- */
@media (max-width: 1099px) {
  .gift {
    padding-inline: var(--gutter);
    padding-block: 64px;
  }
  .gift__stage {
    max-width: 600px;
    margin-inline: auto;
    background: var(--color-bg-surface);
    border-radius: var(--radius-card);
  }
  .gift__card {
    grid-area: auto;
    aspect-ratio: 507 / 488;         /* the image panel alone */
  }
  .gift__panel { width: 100%; }
  .gift__corner { display: none; }
  .gift__copy {
    grid-area: auto;
    margin: 0;
    width: auto;
    padding: 28px 24px 32px;
  }
  .gift__copy .display { font-size: clamp(2rem, 8vw, 2.75rem); }
  .gift__sub { font-size: 1.0625rem; }
}

/* ==========================================================================
   Section 2 · Monthly selections
   --------------------------------------------------------------------------
   Default rules are the END state (Figma 2B): covers peek up from the
   bottom edge and the row has drifted left. Titles stay below the edge.
   All cover geometry is in units of --cw (cover width; 200px in Figma).
   ========================================================================== */
.picks {
  --cw: 200px;
  --gap: calc(var(--cw) * 0.15);         /* 30px between covers */
  overflow: clip;
  padding-top: 96px;
  background: var(--color-bg-surface);
}
.picks__title {
  padding-inline: var(--gutter);
  text-align: center;
  font-size: clamp(2.5rem, 4.45vw, 4rem); /* 64px at 1440 */
}

/* Form. Figma: Field/Email, Text/Legal, Button/Disabled (509px wide). */
.picks__form {
  display: grid;
  gap: 20px;
  width: min(509px, 100% - 2 * var(--gutter));
  margin: 46px auto 0;
}
.field { display: grid; gap: 8px; }
.field__label { font-size: 0.9375rem; font-weight: 500; }
.field__input {
  width: 100%;
  min-height: 48px;
  padding: 0 16px;
  border: 1px solid var(--color-control-border);
  border-radius: var(--radius-control);
  background: var(--color-control-field);
  color: var(--color-text-primary);
  font: 1rem/1.5 var(--font-sans);
}
.field__input::placeholder { color: #5E5A55; opacity: 1; }
.field__input[aria-invalid="true"] { border-color: #B3261E; }
.field__hint {
  font-size: 0.875rem;
  color: var(--color-text-secondary);
}
.picks__legal {
  text-align: center;
  font-size: 0.875rem;
}
.picks__legal a {
  color: var(--color-text-link);
  font-weight: 500;
}
.btn--block { width: 100%; padding-inline: 16px; }

/* The button looks inactive until the email is valid, but it is never
   `disabled`: a disabled button can't be focused or explain itself.
   Pressing it early shows the error instead. */
.picks__submit {
  background: var(--color-brand-primary);
  color: #FFFFFF;
}
.picks__submit:hover { background: var(--color-brand-primary-hover); }
.picks__form:has(.field__input:invalid) .picks__submit {
  background: var(--color-control-disabled-bg);
  color: var(--color-control-disabled-text);
}
.picks__result:empty { display: none; }
.picks__result {
  text-align: center;
  font-size: 0.9375rem;
  color: var(--color-text-secondary);
}

/* Shelf: the empty band under the form where the covers peek up.
   Figma: form ends at y 430 of a 720 frame, so the band is 290px. */
.picks__shelf {
  position: relative;
  height: calc(var(--cw) * 1.45);
}
.picks__row {
  position: absolute;
  top: 100%;                              /* the section's bottom edge */
  left: calc(50% - var(--cw) * 4.3);     /* Figma 2A: row x −140 in 1440 */
  width: calc(var(--cw) * 8 + var(--gap) * 7);
  transform: translateX(calc(var(--cw) * -0.6));   /* end state: drifted 120px left */
}
.cover {
  position: absolute;
  top: calc(var(--cw) * 0.05);            /* 10px below the edge: hidden */
  left: calc(var(--i) * (var(--cw) + var(--gap)));
  width: var(--cw);
  height: calc(var(--cw) * 1.5);
  overflow: hidden;
  border-radius: 2px;
  font-size: var(--cw);                   /* children size in em = fractions of the cover */
  /* End state: rise by the peek height (Figma 2B), plus the 10px offset. */
  transform: translateY(calc((var(--peek) * var(--cw) + var(--cw) * 0.05) * -1));
}
.cover__art,
.cover__art::before,
.cover__art::after {
  position: absolute;
  content: "";
}
.cover__title {
  position: absolute;
  left: 10%;
  top: 60%;
  font: 400 0.15em/1.13 var(--font-serif);
}
.cover__author {
  position: absolute;
  left: 10%;
  top: 88.67%;
  font: 500 0.06em/1.3 var(--font-sans);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

/* Invented covers (Figma Cover/01–08). Shapes are % of the 200 × 300 cover. */
.cover--1 { background: #2F6B4F; color: #FBF7F4; }
.cover--1 .cover__art { left: 20%; top: 12%; width: 60%; height: 40%; border-radius: 50%; background: #F2C14E; }

.cover--2 { background: #E8604C; color: #0E1424; }   /* 5.43:1 */
.cover--2 .cover__art { left: 0; top: 16.67%; width: 100%; height: 24%;
  background: repeating-linear-gradient(#FBF7F4 0 16.67%, transparent 16.67% 41.67%); }

.cover--3 { background: #1C2541; color: #F9BDD7; }
.cover--3 .cover__art { left: 56%; top: 10%; width: 30%; height: 20%; border-radius: 50%; background: #F9BDD7; }
.cover--3 .cover__title { top: 66.67%; font-size: 0.18em; }

.cover--4 { background: #F2C14E; color: #0E3964; }
.cover--4 .cover__art { inset: 0; }
.cover--4 .cover__art::before { left: 13%; top: 12%; width: 35%; height: 23.33%; border-radius: 50%; background: #0E3964; }
.cover--4 .cover__art::after  { left: 50%; top: 26.67%; width: 35%; height: 23.33%; border-radius: 50%; background: #FBF7F4; }

.cover--5 { background: #8FB8DE; color: #0E3964; }
.cover--5 .cover__art { left: 0; top: 40%; width: 100%; height: 13.33%; background: #0E3964; }

.cover--6 { background: #5B2A86; color: #FBF7F4; }
.cover--6 .cover__art { left: 25%; top: 10%; width: 50%; height: 46.67%; border-radius: 50%; background: #F68FBD; }

.cover--7 { background: #FBF7F4; color: #020202; box-shadow: inset 0 0 0 1px #DCDEE0; }
.cover--7 .cover__art { left: 10%; top: 6.67%; width: 80%; height: 46.67%; background: #0A68A6; }

.cover--8 { background: #C44536; color: #FBF7F4; }
.cover--8 .cover__art { left: 25%; top: 13.33%; width: 50%; height: 33.33%; border-radius: 50%; background: #F9BDD7; }

/* --- Small screens: smaller covers, same proportions ------------------- */
@media (max-width: 699px) {
  .picks {
    --cw: 128px;
    padding-top: 64px;
  }
  .picks__form { margin-top: 32px; }
}

/* ==========================================================================
   Motion: only when the browser supports scroll-driven animations and the
   person has not asked for reduced motion. Only transform is animated.
   ========================================================================== */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    .gift { view-timeline: --gift block; }

    .gift__row {
      animation: gift-carousel linear both;
      animation-timeline: --gift;
      animation-range: cover 15% cover 65%;
    }

    /* Desktop: grow to full-bleed, then a short pin while the boxes finish. */
    @media (min-width: 1100px) {
      .gift {
        height: 180svh;              /* stage is 100svh: the pin lasts 0.8 of a viewport */
        padding-block: 0;
      }
      .gift__stage {
        position: sticky;
        top: 0;
        height: 100svh;
        align-items: center;
      }
      .gift__card {
        align-self: center;
        animation: gift-grow linear both;
        animation-timeline: --gift;
        animation-range: entry 50% entry 100%;   /* done when the card's center reaches the viewport's middle */
      }
      .gift__corner {
        animation: gift-corner linear both;
        animation-timeline: --gift;
        animation-range: entry 50% entry 100%;
      }
      .gift__row {
        animation-range: entry 50% contain 100%; /* keeps moving through the pin */
      }
    }

    /* Selections: the shelf (the band under the form) drives both motions. */
    .picks__shelf { view-timeline: --shelf block; }

    /* Slow sideways drift: starts as the shelf enters, ends once it has
       been fully on screen for a while. */
    .picks__row {
      animation: picks-drift linear both;
      animation-timeline: --shelf;
      animation-range: entry 0% contain 60%;
    }

    /* Covers sit at the shelf's bottom edge, so they rise only once the
       whole shelf is on screen ("contain"). Each starts 4% after the one
       before it, left to right, and stops at its peek: titles never show. */
    .cover {
      animation: picks-peek cubic-bezier(0.2, 0.7, 0.3, 1) both;
      animation-timeline: --shelf;
      animation-range: contain calc(var(--i) * 4%) contain calc(30% + var(--i) * 4%);
    }
  }
}

@keyframes picks-peek {
  from { transform: none; }
  to   { transform: translateY(calc((var(--peek) * var(--cw) + var(--cw) * 0.05) * -1)); }
}
@keyframes picks-drift {
  from { transform: none; }
  to   { transform: translateX(calc(var(--cw) * -0.6)); }
}

@keyframes gift-grow {
  from { transform: scale(var(--rest-scale)); }
  to   { transform: none; }
}
@keyframes gift-corner {
  from { transform: scale(1); }
  to   { transform: scale(0); }
}
@keyframes gift-carousel {
  from { transform: none; }
  to   { transform: scale(1.3333); }
}
