/* Wigglepress storefront.
 *
 * Design plan (WEB_BUILD_GUIDE.md §4):
 *   Colour    — warm paper #FFF4E6, deep plum anchor #241733, poster red
 *               #D64031, teal #1F7A6E, marigold #E8A317. Every text/background
 *               pair below clears WCAG AA against the plum or the paper.
 *   Type      — no webfont request: a rounded system stack (SF Pro Rounded on
 *               Apple, Segoe UI Variable on Windows) over a legible fallback.
 *               A self-hosted display face is parked in ideas/.
 *   Layout    — a paper sheet with tilted, thick-outlined catalogue cards laid
 *               out like stickers; one column on a phone, three on a desktop.
 *   Signature — the wordmark's per-syllable wiggle, echoed as a card tilt that
 *               straightens on hover.
 *
 * Buyer-facing surface: this is an adult in a gifting flow, not a child at
 * play. The kid-safe rules that still bind here are the ones about the page
 * itself — no third parties, no flashing, reduced-motion honoured, AA contrast,
 * generous targets.
 *
 * Generous, here, is 56px — the number .btn already ships, so the storefront
 * reuses it rather than inventing a second. WEB_BUILD_GUIDE.md §5's 64px is the
 * kid-facing figure and still binds on kid-facing content; the hands on this
 * surface are the buyer's, and the buyer is an adult (PRODUCT.md). The 44px in
 * debug.js is the floor a generic healthcheck can assert, not this target.
 */

:root {
  --paper: #fff4e6;
  --paper-raised: #fffaf2;
  --ink: #241733;
  --ink-soft: #5c4a63;
  --red: #d64031;
  --teal: #1f7a6e;
  --marigold: #e8a317;
  /* Text-safe variants. The bright marigold is 2.0:1 on paper and the bright
     red is 4.35:1 — both fail WCAG AA as text, though both are fine as fills
     with --ink on top. Measured, not guessed. */
  --marigold-ink: #a86a06; /* 4.07:1 on --paper */
  --red-ink: #b8291b; /* 6.0:1 on --paper-raised */
  --line: var(--ink);
  --radius: 22px;
  --shadow: 5px 6px 0 var(--ink);
  --bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
  --font:
    ui-rounded, 'SF Pro Rounded', 'Segoe UI Variable Display', 'Segoe UI', system-ui, -apple-system,
    'Helvetica Neue', sans-serif;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1.125rem;
  line-height: 1.6;
}

.wrap {
  max-width: 1100px;
  margin: 0 auto;
  padding: 28px 20px 80px;
}

/* --- Masthead ---------------------------------------------------------- */

.masthead {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 20px;
  padding-bottom: 20px;
}

