/* =========================================================
   SecureFast AI — securefastai.com
   Direction: drafting sheet. Bright, measured, legible.
   Palette is two inks on paper. Nothing else gets a colour.
   ========================================================= */

:root {
  /* --- colour: paper + 2 inks, no more --- */
  --paper:      #EDEEE8;
  --paper-lift: #F5F6F1;
  --ink:        #101317;
  --blue:       #1B2FE0;

  --ink-70: rgba(16, 19, 23, .70);
  --ink-45: rgba(16, 19, 23, .60);  /* 4.61:1 on paper */
  --rule:   rgba(16, 19, 23, .14);
  --rule-2: rgba(16, 19, 23, .28);

  /* on the inverted section */
  --paper-70: rgba(237, 238, 232, .70);
  --paper-45: rgba(237, 238, 232, .52); /* 5.01:1 on ink */
  --rule-inv: rgba(237, 238, 232, .18);
  --blue-inv: #7B93FF; /* 6.62:1 on ink; --blue is 2.24:1 there */

  /* --- type --- */
  --display: "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --body:    "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* --- layout --- */
  --maxw: 1440px;
  --pad:  clamp(1.25rem, 4vw, 4rem);
  --gap:  clamp(.75rem, 1.6vw, 1.5rem);

  /* Two mono label specs, not eighteen. Uppercase needs more tracking than
     sentence case; that is the only split this design earns. */
  --fs-label: .75rem;
  --ls-up:    .12em;
  --ls-sent:  .05em;

  --ease: cubic-bezier(.22, .84, .3, 1);
  --snap: cubic-bezier(.16, 1, .3, 1);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  /* Anchor jumps land instantly. Smoothly gliding the 7000px to #contact took 1.4s
     and dragged every section through the viewport, spending 19 of 28 scroll
     reveals at flying speed before the reader ever saw one. */
  scroll-behavior: auto;
  scroll-padding-top: 5.5rem; /* sticky nav clearance for anchor jumps */
  overflow-x: clip; /* backstop only — `hidden` here would kill position:sticky */
}
body, h1, h2, h3, p, ul, ol, li, figure, blockquote { margin: 0; padding: 0; }
ul, ol { list-style: none; }
img, svg { display: block; max-width: 100%; }
button, input, textarea { font: inherit; color: inherit; }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: clamp(1rem, .96rem + .2vw, 1.125rem);
  line-height: 1.55;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  /* no overflow-x:hidden here — it silently kills position:sticky on the nav */
}

::selection { background: var(--blue); color: var(--paper); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--blue); color: var(--paper);
  padding: .75rem 1.25rem; font-family: var(--mono); font-size: var(--fs-label);
}
.skip:focus { left: 0; }

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}
/* the blue ring is 2.24:1 on ink — invisible exactly where the footer links live */
.foot :focus-visible, .section--ink :focus-visible { outline-color: var(--paper); }

/* =========================================================
   EXPOSED GRID — the drafting sheet behind everything
   ========================================================= */
.sheet {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none;
}
.sheet__inner {
  width: 100%; max-width: var(--maxw); height: 100%;
  margin-inline: auto; padding-inline: var(--pad);
  display: grid; grid-template-columns: repeat(12, 1fr);
  column-gap: var(--gap);
}
.sheet__inner > i { border-left: 1px solid var(--rule); transform-origin: top; }
.sheet__inner > i:last-child { border-right: 1px solid var(--rule); }

/* hide the busiest lines on small screens — keep the outer frame */
@media (max-width: 760px) {
  .sheet__inner > i:not(:nth-child(4n+1)) { border-left-color: transparent; }
}

/* The fixed sheet sits behind opaque dark sections, so those carry their own
   inverted copy — otherwise the drawing grid vanishes for a whole screen. */
.sheet--local { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.sheet--local .sheet__inner > i { border-left-color: var(--rule-inv); }
.sheet--local .sheet__inner > i:last-child { border-right-color: var(--rule-inv); }
@media (max-width: 760px) {
  .sheet--local .sheet__inner > i:not(:nth-child(4n+1)) { border-left-color: transparent; }
}

/* =========================================================
   SHARED
   ========================================================= */
.grid {
  position: relative; z-index: 1;
  width: 100%; max-width: var(--maxw);
  margin-inline: auto; padding-inline: var(--pad);
  display: grid; grid-template-columns: repeat(12, 1fr);
  column-gap: var(--gap);
}

.section { padding-block: clamp(5rem, 11vw, 10rem); position: relative; z-index: 1; }
.section + .section { border-top: 0; }
.section + .section::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: var(--rule); transform-origin: left; z-index: 2;
}
.section--ink.section--ink::before { display: none; } /* solid ink is its own edge */

