/* ============================================================
   CIRCUIT LABS  ·  circuitlabs.llc
   Palette lifted from the Subject poster series:
   aubergine ground, violet frames, cream headlines.
   ============================================================ */
:root{
  --ground:#0F0916;
  --ground-2:#150D1E;
  --panel:#1A1127;
  --panel-2:#221735;
  --line:#33264F;
  --frame:#5F4A8C;
  --band:#3B3159;
  --violet:#8B6BDB;          /* resting UI borders (secondary button) */
  --violet-bright:#A180E6;   /* text, labels, focus and hover */
  --violet-soft:rgba(161,128,230,.14);
  --cream:#F6F1C9;
  --cream-ink:#1B1030;
  --ink:#F3EEF8;
  --muted:#B9AFD1;
  --faint:#8F86AA;           /* AA on every surface, incl. panel-2 */
  --danger:#F49485;
  --ok:#9BE8C6;
  --display:"Poppins",system-ui,-apple-system,"Segoe UI",sans-serif;
  --body:"Poppins",system-ui,-apple-system,"Segoe UI",sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,"Cascadia Mono","Courier New",monospace;
  --maxw:1080px;
  --radius:12px;
  --radius-sm:8px;
  --radius-lg:16px;
  --ground-rgb:15,9,22;
  --violet-bright-rgb:161,128,230;
  --cream-rgb:246,241,201;
  --danger-rgb:244,148,133;
  --cream-hover:#FFF9D6;
  --cream-press:#E6E0B8;
  --frame-soft:rgba(95,74,140,.14);
  --grid-line:rgba(161,128,230,.07);
  --shadow-lift:0 40px 80px -40px rgba(0,0,0,.85);           /* shells: .subject, .cta-shell */
  --shadow-cta:0 10px 30px -14px rgba(var(--cream-rgb),.55); /* the cream button only */

  /* motion: one arrival curve, one departure curve, four speeds.
     Nothing here bounces. A bench tool settles, it does not spring. */
  --ease-out:cubic-bezier(.2,.7,.3,1);   /* arrivals, releases, focus */
  --ease-in:cubic-bezier(.4,0,1,1);      /* departures, presses */
  --ease-loop:cubic-bezier(.45,0,.55,1); /* ambient infinite loops, symmetric */
  --dur-press:90ms;
  --dur-micro:180ms;
  --dur-move:260ms;
  --dur-exit:200ms;          /* departures leave faster than they arrive */
  --dur-scene:300ms;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
html,body{margin:0}
body{
  background:var(--ground);
  color:var(--ink);
  font-family:var(--body);
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
  background-image:
    radial-gradient(900px 500px at 10% -10%, rgba(139,107,219,.16), transparent 60%),
    radial-gradient(700px 400px at 100% 10%, var(--frame-soft), transparent 60%);
}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
h1,h2,h3{margin:0;font-family:var(--display);font-weight:800;line-height:1.1;letter-spacing:-.01em;text-wrap:balance}
p{margin:0 0 1em}
::selection{background:var(--violet-bright);color:var(--cream-ink)}
:focus-visible{outline:2px solid var(--cream);outline-offset:3px}

.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:max(20px,env(safe-area-inset-left,0px)) max(20px,env(safe-area-inset-right,0px))}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* mono labels, the clinical voice */
.tag{
  font-family:var(--mono);font-size:12px;font-weight:500;
  letter-spacing:.2em;text-transform:uppercase;color:var(--violet-bright);
}
.tag.faint{color:var(--faint)}

/* ---------- BUTTONS ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  min-height:52px;padding:12px 20px;border-radius:var(--radius);
  font-family:var(--body);font-weight:600;font-size:16px;line-height:1.2;
  border:2px solid transparent;cursor:pointer;white-space:nowrap;min-width:0;max-width:100%;
  /* box-shadow is deliberately NOT transitioned: it repaints every frame and
     this is the cream CTA. It snaps off on press, like a real button. */
  transition:transform var(--dur-micro) var(--ease-out),
             background-color var(--dur-micro) var(--ease-out),
             border-color var(--dur-micro) var(--ease-out);
}
/* the lift is for real pointers only. On a phone the :hover state latches
   after the tap that opens Messages and never clears. */
