/* ===== 00-base.css ================================================= */
/* ==========================================================================
   Syncopation — site styles
   Ported from the original design export. Tokens and measurements are the
   designer's; the JS-driven breakpoints have been rewritten as media queries.
   ========================================================================== */

/* --- Font ---------------------------------------------------------------- */

@font-face {
  font-family: 'Alex Brush';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/alex-brush-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Tokens -------------------------------------------------------------- */
/* Dark is the base; light overrides. site.js stamps data-theme before paint. */

:root {
  --bg: #0F1113;
  --bg2: #191A1C;
  --panel: #2B2B2B;
  --line: rgba(242, 237, 227, .14);
  --fg: #F2EDE3;
  --fg2: rgba(242, 237, 227, .66);
  /* designer had .42 here — 3.7:1 on --bg, below AA. .56 gives 5.7:1 */
  --fg3: rgba(242, 237, 227, .56);
  --accent: #F2EDE3;
  --on-accent: #0F1113;
  --link: #F2EDE3;
  --navbg: rgba(15, 17, 19, .72);

  --maxw: 1024px;
  --maxw-wide: 1100px;
  --gutter: 22px;
  --radius: 22px;
  --radius-card: 18px;
  --gap: 18px;
  --header-h: 48px;
}

html[data-theme="light"] {
  --bg: #FFFFFF;
  --bg2: #F5F5F7;
  --panel: #FFFFFF;
  --line: rgba(29, 29, 31, .12);
  --fg: #1D1D1F;
  --fg2: #6E6E73;
  --fg3: #6E6E73;
  --accent: #8B3A3A;
  --on-accent: #FFFFFF;
  --link: #8B3A3A;
  --navbg: rgba(255, 255, 255, .72);
}

/* --- Reset --------------------------------------------------------------- */

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

/* Any author `display` rule beats the UA stylesheet's [hidden] { display:none },
   so components like .card (display:flex) stay painted when hidden. Restore it. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--fg);
  -webkit-font-smoothing: antialiased;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
               "Helvetica Neue", Helvetica, sans-serif;
  text-wrap: pretty;
  letter-spacing: -.011em;
  overflow-x: hidden;
}

img { max-width: 100%; }

a {
  color: var(--fg);
  text-decoration: none;
  transition: opacity .2s ease;
}
a:hover { opacity: .72; }

::selection { background: var(--accent); color: var(--on-accent); }

/* Visible focus — absent from the export, required for keyboard use */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--accent);
  color: var(--on-accent);
  padding: 12px 20px;
  border-radius: 0 0 8px 0;
  font-size: 14px;
  font-weight: 500;
}
.skip-link:focus { left: 0; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* --- Layout -------------------------------------------------------------- */

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
.wrap--wide { max-width: var(--maxw-wide); }

.section { padding: clamp(56px, 7vw, 100px) var(--gutter); background: var(--bg); }
.section--alt { background: var(--bg2); border-top: 1px solid var(--line); }
.section--center { text-align: center; }

/* --- Typography ---------------------------------------------------------- */

.wordmark { font-family: 'Alex Brush', cursive; line-height: 1; }

.eyebrow {
  font-size: 21px;
  font-weight: 600;
  color: var(--accent);
  margin-bottom: 12px;
}

h1, .h1 {
  font-size: clamp(46px, 5.8vw, 76px);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -.025em;
  margin: 0 0 18px;
}

h2, .h2 {
  font-size: clamp(34px, 4vw, 50px);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -.022em;
  margin: 0 0 14px;
}

.lead {
  font-size: 21px;
  line-height: 1.4;
  color: var(--fg2);
  margin: 0 auto 22px;
  max-width: 560px;
}

.link-row {
  display: flex;
  gap: 26px;
  justify-content: center;
  flex-wrap: wrap;
  font-size: 17px;
}
.link-row a { color: var(--link); }

/* Long-form body copy. Sits between .lead (21px) and .care p (15px) — without
   it every narrative page reinvents the same paragraph style. */
.prose > p {
  font-size: 19px;
  line-height: 1.55;
  color: var(--fg2);
  margin: 0 0 1.1em;
}
.prose > p:last-child { margin-bottom: 0; }

/* Embedded players (Apple Music, Spotify, YouTube). Any page embedding one
   wants this — the panel background sits correctly in both themes. */
.embed {
  max-width: 660px;
  margin: 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--panel);
}
.embed iframe {
  display: block;
  width: 100%;
  max-width: 100%;
  border: 0;
  background: transparent;
}

