/*
 * kuyara landing page.
 *
 * Every colour, space, radius and type role comes from tokens.css. Nothing here
 * authors a new value. Two structural rules from docs/design/design-language.md
 * decide the shape of this file:
 *
 *   Law 1  hierarchy is carried by type and space and only confirmed by surface.
 *          There are no cards-with-shadows here; a plane is a plane.
 *   Law 7  the finished, un-animated page is the page. Scroll motion is an
 *          enhancement layered on top of a document that is already complete,
 *          which is what an engine without scroll-driven animations gets.
 *
 * ADR 0018 binds the stage: the condition tint colours the bounded plane the
 * garments sit on, never a full-width strip, and only primary text or icons may
 * sit on it. In the dark appearance all seven states resolve to the neutral
 * stage, so dark deliberately carries the story through the garments alone.
 */

/* --------------------------------------------------------------- foundation */

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

body.ku-landing {
  margin: 0;
  background: var(--ku-background);
  color: var(--ku-text-primary);
  font-family: var(--ku-font-sans);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

.ku-landing :is(p, h1, h2, ul, ol) {
  margin: 0;
  padding: 0;
  list-style: none;
}

.ku-landing a {
  color: var(--ku-brand-accent);
  text-underline-offset: 3px;
}

.ku-landing :focus-visible {
  outline: var(--ku-border-width-strong) solid var(--ku-focus-ring);
  outline-offset: 3px;
}

.ku-shell {
  width: 100%;
  max-width: var(--ku-max-content-width);
  margin-inline: auto;
  padding-inline: var(--ku-space-lg);
}

/* A band is the landing-page equivalent of a screen, not of a section inside
   one, so it is separated by trailing space rather than by the section step. */
.ku-band {
  padding-block: var(--ku-space-2xl);
}

.ku-band__head {
  display: flex;
  flex-direction: column;
  gap: var(--ku-space-md);
  margin-bottom: var(--ku-space-xl);
}

.ku-measure {
  max-width: 34em;
  color: var(--ku-text-secondary);
}

/* ------------------------------------------------------------------- header
   The switcher markup is _includes/lang-switcher.html and all of its styling
   lives in _includes/lang-head.html, already written against these same tokens.
   Only its trailing space belongs to the page that places it. */

.ku-header .lang-switcher {
  margin-bottom: 0;
  padding-block: var(--ku-space-sm);
}

/* ---------------------------------------------------------------------- hero */

.ku-hero {
  display: flex;
  flex-direction: column;
  gap: var(--ku-space-md);
  padding-top: var(--ku-space-lg);
}

.ku-symbol {
  width: 56px;
  height: 56px;
  fill: var(--ku-brand-accent);
}

.ku-hero__name {
  /* The lowercase spelling is part of the identity and never title-cased. */
  text-transform: lowercase;
}

.ku-hero__line {
  max-width: 30em;
  color: var(--ku-text-secondary);
}

.ku-hero__board {
  margin-top: var(--ku-space-xl);
}

/* --------------------------------------------------------------- the stage
   A bounded plane with the garments on it. Not a full-bleed band: ADR 0021
   section 3 refuses a separate full-width atmosphere strip, and the caption
   therefore sits below the plane rather than on it. */

.ku-stage {
  --ku-board-max: 420px;
  --ku-board-fill: var(--ku-stage);
  --ku-board-ink: var(--ku-text-primary);
  display: grid;
  place-items: center;
  /* The plane is only as wide as the composition it carries plus its container
     inset, so the garments never float in an empty field. */
  max-width: calc(var(--ku-board-max) + var(--ku-space-lg) * 2);
  padding: var(--ku-space-lg);
  background: var(--ku-stage);
  border-radius: var(--ku-radius-sheet);
}

/* The 1.9 stroke is a proportion of the 64-unit drawing, not a CSS pixel value,
   so the rendered scale is what sets how heavy the drawn edge reads. Capping the
   board's width keeps that edge at the weight the silhouettes were authored for. */
.ku-stage .board {
  display: block;
  width: 100%;
  max-width: var(--ku-board-max);
  height: auto;
}

.ku-stage--clear {
  --ku-board-fill: var(--ku-stage-clear-day);
  background: var(--ku-stage-clear-day);
}

.ku-stage--veiled {
  --ku-board-fill: var(--ku-stage-veiled-day);
  background: var(--ku-stage-veiled-day);
}

.ku-stage--falling {
  --ku-board-fill: var(--ku-stage-falling-day);
  background: var(--ku-stage-falling-day);
}

.ku-state {
  display: flex;
  flex-direction: column;
  gap: var(--ku-space-md);
}

.ku-state + .ku-state {
  margin-top: var(--ku-space-xl);
}

/* -------------------------------------------------------------- how it works */

.ku-steps {
  display: flex;
  flex-direction: column;
  gap: var(--ku-space-md);
  max-width: 36em;
}

.ku-step {
  display: flex;
  gap: var(--ku-space-md);
  align-items: baseline;
}

.ku-step__index {
  flex: none;
  min-width: 1.5em;
  color: var(--ku-text-secondary);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------ the alternates */

.ku-alts {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--ku-space-md);
}

.ku-alts .ku-stage {
  padding: var(--ku-space-md);
}

/* ----------------------------------------------------------------- the lines */

.ku-lines {
  display: flex;
  flex-direction: column;
  gap: var(--ku-space-sm);
  max-width: 34em;
}

.ku-lines li {
  padding-left: var(--ku-space-lg);
  border-left: var(--ku-border-width-strong) solid var(--ku-border-defined);
}

/* -------------------------------------------------------------------- the CTA
   Apple's marketing guidelines: minimum badge height 40px, minimum clear space
   one quarter of the rendered height (13px at 50px), one badge per layout, and
   the badge is never modified, angled or animated. Nothing below scales or
   transitions it. The left clear space is the shell's own 16px inset. */

.ku-cta {
  display: flex;
  flex-direction: column;
  gap: var(--ku-space-md);
  align-items: flex-start;
}

.ku-badge {
  display: inline-block;
  margin: 13px 13px 13px 0;
}

.ku-badge img {
  display: block;
  height: 50px;
  width: auto;
}

.ku-cta__soon {
  color: var(--ku-text-secondary);
}

/* ------------------------------------------------------------------- footer */

.ku-footer {
  padding-block: var(--ku-space-2xl);
  border-top: var(--ku-border-width-subtle) solid var(--ku-border-subtle);
}

.ku-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--ku-space-xl);
  margin-bottom: var(--ku-space-md);
}

