/* ==========================================================================
   Sections — header, hero, and shared block patterns
   ========================================================================== */

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

.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  padding: var(--space-2) 0;
  transition: background-color var(--dur) var(--ease);
}

.site-header[data-scrolled="true"] {
  /* Nearly opaque: at 88% the text passing underneath stayed readable through
     the bar and fought with the navigation. */
  background: color-mix(in srgb, var(--ink) 97%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--hairline-dark);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.logo {
  display: inline-block;
  /* The header logo is also a link back to the top of the page — padding
     brings its tap target up near the pills either side of it in the same
     row, instead of the ~26px a bare text line gives a thumb to aim at. */
  padding-block: 0.75rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.125rem;
  letter-spacing: -0.02em;
  color: var(--paper);
}

.logo span {
  color: var(--gen-light);
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.25rem;
  border: 1px solid var(--hairline-dark);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--ink) 70%, transparent);
  backdrop-filter: blur(10px);
}

.site-nav a {
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius-pill);
  font-size: var(--step-small);
  color: var(--paper);
  transition: background-color var(--dur-fast) var(--ease);
}

.site-nav a:hover {
  background: color-mix(in srgb, var(--paper) 12%, transparent);
}

@media (max-width: 64rem) {
  .site-nav {
    display: none;
  }
}

/* Below ~375px the logo and the header CTA no longer fit on one line at full
   size — the button's text was wrapping onto two lines and doubling the
   header's height. Narrower spacing and a smaller pill keep it to one line
   instead. */
@media (max-width: 24rem) {
  .site-header__inner {
    gap: var(--space-1);
  }

  .logo {
    font-size: 1rem;
  }

  .site-header .btn {
    white-space: nowrap;
    flex-shrink: 0;
    padding-inline: 1rem;
    font-size: var(--step-small);
  }
}

/* --------------------------------------------------------------------------
   Hero

   Right now the stage is a CSS scene standing in for the video: a lit screen
   in a dark room. It is deliberately built so the swap to <video> changes one
   element and nothing else. Copy, chips and controls already sit in their
   final positions.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--ink);
  /* Top padding clears the fixed header when the content grows past one
     screen; bottom padding keeps the chips off the fold edge. */
  padding-block: 7.5rem var(--space-5);
}

/* Pushed down with auto margin rather than justify-content: flex-end. On a
   short window the content is taller than the hero, and flex-end sends the
   overflow upward — the headline ends up under the fixed header, unreachable.
   An auto margin keeps any overflow below, where it can be scrolled to. */
.hero__inner {
  margin-top: auto;
}

.hero__stage {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__poster {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 60% 50%;
}

/* Scrim: the headline sits bottom-left, so the frame is darkened from the
   bottom and from the left. Without it the copy fails contrast over the
   brighter parts of the picture. */
.hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
      to top,
      var(--ink) 6%,
      color-mix(in srgb, var(--ink) 72%, transparent) 40%,
      color-mix(in srgb, var(--ink) 20%, transparent) 72%
    ),
    linear-gradient(
      to right,
      color-mix(in srgb, var(--ink) 82%, transparent),
      color-mix(in srgb, var(--ink) 25%, transparent) 55%,
      transparent 80%
    );
}

.hero__inner {
  position: relative;
  z-index: 2;
  display: grid;
  gap: var(--space-3);
}

.hero__eyebrow {
  margin-bottom: var(--space-3);
  color: var(--gen-light);
}

/* ch here is measured against this element's own font (Unbounded, up to
   76px) — it used to sit on the wrapping .hero__copy div instead, where ch
   resolves against the small body font, so the "16 characters" it asked for
   was really about 3 real headline characters wide. The title wrapped to five
   short lines at every viewport as a result, tall enough that the button and
   chips fell off the bottom of an ordinary 1600×900 monitor. 13ch on the
   headline itself gives the two-line break it was always meant to have, and
   the ratio holds at any font size since both scale together. */
.hero__title {
  max-width: 13ch;
  margin-bottom: var(--space-3);
}

/* The turn in the headline. The whole positioning lives in these two words,
   so they get the one accent colour on the screen. */
.hero__title em {
  font-style: normal;
  color: var(--catch);
}