.eyebrow {
  grid-column: 1 / -1;
  font-family: var(--mono); font-size: var(--fs-label); font-weight: 500;
  letter-spacing: var(--ls-up); text-transform: uppercase;
  color: var(--ink-45);
  display: flex; align-items: center; gap: .6rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
}
.eyebrow::after {
  content: ""; flex: 1 1 auto; max-width: 88px; height: 1px;
  background: var(--rule-2); transform-origin: left;
}
.section--ink .eyebrow::after { background: var(--rule-inv); }
/* Below 344px the rule has already shrunk to 0; dropping it frees the flex gap
   so the hero eyebrow stays on one line instead of stranding its dot. */
/* The hero eyebrow runs 37 characters and needs 336px on one line. Below 400px the
   rule has already shrunk to nothing, so drop it and tighten the gap, which buys back
   the 1.3px it was short at 375. Narrower than that it wraps honestly, so the dot is
   pinned to the first line instead of floating between the two. */
@media (max-width: 400px) {
  .hero .eyebrow::after { display: none; }
  .hero .eyebrow { gap: .45rem; align-items: flex-start; }
  .hero .eyebrow .dot { margin-top: .36rem; } /* (18.6px line - 7px dot) / 2 */
}
.ref { color: var(--blue); }
.dot {
  width: 7px; height: 7px; background: var(--blue);
  border-radius: 50%; flex: none;
}

.h2 {
  grid-column: 1 / -1;
  font-family: var(--display); font-stretch: 112%;
  font-weight: 700; font-size: clamp(2rem, 5.2vw, 4.25rem);
  line-height: .96; letter-spacing: -.028em;
  text-wrap: balance;
  max-width: 20ch;
}
/* Mask for the heading reveal, mirroring the hero's .ln__clip. The padding and the
   negative margin cancel exactly, so this adds no geometry and no layout shift.
   .08em clears the last line's ink, which descends .064em below the block box at
   line-height .96. Re-measure if the line-height or the family changes. */
.h2__clip { display: block; overflow: hidden; padding-bottom: .08em; margin-bottom: -.08em; }
.h2__i    { display: block; }

.section__lede {
  grid-column: 1 / -1;
  margin-top: 1.5rem; max-width: 56ch;
  font-size: clamp(1.0625rem, 1rem + .35vw, 1.3125rem);
  line-height: 1.5; color: var(--ink-70);
}
@media (min-width: 900px) {
  .h2 { grid-column: 1 / 9; }
  .section__lede { grid-column: 1 / 7; }
}

/* ---------- buttons + links ---------- */
.btn {
  display: inline-flex; align-items: center; gap: .6rem;
  background: var(--blue); color: var(--paper);
  font-family: var(--mono); font-size: .82rem; font-weight: 500;
  letter-spacing: var(--ls-up); text-transform: uppercase; text-decoration: none;
  white-space: nowrap; /* 'Start a project' broke over two lines below 380px */
  padding: 1.05rem 1.9rem; border: 0; cursor: pointer;
  position: relative; overflow: hidden; isolation: isolate;
}
/* ink wipes up over the blue; z-index:-1 + isolation keeps it under the label */
.btn::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--ink);
  transform: translateY(101%);
  transition: transform .34s var(--snap);
}
.btn:hover::after, .btn:focus-visible::after { transform: translateY(0); }
/* flex: none — as a shrinkable flex item the nav CTA was squeezed narrower than
   its own label, which `white-space: nowrap` then spilled past the button edge.
   Below 344px the wordmark and button cannot both fit; the hero CTA covers it.
   (Was 375px when the label read "Start a project", 26px wider.) */
.btn--sm { padding: .75rem 1.25rem; font-size: var(--fs-label); flex: none; }
@media (max-width: 343px) {
  .nav .btn { display: none; }
}
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:disabled::after { transform: translateY(101%); }

