/* Registered so the wipe position can be interpolated inside the gradient
   stops below. */
@property --academy-lead-wipe {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

@keyframes academy-lead-wipe {
  from {
    --academy-lead-wipe: -12%;
  }

  to {
    --academy-lead-wipe: 112%;
  }
}

@keyframes plans-card-reveal {
  from {
    /* opacity: 0; */
    translate: 0 var(--plans-reveal-offset);
  }

  to {
    /* opacity: 1; */
    translate: 0 0;
  }
}

@layer pages {
  :root {
    /* Matches --color-accent-6, baked in because image bullets cannot inherit
       the accent color. */
    --icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 15 15'%3E%3Cpath d='M10.6015 3.90815C10.7903 3.61941 11.1779 3.53792 11.4667 3.72651C11.7555 3.91533 11.837 4.30288 11.6484 4.59175L7.39837 11.0917C7.29822 11.2449 7.13558 11.3469 6.95404 11.3701C6.77251 11.3932 6.58945 11.3359 6.45404 11.2128L3.70404 8.71284L3.62005 8.61811C3.44857 8.38342 3.4589 8.05252 3.66205 7.82905C3.86511 7.60576 4.19344 7.56371 4.4433 7.71186L4.54584 7.78706L6.75287 9.79292L10.6015 3.90815Z' fill='%237ADAF8' fill-rule='evenodd' clip-rule='evenodd'/%3E%3C/svg%3E");

    --section-spacing: 5rem;
    --section-spacing-cta: 3rem;
  }

  @media (width >= 768px) {
    :root {
      --section-spacing: 7rem;
      --section-spacing-cta: 4rem;
    }
  }

  /* Shared vertical rhythm between page sections. Scoped to `main` so the
     navbar, a sibling of `main`, can never pick these margins up. The closing
     CTA sits closer to the plans above it. */
  @scope (main) {
    section:not(.closing-cta-component) {
      margin-block-start: var(--section-spacing);
    }

    .closing-cta-component {
      margin-block-start: var(--section-spacing-cta);
    }
  }

  @scope (.hero) {
    position: relative;
    height: calc(100lvh - var(--navbar-height));
    padding-inline: 32px;

    @media (width >= 768px) {
      :scope {
        height: 80dvh;
        padding-inline: 10%;
      }
    }

    &::before {
      position: absolute;
      inset: 0;
      z-index: -1;
      background: linear-gradient(to bottom, oklch(0.000% 0.0000 0.00) 0.00%, oklch(10.370% 0.0101 240.75) 14.29%, oklch(15.690% 0.0199 254.69) 28.57%, oklch(22.388% 0.0382 255.58) 42.86%, oklch(29.872% 0.0600 255.91) 57.14%, oklch(35.741% 0.0751 255.87) 71.43%, oklch(39.197% 0.0846 256.23) 85.71%, oklch(40.656% 0.0878 255.97) 100.00%);
      content: '';
    }

    /* A tiled grain instead of the SVG turbulence filter: the noise rasterizes
       once at tile size, not across the whole viewport every frame. Density
       variants keep one noise texel per device pixel so the grain stays fine
       on retina; the plain URLs are the image-set fallback. */
    &::after {
      position: absolute;
      inset: 0;
      z-index: -1;
      background-image: url("/images/grain-4e849628aa3136fcea3ea2bece6cd853.png?vsn=d"), url("/images/grain-4e849628aa3136fcea3ea2bece6cd853.png?vsn=d");
      background-image:
        -webkit-image-set(url("/images/grain-4e849628aa3136fcea3ea2bece6cd853.png?vsn=d") 1x, url("/images/grain@2x-958f155fbc28999b950be73cbd966674.png?vsn=d") 2x, url("/images/grain@3x-ff1292473dd041cf95ae5e79188f3810.png?vsn=d") 3x),
        -webkit-image-set(url("/images/grain-4e849628aa3136fcea3ea2bece6cd853.png?vsn=d") 1x, url("/images/grain@2x-958f155fbc28999b950be73cbd966674.png?vsn=d") 2x, url("/images/grain@3x-ff1292473dd041cf95ae5e79188f3810.png?vsn=d") 3x);
      background-image:
        image-set(url("/images/grain-4e849628aa3136fcea3ea2bece6cd853.png?vsn=d") 1x, url("/images/grain@2x-958f155fbc28999b950be73cbd966674.png?vsn=d") 2x, url("/images/grain@3x-ff1292473dd041cf95ae5e79188f3810.png?vsn=d") 3x),
        image-set(url("/images/grain-4e849628aa3136fcea3ea2bece6cd853.png?vsn=d") 1x, url("/images/grain@2x-958f155fbc28999b950be73cbd966674.png?vsn=d") 2x, url("/images/grain@3x-ff1292473dd041cf95ae5e79188f3810.png?vsn=d") 3x);
      background-position: 0 0, 29px 13px;
      background-repeat: repeat, repeat;
      background-size: 48px 48px, 53px 53px;
      opacity: 0.45;
      pointer-events: none;
      content: '';
    }

    .hero-inner {
      position: relative;
      height: 100%;
      max-inline-size: 1282px;
      margin-inline: auto;
    }

    .background-overlay {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      object-position: center;
      opacity: 0.2;
      mix-blend-mode: plus-lighter;
    }

    .portrait-overlay {
      position: absolute;
      inset: 0;
      display: flex;
      align-items: flex-end;
      justify-content: flex-end;
    }

    .portrait {
      position: relative;
      width: auto;

      height: 60%;
      @media (width >= 1024px) {
        height: 75%;
      }
    }

    .content {
      position: absolute;
      inset: 0;
      display: flex;
      align-items: center;
      justify-content: flex-start;
      padding-inline-end: 40%;

      @media (width >= 1024px) {
        padding-inline-end: 20%;
      }
    }

    .content-inner {
      & > p {
        font-size: var(--font-size--1);
      }

      & > * + * {
        margin-top: 2rem;
      }
    }

    .content-inner h1 {
      color: oklch(90% 0 0);
      line-height: 1;
      font-weight: 600;
      font-style: normal;

      font-size: var(--font-size-4);
    }
  }

  @scope (.academy-intro-component) to ([data-component]) {
    display: flex;
    justify-content: center;
    padding-inline: 32px;

    @media (width >= 768px) {
      :scope {
        padding-inline: 10%;
      }
    }

    .inner {
      flex: 1 1 100%;
      max-inline-size: 1282px;
    }

    .intro {
      max-inline-size: 48rem;
      margin-inline: auto;
      text-align: center;
    }

    .intro > p {
      color: var(--color-text-body);
      font-size: var(--font-size-1);
      font-weight: 300;
      /* Isolates the wipe's repaint to the paragraph it belongs to. */
      contain: paint;

      /* The paragraph is painted with a hard-edged gradient that starts muted
         and wipes to full strength as the text scrolls through the viewport.
         The angle tilts the edge so lower lines trail the ones above them. */
      @supports (animation-timeline: view()) and ((background-clip: text) or (-webkit-background-clip: text)) {
        @media (prefers-reduced-motion: no-preference) {
          --academy-lead-muted: oklch(from var(--color-text-body) l c h / 40%);

          background-image: linear-gradient(
            105deg,
            var(--color-text-body) var(--academy-lead-wipe),
            var(--academy-lead-muted) calc(var(--academy-lead-wipe) + 5%)
          );
          background-clip: text;
          color: transparent;
          animation: academy-lead-wipe linear both;
          animation-timeline: view();
          animation-range: entry 0% cover 33%;
        }
      }
    }

    .intro > p + p {
      margin-top: 1.5rem;
    }

    @media (width < 768px) {
      /* Keyed to the containment range so the wipe starts once the lead is fully
         on screen and runs while it travels up, rather than during entry. */
      .intro > p {
        animation-range: contain 0% contain 50%;
      }
    }
  }

  @scope (.centered-text-component) to ([data-component]) {
    /* Distance from the viewport edge to the section content. Used both to
       inset the static content and to align the full-bleed slider tracks. */
    --inline-edge: 32px;

    /* How far the plan cards start below their resting position during the
       reveal. Shared with the slider's reserved space so it never overflows. */
    --plans-reveal-base-offset: 48px;
    --plans-reveal-offset: var(--plans-reveal-base-offset);
    /* Each later card starts further down, deepening the wave across the row. */
    --plans-reveal-step: 56px;
    /* How much later each card's reveal range starts, which sets the speed
       difference between consecutive cards. */
    --plans-reveal-stagger: 6%;
    /* The deepest staggered offset (4 revealed cards), reserved below the
       slider so no card's translate counts as scrollable overflow. */
    --plans-reveal-max-offset: calc(
      var(--plans-reveal-base-offset) + 3 * var(--plans-reveal-step)
    );

    display: flex;
    justify-content: center;
    /* Track widths need the section's own width, which percentages inside
       grid-auto-columns can't reference (they resolve against the content box). */
    container-type: inline-size;

    @media (width >= 768px) {
      :scope {
        --inline-edge: max(10cqw, calc((100cqw - 1282px) / 2));
      }
    }

    .inner {
      flex: 1 1 100%;
      /* Without this the flex item's automatic min-size becomes the
         min-content width of the plan row, stretching the whole section. */
      min-inline-size: 0;
    }

    header {
      max-inline-size: calc(48rem + 2 * var(--inline-edge));
      margin-inline: auto;
      padding-inline: var(--inline-edge);
      text-align: center;
    }

    header h2 {
      margin-top: 0.75rem;
      color: var(--color-neutral-7);
      font-size: var(--font-size-3);
      font-weight: 600;
      line-height: 1.15;
    }

    header > p {
      margin-top: 1rem;
      color: var(--color-text-body);
      font-size: var(--font-size--1);
    }

    .slider-container {
      margin-top: 3rem;
      /* The plans list is a scroll container of its own, so the timeline is
         keyed to this wrapper to track the page's vertical scrollport. */
      view-timeline-name: --plans-reveal;
    }

    .slider-component {
      display: flex;
      gap: 1.5rem;
      overflow-x: auto;
      /* The reveal's downward translate is contained by this reserved padding,
         so it never counts as scrollable overflow. The negative margin keeps
         the following content where it would sit without the padding. */
      padding-block-end: var(--plans-reveal-max-offset);
      margin-block-end: calc(-1 * var(--plans-reveal-max-offset));
      scroll-snap-type: x mandatory;
      /* Lets the reveal be scoped to the slider's horizontal scroll position. */
      container-type: scroll-state;
      container-name: slider-scroller;
      scrollbar-width: none;
      padding-inline: var(--inline-edge);
      scroll-padding-inline: var(--inline-edge);

      &::-webkit-scrollbar {
        display: none;
      }

      @media (width >= 768px) {
        display: grid;
        grid-auto-flow: column;
        /* Size each track so 3 1/2 cards span from the content edge to the
           viewport edge, letting the last one bleed into the right padding. */
        grid-auto-columns: calc((100cqw - var(--inline-edge) - 3 * 1.5rem) / 3.5);
      }
    }

    .slide-component {
      flex: 0 0 min(calc(100% - 3rem), 360px);
      scroll-snap-align: start;
      /* Cards can exceed the viewport height, so leave breathing room when
         scrollIntoView has to align their top edge to the viewport. */
      scroll-margin-block-start: 2rem;
      display: flex;
      flex-direction: column;
      overflow: hidden;
      border: 1px solid var(--color-neutral-3);
      border-radius: var(--radius-3);
      background-color: var(--color-neutral-2);

      /* Only the cards initially in view slide up; the rest are already
         revealed by the time they are scrolled into the slider. */
      &:nth-child(-n + 4) {
        @supports (animation-timeline: view()) {
          @media (prefers-reduced-motion: no-preference) {
            animation: plans-card-reveal linear both;
            animation-timeline: --plans-reveal;
          }
        }

        /* Scroll timelines ignore time-based animation-delay, so the stagger
           shifts the range: later cards start later and finish together. */
        @supports (animation-range: entry calc(sibling-index() * 1%)) {
          @media (prefers-reduced-motion: no-preference) {
            animation-range: entry
              calc((sibling-index() - 1) * var(--plans-reveal-stagger))
              entry 70%;

            /* Later cards fall from further away so the stagger reads as a
               wave rather than a single block of cards. */
            --plans-reveal-offset: calc(
              var(--plans-reveal-base-offset) + (sibling-index() - 1) *
                var(--plans-reveal-step)
            );
          }
        }

        /* Suppress the reveal once the slider leaves its start position;
           scroll-state queries replace the dropped `:snapped` pseudo-class. */
        @container slider-scroller scroll-state(scrollable: inline-start) {
          animation: none;
        }
      }
    }

    /* Toggled by the slider hook to hold the completed state while the section
       is in view, so scrolling up cannot run the animation in reverse. */
    .slider-container[data-revealed] .slide-component:nth-child(-n + 4) {
      animation: none;
    }

    /* Fallback for engines without scroll-state queries, which cannot match
       the rule above. The slider hook mirrors it as a data attribute. */
    @supports not (container-type: scroll-state) {
      .slider-container[data-scrolled] .slide-component:nth-child(-n + 4) {
        animation: none;
      }
    }

    .slider-actions {
      /* The scroller's reserved bottom padding overlaps this row, and Safari
         hit-tests its composited scroll layer above unpositioned siblings. */
      position: relative;
      z-index: 1;
      display: flex;
      justify-content: flex-end;
      margin-top: 2rem;
      padding-inline: var(--inline-edge);
    }

    .next-slide-button {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      inline-size: 2.75rem;
      block-size: 2.75rem;
      color: var(--color-neutral-7);
      border: 1px solid var(--color-neutral-4);
      border-radius: var(--radius-round);
      background-color: transparent;
      cursor: pointer;
      transition: background-color 160ms var(--ease-quad-out);

      /* Hidden rather than removed from the flow: a disabled button keeps
         absorbing clicks so they never reach the content underneath. */
      &[data-at-end] {
        opacity: 0;
        cursor: default;
      }

      &:hover {
        background-color: var(--color-neutral-3);
      }
    }

    .landing-card-component .media {
      position: relative;
      overflow: hidden;
      aspect-ratio: 21 / 9;
      background: var(--color-neutral-3);
    }

    .landing-card-component .media img {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

    .landing-card-component .media::after {
      content: "";
      position: absolute;
      inset: auto 0 0 0;
      height: 75%;
      pointer-events: none;
      background: linear-gradient(
        to top,
        oklch(from var(--color-card-image-scrim) l c h / 95%) 0%,
        oklch(from var(--color-card-image-scrim) l c h / 60%) 45%,
        transparent 100%
      );
    }

    .landing-card-component .media-content {
      position: absolute;
      inset: auto 0 0 0;
      z-index: 1;
      display: flex;
      flex-direction: column;
      gap: 0.25rem;
      padding: 1.5rem 2rem;
    }

    .landing-card-component .body {
      display: flex;
      flex-direction: column;
      gap: 0.75rem;
      padding: 2rem;
    }

    .landing-card-component .media-content p {
      color: var(--color-neutral-6);
      font-family: 'Space Mono', ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas,
        'DejaVu Sans Mono', monospace;
      font-size: var(--font-size--2);
      font-weight: 500;
      letter-spacing: 0.1em;
      text-transform: uppercase;
    }

    .landing-card-component .media-content h3 {
      color: var(--color-neutral-8);
      font-size: var(--font-size-1);
      font-weight: 600;
    }

    .landing-card-component .body ul {
      margin-top: 0.25rem;
      padding-inline-start: 0;
    }

    .landing-card-component .body li {
      display: flex;
      gap: 0.5rem;
      align-items: flex-start;
      list-style: none;
      color: var(--color-text-body);
      font-size: var(--font-size--1);

      &::before {
        content: '';
        flex: none;
        inline-size: 0.75rem;
        block-size: 1lh;
        background-image: var(--icon-check);
        background-repeat: no-repeat;
        background-position: center;
      }

      & + li {
        margin-top: 0.625rem;
      }
    }
  }

  @scope (.closing-cta-component) {
    padding-inline: 32px;

    @media (width >= 768px) {
      :scope {
        padding-inline: 10%;
      }
    }

    .inner {
      display: flex;
      flex-direction: column;
      row-gap: 1.5rem;
      column-gap: 2rem;
      padding: 2rem;
      border: 1px solid var(--color-neutral-3);
      border-radius: var(--radius-3);
      background-color: var(--color-neutral-2);

      @media (width >= 768px) {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
      }
    }

    h3 {
      color: var(--color-neutral-7);
      font-size: var(--font-size-1);
      font-weight: 600;
      line-height: 1.15;
    }

    p {
      margin-top: 0.75rem;
      color: var(--color-text-body);
      font-size: var(--font-size--1);
    }

    .cta-actions {
      flex: none;
    }
  }

  @scope (.footer-component) to ([data-component]) {
    margin-block-start: var(--section-spacing);
    padding-block: 3rem;
    padding-inline: 32px;
    border-top: 1px solid var(--color-neutral-3);

    @media (width >= 768px) {
      :scope {
        padding-block: 4rem;
        padding-inline: 10%;
      }
    }

    .inner {
      display: grid;
      gap: 2rem;
      max-inline-size: 1282px;
      margin-inline: auto;

      @media (width >= 768px) {
        grid-template-columns: 1fr auto;
        align-items: center;
        gap: 2.5rem 2rem;
      }
    }

    .brand {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 1rem;
    }

    .brand p {
      max-inline-size: 24rem;
      color: var(--color-text-body);
      font-size: var(--font-size--1);
    }

    .social {
      display: flex;
      gap: 1.25rem;

      a {
        display: flex;
        color: var(--color-neutral-5);
        transition: var(--transition-link);

        &:hover {
          color: var(--color-link-hover);
        }
      }
    }

    .inner > p {
      padding-block-start: 2rem;
      border-top: 1px solid var(--color-neutral-3);
      color: var(--color-neutral-5);
      font-size: var(--font-size--2);

      @media (width >= 768px) {
        grid-column: 1 / -1;
      }
    }
  }
}
