/* ============================================================
   YEAR HUB SYSTEM  (/2022/ .. /2026/)   "Option C, Asymmetric Feature"
   ============================================================
   Andrew's approved redesign (2026-07-20), replacing the 2026-07-19
   chapter/strip/rail system. Page shape, top to bottom:

     breadcrumb bar   (page-local, unchanged)
     .yh-hero         cream masthead, giant ghosted year numeral
     .yh-feat         asymmetric feature: series art beside a black panel
     .yh-rows         one row per remaining series
     closing band     (page-local, unchanged)

   The feature band and the rows are GENERATED by
   scripts/check-series-coverage.py from scripts/series-cards.json,
   between the <!-- yr-cards:start --> / <!-- yr-cards:end --> sentinels
   in each YYYY.html. Edit the config, never the markup. This file is the
   ONE place the system is styled (cache-busted as {{year-hub-v}}); the
   pages keep only their series-ed base styles.

   FRAME MAPPING. The design's 56px frame padding maps onto this site's
   existing page wrap (.se-wrap: max-width 1080px, clamp(20px,4vw,40px)
   of padding). Nothing in here re-pads or re-centers horizontally, so
   the hero, the feature, the rows and the closing band all share ONE
   left edge. See THE WIDTH RULE in css/tokens.css.

   MOTION CONTRACT: every entrance animation is double-gated behind
   html.js (set by the year-hub-js partial) AND prefers-reduced-motion:
   no-preference. No JS or reduced motion means everything is simply
   visible, never hidden behind an animation that might not run.
   Transforms and opacity only.
   ============================================================ */

/* Legacy wrapper from the previous design, still present in the hub
   source pages until they are rewritten. Neutralized so it cannot fight
   the generated children. */
.yh-chapters { display: block; }

/* ============================================================
   HERO
   ============================================================ */
.yh-hero {
  position: relative;
  overflow: hidden;                 /* the numeral bleeds; never scrolls */
  background: var(--nh-cream);
  padding: clamp(40px, 5.5vw, 64px) 0;
  min-height: clamp(300px, 34vw, 440px);
  display: flex; flex-direction: column; justify-content: center;
}
/* The wrap is the positioning context, so the numeral's right edge lands
   on the page's content edge (the design's 56px frame inset) rather than
   the viewport edge.

   `width: 100%` is load-bearing, not belt-and-braces. .yh-hero is a COLUMN
   flex container, so .se-wrap's `margin: 0 auto` lands on the cross axis,
   and a cross-axis auto margin cancels the default `align-items: stretch`.
   Without this the wrap shrink-wraps to its widest child (the h1) and
   centers on that, putting the hero's left edge ~86px inside every other
   band and moving it year to year as the headline's length changes.
   Measured 2026-07-20: hero text at 299px against 213px everywhere else.
   See THE WIDTH RULE in css/tokens.css. */
.yh-hero__inner { position: relative; width: 100%; }

.yh-hero__num {
  position: absolute; right: 0; top: 50%;
  transform: translateY(calc(-50% + (var(--yh-drift, 0) * -0.06px)));
  display: flex; align-items: center;
  font-family: var(--font-display); font-weight: 800;
  letter-spacing: -0.05em; line-height: 0.72;
  color: rgba(184, 50, 39, 0.10);   /* --nh-red at 10%; rgba needs the literal */
  font-size: clamp(150px, 33vw, 560px);
  pointer-events: none; user-select: none;
  z-index: 0; will-change: transform;
}
.yh-hero__num span { display: block; }

.yh-hero__eyebrow,
.yh-hero__h1,
.yh-hero__lede,
.yh-hero__meta { position: relative; z-index: 1; }

/* SPECIFICITY NOTE (applies to every prefixed selector in this file).
   Each hub page carries a page-local `<style>` AFTER this stylesheet's
   <link>, and it resets `.series-ed h1,h2,h3 {margin:0}` and
   `.series-ed p {margin:0}` — both (0,1,1). A bare `.yh-hero__h1` is
   (0,1,0) and a bare `.yh-feat__txt p` only ties, so the later page reset
   won and every margin declared here computed to 0px. Any rule below that
   sets a NON-ZERO margin on an h1/h2/h3/p, or that has to beat the
   `.yh-feat__txt p` descendant rule, is prefixed with `.series-ed` (and
   uses a compound `p.yh-...` where it must outrank a sibling descendant
   selector) so it lands at (0,2,1) or higher. Do not strip these prefixes:
   the declarations were always correct, they simply never applied. */
