/* hele.toys shared styles (site redesign, Sep 2026).
   Grid: 8 px atom; body leading is the vertical unit (32 desktop, 28 tablet, 28 mobile);
   12 columns, gutter = one line of leading; running text capped near 60ch.
   Names follow the app's DesignSystem.swift (Surface, Ink, Stroke, Space) so site and app share a vocabulary.
   Type pass, 25 Sep 2026 (PROMPT_SITE_TYPOGRAPHY.md): Instrument Serif for headlines, Bricolage Grotesque for
   everything else, both self-hosted from /fonts/. Serif never below 32px; no text below 15px except the 12px
   uppercase label. Only Bricolage 400 and 600 and Instrument Serif 400 roman + italic are loaded, and
   font-synthesis is off, so nothing is faux bold or faux italic. The Bricolage file is cut to wght 400..600. */

/* the fonts. Filenames carry a version: /fonts/* is cached a year as immutable, like /assets/* */
@font-face { font-family: "Instrument Serif"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("/fonts/instrument-serif-400.v1.woff2") format("woff2"); }
@font-face { font-family: "Instrument Serif"; font-style: italic; font-weight: 400; font-display: swap;
  src: url("/fonts/instrument-serif-400-italic.v1.woff2") format("woff2"); }
@font-face { font-family: "Bricolage Grotesque"; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url("/fonts/bricolage-grotesque-var.v1.woff2") format("woff2-variations"), url("/fonts/bricolage-grotesque-var.v1.woff2") format("woff2"); }
/* metric-matched fallbacks, so the swap does not move the page. Measured with fontTools against each face's
   letter-frequency-weighted advance width (Bricolage at opsz 18, the body size); size-adjust scales the local
   face, the overrides restate the web font's own ascent and descent at that scale. */
@font-face { font-family: "Instrument Serif Fallback"; src: local("Georgia"); size-adjust: 76.92%; ascent-override: 128.71%; descent-override: 40.30%; line-gap-override: 0%; }
@font-face { font-family: "Instrument Serif Fallback"; font-style: italic; src: local("Georgia Italic"), local("Georgia-Italic"); size-adjust: 79.53%; ascent-override: 124.49%; descent-override: 38.98%; line-gap-override: 0%; }
@font-face { font-family: "Bricolage Grotesque Fallback"; src: local("Arial"), local("ArialMT"), local("Helvetica"); size-adjust: 106.41%; ascent-override: 87.40%; descent-override: 25.37%; line-gap-override: 0%; }
/* labels are tracked capitals, which run ~10% narrower against Arial than lowercase does: their own fallback,
   measured on capitals at opsz 12, weight 600 (Arial regular, since synthesis is off) */
@font-face { font-family: "Bricolage Label Fallback"; src: local("Arial"), local("ArialMT"), local("Helvetica"); size-adjust: 96.24%; ascent-override: 96.63%; descent-override: 28.05%; line-gap-override: 0%; }

@view-transition { navigation: auto; }

:root {
  color-scheme: dark;
  /* Surface */
  --surface: #241A12;          /* the ground everywhere */
  --surface-deep: #1A130D;     /* night sections */
  --surface-raised: #2B2017;   /* cards, shelves */
  /* Ink (contrast on --surface: 13.3 / 10.9 / 5.2 : 1). ink-2 is the body text colour: #C9B79E -> #DCCDB4, 25 Sep 2026 */
  --ink: #EDE2CE;
  --ink-2: #DCCDB4;
  --ink-3: #A08B70;
  --brass: #D8B98A;
  --brass-hi: #EBD4A8;
  --label: #B18C4C;            /* labels, eyebrows, nav: 5.5 : 1 on --surface */
  /* Type faces */
  --serif: "Instrument Serif", "Instrument Serif Fallback", Georgia, "Times New Roman", serif;
  --sans: "Bricolage Grotesque", "Bricolage Grotesque Fallback", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --sans-label: "Bricolage Grotesque", "Bricolage Label Fallback", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  /* Stroke */
  --stroke: #3A2B1E;
  /* Space: 8 px atom */
  --s1: 8px; --s2: 16px; --s3: 24px; --s4: 32px; --s5: 40px; --s6: 48px; --s8: 64px; --s10: 80px; --s12: 96px; --s16: 128px; --s20: 160px;
  /* Grid */
  --lead: 32px;                /* body leading = vertical unit */
  --gutter: var(--lead);
  --margin: 80px;
  --container: 1280px;
  --measure: 42.1em;           /* 65ch of Bricolage (its zero is 0.648em). In em, not ch: ch follows whichever font has loaded, so a ch measure reflowed the page when the fonts swapped in */
  /* Radius (tighter inside, softer outside) */
  --r-s: 8px; --r-m: 14px; --r-l: 20px;
  /* Motion: one curve, short durations; everything off under Reduce Motion */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --t-fast: 200ms; --t-reveal: 500ms; --stagger: 60ms;
  /* Type. Headlines scale fluidly (clamp), so the breakpoints below only step body and lead.
     Display is every page's H1: the hero H1 at home, the page title elsewhere. */
  --display: clamp(48px, 7vw, 96px); --display-lh: 0.95;
  --h2: clamp(36px, 4.5vw, 60px); --h2-lh: 0.98;
  --h3: 32px; --h3-lh: 1.05;
  --lead-size: 23px; --lead-lh: 1.5;
  --body: 18px; --body-lh: 1.55;
  --small: 15px; --small-lh: 1.5;
  --micro: 15px; --micro-lh: 1.5;   /* was 13px; nothing reads below 15px now. Uppercase micro text became .label (12px) */
  --label-size: 12px;
  --h1: var(--display); --h1-lh: var(--display-lh);
  --section: var(--s20);
}
@media (max-width: 1080px) {
  :root { --margin: 48px; --lead: 28px; --gutter: 24px;
    --lead-size: 21px; --section: var(--s16); }
}
@media (max-width: 720px) {
  :root { --margin: 24px; --gutter: 16px;
    --lead-size: 19px; --body: 17px; --section: var(--s12); }
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; background: var(--surface); font-synthesis: none; }
body { margin: 0; background: var(--surface); color: var(--ink);
  font: 400 var(--body)/var(--body-lh) var(--sans); font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  min-height: 100svh; display: flex; flex-direction: column; }
body > main { flex: 1 0 auto; }   /* footer sits at the bottom on short pages */
img, video, iframe { display: block; max-width: 100%; }
a { color: var(--brass); text-decoration: none; transition: color var(--t-fast) var(--ease); }
a:hover { color: var(--brass-hi); }
:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; border-radius: 4px; }
p { margin: 0; text-wrap: pretty; }
strong, b { font-weight: 600; }
h1, h2, h3, .display, .h2, .h3 { margin: 0; font-weight: 400; text-wrap: balance; font-family: var(--serif); font-optical-sizing: auto; }
/* the accent: one word or short phrase per headline in the italic, in brass. At most one per screen view. */
:is(h1, h2, h3, .display, .h2, .h3) em { font-style: italic; color: var(--brass); }
/* the label: eyebrows, step numbers, pack status, list heads, the main nav */
.label, .eyebrow, .menu-head, .group-head, .craft-row figcaption .num, .steps li .num, .pack-status, .tune-label .label-kind,
.book-card .num, .book-card small, .book-page .num, .nav-links a:not(.btn) {
  font-family: var(--sans-label); font-size: var(--label-size); line-height: 16px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--label); }
