/* ============================================================================
 * motion.css — every state that moves, in one file, loaded last.
 *
 * Three rules hold the whole thing together.
 *
 *  1. Only transform and opacity move. Colour, border and shadow may change
 *     state, in 200ms or less. Nothing animates on a loop.
 *  2. The composition is split so nothing has to fight for the same property:
 *     a CSS reveal writes the individual `translate` and `scale` properties,
 *     JavaScript parallax and tilt write inline `transform`, and a hover
 *     writes `transform` too. They stack without a wrapper element.
 *  3. Anything hidden until it is revealed is hidden only under `html.js`, so
 *     a reader with no JavaScript is given the page in full.
 *
 * The file ends with one reduced-motion block that returns every state below
 * to rest. It wins on source order, not on `!important`: the blanket switch at
 * the end of base.css is the only `!important` in the motion layer, and it has
 * to stay the last word.
 * ==========================================================================*/

/* --- 1. reveal ------------------------------------------------------------
 * Moved here from base.css. The default is a rise; four variants cover the
 * cases where a rise is the wrong direction.
 * ------------------------------------------------------------------------*/
html.js [data-reveal] {
  opacity: 0;
  translate: 0 18px;
  transition: opacity var(--d-reveal) var(--ease),
              translate var(--d-reveal) var(--ease),
              scale var(--d-reveal) var(--ease);
  transition-delay: calc(var(--i, 0) * 60ms);
}
html.js [data-reveal="left"] { translate: -22px 0; }
html.js [data-reveal="right"] { translate: 22px 0; }
html.js [data-reveal="scale"] { translate: 0 18px; scale: .96; }
html.js [data-reveal="fade"] { translate: none; }
html.js [data-reveal].is-in { opacity: 1; translate: none; scale: none; }

/* The eyebrow's own bar draws itself in after the line it belongs to has
 * arrived, which is the smallest possible way of saying "this section starts
 * here". */
html.js [data-reveal] .eyebrow::before,
html.js .eyebrow[data-reveal]::before {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--d-ui) var(--ease);
  transition-delay: calc(var(--i, 0) * 60ms + 150ms);
}
html.js [data-reveal].is-in .eyebrow::before,
html.js .eyebrow[data-reveal].is-in::before { transform: scaleX(1); }

/* --- 2. dividers ----------------------------------------------------------
 * A row's hairline draws from the left as the row arrives. The real border is
 * made transparent and a pseudo-element stands in for it, so the row keeps
 * exactly the height it had, and a reader without JavaScript still sees a
 * plain border.
 * ------------------------------------------------------------------------*/
html.js .seg[data-reveal],
html.js .cap + .cap[data-reveal] { position: relative; border-top-color: transparent; }
html.js .seg[data-reveal]::before,
html.js .cap + .cap[data-reveal]::before {
  content: '';
  position: absolute; left: 0; right: 0; top: -1px; height: 1px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--d-reveal) var(--ease);
  transition-delay: calc(var(--i, 0) * 60ms);
}
html.js .band--dark .seg[data-reveal]::before,
html.js .band--dark .cap + .cap[data-reveal]::before { background: var(--on-dark-line); }
html.js .seg[data-reveal].is-in::before,
html.js .cap + .cap[data-reveal].is-in::before { transform: scaleX(1); }

/* --- 3. room to drift -----------------------------------------------------
 * A layer that moves inside a clipped box has to be bigger than the box, or
 * the drift uncovers a bare strip at one edge. Each of these buys exactly the
 * clamp its layer is given in the markup.
 * ------------------------------------------------------------------------*/
html.js .deco--tile[data-parallax] { inset: -32px 0; }
html.js .deco--corner[data-parallax] { top: -20px; }
html.js .slot--live img { height: calc(100% + 28px); margin-top: -14px; }

/* --- 4. pointer tilt ------------------------------------------------------
 * motion.js writes the rotation inline. This only declares the 3D context and
 * hints the compositor while a tilt is actually running: a permanent
 * will-change would keep a layer alive on every page for nothing.
 * ------------------------------------------------------------------------*/
.tilt { transform-style: preserve-3d; }
html.js .tilt.is-tilting { will-change: transform; }