.hero__lead {
  max-width: 44ch;
  font-size: var(--step-lead);
  color: color-mix(in srgb, var(--paper) 82%, var(--muted));
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Prompt chips — four directions, live inside the frame */
.hero__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.hero__chips .chip {
  flex-direction: column;
  align-items: flex-start;
  gap: 0.125rem;
}

/* Short viewports — landscape phones, a browser window with a lot of chrome.
   Height is the scarce resource here, not width. The headline's fixed 16ch
   wrap and width-only font size were designed against 100svh worth of room;
   without this, the headline alone can fill a landscape phone screen and push
   the CTA below the fold. Wrap by the real available width instead of a fixed
   character count, and size the headline off height as well as width. */
@media (max-height: 36rem) {
  .hero {
    min-height: auto;
    padding-block: 5rem var(--space-3);
  }

  .hero__inner {
    gap: var(--space-2);
  }

  .hero__title {
    font-size: clamp(1.5rem, 6svh, 3rem);
    margin-bottom: var(--space-1);
  }

  .hero__eyebrow {
    margin-bottom: var(--space-1);
  }

  /* The primary action already lives in the fixed header ("Бесплатный
     урок"), and every chip repeats a direction card further down the page.
     At this height neither is load-bearing — cut here first. */
  .hero__lead,
  .hero__chips {
    display: none;
  }
}

/* --- Film -------------------------------------------------------------------
   Everything below only ever renders when a film is configured on the hero.
   Until then the markup is not created at all, so there are no dead controls.

   The film alternates between a held still and a generated clip. Both fill the
   stage identically, because a clip always opens on the still it replaces —
   any difference in fit would show up as a jump at the join. */

.film__still,
.film__clip {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: 60% 50%;
}

/* Faded rather than removed: a display:none media element stops buffering,
   and the spare player has to keep loading the clip that comes next. */
.film__clip.is-off {
  opacity: 0;
}

.film__still {
  /* The push-in is driven per frame from the timeline, so no transition here:
     it would fight the script and lag the join into the clip. */
  transform-origin: 58% 52%;
  will-change: transform;
}

/* Titles ride on top of the picture as text, never burnt into it. */
.film__caption {
  position: absolute;
  z-index: 2;
  right: var(--gutter);
  bottom: 22%;
  max-width: 28ch;
  text-align: right;
  text-shadow: 0 1px 12px var(--ink);
}

.film__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.125rem, 1.8vw, 1.5rem);
  letter-spacing: -0.015em;
  color: var(--paper);
  margin-top: 0.25rem;
  text-wrap: balance; /* keeps "лет" off a line of its own */
}

.film__caption.is-entering {
  animation: caption-in var(--dur-slow) var(--ease);
}

@keyframes caption-in {
  from {
    opacity: 0;
    transform: translateY(0.5rem);
  }
}

@media (max-width: 60rem) {
  .film__caption {
    display: none; /* the frame is too small to carry copy on both sides */
  }
}

/* One row: the chapter track and the transport share a line so the prompt
   chips stay on the first screen. */
.player {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  max-width: 44rem;
  flex-wrap: wrap;
}

.player__track {
  display: flex;
  gap: 3px;
  height: 2.5rem;
  align-items: center;
  flex: 1 1 12rem;
  min-width: 0;
}

/* One segment per chapter: the shape of the film is visible before it plays.
   The button is 24px tall so it can actually be hit; only the bar inside it is
   drawn, which is why the bar is a separate element rather than the button's
   own background. */
.player__chapter {
  flex: 1 1 0;
  height: 1.5rem;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  display: flex;
  align-items: center;
}

.player__bar {
  display: block;
  width: 100%;
  height: 4px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--paper) 28%, transparent);
  overflow: hidden;
  transition: height var(--dur-fast) var(--ease);
}

.player__chapter:hover .player__bar,
.player__chapter:focus-visible .player__bar {
  height: 8px;
}

.player__fill {
  display: block;
  height: 100%;
  background: var(--catch);
  transform: scaleX(0);
  transform-origin: left;
}

/* The pill is what makes the controls readable over a moving picture, so it
   stays close to opaque — a lighter one measured below AA on bright frames. */
.player__buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  padding: 0.375rem;
  border: 1px solid var(--hairline-dark);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--ink) 88%, transparent);
  backdrop-filter: blur(10px);
  width: fit-content;
}

.player__buttons button {
  min-height: 2.5rem;
  padding: 0.375rem 0.875rem;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease);
}

.player__buttons button:hover {
  background: color-mix(in srgb, var(--paper) 14%, transparent);
}

.player__time {
  padding-inline: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  color: color-mix(in srgb, var(--paper) 82%, transparent);
}