/* --- Header -------------------------------------------------------------- */

.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 80;
  background: var(--navbg);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--line);
}

.header__bar {
  max-width: var(--maxw);
  margin: 0 auto;
  height: var(--header-h);
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.header__brand { font-size: 26px; flex: none; }

.nav {
  display: flex;
  align-items: center;
  gap: clamp(12px, 2.2vw, 30px);
  font-size: 12px;
}
.nav a { color: var(--fg2); }
.nav a[aria-current="page"] { color: var(--fg); font-weight: 500; }

.header__actions { display: flex; align-items: center; gap: 14px; flex: none; }

.icon-btn {
  width: 44px;
  height: 44px;
  margin: -9px 0;
  border: 0;
  background: transparent;
  color: var(--fg2);
  cursor: pointer;
  font-size: 14px;
  display: grid;
  place-items: center;
  font-family: inherit;
  border-radius: 50%;
}
.icon-btn:hover { color: var(--fg); }

.menu-btn { display: none; color: var(--fg); font-size: 15px; }

.menu {
  display: none;
  flex-direction: column;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  padding: 8px var(--gutter) 22px;
}
.menu[data-open="true"] { display: flex; }
.menu a {
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
  font-size: 19px;
  font-weight: 500;
}
.menu a:last-child { border-bottom: 0; }

.header-spacer { height: var(--header-h); }

/* --- Announcement bar ---------------------------------------------------- */

.announce {
  background: var(--bg2);
  border-bottom: 1px solid var(--line);
  padding: 11px var(--gutter);
  text-align: center;
  font-size: 13px;
  color: var(--fg2);
}
.announce strong { color: var(--fg); font-weight: 500; }
.announce a { color: var(--link); }

/* --- Media --------------------------------------------------------------- */

.hero-media {
  max-width: var(--maxw-wide);
  margin: clamp(36px, 5vw, 60px) auto clamp(40px, 5vw, 64px);
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--bg2);
}
.hero-media img,
.hero-media picture {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ==========================================================================
   Text overlays on artwork
   --------------------------------------------------------------------------
   The supplied artwork has the Syncopation wordmark and the chapter names
   burned into the pixels. Baked type cannot be cropped for mobile without
   slicing letters, cannot be selected, translated or read by a screen reader,
   and cannot re-flow. These overlays replace it with live text.

   SVG rather than HTML text on purpose: a viewBox makes the type scale in
   exact proportion to the image at every width, so one declaration covers
   every breakpoint with no font-size media queries and no risk of the words
   wrapping or overflowing their plate.

   Hidden while <html data-art="legacy"> so the current artwork does not read
   twice. Flip "cleanArt": true in src/config.json when the clean files land.
   ========================================================================== */

.plate { position: relative; overflow: hidden; }

.plate__overlay {
  position: absolute;
  display: block;
  overflow: visible;
  pointer-events: none;
  /* the artwork can be light or dark; a soft shadow keeps type legible on both */
  filter: drop-shadow(0 1px 10px rgba(15, 17, 19, .34));
}
.plate__overlay text { fill: #F2EDE3; }

html[data-art="legacy"] .plate__overlay { display: none; }

/* The Alex Brush wordmark, as used across the banners and heroes. */
.plate__mark {
  left: 6%;
  right: 6%;
  width: 88%;
  bottom: 7%;
}
.plate__mark text {
  font-family: 'Alex Brush', cursive;
  font-size: 88px;          /* viewBox units — scales with the plate */
}

/* Chapter names on the square stills. */
.plate__label {
  left: 6%;
  right: 6%;
  width: 88%;
  bottom: 8%;
}
.plate__label text {
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", sans-serif;
  font-size: 118px;         /* viewBox units — matches the burned-in original */
  font-weight: 300;
  letter-spacing: -1px;
}

/* A caption line rather than a mark — e.g. the sentence burned across the
   Our Story closing banner. Set the text uppercase in the markup; SVG does not
   honour text-transform reliably across engines. */
.plate__line {
  left: 8%;
  right: 8%;
  width: 84%;
  bottom: 9%;
}
.plate__line text {
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", sans-serif;
  font-size: 46px;          /* viewBox units */
  font-weight: 400;
  letter-spacing: 2.5px;
}

/* Scrim so live type stays readable over pale artwork — the Velouté cherry
   and the Hold Space bonsai are both near-white where the label sits. */
.plate__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top, rgba(15, 17, 19, .46), rgba(15, 17, 19, 0) 58%);
}
html[data-art="legacy"] .plate__scrim { display: none; }

