/* base.css — sirka-courses · global reset + body + .container
   PAGE-SCAFFOLD owns this file. Section stylesheets are structurally locked out of global
   scope: no section may write *, html, body, img, a, .container or :root.

   NOTE ON THIS COMMENT BLOCK: it contains no closing-comment sequence anywhere inside it.
   FD-141 — a stray one inside a scaffold header comment ate the whole reset on
   ragazzi-community, so body fell back to UA margin 8px + content-box and every section
   measured wrong while the file READ healthy. Nothing in the pipeline asserts that a
   stylesheet parses, so the scaffold asserts it by hand after serving:
   document.styleSheets[n].cssRules.length must be non-zero for every sheet. */

/* ---------- reset ---------- */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  /* clip, NOT hidden: hidden turns html/body into scroll containers and breaks
     position: sticky (CLAUDE.md + brief 1.2). Consequence recorded in brief 1.2 — clip also
     makes a naive page-level horizontal-overflow check inert, so the three sliders must be
     checked with scrollWidth > clientWidth on the scroll container itself. */
  overflow-x: clip;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  overflow-x: clip;
  min-width: 320px;
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: 600;
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  color: var(--c-ink);
  background: var(--c-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  letter-spacing: inherit;
}

ul, ol { list-style: none; }

a {
  color: inherit;
  text-decoration: none;
}

img, video, svg, picture {
  max-width: 100%;
  height: auto;
  display: block;
}

button {
  background: none;
  border: none;
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  text-align: inherit;
}

input, textarea, select {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  outline: none;
  text-transform: inherit;
  letter-spacing: inherit;
}

table { border-collapse: collapse; border-spacing: 0; }

*:focus { outline: none; }
*:focus-visible { outline: 2px solid var(--c-ink); outline-offset: 2px; }

/* ---------- container — defined ONLY here, once ----------
   max-width is 1920px and is NOT --vw-base (1520px): see fluid-formulas.md
   "Two different max widths". Horizontal padding is --gutter (20 mobile / 40 desktop,
   brief 1.1). Written as padding-inline, never as a `padding` shorthand — a shorthand on a
   .container section wipes the gutter (CLAUDE.md), and this way a section adding block
   padding cannot destroy it either. */
.container {
  width: 100%;
  max-width: 1920px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Bleed override — keeps the 1920 cap, drops the gutter. On this page only `hero` needs it
   (full-bleed photo + scrim on both layers, plus the mobile bar). brief 1.3: `cta-footer` is
   full-frame in Figma but paints nothing outside the content box, so it is Pattern A. */
.container--bleed { padding-inline: 0; }

/* ---------- section rhythm — ONE owner, page level ----------
   Mobile: all 10 body boundaries are a single 50px auto-layout gap. Desktop: the drawn gaps
   genuinely differ (120 / 84 / 82 / 120.56 / 120 / 101 / 76 / 119 / 120 / 101.3, brief 4.5) and
   the page total 10011px closes exactly, so they must NOT be averaged into one number.

   The split: this rule gives EVERY boundary the default (--section-gap). A section whose
   drawn desktop gap is one of the five exceptions overrides it from its own stylesheet with a
   class-specificity rule setting THE SAME single property, so an override replaces the default
   instead of adding to it. `hero` is first, so `section + section` never applies to it and it
   must not carry a bottom margin. */
section + section { margin-block-start: var(--section-gap); }

/* ---------- page-level utilities ---------- */

/* Scroll-lock while the mobile menu panel is open (js/nav.js sets this on BOTH <html> and <body>).

   It must be on <html>, and that is not belt-and-braces. `body { overflow: hidden }` only reaches
   the viewport through the propagation rule, which applies solely when the ROOT element's overflow
   is `visible` in both axes. This page sets `html { overflow-x: clip }` (required, or `position:
   sticky` breaks), so <html> stays the scrolling element and a lock on <body> alone is INERT.
   Measured on this build before the fix: `body` computed `overflow: hidden`, `document
   .scrollingElement === document.documentElement`, and the page still scrolled 400px behind the
   open overlay. */
html.is-nav-open,
body.is-nav-open {
  overflow: hidden;
  /* For touch: `overflow: hidden` stops wheel and touch scrolling of the box, and these two stop
     the scroll CHAIN from reaching the viewport on iOS/Android. Note what `hidden` deliberately
     does NOT stop, per spec: PROGRAMMATIC scrolling. A `window.scrollTo(0, 400)` still moves a
     locked page, so a scrollTo-based probe cannot tell a working lock from a broken one — the
     audit that raised this used exactly that probe. What changed here is real: the lock now sits
     on the element that actually scrolls. */
  touch-action: none;
  overscroll-behavior: contain;
}

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

/* Scroll-reveal (js/main.js). Sections opt in with [data-animate]; the audit and QA force
   .is-visible before measuring, so nothing measures a mid-transition state. */
[data-animate] {
  --reveal-shift: 16px;
  opacity: 0;
  transform: translateY(var(--reveal-shift));
  transition: opacity 0.6s ease, transform 0.6s ease;
  /* An in-page anchor to a section that has NOT revealed yet lands on the SHIFTED box, and the
     reveal then lifts that box by the same amount — so the section ends up scrolled past by
     exactly --reveal-shift. Measured when the hero CTA was pointed at #pricing: the section
     settled at top -15.88 / -15.63 / -16.44 across three widths, i.e. its first 16px cut off.
     The margin cancels it, and it is the SAME token as the transform on purpose: two hard-coded
     16s would drift apart the first time the animation is retuned. */
  scroll-margin-top: var(--reveal-shift);
}
/* Once revealed there is no shift left to cancel, so the margin has to go with the transform —
   otherwise an anchor to an already-visible section overshoots by 16px in the other direction. */
[data-animate].is-visible { opacity: 1; transform: none; scroll-margin-top: 0; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  [data-animate] { opacity: 1; transform: none; transition: none; }
}