.skip { position: absolute; left: var(--s2); top: -64px; z-index: 100; padding: var(--s1) var(--s2); background: var(--ink); color: var(--surface); border-radius: var(--r-s); }
.skip:focus { top: var(--s2); }

/* ---------- grid ---------- */
.wrap { max-width: calc(var(--container) + 2 * var(--margin)); margin: 0 auto; padding: 0 var(--margin); }
.grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); }
.section { padding-top: var(--section); }
/* column spans (desktop); collapse rules below */
.c-1-5  { grid-column: 1 / span 5; }
.c-1-6  { grid-column: 1 / span 6; }
.c-1-9  { grid-column: 1 / span 9; }
.c-1-12 { grid-column: 1 / -1; }
.c-6-12 { grid-column: 6 / -1; }
.c-7-12 { grid-column: 7 / -1; }
.c-8-12 { grid-column: 8 / -1; }
.c-5-12 { grid-column: 5 / -1; }
.c-1-4  { grid-column: 1 / span 4; }
@media (max-width: 860px) {
  .grid > [class*="c-"] { grid-column: 1 / -1; }
}

/* ---------- type ---------- */
.display { font-size: var(--display); line-height: var(--display-lh); letter-spacing: -0.01em; }
.h2 { font-size: var(--h2); line-height: var(--h2-lh); }
.h3 { font-size: var(--h3); line-height: var(--h3-lh); }
.lead { font-size: var(--lead-size); line-height: var(--lead-lh); color: var(--ink-2); }
.body { color: var(--ink-2); max-width: var(--measure); }
.small { font-size: var(--small); line-height: var(--small-lh); color: var(--ink-3); }
.stack > * + * { margin-top: var(--s3); }
.stack-s > * + * { margin-top: var(--s2); }

/* ---------- controls ---------- */
.btn { display: inline-flex; align-items: center; gap: var(--s1); min-height: 44px; padding: 0 var(--s3); border-radius: 999px;
  font: 600 16px/1 var(--sans); background: var(--ink); color: var(--surface);
  transition: background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
.btn:hover { background: #fff; color: var(--surface); }
.btn:active { transform: scale(0.97); }
.btn-s { min-height: 32px; padding: 0 var(--s2); font-size: 16px; }
/* one conversion unit, used at the close of every page that sells and once in the middle of the
   home page. A hairline and space rather than a panel: the site argues in editorial rules already
   (.steps, .facts), and a box would read as an advert on a page whose whole claim is restraint. */
.cta { border-top: 1px solid var(--stroke); padding-top: var(--s4); }
.cta .h3 { display: block; }
.cta .body { margin-top: var(--s2); max-width: var(--measure); }
.cta .badge { margin-top: var(--s4); }
.cta .small { margin-top: var(--s3); }
.badge { display: inline-flex; line-height: 0; transition: transform var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease); }
.badge:hover { opacity: 0.88; } .badge:active { transform: scale(0.97); }
.badge img { height: 48px; width: auto; }
.more { font-weight: 600; }
.more::after { content: "\2192"; display: inline-block; margin-left: 0.3em; transition: transform var(--t-fast) var(--ease); }
.more:hover::after { transform: translateX(3px); }

/* ---------- header ---------- */
.site-header { position: sticky; top: 0; z-index: 50; view-transition-name: site-header;
  background: rgba(36, 26, 18, 0.8); -webkit-backdrop-filter: saturate(140%) blur(14px); backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid transparent; transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease); }
.site-header.is-stuck { border-bottom-color: var(--stroke); background: rgba(36, 26, 18, 0.92); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .site-header { background: var(--surface); } }
.site-header nav { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); height: 56px; }
.brand { display: flex; align-items: center; gap: 10px; color: var(--ink); font-weight: 600; font-size: 17px; }
.brand:hover { color: var(--ink); }
.brand img { width: 28px; height: 28px; border-radius: 7px; }
.brand span { font-weight: 400; font-size: 15px; color: var(--ink-3); }
.nav-links { display: flex; align-items: center; gap: var(--s4); }
.nav-links a:not(.btn):hover { color: var(--ink); }
@media (max-width: 860px) { .nav-links a:not(.btn) { display: none; } .brand span { display: none; } }

/* mobile menu (site.js builds it; the button only shows at 860 px and below) */
.menu-btn { display: none; position: relative; width: 44px; height: 44px; margin-right: -10px; padding: 0; border: 0; background: none; color: var(--ink); cursor: pointer; border-radius: 999px; -webkit-tap-highlight-color: transparent; }
.menu-btn span { position: absolute; left: 13px; width: 18px; height: 1.5px; border-radius: 1px; background: currentColor;
  transition: transform var(--t-fast) var(--ease), top var(--t-fast) var(--ease); }
.menu-btn span { transition: transform var(--t-fast) var(--ease), top var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease); }
.menu-btn span:nth-child(1) { top: 15.25px; } .menu-btn span:nth-child(2) { top: 21.25px; } .menu-btn span:nth-child(3) { top: 27.25px; }
.menu-open .menu-btn span:nth-child(1) { top: 21.25px; transform: rotate(45deg); }
.menu-open .menu-btn span:nth-child(2) { opacity: 0; }
.menu-open .menu-btn span:nth-child(3) { top: 21.25px; transform: rotate(-45deg); }
.menu-btn:active { opacity: 0.6; }
@media (max-width: 860px) { .menu-btn { display: inline-block; } .nav-links { gap: var(--s2); } }
.menu-open { overflow: hidden; }   /* html only: overflow on body too makes body the scroller, and the sticky header sticks to it and leaves with the page */
.menu-open .site-header { background: var(--surface-deep); border-bottom-color: var(--stroke); }
.menu { position: fixed; inset: 0; z-index: 49; padding-top: 56px; background: var(--surface-deep); overflow-y: auto; overscroll-behavior: contain;
  opacity: 0; transition: opacity var(--t-fast) var(--ease); }
.menu.is-open { opacity: 1; }
.menu-inner { padding-top: var(--s4); padding-bottom: calc(var(--s8) + env(safe-area-inset-bottom)); display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5) var(--gutter); }
.menu-group.is-big { grid-column: 1 / -1; padding-bottom: var(--s4); border-bottom: 1px solid var(--stroke); }
.menu-head { margin: 0 0 var(--s1); }
.menu ul { list-style: none; margin: 0; padding: 0; }
.menu a { display: flex; align-items: center; min-height: 44px; color: var(--ink-2); font-size: 18px; line-height: 24px; }
.menu .is-big a { min-height: 52px; color: var(--ink); font-family: var(--serif); font-size: 32px; line-height: 36px; font-weight: 400; }
.menu a:hover, .menu a[aria-current="page"] { color: var(--ink); }
.menu a[aria-current="page"] { color: var(--brass); }
.menu-head, .menu li { opacity: 0; transform: translateY(8px);
  transition: opacity 320ms var(--ease), transform 420ms var(--ease); transition-delay: calc(var(--i) * 22ms); }