/* --- Buttons ------------------------------------------------------------- */

.btn {
  border: 0;
  border-radius: 980px;
  background: var(--accent);
  color: var(--on-accent);
  padding: 14px 28px;
  cursor: pointer;
  font-size: 15px;
  font-weight: 500;
  font-family: inherit;
}
.btn:hover { opacity: .85; }
.btn--block { width: 100%; padding: 12px 0; font-size: 14px; }
.btn--quiet {
  background: var(--bg2);
  color: var(--fg2);
  border: 1px solid var(--line);
}

/* --- Product cards ------------------------------------------------------- */

.grid { display: grid; gap: var(--gap); }
.grid--shop { grid-template-columns: repeat(3, 1fr); text-align: left; }
.grid--looks { grid-template-columns: repeat(4, 1fr); }
.grid--care { grid-template-columns: repeat(4, 1fr); gap: clamp(22px, 3vw, 40px); }
/* Three-column sibling of .grid--care. Three page conversions each grew their
   own copy of this; one definition serves all. */
.grid--three { grid-template-columns: repeat(3, 1fr); gap: clamp(22px, 3vw, 40px); }

.card {
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  overflow: hidden;
  transition: transform .45s cubic-bezier(.22, .61, .36, 1), box-shadow .45s ease;
}
.card:hover { transform: translateY(-6px); box-shadow: 0 24px 48px rgba(15, 17, 19, .16); }

.card__media {
  position: relative;
  /* 3:4 portrait, matching the -p crops cut from the full-resolution originals.
     Shows the whole garment instead of the design tool's 760x760 torso square. */
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: var(--bg2);
}
.card__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 30%);
  transition: transform 1s cubic-bezier(.22, .61, .36, 1);
}
.card:hover .card__media img { transform: scale(1.06); }

.card__veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(15, 17, 19, .7), rgba(15, 17, 19, 0) 60%);
  opacity: 0;
  transition: opacity .45s ease;
  pointer-events: none;
}
.card:hover .card__veil { opacity: 1; }

.tag {
  position: absolute;
  border-radius: 980px;
  padding: 5px 11px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .04em;
}
.tag--chapter { left: 12px; top: 12px; background: rgba(255, 255, 255, .92); color: #1D1D1F; }
.tag--sold { right: 12px; top: 12px; background: rgba(15, 17, 19, .78); color: #F2EDE3; }

.card__body {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 18px 18px 20px;
  flex: 1;
}
.card__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: baseline;
}
.card__name { font-size: 16px; font-weight: 600; letter-spacing: -.013em; }
.card__price { font-size: 15px; color: var(--fg2); white-space: nowrap; }
.card__meta { font-size: 13px; color: var(--fg3); }
.card__foot { margin-top: auto; padding-top: 14px; display: flex; }

/* --- Lookbook ------------------------------------------------------------ */

.look {
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border-radius: 16px;
  background: var(--bg2);
  transition: transform .45s cubic-bezier(.22, .61, .36, 1), box-shadow .45s ease;
}
.look:hover { transform: translateY(-6px); box-shadow: 0 24px 48px rgba(15, 17, 19, .16); }
.look img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 40%);
  transition: transform 1s cubic-bezier(.22, .61, .36, 1);
}
.look:hover img { transform: scale(1.06); }
.look__label {
  position: absolute;
  left: 14px;
  bottom: 14px;
  font-size: 12px;
  font-weight: 500;
  color: #F2EDE3;
}

/* --- Filters ------------------------------------------------------------- */