@media (hover:hover) and (pointer:fine){
  .btn:hover{transform:translateY(-1px)}
}
/* press in fast and accelerating, release slow and decelerating */
.btn:active{transform:scale(.955);transition-duration:var(--dur-press);transition-timing-function:var(--ease-in)}
.btn>span{min-width:0;overflow:hidden;text-overflow:ellipsis}
/* box-shadow is still not transitioned, so this snaps. The inset shade reads
   as the face of the button going down under the thumb, which is the only
   feedback there is in the beat before Messages opens on a slow connection. */
.btn-primary:active{background:var(--cream-press);box-shadow:inset 0 3px 0 rgba(27,16,48,.20)}
.btn-secondary:active{background:rgba(var(--violet-bright-rgb),.32);border-color:var(--violet-bright)}
.btn [data-phone]{user-select:all;-webkit-user-select:all}
.btn svg{flex:none}
.btn-primary{background:var(--cream);color:var(--cream-ink);box-shadow:var(--shadow-cta)}
.btn-primary:hover{background:var(--cream-hover)}
.btn-secondary{background:transparent;border-color:var(--violet-bright);color:var(--ink)}
.btn-secondary:hover{background:var(--violet-soft);border-color:var(--violet-bright)}
.btn-sm{min-height:44px;padding:8px 16px;font-size:14px;border-radius:var(--radius-sm)}
.btn[disabled],.btn[aria-disabled="true"]{cursor:wait;transform:none;box-shadow:none;background:var(--cream-press)}
.actions{display:flex;flex-wrap:wrap;gap:12px}
.actions .btn{flex:1 1 180px}

/* ---------- HEADER ---------- */
/* The tab strip is a real column INSIDE the bar, so a tab can never land on
   top of anything else. It used to be absolutely positioned over the bar and
   centred, which printed "About Us" straight through "LAB 00 · CLARK, SD"
   from 1141px up and clipped the phone number at exactly 860px. Nothing in
   this header overlaps now: when space runs short the tab column is the only
   one that gives, and it scrolls rather than collide. */
.top{
  position:sticky;top:0;z-index:40;
  background:rgba(var(--ground-rgb),.86);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border-bottom:1px solid var(--line);
}
.top .bar{
  /* mirrors .wrap's own padding, so the phone tab strip can bleed back out to
     the header edges without the gutter being written down in two places */
  --gl:max(20px,env(safe-area-inset-left,0px));
  --gr:max(20px,env(safe-area-inset-right,0px));
  display:flex;align-items:center;flex-wrap:wrap;column-gap:16px;row-gap:0;
  min-height:60px;padding-block:6px 0;
}
.brand{display:flex;align-items:center;gap:10px;margin-right:auto;font-family:var(--display);font-weight:800;font-size:20px;letter-spacing:-.02em;white-space:nowrap}
.brand .mark{width:32px;height:32px;flex:none}
.brand b{color:var(--violet-bright);font-weight:800}
.bar-actions{display:flex;align-items:center;gap:16px;min-height:48px}
.lab-tag{font-family:var(--mono);font-size:11px;letter-spacing:.16em;color:var(--faint);display:flex;align-items:center;gap:8px;white-space:nowrap}
.lab-tag .dot{position:relative;width:8px;height:8px;border-radius:50%;background:var(--violet-bright)}
/* the ring is drawn once, then only scaled and faded: fully composited.
   The animation itself lives in the motion layer at the foot of this file. */