/* A chip outside its own chapter stays reachable but steps back visually. */
.hero__chips li.is-dimmed .chip {
  opacity: 0.45;
}

/* Where a chip lands. One pulse, then gone — a permanent marker would just be
   another piece of decoration. */
.is-chip-target {
  animation: chip-target 1.4s var(--ease);
}

@keyframes chip-target {
  0%,
  100% {
    border-color: var(--hairline);
  }
  25% {
    border-color: var(--catch);
  }
}

@media (prefers-reduced-motion: reduce) {
  .is-chip-target {
    animation: none;
    border-color: var(--catch);
  }
}

@media (max-width: 48rem) {
  .hero {
    padding-block: 6.5rem var(--space-4);
  }

  .hero__chips .chip {
    width: 100%;
  }

  /* A thumb needs more than 24px to land on a chapter. */
  .player__chapter {
    height: 2.25rem;
  }
}

/* --------------------------------------------------------------------------
   Shared blocks
   -------------------------------------------------------------------------- */

.card {
  padding: var(--space-4);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  background: var(--bg-raised);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.card__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--step-h3);
  letter-spacing: -0.015em;
  line-height: 1.2;
}

.card__meta {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.06em;
  color: var(--fg-muted);
}

.card--featured {
  border-color: var(--fg-accent);
}

/* Card artwork bleeds to the card's edges — the padding lives on the card.
   An image is a replaced element, so align-self: stretch leaves it at its
   content width; the width has to be stated to cover both negative margins. */
.card__art {
  width: calc(100% + var(--space-4) * 2);
  /* The global reset caps images at 100%, which would undo the bleed. */
  max-width: none;
  margin: calc(var(--space-4) * -1) calc(var(--space-4) * -1) 0;
  border-radius: var(--radius-card) var(--radius-card) 0 0;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.figure-wide {
  margin-top: var(--space-5);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.figure-wide img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.figure-wide figcaption {
  padding-top: var(--space-2);
  font-size: var(--step-small);
  color: var(--fg-muted);
}

/* Four directions read as two pairs, not as a row of three with an orphan.
   Each card also needs room for its own prompt line and description. */
.cards--directions {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 48rem) {
  .cards--directions {
    grid-template-columns: minmax(0, 1fr);
  }
}

.rule-list {
  display: grid;
  gap: var(--space-4);
  counter-reset: rule;
}

.rule {
  display: grid;
  gap: var(--space-1);
  padding-top: var(--space-3);
  border-top: 1px solid var(--hairline);
}

.timeline {
  display: grid;
  gap: var(--space-3);
}

.timeline__row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr);
  gap: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px solid var(--hairline);
}

@media (max-width: 40rem) {
  .timeline__row {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
  }
}

.faq__item {
  border-top: 1px solid var(--hairline);
  padding-block: var(--space-2);
}

.faq__item summary {
  cursor: pointer;
  font-weight: 600;
  padding-block: var(--space-1);
}

.faq__item p {
  color: var(--fg-muted);
  padding-top: var(--space-1);
  max-width: 62ch;
}

/* --------------------------------------------------------------------------
   Direction cards — the richest block on the page
   -------------------------------------------------------------------------- */

.card__text {
  color: var(--fg-muted);
}

/* Skills list. A tick would be a decoration; a dash is just a list marker and
   stays out of the way of the words. */
.list-dash li {
  position: relative;
  padding-left: 1.25rem;
  color: var(--fg-muted);
  font-size: var(--step-small);
}

.list-dash li + li {
  margin-top: 0.375rem;
}

.list-dash li::before {
  content: "—";
  position: absolute;
  left: 0;
  color: var(--fg-accent);
}

/* "First lesson" — the concrete promise. Set apart because it is the one line
   a parent quotes back to you. */
.card__first {
  margin-top: auto;
  padding-top: var(--space-2);
  border-top: 1px solid var(--hairline);
  font-size: var(--step-small);
}

.card__first strong {
  color: var(--fg);
}

.card__note {
  font-size: var(--step-small);
  color: var(--fg-muted);
  border-left: 2px solid var(--fg-accent);
  padding-left: var(--space-2);
}

/* --------------------------------------------------------------------------
   Pricing
   -------------------------------------------------------------------------- */

.tariffs {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  align-items: stretch;
}

.tariff__price {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  letter-spacing: -0.02em;
  line-height: 1;
}

.tariff__save {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  color: var(--fg-accent);
  letter-spacing: 0.04em;
}