.lnk {
  display: inline-flex; align-items: center; gap: .5rem;
  color: var(--ink); text-decoration: none;
  font-family: var(--mono); font-size: .82rem; letter-spacing: var(--ls-up);
  text-transform: uppercase;
  position: relative; padding-bottom: .25rem;
  border-bottom: 1px solid var(--rule-2);
  transition: color .2s var(--ease);
}
.lnk::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--blue); transform: scaleX(0); transform-origin: left;
  transition: transform .3s var(--snap);
}
.lnk:hover::after, .lnk:focus-visible::after { transform: scaleX(1); }
.lnk:hover { color: var(--blue); }
.lnk span { transition: transform .28s var(--snap); }
.lnk:hover span { transform: translateX(5px); }

/* =========================================================
   NAV
   ========================================================= */
.nav {
  position: sticky; top: 0; z-index: 100;
  background: var(--paper); /* fallback: color-mix failing must not clear the bar */
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  /* no position:relative here — `sticky` is already a positioned value and gives
     .nav::after its containing block. Re-adding it silently unsticks the nav. */
}
.nav::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--rule); transform: scaleX(0); transform-origin: left;
  transition: transform .32s var(--snap);
}
.nav.is-stuck::after { transform: scaleX(1); }
.nav__inner {
  max-width: var(--maxw); margin-inline: auto;
  padding: 1rem var(--pad);
  display: flex; align-items: center; gap: 2rem;
}
.mark {
  display: flex; align-items: center; gap: .6rem;
  text-decoration: none; color: var(--ink); margin-right: auto;
}
.mark__box {
  width: 30px; height: 30px; flex: none;
  background: var(--blue); color: var(--paper);
  display: grid; place-items: center;
  font-family: var(--mono); font-size: .72rem; font-weight: 500;
  letter-spacing: .02em;
}
.mark__word {
  font-family: var(--display); font-stretch: 112%; font-weight: 700;
  font-size: 1.02rem; letter-spacing: -.02em;
}
.mark__thin { font-weight: 400; color: var(--ink-45); } /* one word: colour separates, not space */

.nav__links { display: none; gap: 1.75rem; }
.nav__links a {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-sent);
  text-decoration: none; color: var(--ink-70);
  display: inline-flex; gap: .45rem; align-items: baseline;
  transition: color .2s var(--ease);
}
.nav__links a:hover, .nav__links a.is-active { color: var(--ink); }
.nav__links a { position: relative; }
.nav__links a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -.5rem; height: 1px;
  background: var(--blue); transform: scaleX(0); transform-origin: left;
  transition: transform .28s var(--snap);
}
.nav__links a.is-active::after { transform: scaleX(1); }
.nav__links a.is-active .ref { color: var(--blue); }
@media (min-width: 940px) { .nav__links { display: flex; } }
@media (max-width: 520px) { .nav .btn--sm { padding: .7rem .9rem; } }

/* =========================================================
   HERO
   ========================================================= */
.hero {
  position: relative; z-index: 1;
  padding-block: clamp(3.5rem, 9vw, 8rem) clamp(4rem, 9vw, 8.5rem);
}
.hero::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--rule); transform-origin: left; z-index: 2;
}
.hero__eyebrow { margin-bottom: clamp(2rem, 4vw, 3rem); }

.hero__title {
  grid-column: 1 / -1;
  font-family: var(--display); font-stretch: 118%; font-weight: 800;
  font-size: clamp(1.75rem, 10.2vw, 9.25rem); /* floor must stay low: .ln__clip cannot wrap */
  /* Leading is bounded by one glyph pair: the 'g' of "gets" sits directly above
     the 'i' of "in" and needs a .921em baseline step to clear. .91 + .11em clip
     padding - .07em pull = .95em step, ~.03em of air. Re-measure if the copy changes. */
  line-height: .91; letter-spacing: -.042em;
  text-transform: none;
}
/* Deliberately stops at 400px. Between 401-480px with BOTH a classic 15px
   scrollbar and a >16px root font, the headline crosses the right hairline into
   the gutter (measured -9.4px at 401px/20px root). Nothing clips or scrolls.
   Widening this query is the wrong trade: it costs every 414/430/480 phone ~10%
   of headline size, and phones use overlay scrollbars so they never hit it. */
@media (max-width: 400px) { /* leaves room for a classic 15px scrollbar */
  .hero__title { font-size: 9.2vw; }
}
.hero__title .hl { color: var(--blue); }

/* Each line is a flex row: [clipped text][annotation]. The annotation is laid out
   after the text rather than positioned over it, so it cannot collide at any width.
   overflow:hidden lives on .ln__clip alone — on .ln it would eat the annotation. */