.filters {
  display: inline-flex;
  background: var(--bg);
  border-radius: 980px;
  padding: 3px;
  margin-bottom: clamp(28px, 3.4vw, 44px);
  justify-content: center;
  /* never wrap — a pill container with a second row reads as broken.
     Scrolls instead if categories are ever added. */
  flex-wrap: nowrap;
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}
.filters::-webkit-scrollbar { display: none; }
.filters button {
  border: 0;
  border-radius: 980px;
  background: transparent;
  color: var(--fg2);
  /* min-height keeps the tap target usable; the design's 9px padding alone
     produced a ~33px control, under the accessible floor */
  min-height: 38px;
  padding: 9px 22px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  white-space: nowrap;
}
.filters button[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }

/* --- Forms --------------------------------------------------------------- */

.form-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}
.input {
  flex: 1;
  min-width: 230px;
  background: var(--bg2);
  border: 1px solid var(--line);
  border-radius: 980px;
  outline: none;
  padding: 14px 20px;
  color: var(--fg);
  font-size: 15px;
  font-family: inherit;
}
.input::placeholder { color: var(--fg3); }
.input:focus-visible { border-color: var(--accent); }

/* Required-field marker (WCAG 3.3.2 — the `required` attribute alone tells
   assistive tech but shows sighted users nothing). aria-hidden on the glyph
   because `required` already conveys the state to a screen reader; announcing
   "asterisk" as well is just noise. */
.req {
  color: var(--accent);
  margin-left: .18em;
  font-weight: 600;
}
.form-legend {
  font-size: 13px;
  color: var(--fg3);
  margin: 0 0 18px;
}
.form-legend .req { margin-left: 0; margin-right: .3em; }

.form-msg {
  font-size: 13px;
  color: var(--accent);
  margin-top: 14px;
  min-height: 16px;
}
.form-note { font-size: 12px; color: var(--fg3); margin-top: 10px; }

/* --- Dialog -------------------------------------------------------------- */

.dialog {
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--panel);
  color: var(--fg);
  padding: 0;
  max-width: 420px;
  width: calc(100% - 44px);
}
.dialog::backdrop { background: rgba(15, 17, 19, .6); backdrop-filter: blur(4px); }
.dialog__inner { padding: 26px 24px 24px; }
.dialog__title { font-size: 21px; font-weight: 600; letter-spacing: -.02em; margin: 0 0 6px; }
.dialog__sub { font-size: 14px; color: var(--fg2); margin: 0 0 18px; }
/* Stack the dialog form — at 420px the input and button can't share a row
   without the button orphaning at half width. */
.dialog .form-row { flex-direction: column; align-items: stretch; }
.dialog .form-row .btn { width: 100%; }

.dialog__close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 36px;
  height: 36px;
  border: 0;
  background: transparent;
  color: var(--fg2);
  font-size: 16px;
  cursor: pointer;
  border-radius: 50%;
}

/* --- Care grid ----------------------------------------------------------- */

/* margin-top reset so this works as a real <h3>, not only as the <div> the
   merch page uses it as. */
.care__title { font-size: 19px; font-weight: 600; margin-top: 0; margin-bottom: 8px; }
.care p { font-size: 15px; line-height: 1.55; color: var(--fg2); margin: 0; }

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

.footer {
  background: var(--bg2);
  border-top: 1px solid var(--line);
  padding: 36px var(--gutter) 44px;
  font-size: 12px;
  color: var(--fg2);
}
.footer__cols {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 26px 40px;
  padding-bottom: 26px;
  border-bottom: 1px solid var(--line);
}
.footer__head { font-size: 12px; font-weight: 600; color: var(--fg); margin-bottom: 12px; }
.footer__list { display: flex; flex-direction: column; gap: 9px; }
.footer__list a { color: var(--fg2); }
.footer__strap,
.footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: space-between;
  color: var(--fg3);
}
.footer__strap { padding-top: 20px; }
.footer__legal { padding-top: 14px; align-items: center; gap: 14px; }
.footer__mark { display: inline-flex; align-items: center; gap: 8px; flex: none; }
.footer__badge {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--fg3);
  font-size: 16px;
  color: var(--fg2);
  padding-left: 1px;
}

