/* ============================================================
   HWW MOTION + MOTIF SYSTEM — wave 3 (Direction 2, ratified 2026-08-22)
   Additive layer over tokens.css + site.css. No colour literals:
   every colour is var() or color-mix() over ratified tokens.

   Vocabulary
   ----------
   .display-xl        Direction-2 display scale (condensed Archivo)
   .eyebrow           mono microcaps section label with terracotta tick
   .grid100 / .cell   the hundred-year grid (signature object)
   .claim-strip       graphite full-bleed inversion moment
   .m-reveal          orchestrated entrance (js adds .in)
   .m-child           staggered child inside a .m-reveal group
   .m-draw            hairline that draws itself on entry
   Motion doctrine: enters ease-out 500-700ms, staggers 60-90ms,
   micro 150-300ms. EVERYTHING dies under prefers-reduced-motion.
   ============================================================ */

/* ---- Direction-2 display scale ------------------------------ */
.display-xl {
  font-family: var(--hw-font-sans);
  font-weight: 800;
  font-stretch: 75%;
  line-height: 0.94;
  letter-spacing: -0.015em;
  font-size: clamp(3.2rem, 7.6vw, 7.25rem);
}
.display-xl em {
  font-style: normal;
  color: var(--hw-terracotta);
}

/* ---- Direction-2 section heading scale ---------------------- */
.display-lg {
  font-family: var(--hw-font-sans);
  font-weight: 800;
  font-stretch: 82%;
  line-height: 1.04;
  letter-spacing: -0.01em;
  font-size: clamp(2.1rem, 3.8vw, 3.4rem);
}

/* ---- eyebrow: mono label with terracotta tick --------------- */
.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--hw-space-3);
  font-family: var(--hw-font-mono);
  font-size: var(--hw-text-caption);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--hw-field-grey);
}
/* An eyebrow is a field label, so its tick takes the field-label ink.
   tokens.css reserves terracotta for true stopping conditions and
   deliberate human emphasis; drawing it automatically on every eyebrow
   on the site spent that reserve on captioning, which left the colour
   meaning nothing where it actually matters. The tick is now
   opt-in: add .stop where the section states a prohibition or a halt.
   Independently ticked registers (.wa-laws, .category-lines,
   .gov-close, the 2026 cell) carry their own rules and are unchanged. */
.eyebrow::before {
  content: "";
  width: 0.65em;
  height: 0.65em;
  background: var(--hw-field-grey);
  flex: none;
}
.eyebrow.stop::before {
  background: var(--hw-terracotta);
}
/* On the graphite claim strip the field-grey tick drops to 2.90:1 against
   the inverted ground, under the 3.01:1 bar tokens.css sets for a
   meaningful non-text mark. Invert it with the surface, as .claim-strip
   already does for the eyebrow's own text — not by reaching back for
   terracotta, which would re-spend the reserve this wave just restored. */
.claim-strip .eyebrow:not(.stop)::before {
  background: color-mix(in srgb, var(--hw-ground) 58%, transparent);
}