.menu.is-open .menu-head, .menu.is-open li { opacity: 1; transform: none; }
.menu:not(.is-open) .menu-head, .menu:not(.is-open) li { transition-delay: 0ms; transition-duration: 120ms; }
@media (prefers-reduced-motion: reduce) {
  .menu, .menu-head, .menu li, .menu-btn span { transition: none !important; }
  .menu-head, .menu li { transform: none; }
}

/* ---------- hero ---------- */
.hero { position: relative; overflow: hidden; }
.hero-media { position: absolute; inset: 0; }
.hero-media img { width: 100%; height: 100%; object-fit: cover; object-position: 70% 50%; }
.hero .grid { position: relative; min-height: min(calc(100svh - 56px), 880px); align-content: center; padding: var(--s12) 0; }
.hero-copy > * + * { margin-top: var(--s3); }
.hero-copy .lead { max-width: 22em; }   /* 29 Sep 2026 (Hans): widened from 19.4em with the copy column (5 -> 6) */
.hero-meta { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; padding-top: var(--s1); }
@media (max-width: 860px) {
  .hero-media { position: relative; inset: auto; aspect-ratio: 1 / 1; margin: 0 calc(-1 * var(--margin)); }
  .hero-media img { object-position: 93% 50%; }
  .hero .grid { min-height: 0; padding: var(--s3) 0 0; }
}

/* ---------- craft (sticky captions beside tall close-ups) ---------- */
.craft-intro { align-items: end; row-gap: var(--s3); }
.craft-list { margin-top: var(--s12); display: grid; row-gap: var(--s10); }
.craft-row { align-items: start; margin: 0; }
.craft-row figcaption { position: sticky; top: calc(50vh - 96px); align-self: start; padding-top: var(--s8); }
.craft-row figcaption .num { line-height: var(--s3); font-variant-numeric: tabular-nums; }
.craft-row figcaption .h3 { margin-top: var(--s1); }
.craft-row figcaption p { margin-top: var(--s2); color: var(--ink-2); max-width: 22.0em; }
.frame { position: relative; overflow: hidden; border-radius: var(--r-l); background: var(--surface-deep); aspect-ratio: 4 / 5; }
.frame img { width: 100%; height: 100%; object-fit: cover; }
.craft-row:nth-child(even) .frame-col { grid-column: 1 / span 6; grid-row: 1; }
.craft-row:nth-child(even) figcaption { grid-column: 8 / -1; grid-row: 1; }
.craft-row:nth-child(odd) .frame-col { grid-column: 7 / -1; grid-row: 1; }
.craft-row:nth-child(odd) figcaption { grid-column: 1 / span 5; grid-row: 1; }
@media (max-width: 860px) {
  .craft-list { row-gap: var(--s10); margin-top: var(--s8); }
  .craft-row .frame-col, .craft-row figcaption { grid-column: 1 / -1 !important; grid-row: auto !important; }
  .craft-row figcaption { position: static; padding-top: var(--s3); }
}

/* compact craft (24 Sep 2026 trim): the five close-ups in one row, captions under them; a swipe strip on phones.
   Overrides the alternating rows above, so it sits after them. */
.craft-list-row { margin-top: var(--s8); grid-template-columns: repeat(5, minmax(0, 1fr)); column-gap: var(--s2); row-gap: 0; }
.craft-list-row .craft-row { display: block; }
.craft-list-row .craft-row .frame-col, .craft-list-row .craft-row figcaption { grid-column: auto; grid-row: auto; }
.craft-list-row .craft-row figcaption { position: static; padding-top: var(--s2); }
.craft-list-row .craft-row figcaption p { margin-top: var(--s1); font-size: var(--small); line-height: var(--small-lh); }
.craft-pair { margin-top: var(--s10); row-gap: var(--s5); }
.craft-pair > [id] { scroll-margin-top: calc(56px + var(--s6)); }
.cta-mid { margin-top: var(--s8); }
@media (max-width: 860px) {
  .craft-list-row { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 68%; column-gap: var(--s2);
    overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
    margin-left: calc(-1 * var(--margin)); margin-right: calc(-1 * var(--margin)); padding: 0 var(--margin) var(--s2); scrollbar-width: none; }
  .craft-list-row::-webkit-scrollbar { display: none; }
  .craft-list-row .craft-row { scroll-snap-align: start; }
  .craft-pair .c-1-6, .craft-pair .c-7-12 { grid-column: 1 / -1; }
  /* phones: square close-ups and each step drawn beside its words, so the merged section stays short */
  .craft-list-row .frame { aspect-ratio: 1; }
  #craft .steps li { display: grid; grid-template-columns: 104px minmax(0, 1fr); column-gap: var(--s2); align-items: start; }
  #craft .steps li > .d-art { grid-column: 1; grid-row: 1 / span 3; margin: 0; max-width: 104px; }
  #craft .steps li > :not(.d-art) { grid-column: 2; }
  .craft-pair { margin-top: var(--s8); }
}

/* ---------- play (the live demo) ---------- */
.stage { position: relative; margin-top: var(--s8); height: min(80vh, 760px); overflow: hidden; container-type: size; border-radius: var(--r-l);
  background: radial-gradient(ellipse 60% 55% at 50% 52%, #2E2218 0%, var(--surface-deep) 72%); }
.stage img { position: absolute; left: calc(50cqw - 322 * min(100cqh, 186.6472cqw) / 1000); top: calc(47cqh - 353.33 * min(100cqh, 186.6472cqw) / 1000);
  width: calc(644 * min(100cqh, 186.6472cqw) / 1000); height: auto; max-width: none; }
.stage iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: transparent; opacity: 0; transition: opacity 450ms var(--ease); }
.steps { list-style: none; margin: var(--s6) 0 0; padding: 0; counter-reset: step; }
.steps li { border-top: 1px solid var(--stroke); padding-top: var(--s2); }
.steps li .num { display: block; line-height: var(--s3); font-variant-numeric: tabular-nums; }
.steps li .h3 { display: block; margin-top: var(--s1); }
.steps li p { margin-top: var(--s1); color: var(--ink-2); font-size: var(--small); line-height: var(--small-lh); }
.steps-grid { row-gap: var(--s4); }
.steps-grid li { grid-column: span 4; }
@media (max-width: 860px) {
  .stage { height: min(120vw, 560px); margin-left: calc(-1 * var(--margin)); margin-right: calc(-1 * var(--margin)); border-radius: 0; }
  .steps-grid li { grid-column: 1 / -1; }
}

/* ---------- night (Sleep) ---------- */
.night { padding-bottom: var(--section); }  /* the Sleep render is dimmed on the page ground; a darker band here would box it */
.night .grid { align-items: center; row-gap: var(--s6); }
.night .frame { background: var(--surface); }

/* ---------- riders shelf ---------- */
.shelf { margin-top: var(--s6); display: grid; grid-auto-flow: column; grid-auto-columns: clamp(168px, calc((min(100vw, 1440px) - 2 * var(--margin) - 4 * var(--s2)) / 5), 256px);  /* five across inside the container */
  gap: var(--s2); overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--margin);
  padding: 0 var(--margin) var(--s3); margin-left: calc(-1 * var(--margin)); margin-right: calc(-1 * var(--margin));
  scrollbar-width: thin; scrollbar-color: var(--stroke) transparent; overscroll-behavior-x: contain; }