.ln {
  display: flex; align-items: baseline;
  gap: clamp(1.25rem, 2.6vw, 2.75rem);
}
.ln__clip {
  display: block; flex: none; overflow: hidden;
  padding-bottom: .11em; margin-bottom: -.07em; /* room for descenders, same line step */
}
.ln__i { display: block; }

.hero__lede {
  grid-column: 1 / -1; margin-top: clamp(2rem, 4vw, 3rem);
  max-width: 46ch; font-size: clamp(1.0625rem, 1rem + .4vw, 1.375rem);
  line-height: 1.45; color: var(--ink-70);
}
.hero__cta {
  grid-column: 1 / -1; margin-top: clamp(2rem, 3.5vw, 2.75rem);
  display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem 2rem;
}
.hero__facts {
  grid-column: 1 / -1; margin-top: clamp(3rem, 6vw, 5rem);
  padding-top: 1.25rem; border-top: 1px solid var(--rule);
  display: grid; gap: .75rem 2rem;
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-sent);
  color: var(--ink-70);
}
.hero__facts li { display: flex; gap: .7rem; align-items: baseline; }
@media (min-width: 940px) { /* three labels need 848px; below that, stack them */
  .hero__facts { grid-auto-flow: column; grid-auto-columns: minmax(0, max-content); }
}
@media (min-width: 1100px) {
  .hero__lede { grid-column: 1 / 6; }
  .hero__cta  { grid-column: 1 / 8; }
}


/* ---------- SIGNATURE: drafting annotations ---------- */
/* Decorative only. Off below 1200px, where there is no spare measure for them. */
.annos { display: none; }
.anno  { display: none; }

@media (min-width: 1360px) {
  .anno {
    display: flex; align-items: center; gap: .6rem;
    flex: 0 1 auto; min-width: 0; overflow: hidden;
    /* reset everything inherited from the 9rem display heading */
    font-family: var(--mono); font-size: .7rem; font-weight: 400;
    font-stretch: normal; line-height: 1.2;
    letter-spacing: var(--ls-up); text-transform: uppercase;
    color: var(--blue); white-space: nowrap;
  }
  .anno__rule {
    display: block; position: relative; flex: none;
    width: 72px; height: 1px; background: var(--blue);
    transform-origin: left;
  }
  .anno__rule::after {
    content: ""; position: absolute; right: -1px; top: -2.5px;
    width: 5px; height: 5px; background: var(--blue); border-radius: 50%;
  }

  /* corner mark, in the clear space above the headline */
  .annos { display: block; position: absolute; inset: 0; pointer-events: none; z-index: 2; }
  .anno--corner {
    position: absolute; top: .23em; right: var(--pad);
    color: var(--ink-45);
  }
  .anno--corner .anno__rule {
    width: 54px; background: var(--ink-45); transform-origin: right;
  }
  .anno--corner .anno__rule::after { right: auto; left: -1px; background: var(--blue); }
}


/* =========================================================
   01 — CARDS
   ========================================================= */
.cards {
  grid-column: 1 / -1; margin-top: clamp(3rem, 6vw, 5rem);
  display: grid; gap: 1px; background: var(--rule);
  border-block: 1px solid var(--rule);
}
/* Tracks are sized so the 1px dividers land on grid hairlines 5 and 9 rather than
   on equal thirds, which sat 8px and 16px short and made the rule visibly jog
   where the band met the sheet. The -1px on track 2 absorbs the first gap;
   the last track is therefore ~24px narrower, which reads as even. */
@media (min-width: 900px) { .cards { grid-template-columns: calc((100% + var(--gap)) / 3) calc((100% + var(--gap)) / 3 - 1px) 1fr; } }

.card {
  background: var(--paper);
  padding: clamp(1.75rem, 3vw, 2.75rem) clamp(1.5rem, 2.4vw, 2.25rem);
  display: flex; flex-direction: column; gap: 1rem;
  transition: background .3s var(--ease);
}
.card:hover { background: var(--paper-lift); }
.card__ref {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-up);
  text-transform: uppercase; color: var(--blue);
}
.card__h {
  font-family: var(--display); font-stretch: 108%; font-weight: 700;
  font-size: clamp(1.35rem, 1.15rem + .8vw, 1.85rem);
  line-height: 1.05; letter-spacing: -.022em;
}
.card p { color: var(--ink-70); }
.card__list {
  margin-top: auto; padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  display: grid; gap: .55rem;
  font-size: .95rem; color: var(--ink-70);
}
.card__list li { padding-left: 1.1rem; position: relative; }
.card__list li::before {
  content: ""; position: absolute; left: 0; top: .58em;
  width: 5px; height: 5px; background: var(--blue);
}