/* ==========================================================================
   Breakpoints — these replace the export's window.innerWidth listener.
   900px = tablet/narrow, 680px = phone, matching the designer's thresholds.
   ========================================================================== */

@media (max-width: 899px) {
  .nav { display: none; }
  .menu-btn { display: grid; }
  .grid--care,
  .grid--three { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 679px) {
  :root {
    --radius: 18px;
    --gap: 12px;
  }
  .eyebrow { font-size: 17px; }
  h1, .h1 { font-size: 40px; }
  h2, .h2 { font-size: 30px; }
  .lead { font-size: 17px; }
  .link-row { font-size: 16px; }

  .hero-media { aspect-ratio: 4 / 5; }
  .grid--looks { grid-template-columns: repeat(2, 1fr); }
  .grid--care,
  .grid--three { grid-template-columns: 1fr; }
  .footer__cols { grid-template-columns: repeat(2, 1fr); }

  /* tighter pills so all four categories fit one row on a 390px screen */
  .filters { justify-content: flex-start; }
  .filters button { padding: 9px 16px; }
}

/* Single column for products on phones. Two columns leaves each card ~167px
   wide, at which the chest print stops being legible; one column lets the
   tighter mobile crops read as intended. */
@media (max-width: 559px) {
  .grid--shop { grid-template-columns: 1fr; }
  .card__media { aspect-ratio: 4 / 5; }
}

@media (min-width: 560px) and (max-width: 899px) {
  .grid--shop { grid-template-columns: repeat(2, 1fr); }
}

/* ===== home.css ==================================================== */
/* ==========================================================================
   Syncopation — home page.
   The export computed these from window.innerWidth inside renderVals();
   here they are media queries at the shared 900px / 680px breakpoints.
   Chapter accents arrive as --accent-chapter on each tile, so the palette
   stays in the markup where the data is and never gets duplicated here.
   ========================================================================== */

/* Tiles sit tighter than the shared --gap so the wide chapter cards and the
   grids under them read as one continuous block. */
.chapters,
.covers,
.stills { gap: 16px; }

@media (max-width: 679px) {
  .chapters,
  .covers,
  .stills { gap: 10px; }
}

/* --- Hero ---------------------------------------------------------------- */
/* The hero standfirst runs larger than the shared .lead — it is the only
   paragraph on the page carrying the whole positioning statement. */

.lead--hero {
  font-size: clamp(21px, 2vw, 26px);
  line-height: 1.35;
  max-width: 600px;
}

@media (max-width: 679px) {
  .lead--hero { font-size: 19px; }
}

/* --- Release player ------------------------------------------------------
   Apple Music and Spotify share one frame; the switcher above it is the stock
   .filters pill group, and .embed now lives in 00-base.css — nothing to
   declare here. */

/* --- Chapters ------------------------------------------------------------ */

.chapters {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: left;
}

.ch-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--panel);
  isolation: isolate;
  transition: transform .5s cubic-bezier(.22, .61, .36, 1),
              box-shadow .5s cubic-bezier(.22, .61, .36, 1);
}
.ch-card:hover { transform: translateY(-8px); box-shadow: 0 26px 54px rgba(15, 17, 19, .28); }

/* Three of the seven chapters are features: they run the full grid width. */
.ch-card--feature { grid-column: span 2; aspect-ratio: 21 / 9; }

.ch-card__media { position: absolute; inset: 0; display: block; z-index: 0; }
.ch-card__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
  transition: transform 1.1s cubic-bezier(.22, .61, .36, 1), filter .6s ease;
}
.ch-card:hover .ch-card__media img {
  transform: scale(1.07);
  filter: saturate(1.12) brightness(1.06);
}

/* Two stacked gradients: ::before always keeps the copy legible over whatever
   the artwork does, ::after deepens it on hover. Both decorative, so neither
   needs to exist in the markup. */
.ch-card::before,
.ch-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.ch-card::before {
  background: linear-gradient(to top,
              rgba(15, 17, 19, .88) 0%, rgba(15, 17, 19, .42) 42%, rgba(15, 17, 19, .06) 78%);
}
.ch-card::after {
  background: linear-gradient(to top,
              rgba(15, 17, 19, .94) 0%, rgba(15, 17, 19, .55) 52%, rgba(15, 17, 19, .12) 88%);
  opacity: 0;
  transition: opacity .6s ease;
}
.ch-card:hover::after { opacity: 1; }