.shelf:focus-visible { outline-offset: -2px; }
.rider { scroll-snap-align: start; margin: 0; border-radius: var(--r-l); background: linear-gradient(180deg, #33261B, var(--surface-raised) 60%);
  box-shadow: inset 0 1px 0 rgba(237, 226, 206, 0.06); aspect-ratio: 4 / 5; display: grid; grid-template-rows: 1fr auto; padding: var(--s2) var(--s2) var(--s2);
  transition: transform 300ms var(--ease); }
.rider img { width: auto; height: 100%; max-height: 100%; justify-self: center; align-self: end; object-fit: contain; min-height: 0;
  filter: drop-shadow(0 12px 12px rgba(10, 6, 3, 0.45)); }
.rider figcaption { margin-top: var(--s2); font-size: var(--small); line-height: var(--small-lh); color: var(--ink-2); text-align: center; }
.rider figcaption small { display: block; font-size: var(--micro); line-height: var(--micro-lh); color: var(--ink-3); }
@media (hover: hover) { .rider:hover { transform: translateY(-4px); } }
.tunes { list-style: none; padding: 0; margin: var(--s5) 0 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: var(--gutter); }
.tunes li { border-top: 1px solid var(--stroke); padding: var(--s2) 0; color: var(--ink); }
.tunes li small { display: block; font-size: var(--micro); line-height: var(--micro-lh); color: var(--ink-3); margin-top: 4px; }
@media (max-width: 720px) { .tunes { grid-template-columns: 1fr 1fr; } .shelf { grid-auto-columns: 40vw; } }

/* ---------- parents ---------- */
.facts { margin: 0; }
.facts > div { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); column-gap: var(--gutter); border-top: 1px solid var(--stroke); padding: var(--s3) 0; }
.facts > div:last-child { border-bottom: 1px solid var(--stroke); }
.facts dt { grid-column: 1 / span 2; font-size: var(--small); line-height: var(--small-lh); color: var(--ink-3); padding-top: 4px; }
.facts dd { grid-column: 3 / -1; margin: 0; color: var(--ink); }
@media (max-width: 720px) {
  .facts > div { grid-template-columns: 1fr; row-gap: 4px; padding: var(--s2) 0; }
  .facts dt, .facts dd { grid-column: 1 / -1; }
}

/* ---------- maker note ---------- */
.maker { padding-bottom: var(--section); }
.maker .h2 { color: var(--ink); }
/* the home note signs the work, so the face is a byline; /made-by carries the real portrait */
.byline-avatar { float: left; width: 56px; height: 56px; border-radius: 50%; margin: 3px var(--s2) 2px 0; }
@media (max-width: 860px) { .byline-avatar { float: none; display: block; margin: 0 0 var(--s2); } }  /* a narrow measure wraps only three lines round it, then steps back to full width */
/* contained, not a cut-out: the dark polo disappeared into the page ground. Round, to match the
   byline on the home page; the asset is square so 50% gives a circle and not an ellipse. */
.maker-portrait { display: block; width: 100%; max-width: 200px; height: auto; border-radius: 50%; }
@media (max-width: 1080px) { .maker-portrait { max-width: 120px; } }

/* ---------- inner pages ---------- */
.page-head { padding: var(--s12) 0 0; }
.nav-links a[aria-current="page"], .site-footer a[aria-current="page"] { color: var(--ink); }

/* ---------- packs: three across on the 12 columns (4 each), two on tablet, one on phones ---------- */
.packs { margin-top: var(--s6); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s6) var(--gutter); }
@media (max-width: 1080px) { .packs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .packs { grid-template-columns: 1fr; gap: var(--s5); } .pack-shot { aspect-ratio: 16 / 9; } }
.pack { margin: 0; display: grid; grid-template-rows: auto 1fr; }
.pack-shot { position: relative; aspect-ratio: 4 / 3; border-radius: var(--r-l); overflow: hidden;
  background: radial-gradient(ellipse 70% 60% at 50% 42%, #3A2B1E 0%, var(--surface-raised) 70%);
  box-shadow: inset 0 1px 0 rgba(237, 226, 206, 0.06);
  display: flex; align-items: flex-end; justify-content: center; padding: 0 var(--s3) 14%; transition: transform 300ms var(--ease); }
.pack-shot::after { content: ""; position: absolute; left: 14%; right: 14%; bottom: 11%; height: 7%; border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(10, 6, 3, 0.55), transparent 70%); z-index: 0; }
.pack-shot img { position: relative; z-index: 1; width: 25%; height: auto; max-height: 76%; object-fit: contain; object-position: center bottom;
  margin: 0 -2.5%; filter: drop-shadow(0 8px 8px rgba(10, 6, 3, 0.4)); }
