/* program.css — section 5 of 11 · 3001:430 (desktop) / 3001:3266 (mobile)
   MOBILE-FIRST. Scoped rules only: .program__* plus scoped overrides of the accordion
   template classes that are already linked globally by the scaffold (css/templates/accordion.css).
   No global selector, no :root, no .container, no template stylesheet copy.

   Numbers come from the JSON cache, not the brief prose. The four geometry facts that hold the
   whole section together:
     1. every row is `padding: 19px` + `border: 1px` — NOT 20 + 1. Figma's CENTER stroke does not
        participate in layout, CSS border does: 1+19+58+19+1 = 98 (desktop row), 1+19+95+19+1 = 135
        (mobile row), 1+19+1400+19+1 = 1440 (desktop width). 20 makes every row 2px too tall AND
        too wide, on both layers and both axes.
     2. the 20px Figma gap between the header row and the body is `padding-top` on .program__body,
        never `gap` on .program__item — a gap applies while the panel is height:0 and would add
        20px to all six collapsed rows.
     3. separators: the 10 horizontal `Line 21`–`Line 30` are ZERO-HEIGHT Figma nodes, so a CSS
        border-top ADDS 1px each; the 1px is subtracted from the following row's padding-top
        (13/12 desktop, 10/9 mobile → panel 469 / 574 exactly). The vertical `Line 36` is a
        ZERO-WIDTH node → a span with border-left and no width.
     4. the trailing CTA is an underlined text link, not a pill: a 2px #000 INSIDE bottom stroke,
        so padding 7/0/5 + border-bottom 2 = 40 (desktop) / 32 (mobile), radius 0.

   Every fluid px value in this section is a plain Figma px on BOTH layers (slice §2.3) and is
   deliberately NOT clamped — the only clamped things are the type tokens and the four scoped
   tokens below. */

/* ============================================================================
   SCOPED TOKENS — declared in ALL THREE BANDS on .program (never :root).
   A scoped token that is missing from the 768–1023 block inherits the MOBILE formula, which
   keeps growing with --max-vw far past its band (ragazzi-pdp2 shipped a badge 2x too large
   exactly this way). So all four are re-declared below, including the two whose value is `auto`.
============================================================================ */
.program {
  /* Desktop-only fixed ordinal column (3001:437 = 60 on all 7 items). Below 1024 the ordinal
     HUGS its glyph (mobile widths 32–37 are content-driven and there is no drawn column width
     to interpolate) — `auto` here is deliberate, not a missing band. */
  --prog-ord-w: auto;
  /* `Урок N` label is a FIXED 63px on both layers (3001:527 = 3001:3363 = 63) — that is what
     keeps all 11 vertical rules on one x. Fluid so it tracks its own fluid type above 1520. */
  --prog-lesson-label-w: clamp(54px, calc(63px + (var(--max-vw) - 375px) * 0.015), 129px);
  /* Vertical `Line 36`: desktop is a centred 15px stub, mobile spans the whole row (STRETCH). */
  --prog-rule-h: auto;
  /* Result-strip label: Oswald 600 / lh 88% / ls −4% / UPPER at M-base 16, D-base 20. No row in
     brief-page §4.3 matches (--text-label is Onest 700/100%/−6.4%), hence a section token. */
  --text-prog-result-label: clamp(14px, calc(16px + (var(--max-vw) - 375px) * 0.015), 33px);
}

/* ============================================================================
   MOBILE BASE (0–767) — 3001:3266, frame 335 wide
============================================================================ */

/* 3001:3266: flex column, gap 30, align MIN, padding 0. The section-to-section rhythm is the
   page token unchanged — mentors→program is 50 mobile / 120.56 desktop, both inside the
   --section-gap default band, so no program-scoped boundary override (slice §2.2). */
.program {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 30px;
  margin-top: var(--section-gap);
}

/* 3001:3268: flex column, gap 20, align CENTER — the accordion stretches, the CTA is centred. */
.program__wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 100%;
}

/* 3001:3269 / 3001:433 — gap 0: adjacent 1px borders are meant to read as ONE line. */
.program__list {
  width: 100%;
  align-self: stretch;
}

