/* ============================================================
   layout.css — grid, section shell, containers, the bleed escape,
   the reveal choreography.
   ============================================================ */

@layer layout {

  /* ---------------------------------------------------------------
     SECTION SHELL

     The rhythm is the whole design: contained block -> full-bleed media
     at ZERO vertical padding -> contained block. Full-bleed media touches
     its neighbours; all breathing room is spent on the contained blocks.
     That is what makes the whitespace read as deliberate rather than as
     uniform padding.

     --pad-section : --gap-block is ~6.9:1 at desktop. Templated sites run
     ~2:1. THIS RATIO IS THE RESTRAINT. Do not tighten it.
     --------------------------------------------------------------- */

  .pg-sect {
    padding-block: var(--pad-section);
    position: relative;
  }

  .pg-sect--sm {
    padding-block: var(--pad-section-sm);
  }

  /* The header and ticker are fixed, so the first section on a page has to
     clear them itself. --pad-section floors at 72px, which is less than the
     92px of chrome, so without this the top of every non-hero page starts
     underneath the nav. The hero opts out because it sets its own padding
     against --h-hero.

     The lead-in uses --pad-section-sm, not --pad-section. A full section's
     rhythm belongs BETWEEN sections; spending it above the first one just
     pushes the page title off the screen. */
  main > .pg-sect:first-child:not(.pg-hero) {
    padding-block-start: calc(var(--h-header) + var(--h-ticker) + var(--pad-section-sm));
  }

  /* Below 768px the ticker docks to the bottom of the viewport, so only the
     header is overhead up here. */
  @media (max-width: 767px) {

    main > .pg-sect:first-child:not(.pg-hero) {
      padding-block-start: calc(var(--h-header) + var(--pad-section-sm));
    }

    /* ...and the docked ticker would otherwise sit on top of the footer. */
    .pg-footer {
      padding-block-end: calc(var(--s-6) + var(--h-ticker) + env(safe-area-inset-bottom));
    }
  }

  .pg-sect--bleed {
    padding-block: var(--pad-bleed);
  }

  /* Media touches its neighbours; no double gap either side. */
  .pg-sect + .pg-sect--bleed,
  .pg-sect--bleed + .pg-sect {
    margin-block-start: 0;
  }

  /* ---------------------------------------------------------------
     THE BLEED ESCAPE

     Full-bleed is a named grid column, never `width: 100vw`. 100vw
     includes the classic scrollbar, so it produces a horizontal scrollbar
     on every Windows and Linux desktop -- and this site makes bleed the
     core rhythm, so that bug would be on nearly every section.
     --------------------------------------------------------------- */

  .pg-sect__inner {
    display: grid;
    grid-template-columns:
      [full-start] minmax(var(--gutter), 1fr)
      [content-start] minmax(0, var(--w-container)) [content-end]
      minmax(var(--gutter), 1fr) [full-end];
  }

  .pg-sect__inner > * {
    grid-column: content;
  }

  .pg-sect__inner > .pg-bleed {
    grid-column: full;
  }

  /* ---------------------------------------------------------------
     GRID
     Permitted spans only: 12 | 7/5 | 5/7 | 4/4/4 | 8/4 | 3/3/3/3.
     6/6 is BANNED for editorial content -- a 50/50 editorial split is the
     fastest way to look like a theme. It is permitted only for the
     two-title catalog card grid, which is a card layout, not composition.
     --------------------------------------------------------------- */

  .pg-grid {
    display: grid;
    gap: var(--gap-grid);
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  @media (min-width: 768px) {
    .pg-grid {
      grid-template-columns: repeat(8, minmax(0, 1fr));
    }
  }

  @media (min-width: 1024px) {
    .pg-grid {
      grid-template-columns: repeat(12, minmax(0, 1fr));
      gap: var(--s-5);
    }
  }

  .pg-col-12 {
    grid-column: span 4;
  }

  .pg-col-8,
  .pg-col-7,
  .pg-col-5,
  .pg-col-4,
  .pg-col-3,
  .pg-col-6 {
    grid-column: span 4;
  }

  @media (min-width: 768px) {

    .pg-col-12 {
      grid-column: span 8;
    }

    .pg-col-8,
    .pg-col-7,
    .pg-col-6 {
      grid-column: span 8;
    }

    .pg-col-5,
    .pg-col-4 {
      grid-column: span 4;
    }

    .pg-col-3 {
      grid-column: span 4;
    }
  }

  @media (min-width: 1024px) {
    .pg-col-12 {
      grid-column: span 12;
    }

    .pg-col-8 {
      grid-column: span 8;
    }

    .pg-col-7 {
      grid-column: span 7;
    }

    .pg-col-6 {
      grid-column: span 6;
    }

    .pg-col-5 {
      grid-column: span 5;
    }

    .pg-col-4 {
      grid-column: span 4;
    }

    .pg-col-3 {
      grid-column: span 3;
    }
  }

  /* House asymmetry. Alignment is left, always -- including the hero. */
  .pg-grid--7-5 > :first-child {
    order: 0;
  }

  .pg-grid--5-7 > :first-child {
    order: 1;
  }

  @media (max-width: 899px) {
    .pg-grid--5-7 > :first-child {
      order: 0;
    }
  }

  /* ---------------------------------------------------------------
     CONTAINERS
     --------------------------------------------------------------- */

  .pg-tight {
    max-inline-size: var(--w-tight);
  }

  .pg-text {
    max-inline-size: var(--w-text);
  }

  .pg-stack > * + * {
    margin-block-start: var(--gap-block);
  }

  .pg-stack--lg > * + * {
    margin-block-start: var(--s-6);
  }

  .pg-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-4);
  }

  /* ---------------------------------------------------------------
     REVEAL CHOREOGRAPHY — "the panel boots"

     The container assembles itself before any content exists inside it.
     Transform-only, so it composites. Nobody in the reference set does
     this, and it is unmistakably "software booting".

     Order: frame top -> frame left -> eyebrow -> title -> body -> CTA.
     --------------------------------------------------------------- */

  [data-reveal-child] {
    opacity: 0;
    transform: translateY(20px);
  }

  .is-in [data-reveal-child] {
    opacity: 1;
    transform: none;
    /* --d is set per child by reveal.js, capped at 5 siblings so a long
       list never trails off screen waiting its turn. */
    transition:
      opacity var(--dur-4) var(--ease-out-hud) var(--d, 0ms),
      transform var(--dur-4) var(--ease-out-hud) var(--d, 0ms);
  }

  /* Line-mask title.
     Two sidebearing fixes, both required:
     - inline: at -0.025em tracking the first glyph's left sidebearing is
       negative and gets clipped by overflow:hidden.
     - block: at line-height 0.94 ascenders and latin-ext diacritics crop.
       The horizontal fix is widely copied; the vertical one is not, and
       it is why most implementations of this effect look subtly wrong. */
  .pg-lm__line {
    display: block;
    overflow: hidden;
    margin-inline-start: -0.5em;
    padding-inline-start: 0.5em;
    margin-block: -0.12em;
    padding-block: 0.12em;
  }

  .pg-lm__line > span {
    display: block;
    transform: translateY(105%);
    transition: transform var(--dur-4) var(--ease-out-hud) var(--d, 0ms);
  }

  .is-in .pg-lm__line > span {
    transform: none;
  }

  /* Reduced motion: the observer STILL fires and applies the final state.
     Content stranded at opacity:0 forever is the classic bug, and it is
     worse than any animation. Only the translate is dropped here -- the
     160ms opacity retention lives in reset.css alongside the blanket
     override it has to outrank. */
  @media (prefers-reduced-motion: reduce) {

    [data-reveal-child] {
      transform: none;
    }

    .pg-lm__line > span,
    .is-in .pg-lm__line > span {
      transform: none;
    }
  }
}