.pack-shot.riders-3 img { width: 29%; }
@media (hover: hover) { .pack:hover .pack-shot { transform: translateY(-4px); } }
/* tune packs: the paper tune card a music box carries, set in the app's type */
.pack-shot.tune-shot { align-items: center; padding: var(--s3); }
.pack-shot.tune-shot::after { display: none; }
.tune-label { width: min(78%, 300px); background: #F2E8D4; color: #45301E; border-radius: 4px; padding: var(--s2) var(--s3);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.6) inset, 0 14px 28px rgba(10, 6, 3, 0.45); }
.tune-label .label-kind { color: #7A5C3E; }   /* on paper: the label face, in the card's own ink (brass fails on cream) */
.tune-label ol { margin: var(--s1) 0 0; padding: 0 0 0 1.4em; font-size: 15px; line-height: 22px; }
.tune-label li::marker { color: #7A5C3E; font-variant-numeric: tabular-nums; }
.tune-label .label-soon { margin-top: var(--s1); font-size: 15px; line-height: 22px; color: #7A5C3E; }
.pack-body { padding-top: var(--s2); }
.pack-body .h3 { margin-top: 4px; }
.pack-lines { margin-top: 4px; font-size: var(--small); line-height: var(--small-lh); color: var(--ink-2); }
.pack-status { margin-top: var(--s1); }
.pack-status.is-on { color: var(--brass); }
.pack-status.is-in { color: var(--ink-2); }
.pack-status.is-later { color: var(--ink-3); }

/* ---------- packs on the home page (written by site-tools/sync-home-packs.py) ---------- */
/* the closing index: chips for what a buyer can get today, named once, after the band has sold them */
.pack-index { padding-bottom: var(--s4); }
.pack-chips { list-style: none; margin: var(--s2) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--s1) var(--s2); }
.pack-chips li { font-size: var(--small); line-height: var(--small-lh); color: var(--ink-2); white-space: nowrap;
  border: 1px solid var(--stroke); border-radius: 999px; padding: 3px var(--s2); background: var(--surface-raised); }
.pack-chips li span { color: var(--ink-3); }
.pack-index .small { margin-top: var(--s2); color: var(--ink-2); max-width: 33.7em; }

/* band: the /packs cards, smaller, on one scrolling row like the riders shelf above it, so the
   fold stays one row tall instead of stacking thirteen cards down the page */
.packs-row { margin-top: var(--s4); display: grid; grid-auto-flow: column;
  grid-auto-columns: clamp(164px, calc((min(100vw, 1440px) - 2 * var(--margin) - 4 * var(--s2)) / 5), 240px);
  gap: var(--s2); overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--margin);
  padding: 0 var(--margin) var(--s3); margin-left: calc(-1 * var(--margin)); margin-right: calc(-1 * var(--margin));
  scrollbar-width: thin; scrollbar-color: var(--stroke) transparent; overscroll-behavior-x: contain; }
.packs-row:focus-visible { outline-offset: -2px; }
.pack-sm { scroll-snap-align: start; }
.pack-sm .pack-shot { aspect-ratio: 4 / 3; padding: 0 var(--s2) 12%; }
.pack-sm .pack-shot img { width: 27%; }
.pack-sm .pack-shot.riders-3 img { width: 31%; }
.pack-sm .pack-body { padding-top: var(--s2); }
.pack-sm .tune-label { width: min(86%, 200px); padding: var(--s2); }
@media (max-width: 720px) { .packs-row { grid-auto-columns: 46vw; } }

/* ---------- text pages (support, privacy, press, accessibility, lullabies, what's new) ---------- */
.page { padding: var(--s12) 0 var(--section); }
.page-col { grid-column: 1 / span 8; }
@media (max-width: 1080px) { .page-col { grid-column: 1 / -1; } }
/* the text column stops at 8 of 12; an <aside> takes the columns that were empty and holds its
   place while the page scrolls past it. Narrow: it leads the page small, above the title. */
.page-aside { grid-column: 10 / -1; grid-row: 1; position: sticky; top: calc(56px + var(--s4)); align-self: start; }
/* the column is wider than the portrait, so a caption left-aligned to the column sits off under the
   disc; hold both to the same width and centre the line */
.page-aside .meta { width: 200px; margin-top: var(--s2); text-align: center; }
@media (max-width: 1080px) { .page-aside .meta { width: auto; text-align: left; } }  /* the caption is wider than a 120px disc */
@media (max-width: 1080px) { .page-aside { grid-column: 1 / -1; grid-row: auto; order: -1; position: static; margin-bottom: var(--s6); } }
.page-col > * + * { margin-top: var(--s8); }
.page-col a { text-decoration: underline; text-decoration-color: rgba(216, 185, 138, 0.35); text-underline-offset: 3px; }
.page-col a:hover { text-decoration-color: currentColor; }
/* inline links in running text anywhere (home maker note, press facts, footer credit) read as links, same treatment as .page-col */
main :is(p, li, dd, .kv-v) a:not([class]), .site-footer div > a { text-decoration: underline; text-decoration-thickness: 1px;
  text-decoration-color: rgba(216, 185, 138, 0.45); text-underline-offset: 3px; transition: color var(--t-fast) var(--ease), text-decoration-color var(--t-fast) var(--ease); }
main :is(p, li, dd, .kv-v) a:not([class]):hover, .site-footer div > a:hover { text-decoration-color: currentColor; }
.display-page { font-size: var(--h1); line-height: var(--h1-lh); letter-spacing: -0.01em; }
.block > * + * { margin-top: var(--s2); }
.block-l > * + * { margin-top: var(--s3); }
.page-col .lead { max-width: var(--measure); }
/* verses: set apart from the prose, not indented like a quote, because the song is the point */
.page-col .lyric { color: var(--ink); font-size: var(--lead-size); line-height: 1.85; max-width: var(--measure); }
.page-col .lyric + .lyric { margin-top: var(--s4); }
.page-col .body, .page-col .qa-a { color: var(--ink-2); max-width: var(--measure); }
.page-col h2.h3, .page-col .h3 { font-size: var(--h3); line-height: var(--h3-lh); }
.list { border-top: 1px solid var(--stroke); }
.qa { padding: var(--s3) 0; border-bottom: 1px solid var(--stroke); }
.qa > * + * { margin-top: 4px; }
/* .qa-q and .group-head are marked up as real headings (site-tools/semantics.py) so the questions
   and sections are machine-readable. They keep the size and face they had as divs, so nothing moves. */
/* Each one carries an id so an answer can be linked to directly (/support/#how-do-i-wind-it). The
   header is sticky, so without this the jump puts the heading 24px ABOVE the viewport, behind it. */
.qa-q[id] { scroll-margin-top: calc(56px + var(--s6)); }
.qa-q { font-weight: 600; color: var(--ink); font-size: var(--body); line-height: var(--body-lh); font-family: var(--sans); text-wrap: pretty; }
.meta { font-size: var(--small); line-height: var(--small-lh); color: var(--ink-3); }
.group-head {
  padding: var(--s6) 0 var(--s2); border-bottom: 1px solid var(--stroke); }
.list > .group-head:first-child { padding-top: var(--s3); }
.kv { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); column-gap: var(--gutter); padding: var(--s2) 0; border-bottom: 1px solid var(--stroke); }
.kv-k { grid-column: 1 / span 2; font-size: var(--small); line-height: var(--small-lh); color: var(--ink-3); padding-top: 4px; }
.kv-v { grid-column: 3 / -1; color: var(--ink); }
@media (max-width: 720px) { .kv { grid-template-columns: 1fr; row-gap: 4px; } .kv-k, .kv-v { grid-column: 1 / -1; } }
.shot { width: 100%; height: auto; border-radius: var(--r-l); }
.shot-s { width: min(100%, 360px); }
.icons { display: flex; gap: var(--s2); flex-wrap: wrap; align-items: flex-end; }
.pt { padding-top: var(--s4); }
.pt > * + * { margin-top: var(--s2); }

/* ---------- footer ---------- */
.site-footer { border-top: 1px solid var(--stroke); padding: var(--s4) 0 var(--s6); font-size: var(--small); line-height: var(--small-lh); color: var(--ink-3); }
.site-footer .row { display: flex; justify-content: space-between; gap: var(--s3); flex-wrap: wrap; }
.site-footer nav { display: flex; gap: var(--s1) var(--s3); flex-wrap: wrap; }
.site-footer a { color: var(--ink-2); }
.site-footer a:hover { color: var(--ink); }

/* ---------- motion ---------- */
/* Reveals only arm when JS has run (html.js), so nothing is hidden without it. */
.js [data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity var(--t-reveal) var(--ease), transform var(--t-reveal) var(--ease);
  transition-delay: calc(var(--i, 0) * var(--stagger)); }
.js [data-reveal].in { opacity: 1; transform: none; }
.js .hero-media img { opacity: 0; transform: scale(1.03); transition: opacity 700ms var(--ease), transform 1200ms var(--ease); }
.js .hero-media img.in { opacity: 1; transform: none; }
/* scroll-linked: close-ups settle as they come into view (browsers with scroll-driven animations only) */
@supports (animation-timeline: view()) {
  .frame img.settle { animation: settle linear both; animation-timeline: view(); animation-range: entry 0% cover 45%; }
  @keyframes settle { from { transform: scale(1.1); } to { transform: scale(1); } }
}
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 260ms; animation-timing-function: var(--ease); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: 0ms !important; animation: none !important; }
  .js [data-reveal], .js .hero-media img { opacity: 1; transform: none; }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}

