/* ==========================================================================
   Crawford Legal — Base
   Reset, document defaults, typography, focus, layout primitives, motion.
   ========================================================================== */

/* ---------- Fonts: self-hosted, preloaded in <head> ---------- */
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-variable.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchor targets clear the fixed header */
  scroll-padding-top: var(--header-h-slim);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--bg-dark);
  color: var(--text-on-dark);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  font-weight: var(--fw-regular);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }

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

/* <picture> is a wrapper, not a box. Without this it generates an auto-height
   block, so a child <img height:100%> resolves against *it* rather than the
   sized container — the image collapses to its intrinsic height instead of
   filling (breaks every object-fit: cover crop on the page). */
picture { display: contents; }

button, input, textarea, select {
  font: inherit;
  color: inherit;
  margin: 0;
}
button { background: none; border: 0; padding: 0; cursor: pointer; }

/* ---------- Typography ---------- */
.u-display,
.u-h1, .u-h2, .u-h3 {
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-heading);
  text-wrap: balance;
}

.u-display {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
}
.u-h1 { font-size: var(--fs-h1); line-height: var(--lh-tight); }
.u-h2 { font-size: var(--fs-h2); line-height: var(--lh-heading); }
.u-h3 { font-size: var(--fs-h3); line-height: var(--lh-heading); }

.u-lead {
  font-size: var(--fs-lead);
  line-height: 1.5;
  max-width: var(--measure);
  text-wrap: pretty;
}
.u-body { max-width: var(--measure); text-wrap: pretty; }
.u-small { font-size: var(--fs-small); }

/* Section label / eyebrow. Always paired with a real heading — never the
   sole means of conveying a section's identity. */
.u-label {
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  line-height: 1.2;
  margin: 0;
}

.u-serif  { font-family: var(--font-serif); }
.u-accent { color: var(--accent-on-dark); }
.t-light .u-accent { color: var(--accent-on-light); }

/* ---------- Links ---------- */
a { color: inherit; text-decoration: none; }

/* Animated underline — the default link treatment in body copy. */
.u-link {
  color: var(--accent-on-dark);
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--d-base) var(--e-out);
  padding-bottom: 2px;
}
.u-link:hover,
.u-link:focus-visible { background-size: 100% 1px; }
.t-light .u-link { color: var(--accent-on-light); }

/* ---------- Focus ---------- */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--focus-on-dark);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
.t-light :focus-visible { outline-color: var(--focus-on-light); }
.t-cta   :focus-visible { outline-color: var(--focus-on-cta); }

.c-skip-link {
  position: absolute;
  top: var(--sp-3);
  left: var(--sp-3);
  z-index: var(--z-skip);
  padding: var(--sp-3) var(--sp-5);
  background: var(--c-orange);
  color: var(--c-black);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  border-radius: var(--r-md);
  transform: translateY(-160%);
  transition: transform var(--d-fast) var(--e-out);
}
.c-skip-link:focus-visible { transform: translateY(0); }

/* ---------- Themes ---------- */
.t-dark {
  background: var(--bg-dark);
  color: var(--text-on-dark);
}
.t-dark-2 {
  background: var(--bg-dark-2);
  color: var(--text-on-dark);
}
.t-light {
  background: var(--bg-light);
  color: var(--text-on-light);
}
.t-light-2 {
  background: var(--bg-light-2);
  color: var(--text-on-light);
}
.t-cta {
  background: var(--bg-cta);
  color: var(--text-on-cta);
}

.t-dark .u-muted, .t-dark-2 .u-muted { color: var(--text-on-dark-muted); }
.t-light .u-muted, .t-light-2 .u-muted { color: var(--text-on-light-muted); }
.t-cta .u-muted { color: var(--text-on-cta-muted); }

/* ---------- Layout ---------- */
.l-shell {
  width: 100%;
  max-width: var(--max-w);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.l-section { padding-block: var(--sp-section); }
.l-section--tight { padding-block: var(--sp-section-y); }

.l-stack > * + * { margin-top: var(--sp-4); }
.l-stack-lg > * + * { margin-top: var(--sp-6); }

/* Section head: label + heading, used across every section. */
.c-section-head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin-bottom: var(--sp-8);
}
.c-section-head .u-label { color: var(--accent-on-dark); }
.t-light .c-section-head .u-label,
.t-light-2 .c-section-head .u-label { color: var(--accent-on-light); }