.ch-card__text {
  position: relative;
  z-index: 2;
  padding: clamp(20px, 2.4vw, 30px);
}

/* Tile copy sits on the dark gradient in both themes, so it is fixed cream
   rather than a token — --fg would invert to near-black in light mode. */
.ch-card__day {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 7px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--accent-chapter, #F2EDE3);
}
.ch-card__day::before {
  content: '';
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-chapter, #F2EDE3);
  transition: transform .5s cubic-bezier(.22, .61, .36, 1), box-shadow .5s ease;
}
.ch-card:hover .ch-card__day::before {
  transform: scale(1.7);
  box-shadow: 0 0 0 5px rgba(242, 237, 227, .18);
}

.ch-card__name {
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -.018em;
  line-height: 1.1;
  color: #F2EDE3;
  margin: 0 0 6px;
}
.ch-card--feature .ch-card__name { font-size: clamp(28px, 3vw, 40px); }

.ch-card__sub { font-size: 14px; color: rgba(242, 237, 227, .74); margin: 0 0 10px; }
.ch-card__copy {
  font-size: 14px;
  line-height: 1.45;
  color: rgba(242, 237, 227, .78);
  margin: 0;
  max-width: 420px;
}

@media (max-width: 899px) {
  .chapters { grid-template-columns: 1fr; }
  /* Nothing spans two columns when there is only one, and the feature tiles
     drop back to the standard crop and title size — same as the export. */
  .ch-card--feature { grid-column: auto; aspect-ratio: 4 / 3; }
  .ch-card--feature .ch-card__name { font-size: 24px; }
}

@media (max-width: 679px) {
  .ch-card,
  .ch-card--feature { aspect-ratio: 4 / 5; }
}

/* --- Video tiles ---------------------------------------------------------
   The Visuals grid reuses .ch-card rather than growing a third card class, so
   it inherits the two stacked gradients that keep copy legible over any
   artwork, the hover lift, the dot on the eyebrow, and cream type that does
   not invert in light mode. Only the crop and the type scale differ.

   Titles sit on the artwork, not under it. This is deliberately NOT the
   .plate__* SVG overlay: that has a fixed viewBox for replacing burned-in
   artwork text and would deform a sentence-length video title.

   9:16 portrait is the owner's decision, taken over square and 16:9 — it is
   the shape the channel's Shorts are shot in, and the only non-square grid on
   the site. Filling it from a 16:9 still keeps about a third of the width, so
   the burned-in wordmark clips on landscape uploads; accepted knowingly, and
   fetch-youtube.js already prefers YouTube's original-aspect thumbnail so
   Shorts arrive as true 9:16 rather than a sliver cropped out of a
   pillarboxed frame. */
.ch-card--video { aspect-ratio: 9 / 16; }

/* Beats the 679px rule above, which drops every .ch-card to 4/5 — a video tile
   keeps its portrait crop at every width. Must stay after it: same
   specificity, so source order decides. */
@media (max-width: 679px) {
  .ch-card--video { aspect-ratio: 9 / 16; }
}

/* Chapter names are one or two words at 24px. Video titles are sentences, so
   they come down a step and stop at three lines. */
.ch-card--video .ch-card__name {
  font-size: 17px;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The title is the link, and its ::after stretches the hit area over the whole
   tile — so the card behaves like one target while the accessible name stays
   the title alone rather than the tile's entire text. */
.ch-card__link {
  color: inherit;
  text-decoration: none;
}
.ch-card__link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
}
.ch-card__link:hover { opacity: 1; }

/* Keyboard focus lands on the link, whose visible box is only the text, so put
   the ring on the tile instead. */