.lab-tag .dot::after{content:"";position:absolute;inset:0;border-radius:50%;box-shadow:0 0 0 1px rgba(var(--violet-bright-rgb),.55);transform:scale(1);opacity:0}
.top-phone{font-family:var(--mono);font-size:14px;color:var(--ink);white-space:nowrap}
.top-phone:hover{color:var(--cream)}
/* phones: the strip wraps to its own line and bleeds out to the header edges */
.tabs{order:3;flex:1 0 100%;margin:6px calc(-1*var(--gr)) 0 calc(-1*var(--gl));border-top:1px solid var(--line)}
.tabs-row{display:flex;gap:4px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding-left:var(--gl);padding-right:var(--gr)}
.tabs-row::-webkit-scrollbar{display:none}
.tabs a{
  flex:none;padding:11px 14px;font-size:14px;font-weight:500;color:var(--muted);
  border-bottom:2px solid transparent;
  transition:color var(--dur-micro) var(--ease-out),border-color var(--dur-micro) var(--ease-out);
}
.tabs a:hover{color:var(--ink)}
.tabs a[aria-current="page"]{color:var(--cream);border-bottom-color:var(--cream)}
@media (min-width:860px){
  /* one row, three columns: brand | tabs | actions */
  .top .bar{
    display:grid;grid-template-columns:max-content minmax(0,1fr) max-content;
    align-items:center;column-gap:16px;min-height:68px;padding-block:6px;
  }
  .brand{margin-right:0;justify-self:start}
  .tabs{order:0;flex:none;min-width:0;margin:0;border-top:0}
  .tabs-row{justify-content:center;padding-inline:0}
  .tabs a{padding:8px 14px;border-bottom:0;border-radius:var(--radius-sm)}
  .tabs a[aria-current="page"]{background:var(--violet-soft);color:var(--cream)}
  .bar-actions{justify-self:end;min-height:0}
}
@media (max-width:859px){
  .top{position:static}
  .top-phone{display:none}
}
@media (max-width:1140px){
  .lab-tag{display:none}
}
@media (max-width:480px){
  .tabs a{font-size:13px;padding:10px 8px}
  .tabs-row{padding-left:12px;padding-right:12px}
}

/* ---------- HERO ---------- */
.hero{
  position:relative;overflow:hidden;
  border-bottom:1px solid var(--line);
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size:28px 28px;
}
.hero::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg, rgba(var(--ground-rgb),0) 0%, rgba(var(--ground-rgb),.55) 70%, var(--ground) 100%);
}
/* bottom is lighter by the 12px touch padding .more carries below its text,
   so the block reads optically centred rather than measured centred */
.hero .wrap{position:relative;z-index:1;padding-block:clamp(28px,6vw,80px) clamp(16px,6vw,68px)}
.hero-grid{max-width:56ch}
.hero-alt{margin:4px 0 0}
.cols>*,.cta-shell>*{min-width:0}
.hero h1{font-size:clamp(32px,6vw,64px);color:var(--cream);margin-top:8px}
/* The setup sets up. The promise is the thing no competitor offers, so it
   takes the cream and its own line. Both are headline scope, cream stays
   reserved rather than becoming a general accent. */
.hero h1 .setup{color:var(--muted);font-weight:600}
.hero h1 em{font-style:normal;color:var(--cream);display:block}
.hero .lead{color:var(--muted);font-size:clamp(16px,1.9vw,19px);max-width:48ch;margin:16px 0 20px}
.hero .lead b{color:var(--ink);font-weight:600}
.hero .actions .btn{min-height:56px}
.hero .fine{font-family:var(--mono);font-size:12px;color:var(--faint);margin:16px 0 0;letter-spacing:.04em}
/* --ink, matching how the same promise reads in .rule p. Violet is the
   label colour everywhere else on this page. */
.hero .fine b{color:var(--ink);font-weight:600}

/* ---------- SECTIONS ---------- */
section{padding-block:clamp(48px,8vw,96px);position:relative}
section.tight{padding-block:clamp(32px,5vw,56px)}
section.band{background:var(--ground-2);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.sec-head{max-width:62ch;margin-bottom:32px}
.sec-head h2,.cols h2{font-size:clamp(26px,4.2vw,42px);margin-top:8px;color:var(--cream)}
.sec-head p{color:var(--muted);margin:16px 0 0;font-size:17px}
.sec-head p b{color:var(--ink);font-weight:600}
.sec-head:last-child{margin-bottom:0}
.sec-head.center{text-align:center;margin-inline:auto}
.divider{border:0;border-top:1px solid var(--line);margin:0}

/* steps */
.steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}
.step{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:20px;position:relative;
}
.step .n{font-family:var(--mono);font-size:11px;letter-spacing:.16em;color:var(--violet-bright);text-transform:uppercase}
.step .n b{display:block;font-size:36px;line-height:1;letter-spacing:0;font-weight:500;color:var(--violet-bright);margin:8px 0 12px}
.step h3{font-size:20px;font-weight:600;margin:0 0 8px;color:var(--ink);line-height:1.25}
.step p{color:var(--muted);font-size:15px;margin:0}

/* chips */
.chips{display:flex;flex-wrap:wrap;gap:10px;margin:24px 0 0;padding:0;list-style:none}
.chip{
  font-family:var(--mono);font-size:13px;letter-spacing:.04em;
  padding:8px 12px;border-radius:999px;border:1px solid var(--frame);color:var(--ink);background:var(--frame-soft);
}
/* renamed off .spec, which is the fact table on about/procedures: it sits
   later in this file at equal specificity and was overriding the pill radius.
   Border drops to --frame so bright violet stays reserved for interactive. */
