/*
 * Site-wide motion and material layer, applied from the apple-design skill
 * (fluid, physical interaction translated for the web).
 *
 * Loaded after load-partials.js on every public page, together with
 * assets/apple-design.js. Rules are prefixed `html body` so they outrank the
 * pages' own inline rules (e.g. `.btn:hover`) and the header/footer partial
 * styles that load later, while deliberately stronger page rules still win.
 * Nothing here changes colour, font, layout or copy.
 *
 * To remove the whole layer: delete this file, apple-design.js, and the two
 * tags that load them.
 */

:root {
  /* Critically damped spring (damping 1.0, response 0.4s), sampled into
     linear(). No overshoot: nothing on this site is thrown by a gesture
     except the phone sheet, which uses --spring-flick. */
  --spring: linear(0, .082, .243, .413, .562, .682, .774, .841, .89, .925, .949, .965, .977, .984, .99, .993, .995, .997, .998, .999, 1);
  --spring-dur: 600ms;
  --press-dur: 100ms;
  interpolate-size: allow-keywords;
}
html body { --ease: 450ms var(--spring); }
html body :is(a, button, summary) { -webkit-tap-highlight-color: transparent; }

/* --- Response: feedback on press, not on release. Hover lifts only where a
   real pointer exists, so a phone never keeps a stuck hover. --- */
html body :is(.btn, .ci-btn, .chip, .nav-link, .cat-link, .tc-btn, .sg-cta, .ji-cta,
              .site-modal-close, .trial-close, .mobile-menu-toggle, .mobile-nav-link) {
  transition: transform var(--spring-dur) var(--spring), background var(--ease),
              border-color var(--ease), color var(--ease), box-shadow var(--ease),
              padding var(--ease), gap var(--ease);
}
html body :is(.btn, .ci-btn, .nav-link, .mobile-menu-toggle, .wa-float):hover { transform: none; }
@media (hover: hover) {
  html body .btn:hover { transform: translateY(-1px); }
  html body .wa-float:hover { transform: translateY(-2px); }
}
html body :is(.btn, .ci-btn, .chip, .nav-link, .cat-link, .tc-btn, .sg-cta,
              .site-modal-close, .trial-close, .mobile-menu-toggle, .mobile-nav-link):active {
  transform: scale(.97);
  transition-duration: var(--press-dur);
  transition-timing-function: ease-out;
}
html body .wa-float { transition: transform var(--spring-dur) var(--spring), box-shadow var(--ease); }
html body .wa-float:active { transform: scale(.95); transition-duration: var(--press-dur); }

/* Cards answer the press only when the press lands on something that
   navigates. A 1.5% squeeze keeps the pointer inside the target. */
html body :is(.ci, .tc, .ji, .offer-card) {
  transition: transform var(--spring-dur) var(--spring), background var(--ease),
              box-shadow var(--ease), border-color var(--ease);
}
html body :is(.ci, .tc, .offer-card):has(:is(a, button):active),
html body .ji:active {
  transform: scale(.985);
  transition-duration: var(--press-dur);
}
/* Hover lifts on cards: pointer devices only. */
html body .tc:hover { transform: none; }
@media (hover: hover) {
  html body .tc:hover { transform: translateY(-3px); }
}

/* --- Materials: the header is a translucent layer that content scrolls
   under. At the top of the page nothing is under it, so no divider; once
   content passes beneath, a soft edge shadow replaces the hard 1px line. --- */