/* A thin rule that draws itself when its section reveals. */
.c-rule {
  height: 1px;
  background: var(--rule-on-dark);
  transform-origin: left center;
  border: 0;
  margin: 0;
}
.t-light .c-rule, .t-light-2 .c-rule { background: var(--rule-on-light); }
.t-cta .c-rule { background: var(--rule-on-cta); }

.u-visually-hidden {
  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;
}

/* ==========================================================================
   Motion primitives
   All reveal animation is transform + opacity only (compositor-friendly).
   Content is visible by default; JS adds .js to <html> before
   paint, which arms the hidden state. Without JS, nothing is ever hidden.
   ========================================================================== */

/* NOTE: deliberately no `will-change` here. There are ~75 reveal targets on
   the page; promoting them all would hold dozens of compositor layers alive
   for the whole session (Chrome starts dropping frames, and headless capture
   can go blank). opacity/transform already composite without the hint.
   will-change is reserved for the two continuously-animated elements: the
   hero image and the parallax image. */
.js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition:
    opacity var(--d-slow) var(--e-editorial),
    transform var(--d-slow) var(--e-editorial);
  transition-delay: var(--reveal-delay, 0ms);
}
.js [data-reveal].is-revealed {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* Line-by-line editorial text reveal. Each line is masked and rises.
   The .c-anim-text markup only exists once JS has split the heading, so
   these rules are inert without JS — the plain heading text renders as-is. */
.c-anim-text { display: block; }
/* The mask crops to the LINE BOX, and --lh-display (0.94) is tighter than the
   glyphs are tall — so caps/ascenders (C, l, f, i-dots) get their tops sliced
   off, and descenders (y) their tails. Pad the mask out and pull it back in
   with negative margins: the mask gains room, the visual line spacing doesn't
   change. Values must exceed the (1 − line-height) overshoot at both ends. */
.c-anim-text__line {
  display: block;
  overflow: hidden;
  padding-top: 0.2em;
  margin-top: -0.2em;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
/* translateY, NOT translate3d. translate3d forces a composited layer, and iOS
   Safari is long-known to mis-clip a composited child against an ancestor's
   `overflow: hidden` — it leaves a seam at the clip edge. Reported on iPhone as
   a faint dotted rule under each line, in that line's own colour, sitting right
   at the mask's bottom boundary. Chrome does not reproduce it. A 2D transform
   still animates on the compositor here but does not force the layer. */
.c-anim-text__inner {
  display: block;
  transform: translateY(100%);
  transition: transform var(--d-slower) var(--e-editorial);
  transition-delay: var(--line-delay, 0ms);
}
/* Revealed by the element itself, or by any revealing ancestor. A split
   heading with no revealing ancestor is marked .is-revealed by JS, so a
   line can never be left stranded off-screen. */
.is-revealed .c-anim-text__inner,
.c-anim-text.is-revealed .c-anim-text__inner { transform: translateY(0); }

/* Belt and braces for the iOS clip seam. The mask exists ONLY to hide the line
   while it slides up; once it has arrived it has no job, and an element that
   isn't clipping can't leave a clip artifact. JS drops this class on
   transitionend, so the mask is live exactly as long as it is needed. Without
   JS, or if the event never fires, the mask simply stays — same as before. */
.c-anim-text__line.is-unmasked { overflow: visible; }

/* Image mask reveal — the image scales down as its cover wipes away. */
.c-mask {
  position: relative;
  overflow: hidden;
  background: var(--c-charcoal-2);
}
.c-mask > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.js .c-mask[data-reveal] > img {
  transform: scale(1.12);
  transition: transform var(--d-hero) var(--e-editorial);
}
.js .c-mask[data-reveal].is-revealed > img { transform: scale(1); }

.js .c-mask[data-reveal]::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--bg-dark);
  transform-origin: bottom center;
  transition: transform var(--d-slower) var(--e-editorial);
  transition-delay: var(--reveal-delay, 0ms);
}
.js .c-mask[data-reveal].is-revealed::after {
  transform: scale3d(1, 0, 1);
}

/* Reduced motion: no travel, no mask wipe, no scale. Only a gentle fade,
   and never a delay that withholds content. */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] {
    transform: none;
    transition: opacity 200ms linear;
    transition-delay: 0ms;
  }
  .js [data-reveal].is-revealed { transform: none; }
  .c-anim-text__line { overflow: visible; }
  .c-anim-text__inner { transform: none; transition: none; transition-delay: 0ms; }
  .js .c-mask[data-reveal] > img { transform: none; transition: none; }
  .js .c-mask[data-reveal]::after { display: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}
