/* ============================================================
   VAULT BASE  ::  the discipline layer every design shares

   Harvested from a-lign.studio (see docs/a-lign-technique-dossier.md).
   Their polish turned out to cost under 1KB of CSS and zero JavaScript;
   the 406KB of animation machinery on top was not the lesson.

   This file is buyer-NEUTRAL on purpose. It carries no personality: no
   colours, no type faces, no spacing values, no component looks. Each
   design keeps all of that. What lives here is the invisible hand that
   makes four visibly different designs feel like one studio made them.

   Every design links this FIRST, then its own stylesheet.
   ============================================================ */

:root {
  /* ---- 1.1 One ease, one duration, everywhere ----
     a-lign registers a single symmetric ease and one default duration, and
     every effect on the site inherits them. That, more than any individual
     animation, is why unrelated effects feel like one hand made them.

     Theirs is 600ms. Ours is 200ms deliberately: a homeowner is in a hurry,
     and motion on a trade site should read as responsiveness, not as
     choreography. Their rule survives even though their number does not.

     The rule: anything driven by scroll position gets --ease-linear (the
     scrollbar IS the easing). Anything triggered gets --ease. */
  --ease: cubic-bezier(.65, 0, .35, 1);
  --ease-linear: linear;
  --dur: 200ms;
  --dur-slow: 320ms;      /* only for things that physically travel further */

  /* ---- 1.5 Measures in ch, not px ----
     Nothing on their site runs the full container width. A measure is a
     property of the TEXT, so it belongs in ch and never needs a breakpoint. */
  --measure-display: 16ch;   /* headlines: short enough to land in one breath */
  --measure-heading: 24ch;
  --measure-body: 62ch;
}

/* ---- 1.11 A complete reduced-motion kill switch ----
   Their site honours the preference but leaves some scroll-driven state
   behind. Ours does it properly: nothing animates, nothing transitions,
   nothing scroll-behaves, and critically NO ELEMENT IS LEFT HIDDEN waiting
   for an animation that will never run. A reveal that starts at opacity 0
   and is never revealed is a blank page, which is worse than no animation.

   `!important` is deliberate here. This block has to beat anything a design
   sets, including inline styles, because the alternative is a page a
   motion-sensitive reader cannot use. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto !important; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  /* anything a design hides pre-animation must be visible, not merely still */
  [data-reveal] { opacity: 1 !important; transform: none !important; }
}

/* ---- Viewport units: svh, never vh ----
   `100vh` on a phone is the viewport WITHOUT the browser chrome, so a
   full-height hero is cut off by the address bar on first paint and then
   jumps when it retracts. `svh` is the small viewport, which is the one
   actually visible. */
.u-screen { min-height: 100svh; }

/* ---- 1.10 The image plate ----
   Every image sits on a neutral plate so a slow photo leaves a considered
   grey rectangle rather than a white hole that collapses the layout. Each
   design supplies the colour; this supplies the behaviour. */
.plate-img { background: var(--plate, rgba(0, 0, 0, .06)); display: block; }
.plate-img > img,
.plate-img > svg { display: block; width: 100%; }

/* ---- Measures as utilities ----
   Designs apply these rather than re-deriving a max-width per component. */
.measure { max-width: var(--measure-body); }
.measure-heading { max-width: var(--measure-heading); }
.measure-display { max-width: var(--measure-display); }

/* ---- Skip link + screen-reader text ----
   Identical in all four designs, so it lives once. Colours come from the
   design via --ink / --paper. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