.chip.key{border-color:var(--frame);color:var(--ink);background:var(--violet-soft);font-weight:500}
/* the homepage's one look at the archive, at archive scale */
.sec-head .latest{
  display:inline-flex;flex-direction:column;align-items:center;gap:6px;
  margin:24px 0 20px;padding:16px 28px;
  border:1px solid var(--frame);border-radius:var(--radius);background:var(--frame-soft);
}
.latest-k{font-family:var(--mono);font-size:10px;letter-spacing:.24em;text-transform:uppercase;color:var(--faint)}
.latest-n{font-family:var(--mono);font-size:13px;letter-spacing:.16em;text-transform:uppercase;color:var(--violet-bright);display:flex;align-items:baseline;gap:12px}
.latest-n b{font-family:var(--display);font-weight:500;font-size:clamp(44px,9vw,64px);line-height:1;letter-spacing:-.01em;color:var(--violet-bright)}
.latest-v{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ok)}
.latest-v::before{content:"● "}

/* in-page navigation link: button shape is reserved for Text and Call */
.more{font-family:var(--mono);font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:var(--violet-bright);text-decoration:underline;text-decoration-color:var(--frame);text-decoration-thickness:1px;text-underline-offset:4px;display:inline-block;padding-block:12px}
/* real pointers only. Same reason as .btn:hover, and .more in the hero points
   at #contact, so a latched hover there never clears. */
@media (hover:hover) and (pointer:fine){
  .more:hover{color:var(--cream);text-decoration-color:var(--cream)}
}

/* trust lines, the two standing rules */
.trust{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:36px 56px;
}
/* The promises carry themselves. No panel to sit in, a measured rule bar above,
   and the number at bench-instrument scale, matching .step .n b. */
.rule{
  border-top:2px solid var(--violet-bright);background:transparent;border-radius:0;
  padding:22px 0 0;
}
.rule .tag{margin:0;display:block}
.rule .tag b{display:block;font-size:clamp(40px,7vw,56px);font-weight:500;line-height:1;letter-spacing:0;color:var(--violet-bright);margin:10px 0 14px}
.rule p{margin:0;font-size:clamp(19px,2.4vw,24px);font-weight:600;color:var(--ink);line-height:1.35;text-wrap:balance}

/* spec table */
.spec{border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:var(--panel)}
.spec .row{display:flex;justify-content:space-between;gap:16px;padding:14px 18px;border-bottom:1px solid var(--line);font-size:15px}
.spec .row:last-child{border-bottom:0}
.spec .k{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--violet-bright);white-space:nowrap;padding-top:3px}
.spec .v{color:var(--ink);text-align:right}
.spec .v a:hover{color:var(--cream)}

/* two column prose */
.cols{display:grid;grid-template-columns:1.1fr .9fr;gap:40px;align-items:start}
.prose p{color:var(--muted);font-size:16px}
.prose p b{color:var(--ink);font-weight:600}
.prose ul{color:var(--muted);padding-left:20px;margin:0 0 1em}
.prose li{margin-bottom:8px}
.prose li b{color:var(--ink);font-weight:600}
.callout{
  font-family:var(--mono);font-size:13px;line-height:1.8;color:var(--cream);
  border:1px dashed var(--frame);border-radius:var(--radius);padding:16px 20px;background:var(--frame-soft);
}

/* ---------- SUBJECT FILES ---------- */
.archive-head{
  padding-block:clamp(36px,6vw,72px);border-bottom:1px solid var(--line);
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size:28px 28px;
}
.archive-head h1{font-size:clamp(34px,6vw,64px);color:var(--cream);text-transform:uppercase;letter-spacing:.01em}
.archive-head p{color:var(--muted);max-width:60ch;font-size:17px;margin-top:14px}
.archive-meta{display:flex;flex-wrap:wrap;gap:8px 22px;margin-top:18px;font-family:var(--mono);font-size:12px;letter-spacing:.12em;color:var(--faint);text-transform:uppercase}
.archive-meta b{color:var(--violet-bright);font-weight:500}