/* =========================================================
   03 — PROCESS (inverted)
   ========================================================= */
/* .section.section--ink, not .section--ink — otherwise `.section + .section`
   (same specificity, earlier in source) keeps winning the border. */
.section--ink.section--ink {
  background: var(--ink); color: var(--paper);
  border-top: 0;
}
.section--ink .eyebrow      { color: var(--paper-45); }
.section--ink .section__lede{ color: var(--paper-70); }
.section--ink .ref          { color: var(--blue-inv); }
.foot .ref                  { color: var(--blue-inv); } /* .foot is dark but not .section--ink */

.phases {
  grid-column: 1 / -1; margin-top: clamp(3rem, 6vw, 5rem);
  border-top: 1px solid var(--rule-inv);
}
.phase {
  display: grid; gap: .5rem 2rem;
  padding-block: clamp(1.75rem, 3.2vw, 2.75rem);
  /* transparent spacer: the visible rule is ::after, so it can be drawn on entry
     without the border's 1px appearing or disappearing and shifting the row */
  border-bottom: 1px solid transparent;
  position: relative;
}
/* the rule that closes each phase, same construction as .section + .section::before */
.phase::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--rule-inv); transform-origin: left; z-index: 1;
}
/* left edge of .phase sits exactly on the grid's column-1 hairline, so hovering
   inks a segment of the drafting sheet itself */
.phase::before {
  content: ""; position: absolute; left: -1px; top: -1px; bottom: -1px; width: 2px;
  background: var(--blue-inv); transform: scaleY(0); transform-origin: top;
  transition: transform .34s var(--snap);
}
.phase:hover::before, .phase:focus-within::before { transform: scaleY(1); }
.phase__n {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-up);
  color: var(--blue-inv);
}
.phase__h {
  font-family: var(--display); font-stretch: 112%; font-weight: 700;
  font-size: clamp(1.6rem, 1.2rem + 2vw, 2.75rem);
  line-height: 1; letter-spacing: -.028em;
  margin-bottom: .7rem;
}
.phase__body p { color: var(--paper-70); max-width: 54ch; }
.phase__out {
  display: inline-block; margin-top: 1rem;
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-sent);
  color: var(--paper-45);
  padding-top: .6rem; border-top: 1px solid var(--rule-inv);
}
@media (min-width: 860px) {
  /* one grid column + one gutter, so .phase__body lands on hairline 2 at any width */
  .phase {
    grid-template-columns: calc((100% - 11 * var(--gap)) / 12 + var(--gap)) 1fr;
    column-gap: 0;
  }
  .phase__n { padding-top: .55rem; }
}

/* =========================================================
   SPEC GRIDS (used by #speed and #security)
   ========================================================= */
.specs {
  grid-column: 1 / -1; margin-top: clamp(3rem, 6vw, 5rem);
  display: grid; gap: 1px; background: var(--rule);
  border-block: 1px solid var(--rule);
}
@media (min-width: 720px)  { .specs { grid-template-columns: calc((100% + var(--gap)) / 2) 1fr; } }
/* A 3-item grid in 2 columns leaves an empty cell, and the container background
   paints through it as a grey block. Let the odd one out span the row instead. */
@media (min-width: 720px) and (max-width: 1079.98px) {
  .specs:has(> :nth-child(3):last-child) .spec:last-child { grid-column: 1 / -1; }
}
@media (min-width: 1080px) { .specs { grid-template-columns: calc((100% + var(--gap)) / 3) calc((100% + var(--gap)) / 3 - 1px) 1fr; } }

.spec {
  background: var(--paper);
  padding: clamp(1.6rem, 2.6vw, 2.25rem);
  position: relative;
  transition: background .3s var(--ease);
}
.spec:hover { background: var(--paper-lift); }