.ku-footer__links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--ku-touch-target);
}

.ku-footer__legal {
  max-width: 44em;
  color: var(--ku-text-secondary);
}

.ku-footer__legal + .ku-footer__legal {
  margin-top: var(--ku-space-sm);
}

/* --------------------------------------------------------------- wide screens
   The measure stays at maxContentWidth 800. Only the alternates row and the
   hero gain a second axis, because those are pictures and not prose. */

@media (min-width: 720px) {
  .ku-band {
    padding-block: calc(var(--ku-space-2xl) * 2);
  }

  .ku-alts {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ------------------------------------------------------- the enhancement layer
   Gated once, on capability alone. `@supports` keeps an engine without
   scroll-driven animations on the finished page; that is the only fallback
   path. The page animates for every reader, whatever the operating system's
   Reduce Motion setting says.
   Transform and opacity only, so the work stays on the compositor thread. */

@supports (animation-timeline: view()) {
  /* The timeline is named on the track, which never moves. The pinned child
     reads it by ancestor lookup, the only lookup direction that exists. */
  .ku-track {
    view-timeline-name: --ku-stage-scene;
    view-timeline-axis: block;
    min-height: 300vh;
  }

  .ku-pin {
    position: sticky;
    top: 0;
    display: grid;
    min-height: 100svh;
    align-content: center;
  }

  /* Stacked in one grid cell. Only the tinted plane cross-dissolves; the
     captions cut, because two texts blended at 50 percent is unreadable and
     reads as a rendering fault rather than a transition. The three boards sit
     on the same three slot centres, so a dissolve swaps a garment in place. */
  .ku-pin > .ku-state {
    grid-area: 1 / 1;
    margin-top: 0;
    padding-block: var(--ku-space-md);
  }

  /* `contain` is exactly the window in which a track taller than the viewport
     covers the scrollport, which is exactly the window in which the stage is
     pinned: progress 0 pins, progress 1 unpins. The first plane never
     animates, so there is always one opaque layer underneath. */
  .ku-state--veiled .ku-stage,
  .ku-state--falling .ku-stage {
    animation: ku-cross linear both;
    animation-timeline: --ku-stage-scene; /* must follow the shorthand */
  }

  .ku-state--veiled .ku-stage {
    animation-range: contain 26% contain 36%;
  }

  .ku-state--falling .ku-stage {
    animation-range: contain 60% contain 70%;
  }

  @keyframes ku-cross {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }

  /* The two cuts land at 31% and 65%, the midpoint of each dissolve, so only
     one caption is ever painted. `step-end` holds each keyframe's value for
     the whole interval, and `both` holds the end values outside the range. */
  .ku-state__caption {
    animation-timing-function: step-end;
    animation-fill-mode: both;
    animation-timeline: --ku-stage-scene;
  }

  .ku-state--clear .ku-state__caption {
    animation-name: ku-cut-out;
    animation-range: contain 30% contain 31%;
  }

  .ku-state--veiled .ku-state__caption {
    animation-name: ku-cut-mid;
    animation-range: contain 0% contain 65%; /* 47.69% of 65% is the 31% cut */
  }

  .ku-state--falling .ku-state__caption {
    animation-name: ku-cut-in;
    animation-range: contain 64% contain 65%;
  }

  @keyframes ku-cut-out {
    from {
      opacity: 1;
    }
    to {
      opacity: 0;
    }
  }

  @keyframes ku-cut-in {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }

  @keyframes ku-cut-mid {
    0% {
      opacity: 0;
    }
    47.69% {
      opacity: 1;
    }
    100% {
      opacity: 0;
    }
  }

  /* Content arrives in reading order (Law 7). Nothing translates under a hero
     value and nothing loops, so no ambient motion sits behind large type. */
  .ku-rise {
    animation: ku-rise linear both;
    animation-timeline: view();
    animation-range: entry 10% entry 70%;
  }

  @keyframes ku-rise {
    from {
      opacity: 0;
      transform: translateY(2vh);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }
}

/* --------------------------------------------- the Firefox reveal, JS-applied
   landing.js adds `ku-js-reveal` only where the CSS path is absent, so these
   rules never hide content on a page whose script did not run. */

.ku-js-reveal .ku-rise {
  opacity: 0;
  transform: translateY(2vh);
  transition:
    opacity var(--ku-motion-deliberate) linear,
    transform var(--ku-motion-deliberate) linear;
}

.ku-js-reveal .ku-rise.ku-is-in {
  opacity: 1;
  transform: none;
}