.subjects{display:grid;gap:28px;padding-block:clamp(28px,5vw,56px)}
.subject{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;
  box-shadow:var(--shadow-lift);
}
.subject-head{
  display:grid;grid-template-columns:auto 1fr auto;gap:18px;align-items:end;
  padding:22px 22px 18px;border-bottom:1px solid var(--line);
  background:linear-gradient(180deg,var(--panel-2),var(--panel));
}
.subject-head>*{min-width:0}
.sub-no{display:flex;flex-direction:column;line-height:1}
.sub-no span{font-family:var(--mono);font-size:10px;letter-spacing:.24em;text-transform:uppercase;color:var(--violet-bright)}
.sub-no b{font-family:var(--display);font-weight:500;font-size:44px;color:var(--violet-bright);letter-spacing:-.01em;margin-top:4px}
.sub-title h2{font-size:clamp(22px,3.4vw,32px);text-transform:uppercase;color:var(--cream);letter-spacing:.01em;overflow-wrap:anywhere}
.sub-device{font-family:var(--mono);font-size:13px;color:var(--muted);margin-top:6px;letter-spacing:.04em;overflow-wrap:anywhere}
.sub-status{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ok);white-space:nowrap;padding-bottom:6px}
.sub-status::before{content:"● ";}

.specimen{
  margin:16px;border:2px solid var(--frame);border-radius:var(--radius);background:var(--band);padding:10px;
  display:grid;grid-template-columns:1fr 1fr;gap:10px;
}
.specimen figure{margin:0;display:flex;flex-direction:column;gap:8px;min-width:0}
.specimen figcaption{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;text-align:center;color:var(--ink)}
.specimen figure.before figcaption{color:var(--danger)}
.specimen figure.after figcaption{color:var(--ok)}
.specimen img{width:100%;height:auto;border-radius:4px;background:#000}

.sub-notes{
  display:grid;grid-template-columns:auto 1fr;gap:8px 18px;margin:0;padding:6px 22px 22px;font-size:15px;
}
.sub-notes dt{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--violet-bright);padding-top:4px;white-space:nowrap}
.sub-notes dd{margin:0;color:var(--muted)}
.sub-notes dd b{color:var(--ink);font-weight:500}

.subject.pending{border-style:dashed;border-color:var(--frame);background:transparent;box-shadow:none}
.subject.pending .subject-head{background:transparent}
.subject.pending .sub-no b{color:var(--faint)}
.subject.pending .sub-status{color:var(--cream)}
.subject.pending .body{padding:22px}
.subject.pending .body p{color:var(--muted);max-width:56ch}
.archive-note{font-family:var(--mono);font-size:12px;color:var(--faint);letter-spacing:.04em;line-height:1.8;text-align:center;padding-bottom:8px}

@media (max-width:640px){
  .specimen.wide{grid-template-columns:1fr}
  .subject-head{grid-template-columns:auto 1fr;gap:14px}
  .sub-status{grid-column:1 / -1;padding-bottom:0}
  .sub-no b{font-size:38px}
  .specimen{margin:12px;padding:8px;gap:8px}
  .sub-notes{grid-template-columns:1fr;gap:4px 0;padding:4px 18px 18px}
  .sub-notes dd{margin-bottom:8px}
}

/* ---------- FORM ---------- */
.lead{position:relative}
.lead .hp{position:absolute;left:-9999px;opacity:0;height:0;width:0}
.field{margin-bottom:16px}
.field label{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--violet-bright);margin-bottom:8px}
.field label span{color:var(--faint);letter-spacing:.08em;text-transform:none}
.field input,.field textarea{
  width:100%;background:var(--ground);border:1px solid var(--faint);border-radius:var(--radius-sm);
  color:var(--ink);font-family:var(--body);font-size:16px;padding:12px 16px;min-height:52px;
  /* box-shadow (the focus ring) deliberately not transitioned, same policy as
     .btn: it is a paint property and an input is a large box. The ring snaps. */
  transition:border-color var(--dur-micro) var(--ease-out);
}
.field textarea{resize:vertical;min-height:72px}
.field input::placeholder,.field textarea::placeholder{color:var(--faint)}
.field input:focus,.field textarea:focus{outline:none;border-color:var(--violet-bright);box-shadow:0 0 0 3px var(--violet-soft)}
.field input[aria-invalid="true"]{border-color:var(--danger);box-shadow:0 0 0 3px rgba(var(--danger-rgb),.14)}
.lead .btn-primary{width:100%}
.lead .err{display:block;margin:12px 0 0;padding:12px;border-radius:var(--radius-sm);background:rgba(var(--danger-rgb),.1);border:1px solid rgba(var(--danger-rgb),.4);color:var(--danger);font-size:14px}
.lead .err:empty{padding:0;border:0;margin:0}
.lead .err .err-text{display:block;margin-top:8px;min-height:44px;line-height:44px;color:var(--cream);font-weight:600;text-decoration:underline;text-underline-offset:4px}
.consent{font-family:var(--mono);font-size:12px;line-height:1.7;color:var(--faint);margin:12px 0 0}
.lead .done{display:none;text-align:center;padding:12px 4px 4px}
.lead .done.show{display:block}
.lead .done .done-mark{display:block;margin:0 auto 12px;color:var(--cream)}
/* cream, not --ok. Green-success against coral-error is the one pair both
   deuteranopia and protanopia collapse, and mint is not in this palette.
   The focus outline stays: site.js moves focus here, so it needs a landing point. */