/* corner registration marks — drawing-office furniture, not a tab underline */
.card, .spec { position: relative; }
.card::before, .card::after, .spec::before, .spec::after {
  content: ""; position: absolute; top: 0; left: 0; background: var(--blue);
}
.card::before, .spec::before {
  width: 26px; height: 2px; transform: scaleX(0); transform-origin: left;
  transition: transform .26s var(--snap);
}
.card::after, .spec::after {
  width: 2px; height: 26px; transform: scaleY(0); transform-origin: top;
  transition: transform .26s var(--snap);
}
.card:hover::before, .spec:hover::before { transform: scaleX(1); }
.card:hover::after,  .spec:hover::after  { transform: scaleY(1); transition-delay: .05s; }

/* Second corner, diagonally opposite: a drawing is registered at two corners, and on a
   joined plate two marks lift one cell out where one just ticks it. Both pseudos on
   .card/.spec are spent, so these hang off the first child and resolve against the
   card because it is the nearest positioned ancestor. The `position: static` below is
   load-bearing, not decorative: position these and the marks jump to the label. */
.card__ref, .spec__h { position: static; }
.card__ref::before, .card__ref::after,
.spec__h::before,   .spec__h::after {
  content: ""; position: absolute; bottom: 0; right: 0; background: var(--blue);
}
.card__ref::before, .spec__h::before {
  width: 26px; height: 2px; transform: scaleX(0); transform-origin: right;
  transition: transform .26s var(--snap);
}
.card__ref::after, .spec__h::after {
  width: 2px; height: 26px; transform: scaleY(0); transform-origin: bottom;
  transition: transform .26s var(--snap);
}
.card:hover .card__ref::before, .spec:hover .spec__h::before { transform: scaleX(1); }
.card:hover .card__ref::after,  .spec:hover .spec__h::after  { transform: scaleY(1);
  transition-delay: .05s; }
.spec__h {
  font-family: var(--display); font-stretch: 108%; font-weight: 700;
  font-size: 1.15rem; letter-spacing: -.018em; line-height: 1.15;
  margin-bottom: .6rem;
}
.spec p { color: var(--ink-70); font-size: .95rem; }

/* =========================================================
   05 — ABOUT
   ========================================================= */
.pull {
  grid-column: 1 / -1;
  font-family: var(--display); font-stretch: 106%; font-weight: 700;
  font-size: clamp(1.6rem, 1.1rem + 2.6vw, 3.25rem);
  line-height: 1.06; letter-spacing: -.03em;
  text-wrap: balance;
  position: relative; padding-left: clamp(1rem, 2vw, 1.75rem);
  /* had no margin at all: it used to follow the eyebrow, which supplied the gap.
     Now it follows .section__lede, so it needs its own. */
  margin-top: clamp(3rem, 6vw, 5rem);
}
.pull::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--blue); transform-origin: top;
}
.about__body {
  grid-column: 1 / -1; margin-top: clamp(2rem, 4vw, 3rem);
  display: grid; gap: 1.1rem; max-width: 62ch; color: var(--ink-70);
}
/* 900px, not 960: .pull mirrors .h2 (1/9) and .about__body mirrors .section__lede
   (1/7), both of which narrow at 900. At 960 they overhung the heading by 287px. */
@media (min-width: 900px) {
  .pull        { grid-column: 1 / 9; }
  .about__body { grid-column: 1 / 7; }
}

/* =========================================================
   06 — CONTACT
   ========================================================= */
.form {
  grid-column: 1 / -1; margin-top: clamp(3rem, 6vw, 5rem);
  display: grid; gap: 1.5rem;
}
@media (min-width: 780px) {
  .form { grid-column: 1 / 9; grid-template-columns: repeat(2, 1fr); }
  .field--full, .form__foot, .form__status { grid-column: 1 / -1; }
}
.field { display: grid; gap: .5rem; }
.field label {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-up);
  text-transform: uppercase; color: var(--ink-45);
}
.field input, .field textarea {
  background-color: transparent;
  background-image: linear-gradient(var(--blue), var(--blue));
  background-repeat: no-repeat; background-position: left bottom;
  background-size: 0 2px;
  transition: background-size .34s var(--snap);
  border: 0;
  border-bottom: 1px solid rgba(16, 19, 23, .48); /* 3.18:1 — this line IS the input */
  padding: .7rem 0; font-size: 1rem; width: 100%;
  border-radius: 0;
}
.field input:focus-visible, .field textarea:focus-visible {
  outline: 2px solid var(--blue); outline-offset: 2px;
}
.field input:focus, .field textarea:focus { background-size: 100% 2px; }
.field textarea { resize: vertical; }
.field.is-bad input, .field.is-bad textarea { border-bottom-color: #C02617; }
.err {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-sent); color: #C02617;
  min-height: 1em;
}
.hp { position: absolute; left: -9999px; opacity: 0; }