.series-ed .yh-hero__h1 {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(44px, 6.4vw, 96px);
  letter-spacing: -0.02em; line-height: 0.9;
  color: var(--nh-ink);
  margin: 8px 0 16px;
  /* Two lines on purpose. The approved design sets "The 2026" / "collection."
     with a hard <br>, so the ghosted numeral sits beside the headline instead
     of underneath it. A width cap does the same job but keeps wrapping under
     the browser's control, so the headline still behaves at every viewport.
     A local cap on a hero H1 is explicitly outside the --measure system: see
     the "Small utility caps" note in THE WIDTH RULE. px, not ch, so the edge
     does not move with the font. */
  max-width: 620px;
}
.series-ed .yh-hero__h1 em { font-style: normal; color: var(--nh-red); }
.yh-hero__lede {
  font-family: var(--font-scripture); font-style: italic;
  font-size: clamp(18px, 1.6vw, 24px); line-height: 1.5;
  color: var(--nh-ink-2); max-width: var(--measure);
}
.series-ed .yh-hero__meta {
  font-family: var(--font-display); font-size: 12px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--nh-mute);
  margin-top: 14px;
}

/* ============================================================
   BUTTONS  (year-hub scale: smaller than the page's .se-pill)
   ============================================================ */
.yh-btn {
  font-family: var(--font-display); font-weight: 700; font-size: 13px;
  letter-spacing: 0.04em; text-transform: uppercase;
  border-radius: var(--r-pill); padding: 11px 20px;
  border: 1px solid transparent;
  display: inline-flex; align-items: center; gap: 8px;
  white-space: nowrap; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease,
              border-color 0.15s ease, transform 0.15s ease;
}
.yh-btn:hover { transform: translateY(-1px); }
.yh-btn:focus-visible { outline: 3px solid var(--nh-red); outline-offset: 3px; }
.yh-btn svg { width: 14px; height: 14px; flex-shrink: 0; }

.yh-btn--red { background: var(--nh-red); color: var(--nh-paper); }
.yh-btn--red:hover { background: var(--nh-red-deep); }

.yh-btn--ghost { background: transparent; color: var(--nh-ink); border-color: var(--line-strong); }
.yh-btn--ghost:hover { background: var(--nh-stone); border-color: var(--nh-ink); }

/* ghost on the black feature panel */
.yh-btn--on-deep { background: transparent; color: var(--on-deep); border-color: rgba(246, 242, 236, 0.34); }
.yh-btn--on-deep:hover { background: rgba(246, 242, 236, 0.10); border-color: var(--on-deep); }

/* ============================================================
   FEATURE BAND
   ============================================================ */
.yh-feat {
  display: grid; grid-template-columns: 1.5fr 0.82fr; gap: 0;
  background: var(--nh-ink); align-items: start;
  border-radius: var(--r-md); overflow: hidden;
}
.yh-feat__art { display: block; }
/* `height: auto` is load-bearing. The <img> carries width/height ATTRIBUTES
   (they reserve layout space and prevent CLS), and a height attribute is a
   presentational hint that beats `aspect-ratio` — without this the cover
   renders at its intrinsic 1080px tall instead of a 16/9 box. */
.yh-feat__art img { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; display: block; }
.yh-feat__art:focus-visible { outline: 3px solid var(--nh-red); outline-offset: -3px; }

/* A series booked before its artwork exists (Christmas @ New Hope) gets a
   typographic plate in the same 16/9 box, never <img src="">. */
.yh-feat__plate {
  display: flex; flex-direction: column; justify-content: flex-end;
  aspect-ratio: 16 / 9; padding: clamp(20px, 3vw, 34px);
  background: var(--nh-cream); color: var(--nh-ink);
  border: 1px solid var(--line);
}
.yh-feat__plate-title {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(22px, 2.6vw, 38px); line-height: 1.02; letter-spacing: -0.02em;
}

.yh-feat__txt {
  padding: 30px clamp(24px, 3vw, 42px);
  color: var(--on-deep);
  display: flex; flex-direction: column; justify-content: center; align-self: stretch;
}
/* Status pill. Rendered ONLY when there is a real live status; a past year
   never gets one, because inventing one would be a false claim. Red fill is
   the approved design value, so no button beside it may reuse that fill
   (badge-distinct-from-buttons rule) — the feature CTA is the ghost-on-deep
   treatment for exactly that reason. */