.ch-card:has(.ch-card__link:focus-visible) {
  outline: 2px solid var(--gold, #F2EDE3);
  outline-offset: 3px;
}
.ch-card__link:focus-visible { outline: none; }

/* The tighter portrait crop leaves less room than a 4:3 chapter tile. */
.ch-card--video .ch-card__text { padding: clamp(14px, 1.4vw, 18px); }
.ch-card--video .ch-card__day { font-size: 10px; margin-bottom: 5px; }

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

.covers {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  list-style: none;
  margin: clamp(34px, 4vw, 54px) 0 0;
  padding: 0;
  text-align: left;
}

.cover {
  display: block;
  transition: transform .45s cubic-bezier(.22, .61, .36, 1);
}
/* Cancels the global a:hover fade — the card lifts instead of dimming. */
.cover:hover,
.cover:focus-visible { opacity: 1; transform: translateY(-6px); }

.cover__media {
  display: block;
  position: relative;
  overflow: hidden;
  border-radius: 14px;
  background: var(--panel);
}
.cover__media img {
  display: block;
  width: 100%;
  /* height:auto is load-bearing, not tidiness. The build writes width/height
     attributes onto every <img>, and those are presentational hints — with a
     height attribute in play the box has both dimensions already, so
     aspect-ratio never gets to compute one and the square becomes a 252x800
     sliver. Every other component escapes this only because it pins an
     explicit height of its own. */
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  transition: transform 1s cubic-bezier(.22, .61, .36, 1);
}
.cover:hover .cover__media img,
.cover:focus-visible .cover__media img { transform: scale(1.06); }

.cover__veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(15, 17, 19, .72), rgba(15, 17, 19, 0) 62%);
  opacity: 0;
  transition: opacity .45s ease;
}
.cover:hover .cover__veil,
.cover:focus-visible .cover__veil { opacity: 1; }

.cover__play {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  color: #1D1D1F;
  display: grid;
  place-items: center;
  font-size: 17px;
  padding-left: 3px;
  opacity: 0;
  transform: translate(-50%, -50%) scale(.82);
  transition: opacity .4s ease, transform .5s cubic-bezier(.22, .61, .36, 1);
}
.cover:hover .cover__play,
.cover:focus-visible .cover__play { opacity: 1; transform: translate(-50%, -50%) scale(1); }

.cover__name { display: block; font-size: 15px; font-weight: 500; margin-top: 12px; }
.cover__meta { display: block; font-size: 13px; color: var(--fg3); margin-top: 3px; }

@media (max-width: 899px) { .covers { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 679px) { .covers { grid-template-columns: repeat(2, 1fr); } }

/* --- Visuals ------------------------------------------------------------- */

.stills {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  list-style: none;
  margin: 0;
  padding: 0;
}

.still {
  position: relative;
  /* The design specified 4/5, but these sources are square with the chapter
     name burned into the pixels edge to edge — a 4/5 crop cuts the first and
     last letters off ("Hold Space" -> "old Spac"). 1/1 matches the source and
     keeps the names readable. Revert to 4/5 only with re-cut artwork. */
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: 16px;
  background: var(--bg2);
}
.still img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
  transition: transform .7s cubic-bezier(.22, .61, .36, 1);
}
.still:hover img { transform: scale(1.045); }

@media (max-width: 899px) { .stills { grid-template-columns: repeat(2, 1fr); } }

/* --- About --------------------------------------------------------------- */

.about-media {
  border-radius: 20px;
  overflow: hidden;
  aspect-ratio: 21 / 9;
  background: var(--bg2);
}
.about-media picture { display: block; width: 100%; height: 100%; }
.about-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 35%);
}

@media (max-width: 679px) { .about-media { aspect-ratio: 16 / 9; } }

/* Four short value statements. Same component as .grid--care, but they stay
   four across at tablet and pair up on phones rather than stacking — three
   words each does not earn a full row. */
.grid--values {
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(24px, 3vw, 44px);
  max-width: 900px;
  margin: clamp(34px, 4vw, 54px) auto 0;
  text-align: left;
}

@media (max-width: 679px) { .grid--values { grid-template-columns: repeat(2, 1fr); } }

/* ===== story.css =================================================== */
/* ==========================================================================
   Our story — page styles

   Everything here is the designer's own measurement, lifted out of
   renderVals() in "Syncopation Our Story.dc.html". The phone (<680) and
   narrow (<900) branches in that method are media queries here; the page
   ships no JavaScript.
   ========================================================================== */