.form__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.75rem;
  margin-top: .5rem;
}
.form__note {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-sent);
  color: var(--ink-45);
}
.form__status {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-sent);
  min-height: 1.2em;
}
.form__status.is-ok  { color: var(--blue); }
.form__status.is-bad { color: #C02617; }

/* =========================================================
   FOOTER
   ========================================================= */
.foot {
  background: var(--ink); color: var(--paper);
  padding-block: clamp(3rem, 6vw, 5rem);
  position: relative; z-index: 1;
}
.foot__grid { row-gap: 2.5rem; align-items: start; }
.foot__mark {
  grid-column: 1 / -1; display: flex; gap: 1rem; align-items: flex-start;
  font-family: var(--display); font-stretch: 110%; font-weight: 700;
  line-height: 1.3;
}
.foot__loc {
  font-family: var(--mono); font-size: var(--fs-label); font-weight: 400;
  letter-spacing: var(--ls-sent); color: var(--paper-45);
}
.foot__nav { grid-column: 1 / -1; display: grid; gap: .1rem; }
.foot__nav a {
  display: inline-flex; gap: .45rem; align-items: baseline;
  padding-block: .5rem; /* 18.6px tall was under the 24px minimum target size */
  color: var(--paper-70); text-decoration: none;
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-sent);
  transition: color .2s var(--ease);
  justify-self: start;
}
.foot__nav a:hover { color: var(--paper); }
.foot__legal {
  grid-column: 1 / -1;
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-sent);
  color: var(--paper-45);
  padding-top: 1.5rem; border-top: 1px solid var(--rule-inv);
}
@media (min-width: 860px) {
  .foot__mark  { grid-column: 1 / 6; }
  .foot__nav   { grid-column: 8 / -1; }  /* 8/11 was too narrow: link wrapped at 860-955 */
  .foot__legal { grid-column: 1 / -1; margin-top: 1.5rem; }
}

/* =========================================================
   SCROLL REVEAL
   ========================================================= */


/* =========================================================
   MOTION
   Every entrance state lives in here and nowhere else.
   RULE: no `opacity: 0`, no transform offset and no entrance
   `animation` may be authored outside this block. Forget, and
   the element is simply visible — never invisible. That is why
   the reduce block below is a backstop and not a list.
   Hover/focus indicators are exempt: hidden is their real
   resting state, and the backstop makes them snap.
   ========================================================= */