/* Compound `p.yh-feat__now`: this has to outrank BOTH the page-local
   `.series-ed p` reset and the `.yh-feat__txt p` rule further down this
   file, which was overriding the pill's colour to --on-deep-mute (2.93:1
   on the red fill, an AA failure) and its size to 15.5px. */
.series-ed .yh-feat__txt p.yh-feat__now {
  align-self: flex-start;
  font-family: var(--font-display); font-weight: 700; font-size: 11px;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--nh-paper); background: var(--nh-red);
  border-radius: var(--r-pill); padding: 6px 14px; margin-bottom: 18px;
}
.series-ed .yh-feat__txt p.yh-feat__meta {
  font-family: var(--font-display); font-weight: 600; font-size: 12px;
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--on-deep-mute); margin-bottom: 10px;
}
.series-ed .yh-feat__txt h2 {
  font-family: var(--font-display); font-weight: 800; font-size: clamp(28px, 2.8vw, 38px);
  letter-spacing: -0.02em; line-height: 0.98; margin: 0 0 10px;
  color: var(--on-deep);
}
.yh-feat__txt h2 a { color: inherit; }
.yh-feat__txt h2 a:hover { color: var(--nh-red-soft); }
.series-ed .yh-feat__txt p {
  color: var(--on-deep-mute); font-size: 15.5px; line-height: 1.45;
  margin: 0 0 16px;
}
/* The panel is a flex COLUMN, so the button would stretch to full width
   without this. Deliberately not on .yh-btn itself: the rows lay their CTA
   out in a GRID, where `align-self` is the block axis and this would push
   the button to the top of the row instead of centering it. */
.yh-feat__cta { align-self: flex-start; }

@media (max-width: 860px) {
  .yh-feat { grid-template-columns: minmax(0, 1fr); }
  .yh-feat__txt { padding: 26px clamp(20px, 5vw, 32px) 30px; }
}

/* ============================================================
   ROWS
   ============================================================ */
.yh-rows { padding: 8px 0 40px; }

.yh-row {
  display: grid;
  grid-template-columns: 108px 260px minmax(0, 1fr) auto;
  grid-template-areas: "mo art body cta";
  gap: 36px; align-items: center;
  padding: 40px 0;
  border-bottom: 1px solid var(--line);
}
.yh-row__mo   { grid-area: mo; }
.yh-row__art  { grid-area: art; }
.yh-row__body { grid-area: body; }
.yh-row__cta  { grid-area: cta; }

/* 108px, not the mock's 96px: measured in Outfit 800 at 44px, the widest
   three-letter months (MAR, NOV) run 100px, so a 96px box broke them
   mid-word as "NO / V". `nowrap` is the belt-and-braces guard so a future
   font or size change can never re-introduce a split month. */
.yh-row__mo {
  font-family: var(--font-display); font-weight: 800; font-size: 44px;
  color: var(--nh-red); line-height: 1; text-transform: uppercase;
  width: 108px; white-space: nowrap;
}

.yh-row__art { display: block; }
.yh-row__art img {
  width: 100%; height: auto;        /* see the note on .yh-feat__art img */
  aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: 10px; display: block;
}
.yh-row__art:focus-visible { outline: 3px solid var(--nh-red); outline-offset: 3px; border-radius: 10px; }

/* text plate, same 16/9 box as a real cover so the rows stay aligned */
.yh-row__plate {
  display: flex; align-items: flex-end;
  aspect-ratio: 16 / 9; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--nh-cream); color: var(--nh-ink);
  transition: border-color 0.2s ease;
}
.yh-row__plate:hover { border-color: var(--nh-red); }
.yh-row__plate span {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(14px, 1.4vw, 19px); line-height: 1.05; letter-spacing: -0.01em;
}

.yh-row__body { display: flex; flex-direction: column; gap: 2px; }
.yh-row__meta {
  font-family: var(--font-display); font-weight: 600; font-size: 12px;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--nh-mute);
}
.series-ed .yh-row h3 {
  font-family: var(--font-display); font-weight: 700; font-size: clamp(24px, 2.4vw, 32px);
  letter-spacing: -0.01em; color: var(--nh-ink); margin: 6px 0;
  overflow-wrap: normal;            /* headings never break mid-word */
}
.yh-row h3 a { color: inherit; }
.yh-row h3 a:hover { color: var(--nh-red); }
.yh-row__body p {
  margin: 0; color: var(--nh-ink-2); line-height: 1.5;
  max-width: var(--measure-tight);
}