/* ---------- conversion pass, 23 Sep 2026 ---------- */
/* the header button stays 32px to the eye but takes a 44px touch, Apple's minimum */
.btn-s { position: relative; }
.btn-s::after { content: ""; position: absolute; left: 0; right: 0; top: -6px; bottom: -6px; }

/* parents' own words, from the App Store. Editorial rules like .steps, not cards */
.quotes { list-style: none; margin: var(--s6) 0 0; padding: 0; row-gap: var(--s4); }
.quotes li { grid-column: span 6; border-top: 1px solid var(--stroke); padding-top: var(--s3); margin: 0; }
.quotes blockquote { margin: 0; font-size: var(--lead-size); line-height: var(--lead-lh); color: var(--ink); text-wrap: pretty; }
.quotes .who { display: block; margin-top: var(--s2); font-size: var(--small); line-height: var(--small-lh); color: var(--ink-3); }
@media (max-width: 860px) { .quotes li { grid-column: 1 / -1; } }

/* desktop only: a phone is needed to install, so the badge gets a code the phone can read */
.qr { display: none; align-items: center; gap: var(--s2); font-size: var(--micro); line-height: var(--micro-lh); color: var(--ink-3); }
.qr img { width: 72px; height: 72px; border-radius: 6px; background: var(--ink); padding: 5px; }
@media (min-width: 1081px) and (hover: hover) and (pointer: fine) { .qr { display: inline-flex; } }

/* phones: the close-ups become one swipeable row instead of five screens of scrolling, and the
   embedded toy steps aside for its full-screen link (the hero render is the same object a screen up) */
@media (max-width: 860px) {
  .craft-list { display: grid; grid-auto-flow: column; grid-auto-columns: 78vw; column-gap: var(--s2); row-gap: 0;
    overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scrollbar-width: none;
    margin: var(--s6) calc(-1 * var(--margin)) 0; padding: 0 var(--margin); scroll-padding-inline: var(--margin); }
  .craft-list::-webkit-scrollbar { display: none; }
  .craft-row { display: block; scroll-snap-align: start; }
  .craft-row .frame img.settle { animation: none; }
  #demo .stage { display: none; }
}

/* spacing pass, 23 Sep 2026: one 96px step between sections on phones. The Sleep band's own bottom
   padding stacked on the parents' section padding (192px, a third of a screen of nothing), and the
   closing packs line added its top margin to the section padding. Cosmetic, so no file-name bump. */
@media (max-width: 860px) { .night { padding-bottom: 0; } }
.pack-index .c-1-12 > .small:first-child { margin-top: 0; }

/* ---------- diagrams (site-tools/diagrams.py), 23 Sep 2026 ----------
   One hairline drawing at the top of each step: parts at rest in ink-3, the moving part in ink, the
   motion in brass. The drawing arrives with its step (the step's own reveal), makes its one movement,
   and ends where it started. No stroke draw-on: it never ran in Chrome and left only line caps. */