/* ---- the seven rows ---- */
.program__item {
  border: var(--bw-hairline) solid var(--c-hairline);
  padding: 19px;
}
/* Collapse the shared seam to a single 1px line. Accepted deviation: this makes the collapsed
   list 6px shorter than Figma's 1253, because Figma paints coincident CENTER strokes as one line
   AND keeps the full stack height; CSS cannot do both, and the visible half is the 1px seam. */
.program__item + .program__item {
  margin-top: -1px;
}
/* 3001:3342 / 3001:506 are the only rows with an explicit white fill (D-10). Inert on a white
   page, shipped so the JSON diff matches and so a future page bg cannot break the open row. */
.program__item.active {
  background: var(--c-bg);
}

/* ---- header row = the trigger (3001:3271, MIN-aligned, icon pinned top) ---- */
.program__trigger {
  display: flex;
  width: 100%;
  align-items: flex-start;
  gap: 15px;                 /* dominant mobile value: 5 of 7 rows are 15, items 01/05 drift to 20 */
}

/* Mobile: the ordinal sits ABOVE the title block (3001:3272 = column, gap 15).
   Fills the row so the toggle is pushed to the right edge: 295 − 15 − 18 = 262. */
.program__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 15px;
  flex: 1 1 auto;
  min-width: 0;
}

.program__ord {
  flex: 0 0 auto;
  width: var(--prog-ord-w);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-stat);
  line-height: var(--lh-stat);
  letter-spacing: var(--ls-stat);
  color: var(--c-ink);
}

/* 3001:3274 / 3001:438: column, gap 6. HUGS its content on both layers — the Figma widths
   (251/255/260 mobile, 313/365/201… desktop) are the longest child, not the row width. */
.program__titles {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  min-width: 0;
  max-width: 100%;
}

.program__item-title {
  font-family: var(--font-body);
  font-weight: 800;
  font-size: var(--text-h5);
  line-height: var(--lh-h5);
  letter-spacing: var(--ls-h5);
  text-transform: uppercase;   /* Figma textCase UPPER — the DOM string stays as typed (FD-79) */
  color: var(--c-ink);
}

/* 3001:3276 / 3001:440: 3 chips in a row, gap 20, never wrapping and never scrolling — Figma
   fits all three in 248–260 inside a 251–262 column on mobile and in 277–298 of 1350 on desktop.
   If they ever did exceed the column the fix is a smaller --text-meta, not a wrap. */
.program__meta {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--grid-gap);
}
.program__chip {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: var(--text-meta);
  line-height: var(--lh-meta);
  letter-spacing: var(--ls-meta);
  text-transform: uppercase;
  color: var(--c-ink-70);       /* #232323b2 on all 42 chip texts — NOT full ink */
}
.program__chip-num  { font-weight: 400; }
.program__chip-unit { font-weight: 500; }

/* ---- toggle icon ----
   accordion.js appends <span class="accordion-icon"> as the LAST child of the trigger and swaps
   the SVG inside it on state change, so the ROTATION lives on the span (which survives the swap)
   and not on the SVG (which is replaced, and would jump). Mobile box is 18x18 with the glyph
   filling it; desktop is a 30x30 box around a 14x14 glyph — per-layer, never collapsed to one. */
.program__trigger .accordion-icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  color: var(--c-ink);
  transition: transform 0.3s ease;
}
.program__trigger .accordion-icon .program__glyph {
  width: 18px;
  height: 18px;
  fill: currentColor;
}
.program__item.active .accordion-icon {
  transform: rotate(90deg);     /* ↗ closed → ↘ open, about the box centre (D-9) */
}
@media (prefers-reduced-motion: reduce) {
  .program__trigger .accordion-icon { transition: none; }
}

/* ---- the disclosure panel ----
   MUST-APPLY: the template stylesheet ships these three declarations on `.faq-answer` only, so
   renaming the CSS class without porting them leaves every panel permanently open. accordion.js
   owns the inline height; never add display:none. */
.program__answer {
  height: 0;
  overflow: hidden;
  transition: height 0.3s ease;
}
/* The Figma 20px gap between header row and body, as padding on the INNER wrapper (see note 2). */
.program__body {
  display: flex;
  flex-direction: column;
  gap: var(--grid-gap);
  padding-top: 20px;
}