:root {
  /* The one colour this page adds. "With you." is set in a rose that appears
     nowhere else on the site, so it stays page-scoped rather than becoming a
     site token — but it still has to answer to the theme. */
  --story-pink: #E8A9B6;
  /* Cream plate behind the wordmark hero so the frame matches the artwork
     while the image is still decoding. One value, both themes. */
  --story-hero-bg: #E9E8DF;
}
html[data-theme="light"] { --story-pink: #B4536B; }

/* --- Media --------------------------------------------------------------- */

.story-hero { background: var(--story-hero-bg); }

/* The wordmark and cloak plates are 21:9 artwork. The base sheet already
   drops .hero-media to 4/5 at 679px, which is the ratio the mobile crops are
   cut to, so this only has to speak above the phone breakpoint. */
@media (min-width: 680px) {
  .story-media--wide { aspect-ratio: 21 / 9; }
}

/* The export put a slow hover zoom on its hero figure (.sc-fig / .sc-img).
   Same gesture the cards use, a touch gentler. */
.story-fig img { transition: transform 1.2s cubic-bezier(.22, .61, .36, 1); }
.story-fig:hover img { transform: scale(1.05); }

/* --- "Where it begins" statement ----------------------------------------- */

.story-statement { display: flex; flex-direction: column; gap: 14px; }

.story-statement__line {
  font-size: clamp(30px, 3.6vw, 44px);
  font-weight: 600;
  line-height: 1.14;
  letter-spacing: -.022em;
  margin: 0;
}
.story-statement__line--quiet { color: var(--fg3); }

.story-statement__script {
  font-size: clamp(60px, 7vw, 96px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -.011em;
  color: var(--story-pink);
  margin: 6px 0 0;
}

/* --- Long-form prose ------------------------------------------------------ */
/* Direct children only: these sections also hold .care grids, whose own
   15px type must not be swallowed by the body size. */

.story-prose > p {
  font-size: 19px;
  line-height: 1.55;
  color: var(--fg);
  margin: 0 0 18px;
}
.story-prose > p:last-child { margin-bottom: 0; }
.story-prose > p.story-soft { color: var(--fg2); }

.story-quote {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 26px 0;
  padding: 0 0 0 20px;
  border-left: 2px solid var(--accent);
}
.story-quote p {
  font-size: 19px;
  line-height: 1.4;
  color: var(--fg2);
  margin: 0;
}

/* --- "We are because you are" split --------------------------------------- */

.story-split {
  display: grid;
  grid-template-columns: minmax(280px, 1fr) minmax(260px, .9fr);
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}

.story-moments {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.story-moments li {
  display: flex;
  align-items: center;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 20px 18px;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: -.012em;
  transition: opacity .55s ease, border-color .45s ease;
}
.story-moments li:hover { opacity: .42; }
/* Five moments, two columns — the last one runs full width rather than
   leaving a hole in the grid. */
.story-moments li:last-child { grid-column: span 2; }

/* --- Script refrains ------------------------------------------------------ */

.story-refrain {
  font-size: clamp(42px, 4.6vw, 58px);
  line-height: 1.1;
  color: var(--accent);
  text-align: center;
  margin: clamp(34px, 4vw, 56px) 0 0;
}

.story-welcome {
  font-size: clamp(56px, 6.4vw, 88px);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -.011em;
  color: var(--accent);
  margin: 0 0 14px;
}

/* .care__title is a <div> in the base sheet; as the <h3> this page needs it
   also has to lose the UA top margin. */
h3.care__title { margin-top: 0; }

/* ==========================================================================
   Breakpoints — 900px and 680px, the designer's own thresholds.
   ========================================================================== */

@media (max-width: 899px) {
  .story-split { grid-template-columns: 1fr; }
}

@media (max-width: 679px) {
  .story-statement__line { font-size: 26px; }
  .story-statement__script { font-size: 52px; }

  .story-prose > p,
  .story-quote p { font-size: 17px; }

  .story-moments { grid-template-columns: 1fr; gap: 10px; }
  .story-moments li:last-child { grid-column: auto; }

  .story-refrain { font-size: 38px; }
  .story-welcome { font-size: 48px; }
}