.lead .done h3{font-family:var(--display);font-weight:800;font-size:24px;color:var(--cream);margin-bottom:8px;line-height:1.25}
.lead .done .echo{color:var(--cream);font-weight:600}
.lead .done p{color:var(--muted);font-size:14px;margin:0}
.lead .done .num{font-family:var(--mono);color:var(--ink)}

/* The fields stay hidden until JS has actually wired the form, so a blocked,
   404ed or broken site.js can never leave a native POST as the only thing a
   tap can do. This supersedes the old noscript style: it covers JS off AND
   JS broken. transition-behavior is its own declaration on purpose, a browser
   that cannot parse it drops that line and the fields snap away as before. */
.lead .fields{display:none}
.lead.ready .fields{display:block}
/* The fields snap away rather than fading. A discrete display transition only
   completes if the transition clock advances, and when it does not the form
   stays on screen alongside the confirmation. The success beat is carried by
   the panel rise and the check seal instead. */
.lead.sent .fields{display:none}
/* direct child only. .cta-form also contains the .done headline, and the
   descendant form of this rule was hiding the success message itself. */
.cta-form:has(.lead.sent)>h3{display:none}
.lead-offline{font-family:var(--mono);font-size:13px;line-height:1.7;color:var(--cream);border:1px dashed var(--frame);background:var(--frame-soft);padding:12px 16px;border-radius:var(--radius-sm);margin:0}
.lead-offline a{color:var(--cream);text-decoration:underline;text-underline-offset:3px;overflow-wrap:anywhere}
.lead.ready .lead-offline{display:none}

/* ---------- FINAL CTA (every page ends here) ---------- */
.cta-final{
  border-top:1px solid var(--line);
  background:linear-gradient(180deg,var(--ground),var(--ground-2));
}
.cta-shell{
  display:grid;grid-template-columns:1fr 1fr;
  border:1px solid var(--violet);border-radius:var(--radius-lg);overflow:hidden;background:var(--panel);
  box-shadow:var(--shadow-lift);
}
.cta-copy{padding:clamp(24px,4vw,40px);border-right:1px solid var(--line)}
.cta-copy h2{font-size:clamp(26px,3.6vw,38px);margin:8px 0 12px;color:var(--cream)}
.cta-copy p{color:var(--muted);font-size:16px;margin:0 0 16px}
.cta-copy p:last-child{margin-bottom:0}
.cta-copy .or{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--faint);margin:20px 0 10px;display:flex;align-items:center;gap:12px}
.cta-copy .or::before,.cta-copy .or::after{content:"";flex:1;border-top:1px solid var(--line)}
.cta-form{padding:clamp(24px,4vw,40px);background:var(--panel-2)}
.cta-form h3{font-size:18px;font-weight:600;margin-bottom:16px;line-height:1.25}

/* ---------- FOOTER ---------- */
footer{border-top:1px solid var(--line);padding-block:40px;background:var(--ground)}
.foot{display:flex;flex-wrap:wrap;gap:24px;justify-content:space-between;align-items:flex-start}
.foot-brand{display:flex;align-items:center;gap:10px;font-family:var(--display);font-weight:800;font-size:16px}
.foot-brand .mark{width:24px;height:24px}
.foot-legal{font-family:var(--mono);font-size:12px;color:var(--faint);margin-top:12px;line-height:1.8;letter-spacing:.04em}
.foot-meta{font-family:var(--mono);font-size:13px;color:var(--muted);line-height:2}
.foot-meta a:hover{color:var(--cream)}
.foot-nav{display:flex;flex-wrap:wrap;gap:8px 16px;font-size:14px;color:var(--muted);margin-top:4px}
.foot-nav a:hover{color:var(--ink)}