/* ---- lesson list (item 05 only) ---- */
.program__lessons {
  display: flex;
  flex-direction: column;
}
.program__lesson {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* Figma gap 10 → 10 + 9 + the 1px border = 20 per seam: 374 + 10x20 = 574 ✓ (naive 10/10 → 584) */
.program__lesson:not(:last-child)  { padding-bottom: 10px; }
.program__lesson:not(:first-child) { padding-top: 9px; border-top: var(--bw-hairline) solid var(--c-hairline); }

.program__lesson-label {
  flex: 0 0 var(--prog-lesson-label-w);
  width: var(--prog-lesson-label-w);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-small);
  line-height: var(--lh-small);
  letter-spacing: var(--ls-small);
  text-transform: uppercase;
  color: var(--c-ink-50);        /* #23232380 */
}
/* `Line 36` is width 0 with a 1px CENTER stroke in #232323 — a different ink from the #000000
   row/lesson rules on purpose (the gate compares exact hex; unifying them manufactures a P1). */
.program__lesson-rule {
  flex: 0 0 auto;
  width: 0;
  height: var(--prog-rule-h);
  align-self: stretch;           /* mobile: spans the full row (3001:3364 = 51/34/17 tall) */
  border-left: var(--bw-hairline) solid var(--c-ink);
  /* Figma's node is width 0 with a CENTER stroke, so it straddles the flex position and costs
     the row NOTHING; a CSS border-left costs 1px. Give that 1px back instead of leaving it in:
     measured, the missing pixel narrowed the mobile lesson title from 212 to 211 and pushed
     lesson 06 to a THIRD line (row 34 -> 51). The 10px gaps are untouched — the rule simply
     occupies zero width, and the title starts at x=83 exactly as in Figma. */
  margin-right: -1px;
}
.program__lesson-title {
  flex: 1 1 0;
  min-width: 0;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-body-alt);
  line-height: var(--lh-body-alt);
  letter-spacing: var(--ls-body-alt);
  color: var(--c-ink);
}

/* ---- result strip (3001:3416 / 3001:580) ---- */
.program__result {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 19px;                 /* same 19+1 arithmetic as the rows: 1+19+60+19+1 = 100 ✓ */
  border: var(--bw-hairline) solid var(--c-hairline);
  background: var(--c-ink);
  color: var(--c-bg);            /* the page's only white */
}
.program__result-inner {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
}
.program__result-label {
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-prog-result-label);
  line-height: var(--lh-meta);       /* 0.88 — same metric as the meta row, per node */
  letter-spacing: var(--ls-meta);    /* −4% */
  text-transform: uppercase;
}
.program__result-text {
  flex: 1 1 0;
  min-width: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-meta);
  line-height: var(--lh-meta);
  letter-spacing: var(--ls-meta);
  /* NOT uppercased — --text-meta carries case:UPPER in the ramp, but this node does not (D-5). */
}

/* ---- the six items Figma left without body copy (ADAPT.md [CONTENT NEEDED], §10 BA-3).
   They stay REAL triggers: no tabindex="-1", nothing inert — that would mask the gap and fake
   a11y. Every instance is listed in the run's Outstanding Content. ---- */
.program__placeholder {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-body-alt);
  line-height: var(--lh-body-alt);
  letter-spacing: var(--ls-body-alt);
  font-style: italic;
  color: var(--c-ink-50);
}

/* ---- trailing collapse-all CTA (3001:3456 / 3001:620) ---- */
.program__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 7px 0 5px;                     /* 7 + 18 + 5 + 2 = 32 ✓ mobile / 7 + 26 + 5 + 2 = 40 ✓ */
  border-bottom: 2px solid var(--c-hairline);
  border-radius: var(--r-flat);           /* explicitly flat: this is a text link, not a pill */
  color: var(--c-hairline);               /* the label fills #000000 — same value, page token */
}
/* .t-btn supplies the type; --lh-btn is already `normal`, NOT 1 — 3001:621 is 20px type in a
   26px box (1.30) and 3001:3457 is 14px in 18 (1.286), i.e. Figma AUTO leading (FD-175). A
   line-height of 1 shrinks this control to 34/28 instead of 40/32. */