.wordmark {
  margin: 0;
  font-size: clamp(2rem, 7vw, 3rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  text-decoration: none;
}

/* Only the anchor form (personalize masthead) is a tap target — the landing
   page's wordmark is a <p>. As a flex item the anchor is blockified, so bare
   padding would push <main> down; the equal negative margin cancels it, growing
   the hit rect to the 56px target at the top of this file without moving
   anything. At 375px the type scale bottoms out at 2rem (32px tall), so 13px
   each way is what clears 56 there — every wider viewport clears it by more. */
a.wordmark {
  padding: 13px 12px;
  margin: -13px -12px;
}

.wordmark span {
  display: inline-block;
}
.wordmark .l1 {
  color: var(--red);
}
.wordmark .l2 {
  color: var(--teal);
}
.wordmark .l3 {
  color: var(--marigold-ink);
}

@media (prefers-reduced-motion: no-preference) {
  .wordmark span {
    animation: wiggle 2.6s ease-in-out infinite;
  }
  .wordmark span:nth-child(2) {
    animation-delay: 0.35s;
  }
  .wordmark span:nth-child(3) {
    animation-delay: 0.7s;
  }
  @keyframes wiggle {
    0%,
    100% {
      transform: rotate(0deg) translateY(0);
    }
    25% {
      transform: rotate(-2.5deg) translateY(-2px);
    }
    75% {
      transform: rotate(2.5deg) translateY(1px);
    }
  }
}

.tagline {
  margin: 0;
  color: var(--ink-soft);
  font-size: 1rem;
}

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

.hero {
  padding: 24px 0 8px;
}

/* Measure in `ch` of the heading's own size, not the body's — capping the
   whole .hero at 34ch made a 46px headline break over five lines on desktop. */
.hero h1 {
  margin: 0 0 12px;
  max-width: 15ch;
  font-size: clamp(1.9rem, 6vw, 2.9rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.hero p {
  margin: 0;
  color: var(--ink-soft);
  max-width: 46ch;
}

/* --- Catalogue --------------------------------------------------------- */

.section-head {
  margin: 44px 0 18px;
  font-size: 1.35rem;
}

.grid {
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--paper-raised);
  border: 4px solid var(--line);
  border-radius: var(--radius);
  padding: 20px 20px 22px;
  box-shadow: var(--shadow);
  transition:
    transform 0.25s var(--bounce),
    box-shadow 0.25s var(--bounce);
}

/* Cards are a uniform height so the skeletons in index.html reserve exactly
   what the real cards take, and the grid never resizes on load. 340px fits the
   longest blurb at the narrowest column; anything longer would reintroduce the
   shift, so keep blurbs short. */
.card {
  min-height: 340px;
}

.card--skeleton {
  background: color-mix(in srgb, var(--paper-raised) 70%, var(--paper));
  border-style: dashed;
  border-color: var(--ink-soft);
  box-shadow: none;
}

.card:nth-child(3n + 1) {
  transform: rotate(-1.1deg);
}
.card:nth-child(3n + 3) {
  transform: rotate(1.1deg);
}

.card:hover,
.card:focus-within {
  transform: rotate(0deg) translateY(-4px);
  box-shadow: 7px 9px 0 var(--ink);
}

@media (prefers-reduced-motion: reduce) {
  .card,
  .card:hover,
  .card:focus-within {
    transform: none;
    transition: none;
  }
}

.card h3 {
  margin: 0;
  font-size: 1.35rem;
  line-height: 1.2;
}

.card p {
  margin: 0;
  font-size: 0.98rem;
  color: var(--ink-soft);
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.tag {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 999px;
  border: 2px solid var(--line);
  background: var(--paper);
}

.tag--line {
  background: var(--marigold);
}
.tag--occasion {
  background: var(--teal);
  color: #fff;
  border-color: var(--teal);
}

.card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
  padding-top: 8px;
}

.price {
  font-weight: 800;
  font-size: 1.1rem;
  font-variant-numeric: tabular-nums;
}

/* --- Controls ---------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  padding: 12px 24px;
  font: inherit;
  font-weight: 800;
  color: #fff;
  background: var(--red);
  border: 4px solid var(--line);
  border-radius: 999px;
  box-shadow: 3px 4px 0 var(--ink);
  cursor: pointer;
  text-decoration: none;
  transition: transform 0.2s var(--bounce);
}

.btn:hover {
  transform: translateY(-2px) scale(1.03);
}

.btn:active {
  transform: translateY(1px) scale(0.99);
  box-shadow: 1px 2px 0 var(--ink);
}

.btn--quiet {
  background: var(--paper-raised);
  color: var(--ink);
}

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: none;
  }
  .btn:hover,
  .btn:active {
    transform: none;
  }
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible {
  outline: 4px solid var(--teal);
  outline-offset: 3px;
}

/* --- Personalize form -------------------------------------------------- */

.panel {
  background: var(--paper-raised);
  border: 4px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
  box-shadow: var(--shadow);
}

.two-col {
  display: grid;
  gap: 26px;
  grid-template-columns: 1fr;
}

@media (min-width: 860px) {
  .two-col {
    grid-template-columns: minmax(0, 4fr) minmax(0, 5fr);
    align-items: start;
  }
}

.field {
  display: block;
  margin-bottom: 20px;
}

/* The label only. `.hint` and `.error` are also direct child spans, and a
   bare `.field > span` rule made both of them bold. */
.field > .field-label {
  display: block;
  font-weight: 700;
  margin-bottom: 6px;
}

.field input,
.field select {
  width: 100%;
  min-height: 56px;
  padding: 10px 14px;
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 3px solid var(--line);
  border-radius: 14px;
}

.hint {
  display: block;
  margin-top: 6px;
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.error {
  display: block;
  margin-top: 6px;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--red-ink);
}

[aria-invalid='true'] {
  border-color: var(--red);
}

/* --- Preview ----------------------------------------------------------- */

.spread {
  border: 3px dashed var(--ink-soft);
  border-radius: 16px;
  padding: 18px 20px;
  margin-bottom: 14px;
  background: var(--paper);
}

.spread .page-no {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.spread p {
  margin: 6px 0 0;
  font-size: 1.15rem;
}

.qa-note {
  margin-top: 16px;
  font-size: 0.92rem;
  color: var(--ink-soft);
}

.empty {
  color: var(--ink-soft);
}

/* --- Footer ------------------------------------------------------------ */

footer {
  margin-top: 60px;
  padding-top: 20px;
  border-top: 3px solid var(--line);
  color: var(--ink-soft);
  font-size: 0.85rem;
}

/* The one navigation link down here was rendering user-agent blue — the only
   element on the site outside the palette. Teal is the palette's link-safe
   colour at this size (4.7:1 on --paper).

   Sizing it to 56 is the awkward part: it is a link inside a sentence that
   wraps at 375px, and a:focus-visible draws its ring 3px outside the element's
   rect — so a rect tall enough to hit puts the ring on the line below. It did:
   the ring struck through "of the real pages."

   So the rect grows upward only. padding-top is above the baseline, where the
   footer's own padding and the <p>'s margin leave an empty band; the box below
   the baseline is left alone, which is where the sentence is. margin-bottom is
   then the one thing that moves anything: 8px of extra line-box depth, the
   minimum that gets the ring past the wrapped line (3.76px of it was already
   there, the ring needs 7). inline-block is what makes both work — vertical
   margins are ignored on a true inline, and the negative margin-top cancels the
   padding so the line box, and everything above this footer, stays put.

   Measured at 375×812 and 1440×900, Chromium: rect 98.3×56.8, ring clear of
   every line box in the paragraph (2.5px at 375, where it wraps), CLS still
   0.299 / 0.194. Anything that changes this footer's leading or padding, or the
   outline offset in a:focus-visible, needs re-measuring. */
footer a {
  display: inline-block;
  color: var(--teal);
  font-weight: 700;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  padding: 35px 0 0;
  margin: -35px 0 8px;
}

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