/* --- 5. header ------------------------------------------------------------
 * At rest the pill is a quiet tint over the hero. Once the page has moved it
 * takes a shadow, a brighter edge, and four per cent off its own size, because
 * it is now over content rather than over its own band. The shrink is a
 * transform, so the header's height never changes: everything that measures
 * the header — the sub-navigation rail, the sticky media, the offset a
 * fragment link needs — gets one number for the whole page.
 *
 * Scrolling away hides it; scrolling back, focusing inside it, or opening a
 * menu brings it straight back.
 * ------------------------------------------------------------------------*/
.site-header { transition: transform var(--d-ui) var(--ease); }
.site-header .nav {
  /* The pill overrides .glass's tint per scroll state, so the scrim strength
   * has to be kept in step with it by hand: page text must not resolve through
   * the glass in either state. */
  background: rgba(13, 19, 51, .82);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18), inset 0 -1px 0 rgba(255, 255, 255, .04);
  transform-origin: 50% 0;
  transition: background var(--d-ui) var(--ease),
              border-color var(--d-ui) var(--ease),
              box-shadow var(--d-ui) var(--ease),
              transform var(--d-ui) var(--ease);
}
.site-header.is-stuck .nav {
  background: rgba(13, 19, 51, .94);
  border-color: rgba(255, 255, 255, .26);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22), inset 0 -1px 0 rgba(255, 255, 255, .04), var(--shadow-dark);
  transform: scale(.96);
}
html.js .site-header.is-hidden { transform: translateY(-110%); }

/* --- 5b. the light on the glass ---------------------------------------------
 * The lens glides between items and the sheen slides under the pointer. The
 * lens's travel is a FLIP: glass.js sets its final width and height at once,
 * starts it at a transform that reproduces the box it had a frame ago, and
 * lets that transform run to rest. The capsule stretches a little in flight
 * and is a true pill again the moment it lands. Nothing but transform and
 * opacity ever animates.
 * ------------------------------------------------------------------------*/
.lens { transition: transform var(--d-glass) var(--ease-glass), opacity var(--d-ui) var(--ease); }
.glass__sheen { transition: opacity var(--d-cross) var(--ease); }
.glass__sheen.is-lit { opacity: 1; }

/* --- 5c. the dock -----------------------------------------------------------
 * Off the screen inside the hero and once the footer is in view: the bubble
 * drops below the bottom edge. Opening swaps the bubble for the tray: the tray
 * grows up out of the bubble's position while the bubble shrinks away under
 * it. Visibility steps rather than eases, for the same reason the menu panels
 * step it: focus cannot move into a thing the browser still calls hidden.
 * ------------------------------------------------------------------------*/
html.js .subnav--dock {
  translate: 0 120%; opacity: 0; visibility: hidden;
  transition: translate var(--d-glass) var(--ease-glass), opacity var(--d-ui) var(--ease),
              visibility 0s linear var(--d-glass);
}
html.js .subnav--dock.is-shown {
  translate: none; opacity: 1; visibility: visible;
  transition: translate var(--d-glass) var(--ease-glass), opacity var(--d-ui) var(--ease), visibility 0s;
}
html.js .subnav--dock .subnav__handle {
  transform-origin: 50% 100%;
  transition: opacity var(--d-ui) var(--ease), scale var(--d-ui) var(--ease), visibility 0s;
}
html.js .subnav--dock.is-open .subnav__handle {
  opacity: 0; scale: .9; visibility: hidden;
  transition: opacity var(--d-ui) var(--ease), scale var(--d-ui) var(--ease), visibility 0s linear var(--d-ui);
}
html.js .subnav--dock .subnav__tray {
  opacity: 0; translate: 0 10px; scale: .9; visibility: hidden;
  transform-origin: 50% 100%;
  transition: opacity var(--d-ui) var(--ease), translate var(--d-ui) var(--ease),
              scale var(--d-ui) var(--ease), visibility 0s linear var(--d-ui);
}
html.js .subnav--dock.is-open .subnav__tray {
  opacity: 1; translate: none; scale: none; visibility: visible;
  transition: opacity var(--d-ui) var(--ease), translate var(--d-glass) var(--ease-glass),
              scale var(--d-glass) var(--ease-glass), visibility 0s;
}

/* --- 6. the walkthrough ---------------------------------------------------
 * The pinned device's screens cross-fade with a short rise, so a screen
 * arrives rather than simply appearing. Below 900px nothing here applies:
 * every step already carries its own screen.
 * ------------------------------------------------------------------------*/