.steps li .d-art { display: block; width: 100%; max-width: 240px; height: auto; margin: var(--s1) 0 var(--s3); overflow: visible; }
.d-art * { fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.d-art .rest, .d-art .rest * { stroke: var(--ink-3); }
.d-art .part, .d-art .part * { stroke: var(--ink); }
.d-art .m { stroke: var(--brass); }
.d-art .dots circle { fill: var(--ink-3); stroke: none; }
@media (max-width: 860px) { .steps li .d-art { max-width: 200px; margin-bottom: var(--s2); } }
@media (prefers-reduced-motion: no-preference) {
  /* the key makes a half turn (a butterfly key looks the same after it), its notches clicking in one by one */
  .js .steps li.in .turn { animation: d-turn 1600ms cubic-bezier(0.45, 0, 0.2, 1) 700ms both; }
  @keyframes d-turn { from { transform: rotate(0); } to { transform: rotate(180deg); } }
  .js .steps li .tick { opacity: 0.25; }
  .js .steps li.in .tick { opacity: 1; transition: opacity 120ms linear calc(700ms + var(--k) * 150ms); }
  /* the slowing marks arrive further and further apart */
  .js .steps li .slow { opacity: 0; }
  .js .steps li.in .slow { opacity: 1; transition: opacity 300ms var(--ease) 700ms; }
  .js .steps li.in .slow[style*="--k:1"] { transition-delay: 1000ms; }
  .js .steps li.in .slow[style*="--k:2"] { transition-delay: 1500ms; }
  .js .steps li.in .slow[style*="--k:3"] { transition-delay: 2300ms; }
  /* the lever tips over and comes back */
  .js .steps li.in .tip { animation: d-tip 1400ms var(--ease) 700ms both; }
  @keyframes d-tip { 0% { transform: rotate(0); } 40%, 70% { transform: rotate(28deg); } 100% { transform: rotate(0); } }
}
/* a fingertip: where a person touches (the key's wing, the lever's knob) */
.d-art .touch { stroke: var(--ink-2); stroke-dasharray: 2.5 3; }

/* first screen on phones, 23 Sep 2026: what it is, the promise and the button, before the lead.
   The render crops to 5:4 (the toy still fits whole), the badge row moves up under the headline by
   order only (markup and reading order unchanged), and "Try it" becomes a link under the badge. */
.hero-try { display: none; }
@media (max-width: 860px) {
  .hero-media { aspect-ratio: 5 / 4; }
  /* 93% centred the toy in the old 1:1 crop; at 5:4 no value up to 100% can (it sat ~9% right). The pole is at
     68.97% of the render's width, so (0.6897 x 1.4222 - 0.5) / 0.4222 = 113.9%. The sliver it uncovers on the right
     is #241A12, the same as --surface, so there is no seam. Measured, not eyeballed; re-measure if the render changes. */
  .hero-media img { object-position: 113.9% 50%; }
  .hero-copy { display: flex; flex-direction: column; }
  .hero-copy .eyebrow { order: 0; } .hero-copy h1 { order: 1; } .hero-meta { order: 2; } .hero-copy .lead { order: 3; }
  .hero-meta { row-gap: var(--s2); }
  .hero-try { display: inline-block; flex-basis: 100%; font-size: var(--small); line-height: var(--small-lh); }
  #demo { display: none; }
  #demo + #what { padding-top: var(--section) !important; }
}

/* Sleep timeline (site-tools/diagrams.py), 23 Sep 2026: the light over a Sleep timer, checked against 1.0.
   One dim step when Sleep starts, a flat hold, and a fall to dark at 15, 30 or 45 minutes. The falls arrive
   one after another with the column's reveal; reduced motion shows all three. Its labels are the only text
   in a drawing, so this file became v10: under a cached v9 they would inherit fill: none and vanish. */
.d-sleep { display: block; width: 100%; max-width: 360px; height: auto; margin: var(--s2) 0 var(--s1); overflow: visible; }
.d-art text { fill: var(--label); stroke: none; font-size: 12px; font-weight: 600; text-transform: uppercase; font-variant-numeric: tabular-nums; letter-spacing: 0.14em; }
@media (prefers-reduced-motion: no-preference) {
  .js .night [data-reveal] .fall { opacity: 0; }
  .js .night [data-reveal].in .fall { opacity: 1; transition: opacity 400ms var(--ease) calc(900ms + var(--k) * 500ms); }
}

/* ---------- the Workshop Book (site.v14.css, 24 Sep 2026) ----------
   Home section + /workshop-book/, generated by site-tools/book-grid.py from the shipped copy. The cards are
   the app's All pages screen redrawn in the site's own type (a real grid, not a capture): tap one and its
   page shows beside it. Every page is in the DOM, one shown; site.v2.js makes the cards tabs, and without
   it a #rider hash on /workshop-book/ shows that page (:target). The facts card is a raised surface like
   the app's (Surface.card), not an outline. */
/* home: the whole book, small tiles six across under the intro's left column, the open page sticky under its
   right column, so the two columns share the intro's split and both start on one line (no head, no rule) */
.book-grid { margin-top: var(--s8); align-items: start; row-gap: var(--s6); }
.book-grid .book-cards-col { grid-column: 1 / span 6; }
.book-grid .book-page-col { grid-column: 7 / -1; position: sticky; top: calc(56px + var(--s4)); align-self: start; }
.book-grid .book-page { border-top: 0; padding-top: 0; }
.book-cards { list-style: none; margin: var(--s3) 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s2); }
.book-cards > li { display: grid; min-width: 0; }   /* the link fills the cell, so a row of cards shares one height */
.book-cards-note { margin-top: var(--s3); color: var(--ink-3); }
.book-card { display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; min-width: 0; justify-items: center; padding: var(--s2) var(--s1); border-radius: var(--r-l); border: 1px solid var(--stroke);
  background: linear-gradient(180deg, #33261B, var(--surface-raised) 60%); color: var(--ink-2); text-decoration: none;
  transition: transform 200ms var(--ease), border-color 200ms var(--ease), color 200ms var(--ease); }
a.book-card:hover { color: var(--ink); border-color: var(--ink-3); }
@media (hover: hover) { a.book-card:hover { transform: translateY(-4px); } }
.book-card:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
.book-card[aria-selected="true"] { border-color: var(--brass); color: var(--ink); }
.book-card .art { position: relative; width: 100%; min-width: 0; aspect-ratio: 1; }   /* the render is positioned, not flowed: a grid track would size to the image and a wide rider (bangus) pushed past the card */
.book-card .art img { position: absolute; inset: var(--s1) 0 0; width: 100%; height: calc(100% - var(--s1)); object-fit: contain; object-position: 50% 100%; }
.book-card .num { white-space: nowrap; margin-top: var(--s2); font-variant-numeric: tabular-nums; }
.book-card .name { font-size: var(--small); line-height: var(--small-lh); font-weight: 600; text-align: center; }
.book-card small { color: var(--ink-3); }   /* "Still to come" is a status, like .pack-status: set as a label (in the label list above) */
.book-card.is-later { color: var(--ink-3); }
.book-card.is-later .num { color: var(--ink-3); }
.book-card.is-later .art img { opacity: 0.35; filter: grayscale(1) brightness(0.6); }
.book-pages, .book-page { scroll-margin-top: calc(56px + var(--s4)); }
.book-pages > .book-page[hidden]:target { display: block; }
.book-pages:has(> .book-page:target) > .book-page:not(:target) { display: none; }
.book-page { border-top: 1px solid var(--stroke); padding-top: var(--s3); }
.book-page .rider-art { display: block; height: 200px; width: auto; margin: 0 0 var(--s3); }
.book-page .num { display: block; line-height: var(--s3); font-variant-numeric: tabular-nums; }
.book-page .name { display: block; font-family: var(--serif); font-size: var(--h3); line-height: var(--h3-lh); font-weight: 400; margin-top: var(--s1); }
.book-page .subtitle { display: block; color: var(--ink-2); }
.book-page .story { margin-top: var(--s3); color: var(--ink); max-width: 29.8em; }
.book-page .ask { margin-top: var(--s2); color: var(--brass); font-weight: 600; max-width: 29.8em; }
.book-page .card { margin: var(--s3) 0 0; padding: var(--s3); background: var(--surface-raised); border-radius: var(--r-m); display: grid; row-gap: var(--s2); max-width: 33.7em; }
.book-page .card > div { display: grid; grid-template-columns: 112px minmax(0, 1fr); column-gap: var(--s2); }
.book-page .card dt { font-size: var(--small); line-height: var(--small-lh); color: var(--ink-3); }
.book-page .card dd { margin: 0; font-size: var(--small); line-height: var(--small-lh); color: var(--ink-2); }
.book-page .found { margin-top: var(--s2); font-size: var(--micro); line-height: var(--micro-lh); color: var(--ink-3); }
/* arriving from a home tile (/workshop-book/#bear) focuses the page; that is not a keyboard move, no ring */
.book-pages > .book-page:target { outline: none; }
.book-page .book-get { margin-top: var(--s3); font-size: var(--small); line-height: var(--small-lh); color: var(--ink-2); max-width: 29.8em; }
/* /workshop-book/: every rider, four across, the open page sticky beside the cards */
.book-browse { margin: var(--s8) 0; align-items: start; row-gap: var(--s6); }
.book-browse .book-cards-col { grid-column: 1 / span 7; }
.book-browse .book-aside { grid-column: 8 / -1; position: sticky; top: calc(56px + var(--s4)); align-self: start; }
.book-browse .book-page { border-top: 0; padding-top: 0; }
.book-cards-all { margin-top: 0; grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* home tiles: six across, after .book-cards so the source order lets it win */
.book-cards-home { margin-top: 0; grid-template-columns: repeat(6, minmax(0, 1fr)); }
.book-cards-home .book-card { padding: var(--s1) var(--s1) var(--s2); }
@media (max-width: 1080px) { .book-cards-all { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* small laptops and landscape tablets: half the width made six tiles 64px wide, so the home book stacks,
   tiles across the full width and the sample page under them (the tiles are links, not tabs, since 24 Sep) */
@media (min-width: 861px) and (max-width: 1320px) {
  .book-grid .book-cards-col, .book-grid .book-page-col { grid-column: 1 / -1; }
  .book-grid .book-page-col { position: static; }
  .book-cards-home { grid-template-columns: repeat(9, minmax(0, 1fr)); }
}
@media (min-width: 861px) and (max-width: 999px) { .book-cards-home { grid-template-columns: repeat(6, minmax(0, 1fr)); } }
@media (max-width: 860px) {
  .book-grid, .book-browse { row-gap: var(--s5); }
  .book-grid .book-cards-col, .book-grid .book-page-col, .book-browse .book-cards-col, .book-browse .book-aside { grid-column: 1 / -1; }
  .book-browse .book-aside, .book-grid .book-page-col { position: static; }
  /* phones and tablets: the 36 tiles as a two-row swipe strip, like the riders shelf, so the book does not
     add a screen to the home page; scrolls past the container edge on purpose (measure scripts: ignore) */
  .book-cards-home { grid-auto-flow: column; grid-template-rows: repeat(2, auto); grid-template-columns: none; grid-auto-columns: 104px; gap: var(--s1);
    overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
    margin-left: calc(-1 * var(--margin)); margin-right: calc(-1 * var(--margin)); padding: 0 var(--margin) var(--s2); scrollbar-width: none; }
  .book-cards-home::-webkit-scrollbar { display: none; }
  .book-cards-home > li { scroll-snap-align: start; }
  .book-page .rider-art { height: 144px; }
  .book-page .card > div { grid-template-columns: 96px minmax(0, 1fr); }
}
/* hero trust line: the chart position, dated so it stays true as the chart moves */
.hero-meta .trust { flex-basis: 100%; }
/* hero trim, 25 Sep 2026: badge and QR share one action row (the QR at the badge's height plus a little), and the
   chart line is the only proof under it. The facts line and the version line left the hero. */
.hero-meta .qr img { width: 56px; height: 56px; padding: 4px; }
.hero-meta .updated { flex-basis: 100%; margin-top: calc(-1 * var(--s2)); color: var(--ink-2); text-decoration: underline; text-decoration-color: var(--stroke); text-underline-offset: 3px; }
.hero-meta .updated:hover { color: var(--ink); }

/* rider close-ups on /packs (26 Sep 2026): the compact craft row with six frames, three by two on wider screens;
   phones keep the swipe strip from .craft-list-row */
@media (min-width: 861px) {
  .craft-list-row.is-six { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: var(--s5); }
}

/* ---------- alive pass (site.v22.css + site.v4.js, 26 Sep 2026) ----------
   Motion that is the toy's own, never decoration: the hero winds down once, the lamp follows the hand, things
   press like wood and brass under a finger. All of it sits behind prefers-reduced-motion: no-preference. */
/* hero film: the same crop as the still above it; fades in once playing and back out to the (sharper) still at the
   end. The first and last frames are the still's pose, so neither fade shows a seam. */
.hero-film { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 70% 50%;
  opacity: 0; transition: opacity 700ms var(--ease); pointer-events: none; }
.hero-film.in { opacity: 1; }
@media (max-width: 860px) { .hero-film { object-position: 113.9% 50%; } }
.hero-media.can-wind { cursor: pointer; -webkit-tap-highlight-color: transparent; }
/* the lamp: a warm pool of light behind the toy that follows the pointer slowly, like the lamp you place in the app.
   Fine pointers only; on phones the light stays where the render put it. */
.hero-lamp { position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity 1200ms var(--ease); mix-blend-mode: screen;
  background: radial-gradient(34% 52% at var(--lx, 66%) var(--ly, 50%), rgba(255, 190, 120, 0.085), rgba(255, 190, 120, 0) 72%); }
.hero.lamp-on .hero-lamp { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  /* rider tiles turn a few degrees toward the pointer, like a carved toy picked up and looked at */
  @media (hover: hover) and (pointer: fine) {
    .rider img { transform: perspective(700px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); transition: transform 500ms var(--ease); will-change: transform; }
  }
  /* touch: a press you can see under the finger, then a slow lift */
  @media (hover: none) {
    .rider, .pack-shot, .book-card, .badge { transition: transform 420ms var(--ease); }
    .rider:active, .pack:active .pack-shot, a.book-card:active, .badge:active { transform: scale(0.97); transition-duration: 90ms; }
  }
  /* phones: the close-ups in the swipe strips settle in once each comes into view (the scroll-linked settle is
     off there, it reads a vertical scroll the strip does not have) */
  @media (max-width: 860px) {
    .js .frame.push img.settle { transform: scale(1.06); transition: transform 1800ms var(--ease); }
    .js .frame.push.in img.settle { transform: none; }
  }
}

/* home Workshop Book (site.v23.css, 27 Sep 2026): the tiles open their page in place, so the open one is marked like a tab */
.book-card[aria-current="true"] { border-color: var(--brass); color: var(--ink); }

/* 29 Sep 2026, 2.0: the offer line sits right above the badge row, full ink so it reads before the chart line */
.hero-meta .offer { flex-basis: 100%; color: var(--ink); font-size: var(--small); line-height: var(--small-lh); margin-bottom: calc(-1 * var(--s1)); }
/* the wider copy column must not pull the H1 onto one line: it stays "Your child / winds it." on desktop (one line is 6.49em) */
@media (min-width: 861px) { .hero-copy h1 { max-width: 6.2em; } }
@media (max-width: 860px) { .hero-meta .offer { margin-bottom: 0; } }
/* the chart line wraps at the lead's width (22em of 23px = 506px = 33.5em of 15px) so the hero block keeps one right edge */
.hero-meta .trust { max-width: 33.5em; }
/* 29 Sep 2026: "Still to come" needs ~108px on one line; home tiles are 72 to 104px, so it wraps. Centered and balanced
   ("STILL / TO COME") under the centered name, not left-aligned "STILL TO / COME" */
.book-card small { text-align: center; text-wrap: balance; }
/* 29 Sep 2026: between 861 and ~1000px the nav wrapped ("Lullaby Music / Box", "HOW IT / PLAYS", "App / Store"; live since
   before the rename). Labels never wrap; the lockup's name drops first, as it already does under 861px */
.brand span, .nav-links a { white-space: nowrap; }
@media (max-width: 999px) { .brand span { display: none; } }   /* measured: with it, the nav overflows under 941px and is cramped to ~970px */