html body header {
  background: rgba(247,244,236,.72);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  border-bottom-color: transparent;
  transition: box-shadow var(--ease), border-color var(--ease), background var(--ease);
}
html body.is-scrolled header {
  box-shadow: 0 1px 0 rgba(23,23,23,.06), 0 10px 24px -14px rgba(23,23,23,.18);
}
@media (prefers-reduced-transparency: reduce) {
  html body header { background: var(--bg); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  html body header { background: var(--bg); border-bottom-color: var(--text); backdrop-filter: none; }
}

/* --- Header dropdowns grow down out of their trigger and return the same
   way. The 140ms close delay stays: it forgives a pointer that briefly slips
   off the menu. --- */
html body header .cat-popover {
  transform-origin: top center;
  transform: translateX(-50%) translateY(-4px) scale(.96);
  transition: opacity 200ms ease-out, transform var(--spring-dur) var(--spring);
  transition-delay: 140ms;
}
html body header .cat-item:hover .cat-popover,
html body header .cat-item:focus-within .cat-popover {
  transform: translateX(-50%) translateY(0) scale(1);
  transition-delay: 0ms;
}

/* Phone menu slides down from under the header and back up. Needs
   @starting-style / allow-discrete; older browsers simply show it. */
@media (max-width: 720px) {
  html body header .mobile-nav {
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 200ms ease-out, transform var(--spring-dur) var(--spring),
                display var(--spring-dur) allow-discrete;
  }
  html body header.is-mobile-nav-open .mobile-nav {
    opacity: 1;
    transform: none;
  }
  @starting-style {
    html body header.is-mobile-nav-open .mobile-nav { opacity: 0; transform: translateY(-8px); }
  }
}

/* --- Typography: even line breaks on headings, no orphans in body copy. --- */
html body :is(h1, h2) { text-wrap: balance; }
html body main p { text-wrap: pretty; }

/* --- Reveals: shorter travel, spring settle. The first reveal on a page is
   its hero, which is on screen immediately (apple-design.js marks it). --- */
html body .r {
  transform: translateY(14px);
  transition: opacity 400ms ease-out, transform var(--spring-dur) var(--spring);
}
html body .r.in { transform: none; }
html body .r.ad-instant { opacity: 1; transform: none; transition: none; }

/* Filtering is not a flick, so filtered cards settle without overshoot. */
html body .subject-rail .ci.ci-pop { animation: adSettle var(--spring-dur) var(--spring) both; }
@keyframes adSettle {
  from { opacity: 0; transform: scale(.96) translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* --- Filter chips: one selection pill slides between chips, so the eye
   follows the change. It retargets from wherever it is, so rapid clicks
   never jump. apple-design.js adds .has-pill and the pill element. --- */
html body .has-pill { position: relative; }
html body .has-pill > .chip { position: relative; z-index: 1; }
html body .has-pill > .chip.on { background: transparent; border-color: transparent; }
html body .chip-pill {
  position: absolute; top: 0; left: 0; z-index: 0;
  border-radius: 8px; background: var(--text); pointer-events: none;
  transition: transform var(--spring-dur) var(--spring), width var(--spring-dur) var(--spring);
}
html body .chip-pill.no-anim { transition: none; }

/* --- FAQ <details>: open and close as a spring instead of a jump. --- */
html body details::details-content {
  height: 0; overflow: clip;
  transition: height var(--spring-dur) var(--spring), content-visibility var(--spring-dur) allow-discrete;
}
html body details[open]::details-content { height: auto; }

/* --- Modals: grow out of the button that opened them and shrink back into
   it (transform-origin comes from the press point, set by script), and the
   backdrop materialises (blur ramps in) rather than just fading. --- */
html body :is(.site-modal, .trial-modal) {
  background: rgba(19,19,19,0);
  -webkit-backdrop-filter: blur(0px);
  backdrop-filter: blur(0px);
  transition: opacity 300ms ease-out, visibility 300ms, background 300ms ease-out,
              backdrop-filter 300ms ease-out, -webkit-backdrop-filter 300ms ease-out;
}
html body :is(.site-modal, .trial-modal).is-open {
  background: rgba(19,19,19,.44);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
html body :is(.site-modal-dialog, .trial-dialog) {
  transform-origin: var(--origin, 50% 50%);
  transform: scale(.9);
  opacity: 0;
  transition: transform var(--spring-dur) var(--spring), opacity 250ms ease-out;
}
html body :is(.site-modal, .trial-modal).is-open :is(.site-modal-dialog, .trial-dialog) {
  transform: none; opacity: 1;
}

/* --- Phones: the free-trial form is a bottom sheet. It rises from the
   bottom edge, and can be dragged down (grab the header or the handle) to
   dismiss. apple-design.js drives the drag; these are the rest states. --- */
@media (max-width: 720px) {
  /* The layer stays opaque and only hides once the sheet is fully down, so
     the slide-out is visible instead of being cut off by a fade. */
  html body .trial-modal {
    padding: 0; place-items: end stretch; opacity: 1;
    transition: visibility 0s linear var(--spring-dur), background 300ms ease-out,
                backdrop-filter 300ms ease-out, -webkit-backdrop-filter 300ms ease-out;
  }
  html body .trial-modal.is-open { transition-delay: 0s; }
  html body .trial-dialog {
    width: 100%;
    max-height: calc(100dvh - 24px);
    border-radius: 22px 22px 0 0;
    transform: translateY(100%);
    opacity: 1;
    transform-origin: 50% 100%;
    padding-bottom: env(safe-area-inset-bottom);
  }
  html body .trial-modal.is-open .trial-dialog { transform: translateY(0); }
  html body .trial-dialog.is-dragging { transition: none; }
  html body .trial-head { touch-action: none; cursor: grab; position: relative; padding-top: 26px; }
  html body .trial-head::before {
    content: ''; position: absolute; top: 9px; left: 50%; transform: translateX(-50%);
    width: 40px; height: 5px; border-radius: 999px; background: rgba(23,23,23,.18);
  }
}

@media (prefers-reduced-transparency: reduce) {
  html body :is(.site-modal, .trial-modal).is-open { background: rgba(19,19,19,.7); backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* Reduced motion: keep every state change, drop the travel. The pages'
   own reduced-motion rule already removes transitions; these make sure
   nothing rests at a transformed position. */
@media (prefers-reduced-motion: reduce) {
  html body :is(.site-modal-dialog, .trial-dialog, .r, header .mobile-nav) { transform: none !important; }
  html body header .cat-popover { transform: translateX(-50%) !important; }
  html body details::details-content { transition: none; }
}