@media (prefers-reduced-motion: no-preference) {

  @keyframes sheetDraw { to { transform: scaleY(1); } }
  @keyframes lineUp    { to { transform: translateY(0); } }
  @keyframes ruleOut   { to { transform: scaleX(1); } }
  @keyframes fadeIn    { to { opacity: 1; } }
  @keyframes fadeUp    { from { opacity: 0; transform: translateY(14px); }
                         to   { opacity: 1; transform: translateY(0); } }
  @keyframes ruleTraverse { from { transform: translateX(-100%); }
                            to   { transform: translateX(100%); } }

  /* submit in flight: a rule runs under the label. Looping is honest here because
     the wait is real. #form-status announces "Sending…" for everyone else. */
  .btn[aria-busy="true"]::before {
    content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 2px;
    background: var(--paper); transform: translateX(-100%);
    animation: ruleTraverse 1.1s linear infinite;
  }

  /* ---- load: the sheet is ruled, then the title block is set ---- */
  .sheet__inner > i {
    transform: scaleY(0);
    animation: sheetDraw .7s var(--snap) forwards;
    animation-delay: calc(var(--c) * 40ms);
  }
  @media (max-width: 760px) { /* 9 of 12 are transparent here — animate nothing */
    .sheet__inner > i:not(:nth-child(4n+1)) { animation: none; }
  }

  .ln__i { transform: translateY(115%); animation: lineUp .55s var(--snap) forwards; }
  .ln:nth-child(1) .ln__i { animation-delay: .12s; }
  .ln:nth-child(2) .ln__i { animation-delay: .19s; }
  .ln:nth-child(3) .ln__i { animation-delay: .26s; }

  .hero__lede  { opacity: 0; animation: fadeUp .5s var(--ease) .40s forwards; }
  .hero__cta   { opacity: 0; animation: fadeUp .5s var(--ease) .48s forwards; }
  .hero__facts { opacity: 0; animation: fadeUp .5s var(--ease) .56s forwards; }

  /* the hero's bottom rule is the closing beat of the load sequence */
  .hero::after { transform: scaleX(0); animation: ruleOut .9s var(--snap) .58s forwards; }

  @media (min-width: 1360px) {
    .anno__rule { transform: scaleX(0); animation: ruleOut .5s var(--snap) .62s forwards; }
    .anno__txt  { opacity: 0;           animation: fadeIn  .4s var(--ease) .78s forwards; }
    .anno--corner .anno__rule { animation-delay: .80s; }
    .anno--corner .anno__txt  { animation-delay: .96s; }
  }

  /* ---- scroll: double-gated, motion allowed AND js running ---- */
  .js .rev {
    opacity: 0; transform: translateY(18px);
    transition: opacity .6s var(--ease), transform .6s var(--snap);
    transition-delay: var(--d, 0ms);
  }
  .js .rev.is-in { opacity: 1; transform: none; }

  /* The nav's own hairline reads the pen's travel down the sheet. Scroll-driven, so
     it costs no listener and no layout read. Nested inside no-preference on purpose:
     the reduce backstop's `animation-duration: .001ms !important` would break a
     scroll timeline, so reduce users simply keep the plain .is-stuck hairline. */
  @supports (animation-timeline: scroll()) {
    .nav::before {
      content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
      background: var(--rule-2); transform: scaleX(0); transform-origin: left; z-index: 1;
      animation: ruleOut linear both;
      animation-timeline: scroll(root block);
    }
  }

  /* section delimiters are drawn by the same pen as the grid, at plotter speed */
  .js .section + .section::before {
    transform: scaleX(0); transition: transform .95s var(--snap);
  }
  .js .section + .section.is-in::before { transform: scaleX(1); }

  /* the inverted sheets plot themselves too — they never used to */
  .js .sheet--local .sheet__inner > i {
    transform: scaleY(0);
    transition: transform .7s var(--snap);
    transition-delay: calc(var(--c, 0) * 40ms);
  }
  .js .sheet--local.is-in .sheet__inner > i { transform: scaleY(1); }

  /* each phase is ruled off after its own text has registered: drafting order */
  .js .phase.rev::after       { transform: scaleX(0);
    transition: transform .8s var(--snap) calc(var(--d, 0ms) + 180ms); }
  .js .phase.rev.is-in::after { transform: scaleX(1); }

  .js .pull::before        { transform: scaleY(0); transition: transform .55s var(--snap) .12s; }
  .js .pull.is-in::before  { transform: scaleY(1); }

  /* section-scale echo of the hero's annotation rule */
  .js .eyebrow.rev::after       { transform: scaleX(0);
    transition: transform .5s var(--snap) calc(var(--d, 0ms) + 120ms); }
  .js .eyebrow.rev.is-in::after { transform: scaleX(1); }

  /* The heading registers behind its mask instead of fading: same instrument as the
     hero headline, same .55s var(--snap). The block itself no longer moves at all. */
  .js .h2.rev { opacity: 1; transform: none; }
  .js .h2.rev .h2__i {
    transform: translateY(102%);
    transition: transform .55s var(--snap);
    transition-delay: var(--d, 0ms);
  }
  .js .h2.rev.is-in .h2__i { transform: none; }
}

/* =========================================================
   REDUCED MOTION — everything lands, nothing moves
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- print ---------- */
@media print {
  .sheet, .sheet--local, .nav, .annos { display: none; }
  body { background: #fff; color: #000; }
  .js .rev { opacity: 1; transform: none; }
  /* the drawn rules default to scaleX(0)/scaleY(0) until scrolled into view —
     printing an unscrolled page would otherwise drop every hairline */
  .js .section + .section::before, .js .pull::before,
  .js .eyebrow.rev::after, .hero::after { transform: none; animation: none; }
  .js .sheet--local .sheet__inner > i { transform: none; }
  .js .h2.rev .h2__i { transform: none; }
  .js .phase.rev::after { transform: none; }
  /* these declare paper-on-ink; printers drop the ink and leave white on white */
  .section--ink, .foot { background: #fff !important; color: #000 !important; }
  .section--ink .eyebrow, .section--ink .section__lede, .phase__body p,
  .phase__out, .foot__nav a, .foot__legal, .foot__loc { color: #000 !important; }
}