/* --- tablet: month over a two-column art + body ---
   Breaks at 1100, not 1023: at iPad-landscape widths the four-column row
   squeezes the body column to ~270px between a fixed 260px cover and a
   ~190px button, so titles rag over three lines. Measured 2026-07-20.
   (Chrome matches media queries against the viewport INCLUDING the
   scrollbar, so a 1024px window sees 1024px here.) */
@media (max-width: 1100px) {
  .yh-row {
    grid-template-columns: 220px minmax(0, 1fr);
    grid-template-areas:
      "mo   mo"
      "art  body"
      "art  cta";
    align-items: start;
    column-gap: 28px; row-gap: 16px;
    padding: 32px 0;
  }
  .yh-row__mo { font-size: 28px; width: auto; }
  /* `justify-self` matters as much as `align-self` here. At desktop the CTA
     sits in an `auto` track and shrink-wraps; at tablet it moves into the
     `minmax(0,1fr)` body column, where a grid item's default `stretch` blows
     the pill out to the full column width (measured 880px at 1024). The
     phone breakpoint below deliberately DOES go full width, so this is
     scoped to the tablet range only. */
  .yh-row__cta { align-self: start; justify-self: start; }
}

/* --- phone: one column --- */
@media (max-width: 640px) {
  .yh-row {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "mo" "art" "body" "cta";
    row-gap: 14px; padding: 28px 0;
  }
  .yh-row__mo { font-size: 24px; }
  .yh-btn { width: 100%; justify-content: center; }
}

/* ============================================================
   MOTION  (double-gated: html.js + prefers-reduced-motion)
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  html.js .yh-anim {
    opacity: 0; transform: translateY(20px);
    transition: opacity 0.6s cubic-bezier(.2,.7,.2,1), transform 0.6s cubic-bezier(.2,.7,.2,1);
  }
  html.js .yh-feat .yh-anim--art { transform: translateX(-36px); }
  html.js .yh-row .yh-anim--art  { transform: translateX(-24px); }
  html.js .yh-anim.is-in { opacity: 1; transform: none; }

  /* hero load-in */
  html.js .yh-hero .yh-load {
    opacity: 0; transform: translateY(24px);
    animation: yhRise 0.8s cubic-bezier(.2,.7,.2,1) forwards;
  }
  html.js .yh-hero .yh-load:nth-child(1) { animation-delay: 0.05s; }
  html.js .yh-hero .yh-load:nth-child(2) { animation-delay: 0.15s; }
  html.js .yh-hero .yh-load:nth-child(3) { animation-delay: 0.28s; }
  html.js .yh-hero .yh-load:nth-child(4) { animation-delay: 0.38s; }

  /* the year digits rise one after another */
  html.js .yh-hero__num span {
    opacity: 0; transform: translateY(18%);
    animation: yhRise 0.9s cubic-bezier(.2,.7,.2,1) forwards;
  }
  html.js .yh-hero__num span:nth-child(1) { animation-delay: 0.06s; }
  html.js .yh-hero__num span:nth-child(2) { animation-delay: 0.14s; }
  html.js .yh-hero__num span:nth-child(3) { animation-delay: 0.22s; }
  html.js .yh-hero__num span:nth-child(4) { animation-delay: 0.30s; }

  @keyframes yhRise { to { opacity: 1; transform: none; } }
}

/* PRINT. The reveal above starts every .yh-anim at opacity:0 and only the
   scroll observer clears it, so printing a hub that has not been scrolled
   rendered the feature band and every series row blank (42 of 47 elements
   hidden, measured at 1440 under emulateMediaType('print')). Print has no
   scrolling and no observer, so the entrance state has to be cancelled
   outright. This block sits OUTSIDE the prefers-reduced-motion query on
   purpose: the state it undoes is set inside that query, but a print
   stylesheet must win regardless of the reader's motion preference. */
@media print {
  html.js .yh-anim,
  html.js .yh-hero .yh-load,
  html.js .yh-hero__num span {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
    transition: none !important;
  }
}