/* pressed state for everything that is not a .btn. Colour only, no transform:
   these are text links and moving them shifts the line box. */
.more:active,.tabs a:active,.top-phone:active,.foot-meta a:active,
.foot-nav a:active,.spec .v a:active,.lead-offline a:active,.lead .err .err-text:active{
  color:var(--cream-press);
}
.more:active{text-decoration-color:var(--cream-press)}

/* ---------- STICKY THUMB BAR (mobile, JS-enhanced) ---------- */
.thumb-bar{
  position:fixed;left:0;right:0;bottom:0;z-index:45;display:none;
  /* left/right insets too: a fixed element does not get .wrap padding, so in
     landscape on a notched phone the Text button sits under the housing */
  padding:12px max(20px,env(safe-area-inset-right,0px)) calc(12px + env(safe-area-inset-bottom,0px)) max(20px,env(safe-area-inset-left,0px));
  background:rgba(var(--ground-rgb),.92);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border-top:1px solid var(--violet);
  /* exit: shorter, accelerating. It is getting out of the way. */
  transform:translateY(110%);visibility:hidden;
  transition:transform var(--dur-exit) var(--ease-in),visibility 0s var(--dur-exit);
}
/* enter: longer, decelerating. It is arriving and should feel placed. */
.thumb-bar.show{transform:translateY(0);visibility:visible;transition:transform var(--dur-move) var(--ease-out),visibility 0s}
.thumb-bar .actions{gap:10px}
.thumb-bar .btn{min-height:48px;font-size:15px}
@media (max-width:859px){
  .thumb-bar{display:block}
  body.has-thumb-bar{padding-bottom:calc(84px + env(safe-area-inset-bottom,0px))}
  body.thumb-showing .top .btn-sm{visibility:hidden}
}

/* ---------- RESPONSIVE ---------- */
@media (max-width:859px){
  .cols,.cta-shell{grid-template-columns:1fr}
  .cta-copy{border-right:0;border-bottom:1px solid var(--line)}
}
@media (max-width:480px){
  .hero .wrap{padding-block:12px 24px}
  .hero .tag{letter-spacing:.12em} /* keeps the eyebrow on one line at 375px, protects the fold */
  .hero h1{font-size:29px}
  .hero .lead{margin:8px 0 12px;font-size:15px}
  .hero .actions{flex-wrap:nowrap}
  .hero .actions .btn{min-height:52px;font-size:15px;padding-inline:12px}
  .hero .actions .btn-primary{flex:1 1 auto}
  .hero .actions .btn-secondary{flex:0 0 auto}
  .hero .actions .btn-secondary svg{display:none}
  .hero .fine{margin-top:8px;font-size:12px;line-height:1.5}
  .cta-final .actions .btn{flex-basis:100%}
  .thumb-bar .actions{flex-wrap:nowrap}
  .thumb-bar .actions .btn{flex:1 1 auto}
}
/* Short viewports. A 360x640 phone rotated is 640x360, so none of the width
   queries above fire. Keep the headline, both actions and the bar on screen. */
@media (max-height:520px) and (orientation:landscape){
  .hero .wrap{padding-block:12px 16px}
  .hero h1{font-size:clamp(22px,4.2vw,30px)}
  .hero p.lead{font-size:15px;margin:8px 0 12px;max-width:60ch}
  .hero .fine{margin-top:8px}
  .hero .actions .btn{min-height:44px}
  section{padding-block:32px}
  .thumb-bar{padding-top:6px}
  .thumb-bar .btn{min-height:44px;font-size:14px}
  body.has-thumb-bar{padding-bottom:calc(64px + env(safe-area-inset-bottom,0px))}
}

/* ============================================================
   MOTION LAYER  ·  transform and opacity only, everywhere.
   Entrances are time-based CSS keyframes with fill-mode backwards.
   No JS, no IntersectionObserver, no class toggling: the resting
   state of every element below is its normal, visible one. If this
   stylesheet never loads, the page is plain visible HTML.
   ============================================================ */