.tariff .btn {
  margin-top: auto;
}

.tariff {
  position: relative;
}

/* Sits in normal flow, above the title. It used to float out of the flow to
   keep the three tariff titles on one baseline, but "Мастерская" plus the
   badge is wider than a card ever reliably is — the title's font size scales
   with viewport width while the card's own width scales with the grid and
   the rail, and those two don't move together. At some combination of the
   two an absolute badge collided with the title text (confirmed at several
   widths, including plain desktop). A badge that pushes the title down by a
   fixed, small amount is a far more common pricing-page pattern than one
   that overlaps it. */
.tariff__badge {
  display: inline-block;
  margin-bottom: var(--space-2);
  padding: 0.25rem 0.75rem;
  border-radius: var(--radius-pill);
  background: var(--fg-accent);
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.06em;
}

.payment {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--hairline);
}

.payment__list {
  display: grid;
  gap: var(--space-2);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  margin-top: var(--space-3);
}

.payment__list li {
  font-size: var(--step-small);
  color: var(--fg-muted);
}

.payment__list strong {
  display: block;
  color: var(--fg);
}

/* --------------------------------------------------------------------------
   Parents, teachers, works
   -------------------------------------------------------------------------- */

.promises {
  display: grid;
  gap: var(--space-4);
}

.promise {
  display: grid;
  gap: var(--space-1);
  padding-top: var(--space-3);
  border-top: 1px solid var(--hairline);
}

.promise h3 {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--step-h3);
}

.promise p {
  color: var(--fg-muted);
  max-width: 56ch;
}

/* Reserves two lines whether the role needs them or not, so the description
   under it starts at the same height in every card. */
.teacher__role {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  color: var(--fg-machine);
  letter-spacing: 0.04em;
  min-height: 2.7em;
}

.teacher blockquote {
  color: var(--fg);
  font-style: italic;
}

/* Student work told in the child's own voice. Deliberately not tidied up — the
   unevenness is the proof. */
.work__quote {
  color: var(--fg-muted);
}

.work__by {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.04em;
  color: var(--fg-accent);
}

/* --------------------------------------------------------------------------
   Form
   -------------------------------------------------------------------------- */

.form {
  display: grid;
  gap: var(--space-2);
  max-width: 34rem;
  margin-top: var(--space-4);
}

.form__row {
  display: grid;
  gap: var(--space-2);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
}

.field {
  display: grid;
  gap: 0.375rem;
}

.field label {
  font-size: var(--step-small);
  color: var(--fg-muted);
}

.field input {
  /* Inputs carry an intrinsic width of about 20 characters. Left alone it
     pushes the grid track past the viewport on narrow screens. */
  min-width: 0;
  width: 100%;
  min-height: 3rem;
  padding: 0.625rem 0.875rem;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-input);
  background: var(--bg-raised);
  color: var(--fg);
}

.field input::placeholder {
  color: color-mix(in srgb, var(--fg-muted) 80%, transparent);
}

.consent {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  font-size: var(--step-small);
  color: var(--fg-muted);
}

.consent input {
  margin-top: 0.3rem;
  width: 1.125rem;
  height: 1.125rem;
  accent-color: var(--catch);
  flex: none;
}

.form__notice {
  min-height: 1.5rem;
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  color: var(--fg-accent);
}

.form__note {
  font-size: var(--step-small);
  color: var(--fg-muted);
  max-width: 46ch;
}

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

.site-footer {
  background: var(--ink);
  color: var(--paper);
  padding-block: var(--space-6) var(--space-4);
  border-top: 1px solid var(--hairline-dark);
}

.footer-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  margin-block: var(--space-4);
}

.footer-grid h2 {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--space-2);
}

/* Footer links are the smallest touch targets on the page, so they get their
   own padding rather than relying on the line box. */
.footer-grid a {
  display: inline-block;
  padding-block: 0.4375rem;
  font-size: var(--step-small);
}

.footer-grid a:hover {
  color: var(--gen-light);
}

/* Legal items with no page to link to yet. Muted and unstyled as a link so
   they don't read as clickable when they are not — a fake link is worse than
   plain text. */
.footer-grid li:not(:has(a)) {
  padding-block: 0.4375rem;
  font-size: var(--step-small);
  color: var(--muted);
}

.footer__contacts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  font-size: var(--step-small);
  color: var(--muted);
}

.footer__legal {
  margin-top: var(--space-3);
  font-size: var(--step-small);
  color: var(--muted);
}