/* The glyph is `#i-arrow`, drawn ↗. Collapsed it points ↘ (open this), expanded it returns to the
   glyph's own ↗ (close this) — user, 2026-08-13. Figma draws only the expanded state, so the
   ROTATION of that state is the drawn one and the collapsed 90° is the added half of the pair. */
.program__cta-arrow {
  transform: rotate(90deg);               /* ↘ — collapsed */
  transition: transform 0.3s ease;
}
.program__cta[aria-expanded="true"] .program__cta-arrow {
  transform: rotate(0deg);                /* ↗ — expanded, i.e. the glyph as drawn */
}

@media (prefers-reduced-motion: reduce) {
  .program__cta-arrow { transition: none; }
}

/* The list shows the first `data-visible-count` modules; js/program.js moves the rest into this
   wrapper, which it CREATES — there is no such element in the markup, so with JS off every module
   stays listed and nothing here can hide it. That is the right way round for a disclosure that
   hides real copy.
   The animation is height, driven from JS (0 <-> the measured px, then `auto` once open). A
   wrapper is what makes that possible at all: each row has its own border and 19px padding, so
   animating seven independent heights would be seven transitions to keep in step, and the
   0fr/1fr grid trick cannot carry a border-box either.
   `height: auto` after the open transition is NOT tidiness — it is load-bearing. These rows are
   accordions: opening module 07 grows the wrapper's content, and a wrapper frozen at its px
   height would clip that panel with no scroll to recover it. */
.program__extra {
  overflow: hidden;
  height: 0;
  margin-top: -1px;                       /* the 05|06 seam the sibling rule can no longer make */
  transition: height 0.4s ease;
}

@media (prefers-reduced-motion: reduce) {
  .program__extra { transition: none; }
}

/* Figma draws only the expanded label (`Скрыть всю программу`, 3001:621 / 3001:3457). The
   collapsed one has no node to copy, so it ships alongside and the state picks — the drawn string
   is never rewritten in place. Both are inside the button, so its box is sized by the LONGER of
   the two either way and does not jump when the label changes. */
.program__cta[aria-expanded="false"] .program__cta-label--less,
.program__cta[aria-expanded="true"]  .program__cta-label--more {
  display: none;
}

/* The [disabled] pair that used to live here is gone with the collapse-all behaviour it belonged
   to (§10 BA-2): this control now always has something to do. */

/* ============================================================================
   PSEUDO-TABLET 768–1023 — INTERPOLATED, nothing is drawn here.
   Structure stays MOBILE through this whole band on purpose (D-3): the ordinal stays ABOVE the
   title, the trigger stays flex-start, the icon stays 18px. The row/column flip belongs at 1024
   with the rest of the drawn desktop band — flipping it at 768 would put a 48px-scale numeral
   beside a two-line title in a ~700px box. brief-page §7.4's 768 split-row rule governs 50/50
   image+content pairs and does not apply to a text-beside-text micro-row.
   Only the scoped tokens change here, and ALL FOUR are re-declared.
============================================================================ */
@media (min-width: 768px) {
  .program {
    --prog-ord-w: auto;                  /* still hugs — the flip is at 1024, not here */
    --prog-lesson-label-w: 63px;         /* M-base == D-base == 63, so the ramp is flat through
                                            the band (same treatment as --text-logo in tokens.css) */
    --prog-rule-h: auto;                 /* still STRETCH — see .program__lesson-rule */
    --text-prog-result-label: clamp(16px, calc(16px + (var(--max-vw) - 768px) * 0.025), 20px);
  }
}