@media (min-width: 900px) {
  html.js .showcase__screens .device {
    translate: 0 12px;
    scale: .98;
    transition: opacity var(--d-cross) var(--ease),
                translate var(--d-cross) var(--ease),
                scale var(--d-cross) var(--ease);
  }
  html.js .showcase__screens .device.is-on { translate: none; scale: none; }
}

/* --- 7. hover -------------------------------------------------------------
 * Only where there is a pointer that can hover, and only ever a nudge. Hover
 * uses `transform`, which leaves `translate` free for the reveal underneath
 * it, so a card that has just arrived can still be lifted.
 * ------------------------------------------------------------------------*/
@media (hover: hover) and (pointer: fine) {
  .card {
    transition: transform var(--d-ui) var(--ease),
                box-shadow var(--d-ui) var(--ease),
                border-color var(--d-ui) var(--ease);
  }
  .card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
  .card--dark:hover { box-shadow: var(--shadow-dark); }
  .footer-col a { transition: transform var(--d-ui) var(--ease), color var(--d-ui) var(--ease); }
  .footer-col a:hover { transform: translateX(2px); }
}

/* --- 8. panels that open --------------------------------------------------
 * Content only. A height never animates: a <details> that grows by measuring
 * itself is the kind of thing that breaks the moment the copy changes.
 * ------------------------------------------------------------------------*/
@keyframes dw-fade-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}
html.js .faq-item[open] > div,
html.js .cur[open] .cur__menu { animation: dw-fade-in var(--d-ui) var(--ease) both; }

/* --- 9. motion off --------------------------------------------------------
 * Every state above, back at rest, and every transition that could carry it
 * there switched off at source.
 *
 * base.css ends with a blanket that takes every duration on the page to
 * nothing, and that blanket is what ships. It is not what is tested: the gate
 * deletes it from the CSSOM first and then measures, so this block has to
 * stand on its own. Anything with a duration and a name on the watched list
 * belongs here — including the ones that only change colour, which are
 * allowed to take 200ms when motion is on and should not when it is off.
 * ------------------------------------------------------------------------*/
@media (prefers-reduced-motion: reduce) {
  html.js [data-reveal] { opacity: 1; translate: none; scale: none; transition: none; }

  html.js [data-reveal] .eyebrow::before,
  html.js .eyebrow[data-reveal]::before,
  html.js .seg[data-reveal]::before,
  html.js .cap + .cap[data-reveal]::before,
  html.js .showcase__steps::after { transform: none; transition: none; }

  html.js .showcase__screens .device { translate: none; scale: none; transition: none; }
  html.js .show-step,
  html.js .show-step__n { transition: none; }

  html.js .deco--tile[data-parallax] { inset: 0; }
  html.js .deco--corner[data-parallax] { top: 0; }
  html.js .slot--live img { height: 100%; margin-top: 0; }

  /* The header still changes ground and shadow when it sticks — that is a
   * state, not a movement — but it does so at once, and the pill does not
   * shrink, because a scale that snaps is a jump. */
  .site-header,
  .site-header .nav { transition: none; }
  .site-header.is-stuck .nav { transform: none; }
  html.js .site-header.is-hidden { transform: none; }
  html.js .tilt.is-tilting { will-change: auto; }

  html.js .nav__menu,
  html.js .nav__trigger[aria-expanded="true"] + .nav__menu { transition: none; }

  /* The lens still marks the current item; it jumps there. The sheen is off
   * altogether: glass.js stops writing it. The dock still appears and opens,
   * with nothing sliding or growing. */
  .lens, .glass__sheen { transition: none; }
  html.js .subnav--dock,
  html.js .subnav--dock.is-shown,
  html.js .subnav--dock .subnav__handle,
  html.js .subnav--dock.is-open .subnav__handle,
  html.js .subnav--dock .subnav__tray,
  html.js .subnav--dock.is-open .subnav__tray { transition: none; }
  html.js .subnav--dock { translate: none; }
  html.js .subnav--dock.is-open .subnav__handle,
  html.js .subnav--dock .subnav__tray { translate: none; scale: none; }

  html.js .faq-item[open] > div,
  html.js .cur[open] .cur__menu { animation: none; }

  /* .btn:active keeps its one-pixel press: that is feedback, not motion. */
  .btn, .card, .footer-col a { transition: none; }
  .card:hover, .card--dark:hover, .footer-col a:hover { transform: none; }
}