/* base for the subject-number underline. Sits at scaleX(0) with no animation
   attached, which is exactly what the page looks like today. */
.sec-head [data-subject]{position:relative;display:inline-block}
.sec-head [data-subject]::after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:2px;border-radius:2px;background:var(--violet-bright);transform:scaleX(0);transform-origin:left center}

@media (prefers-reduced-motion:no-preference){

  /* 1 - hero entrance, top to bottom. The two actions are pinned to the same
        beat as the sentence above them, so the CTA is never last to land.
        Transform only: nothing in the hero can ever be animated to invisible,
        whatever happens to the animation clock. */
  .hero-grid>div>.tag{animation:cl-rise var(--dur-scene) var(--ease-out) 0ms backwards}
  .hero h1{animation:cl-rise var(--dur-scene) var(--ease-out) 60ms backwards}
  .hero p.lead,.hero .actions{animation:cl-rise var(--dur-scene) var(--ease-out) 120ms backwards}
  .hero .fine{animation:cl-rise var(--dur-scene) var(--ease-out) 160ms backwards}
  .hero-alt{animation:cl-rise var(--dur-scene) var(--ease-out) 180ms backwards}

  /* 2 - below the fold only. Transform, never opacity: if a view timeline
        never resolves the worst case is a 12px offset, not hidden text. */
  @supports (animation-timeline:view()){
    .steps .step{animation:cl-settle linear both;animation-timeline:view();animation-range:entry 12% cover 26%}
    .steps .step:nth-child(2){animation-range:entry 6% cover 30%}
    .steps .step:nth-child(3){animation-range:entry 0% cover 34%}
    .sec-head [data-subject]::after{animation:cl-underline linear both;animation-timeline:view();animation-range:entry 45% cover 50%}
  }

  /* 3 - ambient. Desktop only, the header status dot. The solder-joint blink
        that used to sit here was cut: it rendered 2.8px on a phone, which is
        too small to read as the liveness signal it was added to be, and opacity
        on an SVG child is not composited, so it repainted the mark inside a
        backdrop-filtered header on every frame, forever, on all four pages. */
  .lab-tag .dot::after{animation:cl-ping 2400ms var(--ease-out) infinite}

  /* 4 - the form answering back */
  .field input[aria-invalid="true"]{animation:cl-flag var(--dur-micro) var(--ease-out) backwards}
  .lead .err:not(:empty){animation:cl-rise var(--dur-micro) var(--ease-out) backwards}
  .lead .done.show{animation:cl-rise var(--dur-scene) var(--ease-out) 120ms backwards}
  .lead .done.show .done-mark{animation:cl-seal var(--dur-scene) var(--ease-out) var(--dur-scene) backwards}
  .btn[aria-disabled="true"]{animation:cl-working 1200ms var(--ease-loop) infinite}

  /* 5 - thumb bar children settle behind the parent. No forwards fill, so
        :active press feedback resumes the instant this completes. */
  .thumb-bar.show .actions .btn{animation:cl-settle var(--dur-move) var(--ease-out) 60ms backwards}
  .thumb-bar.show .actions .btn+.btn{animation-delay:110ms}
}

@keyframes cl-rise{from{transform:translateY(8px)}to{transform:translateY(0)}}
@keyframes cl-settle{from{transform:translateY(12px)}to{transform:translateY(0)}}
@keyframes cl-seal{from{transform:scale(.82)}to{transform:scale(1)}}
@keyframes cl-flag{from{transform:translateX(5px)}to{transform:translateX(0)}}
@keyframes cl-underline{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes cl-ping{0%{transform:scale(1);opacity:.7}70%,100%{transform:scale(3);opacity:0}}
@keyframes cl-working{0%,100%{opacity:1}50%{opacity:.62}}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  /* Movement off, feedback kept. Reduced motion means do not move me, not do
     not answer me. Opacity is not a vestibular trigger, so confirmations
     still cross-fade rather than cutting. */
  .btn:hover,.btn:active{transform:none}
  .btn{transition:background-color 120ms linear,border-color 120ms linear}
  .thumb-bar{transform:none;opacity:0;transition:opacity 140ms linear,visibility 0s 140ms}
  .thumb-bar.show{transform:none;opacity:1;transition:opacity 140ms linear,visibility 0s}
  .lead .done.show,.lead .done.show .done-mark,.lead .err:not(:empty){animation:none}
  .field input[aria-invalid="true"]{animation:none}
}