/* ============================================================================
   DESKTOP 1024+ — 3001:430, drawn at 1520 (--vw-base), content box 1440
============================================================================ */
@media (min-width: 1024px) {
  .program {
    --prog-ord-w: clamp(40px, calc(60px * (var(--max-vw) / var(--vw-base))), 76px);
    --prog-lesson-label-w: clamp(42px, calc(63px * (var(--max-vw) / var(--vw-base))), 80px);
    --prog-rule-h: clamp(10px, calc(15px * (var(--max-vw) / var(--vw-base))), 19px);
    --text-prog-result-label: clamp(13px, calc(20px * (var(--max-vw) / var(--vw-base))), 25px);

    /* RESPONSIVE (STEP 5b): 3001:430.gap = 40 is the value drawn at 1520 and the MOBILE node
       3001:3266 draws 30 — two different per-layer values, so this is NOT a design-invariant
       atom and it must scale with the band like every other distance.
       D-min = round(40 x 1024/1520) = 27 · D-base = 40 · D-max = round(40 x 1920/1520) = 51 */
    gap: clamp(27px, calc(40px * (var(--max-vw) / var(--vw-base))), 51px);
  }

  /* 3001:432.gap = 30 desktop against 3001:3268.gap = 20 mobile — per-layer, so it ramps.
     D-min = round(30 x 1024/1520) = 20 · D-max = round(30 x 1920/1520) = 38 */
  .program__wrap { gap: clamp(20px, calc(30px * (var(--max-vw) / var(--vw-base))), 38px); }

  /* The section's one real layout change: the ordinal moves from ABOVE the title to BESIDE it,
     and the whole header row centres (3001:435/436 = row, align CENTER, gap 20). The ordinal
     becomes a fixed 60px column that must scale with its own fluid numeral, or `01` collides
     with the title above 1520 (D-7). */
  .program__trigger { align-items: center; gap: var(--grid-gap); }
  .program__head { flex-direction: row; align-items: center; gap: var(--grid-gap); }

  /* All seven desktop titles are single-line in Figma (201–365px inside a 1350px column). */
  .program__item-title { white-space: nowrap; }

  /* Box 30 desktop / 18 mobile and glyph 14 desktop / 18 mobile — both per-layer, so both ramp
     (a flat 30px box would sit at 100% of its 1520 size inside a band rendering at 67%, and
     would stop growing entirely above --vw-base).
     30 → D-min round(30 x 1024/1520) = 20 · D-max round(30 x 1920/1520) = 38
     14 → D-min round(14 x 1024/1520) =  9 · D-max round(14 x 1920/1520) = 18 */
  .program__trigger .accordion-icon {
    width:  clamp(20px, calc(30px * (var(--max-vw) / var(--vw-base))), 38px);
    height: clamp(20px, calc(30px * (var(--max-vw) / var(--vw-base))), 38px);
  }
  .program__trigger .accordion-icon .program__glyph {
    width:  clamp(9px, calc(14px * (var(--max-vw) / var(--vw-base))), 18px);
    height: clamp(9px, calc(14px * (var(--max-vw) / var(--vw-base))), 18px);
  }

  /* Figma gap 13 → 13 + 12 + 1px border = 26 per seam: 209 + 10x26 = 469 ✓ (naive 13/13 → 479).
     Mobile draws 10 (3001:3361.gap) against desktop 13 (3001:525.gap), so the pair is per-layer
     and ramps; the clamp returns EXACTLY 13/12 at --vw-base, so the drawn 469 panel is unchanged
     at 1520. Ten seams x 8px of non-scaling padding was the largest single contributor to this
     section rendering at 83% of its 1520 height at 1024 instead of the band's 67%.
     13 → D-min 9 · D-max 16   ·   12 → D-min 8 · D-max 15 */
  .program__lesson:not(:last-child)  { padding-bottom: clamp(9px, calc(13px * (var(--max-vw) / var(--vw-base))), 16px); }
  .program__lesson:not(:first-child) { padding-top:    clamp(8px, calc(12px * (var(--max-vw) / var(--vw-base))), 15px); }
  .program__lesson-rule { align-self: center; }   /* 15px stub centred in the 19px row */

  /* Single line at every desktop width: the longest lesson title is ~440px of a 1317px column
     and the result body ~770px of 1262px, and both shrink with the type at 1024. */
  .program__lesson-title { white-space: nowrap; }
  .program__result-text  { white-space: nowrap; }

  /* 3001:620.gap = 10 desktop against 3001:3456.gap = 5 mobile — per-layer, so it ramps.
     D-min = round(10 x 1024/1520) = 7 · D-max = round(10 x 1920/1520) = 13 */
  .program__cta { gap: clamp(7px, calc(10px * (var(--max-vw) / var(--vw-base))), 13px); }
}