/* ---- the hundred-year grid ---------------------------------- */
.century {
  position: relative;
}
.century-label {
  display: flex;
  justify-content: space-between;
  gap: var(--hw-space-3);
  font-family: var(--hw-font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--hw-field-grey);
  margin-bottom: var(--hw-space-3);
}
.grid100 {
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  gap: clamp(4px, 0.5vw, 7px);
}
.grid100 .cell {
  aspect-ratio: 1;
  background: color-mix(in srgb, var(--hw-graphite) 86%, var(--hw-plan-blue));
  position: relative;
}
.grid100 .cell:hover {
  background: var(--hw-plan-blue);
}
/* year tooltip on hover — data, not decoration */
.grid100 .cell:hover::after {
  content: attr(data-year);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translateX(-50%);
  white-space: nowrap;
  font-family: var(--hw-font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  background: var(--hw-graphite);
  color: var(--hw-ground);
  padding: 4px 8px;
  z-index: 2;
  pointer-events: none;
}
.grid100 .cell.now {
  background: var(--hw-terracotta);
}
/* The 2026 flag: permanent, absolutely positioned above the cell and
   right-anchored (the now-cell is the last column) so it never enters
   flow or overflows the viewport. Hover styling does not apply. */
.grid100 .cell.now::after {
  content: attr(data-year) " — THE REDRAW";
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  white-space: nowrap;
  font-family: var(--hw-font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  background: var(--hw-graphite);
  color: var(--hw-ground);
  padding: 4px 8px;
  z-index: 2;
  pointer-events: none;
}
.grid100 .cell.now:hover::after {
  left: auto;
  right: 0;
  transform: none;
}
/* Running prose, so it takes the caption step and near-zero tracking — see
   the note on .findings-note in index.html. --hw-text-code stays reserved for
   field codes, declaration strips, and chips. */
.century-note {
  font-family: var(--hw-font-mono);
  font-size: var(--hw-text-caption);
  letter-spacing: 0.01em;
  line-height: 1.65;
  color: var(--hw-field-grey);
  margin-top: var(--hw-space-3);
  max-width: 46ch;
}
.century-note b {
  color: var(--hw-terracotta);
  font-weight: 500;
}

/* ---- graphite claim strip ----------------------------------- */
.claim-strip {
  background: var(--hw-graphite);
  color: var(--hw-ground);
  padding: clamp(4rem, 9vw, 6.5rem) var(--hw-margin-sheet);
}
.claim-strip .claim-inner {
  max-width: var(--hw-sheet-max, 72rem);
  margin: 0 auto;
}
.claim-strip .eyebrow {
  color: color-mix(in srgb, var(--hw-ground) 58%, transparent);
}
.claim-strip p.claim-text {
  font-family: var(--hw-font-serif);
  font-weight: 300;
  font-size: clamp(1.55rem, 3.1vw, 2.6rem);
  line-height: 1.34;
  margin-top: var(--hw-space-4);
  text-wrap: balance;
  max-width: 30em;
}
.claim-strip p.claim-text b {
  font-weight: 600;
  border-bottom: 3px solid var(--hw-terracotta);
}

/* ---- orchestrated entrances ---------------------------------
   The hidden pre-entrance state exists ONLY under html.motion, which
   js/motion.js adds after confirming it can animate. No JS, blocked JS,
   or reduced motion => content is simply visible. */
html.motion .m-reveal,
html.motion .m-child {
  opacity: 0;
  transform: translateY(14px);
}
html.motion .m-reveal.in,
html.motion .m-child.in {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.65s cubic-bezier(0.2, 0.6, 0.2, 1),
    transform 0.65s cubic-bezier(0.2, 0.6, 0.2, 1);
  transition-delay: var(--m-delay, 0s);
}
/* grid cells drop with per-cell delay set by js */
html.motion .grid100 .cell {
  opacity: 0;
  transform: translateY(8px);
}
html.motion .grid100.in .cell {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.4s ease-out,
    transform 0.4s ease-out;
  transition-delay: var(--m-delay, 0s);
}
/* the 2026 cell breathes once the grid has landed */
.grid100.in .cell.now {
  animation: hw-breathe 3.4s 2.2s ease-in-out infinite;
}
@keyframes hw-breathe {
  50% {
    transform: scale(0.86);
  }
}
/* hairline that draws itself */
.m-draw {
  position: relative;
  border: 0 !important;
}
.m-draw::before {
  content: "";
  position: absolute;
  inset: 0 auto auto 0;
  height: var(--hw-hairline-w, 1px);
  width: 100%;
  background: color-mix(in srgb, var(--hw-hairline) 55%, transparent);
  transform-origin: left;
}
html.motion .m-draw::before {
  transform: scaleX(0);
}
html.motion .m-draw.in::before {
  transform: scaleX(1);
  transition: transform 0.9s cubic-bezier(0.4, 0, 0.2, 1);
  transition-delay: var(--m-delay, 0s);
}

@media (prefers-reduced-motion: reduce) {
  .m-reveal,
  .m-child,
  .grid100 .cell {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }
  .m-draw::before {
    transform: scaleX(1) !important;
    transition: none !important;
  }
  .grid100 .cell.now {
    animation: none !important;
  }
}
