/* ==========================================================================
   Allutech Systems — reset, typography, utilities
   ========================================================================== */

/* ---- Reset --------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 96px;
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd, ul, ol {
  margin: 0;
}

/* Wrapped in :where() so the reset carries ZERO specificity. As a bare
   `ul[class]` it scored (0,1,1) and silently beat any component rule that set
   padding on a list — `.stats` (0,1,0) lost its panel padding, and
   `.breadcrumbs__list` lost its vertical padding, with no error to notice. */
:where(ul[class], ol[class]) {
  padding: 0;
  list-style: none;
}

body {
  min-height: 100vh;
  background: var(--mist);
  color: var(--ink-60);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img, picture, video, canvas, svg, iframe {
  display: block;
  max-width: 100%;
}

img { height: auto; }

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

table {
  border-collapse: collapse;
  width: 100%;
}

/* The [hidden] attribute is the single source of truth for open/closed state on
   mega panels, the drawer and back-to-top. An author `display` rule on those
   components would otherwise beat the UA stylesheet's [hidden] and strand them
   visible, so make it unconditional. */
[hidden] { display: none !important; }

hr {
  border: 0;
  border-top: var(--hairline);
  margin: 0;
}

::selection {
  background: var(--edge);
  color: var(--pane);
}

/* ---- Typography ----------------------------------------------------- */

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' var(--wdth-display);
  font-weight: 600;
  line-height: var(--lh-head);
  letter-spacing: var(--ls-display);
  color: var(--ink);
  text-wrap: balance;
}

h1 { font-size: var(--fs-h2); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-h4); }

.display {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
}

p { text-wrap: pretty; }

p + p { margin-top: 1em; }

a {
  color: inherit;
  text-decoration-color: var(--aluminium);
  text-underline-offset: .18em;
  transition: color var(--dur-fast) var(--ease-out),
              text-decoration-color var(--dur-fast) var(--ease-out);
}

a:hover {
  color: var(--edge);
  text-decoration-color: currentColor;
}

strong, b { font-weight: 500; color: var(--ink); }

small { font-size: var(--fs-small); }

/* The mono face is the voice of the spec sheet: eyebrows, spec tables,
   step numbers, dimension labels. Nowhere else. */
.mono {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: var(--ls-mono);
  text-transform: uppercase;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--ls-mono);
  text-transform: uppercase;
  color: var(--edge);
}

.lead {
  font-size: clamp(1rem, .95rem + .22vw, 1.125rem);
  color: var(--ink-60);
}

/* ---- Accessibility --------------------------------------------------- */

:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
  border-radius: 2px;
}

:focus:not(:focus-visible) { outline: none; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: 0;
  left: var(--gutter);
  z-index: var(--z-toast);
  transform: translateY(-120%);
  background: var(--ink);
  color: var(--pane);
  padding: 12px 20px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  letter-spacing: var(--ls-mono);
  text-transform: uppercase;
  text-decoration: none;
  transition: transform var(--dur-fast) var(--ease-out);
}

.skip-link:focus {
  transform: translateY(0);
  color: var(--pane);
}

/* ---- Utilities ------------------------------------------------------- */

.u-hide { display: none !important; }
.u-ink { color: var(--ink); }
.u-edge { color: var(--edge); }
.u-center { text-align: center; }
.u-nowrap { white-space: nowrap; }
.u-measure { max-width: 62ch; }
.u-measure-narrow { max-width: 46ch; }
.u-mt-s { margin-top: 12px; }
.u-mt-m { margin-top: 24px; }
.u-mt-l { margin-top: var(--stack); }

/* ---- Sash reveal ------------------------------------------------------
   Elements slide open like a window sash rather than fading up.
   assets/js/reveal.js adds .is-revealed via IntersectionObserver.
   Without JS everything stays visible: the closed state is only applied
   once the observer has claimed the element (html.js + [data-reveal]).   */

[data-reveal] {
  clip-path: inset(0 0 0 0);
}

.js [data-reveal]:not(.is-revealed) {
  clip-path: inset(0 0 0 100%);
}

.js [data-reveal] {
  transition: clip-path var(--dur-sash) var(--ease-sash);
  transition-delay: var(--reveal-delay, 0ms);
}
/* Deliberately no will-change here: there are 50+ reveal targets on the
   homepage, and promoting every one to its own compositing layer for the
   whole session costs far more than it saves on a single 620ms transition. */

/* ---- Reveal: rise ------------------------------------------------------
   For cards. A sash wipe suits a photograph or a block of type, where the
   clip edge reads as a pane opening — but travelling that same hard edge
   across a card that carries its own shadow reads as a rendering glitch,
   because the shadow appears before the card it belongs to. These rise and
   fade instead, which is what "arriving" looks like.
   Same specificity as the rules above (0,2,0), so this must stay after them. */

.js [data-reveal="rise"] {
  clip-path: none;
  transition: opacity 560ms var(--ease-out),
              transform 620ms var(--ease-sash);
  transition-delay: var(--reveal-delay, 0ms);
}

.js [data-reveal="rise"]:not(.is-revealed) {
  clip-path: none;
  opacity: 0;
  /* Small. A card that travels far enough to notice is a card that arrives
     late, and six of them in sequence turns a section into a wait. */
  transform: translateY(16px);
}

.js [data-reveal="rise"].is-revealed {
  opacity: 1;
  transform: none;
}

/* ---- Motion budget ---------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }

  .js [data-reveal]:not(.is-revealed) { clip-path: inset(0 0 0 0); }
}
