/* ==========================================================================
   Site stylesheet

   Two accents, used in equal measure:
     purple — structure, navigation, links, the design practice
     green  — verification, measured results, the security practice

   The split rules (--rule-h / --rule-v) are literally 50/50 and appear on
   every major structural edge, so neither colour dominates a page.
   ========================================================================== */

/* --- Design tokens: light (default) --------------------------------------- */
:root {
  color-scheme: light;

  --bg:          #F4F5F8;
  --surface:     #FFFFFF;
  --surface-2:   #E9EBF0;
  --line:        #D3D6DF;
  --line-strong: #AEB3C1;

  --ink:   #14161C;
  --ink-2: #414755;
  --ink-3: #6B7182;

  /* Brand pair — never remapped, so split rules stay balanced everywhere */
  --brand-purple:        #5C41A8;
  --brand-purple-ink:    #4E3793;
  --brand-purple-pastel: #A88FE0;
  --brand-green:         #0F7A5A;
  --brand-green-ink:     #0C6249;
  --brand-green-pastel:  #63BE9C;

  /* Working accent — defaults to purple, swapped inside a security context */
  --accent:        var(--brand-purple);
  --accent-ink:    var(--brand-purple-ink);
  --accent-pastel: var(--brand-purple-pastel);
  --accent-soft:   #EBE7F5;
  --on-accent:     #FFFFFF;

  --green-soft: #E3F2EC;

  /* The 50/50 rule, horizontal and vertical */
  --rule-h: linear-gradient(90deg, var(--brand-purple) 0 50%, var(--brand-green) 50% 100%);
  --rule-v: linear-gradient(180deg, var(--brand-purple) 0 50%, var(--brand-green) 50% 100%);

  /* Binary rain: half the columns each */
  --rain-a: #A88FE0;
  --rain-b: #63BE9C;
  --rain-opacity: 0.15;   /* raise for a stronger effect, 0 to disable */

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

  --wrap: 70rem;
  --gutter: clamp(1.25rem, 5vw, 3rem);
  --radius: 3px;
}

/* --- Design tokens: dark, when the system asks for it ---------------------- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg:          #0F1116;
    --surface:     #161921;
    --surface-2:   #1E222C;
    --line:        #2A2F3B;
    --line-strong: #3D4453;

    --ink:   #E8EAEF;
    --ink-2: #AEB4C2;
    --ink-3: #7C8394;

    --brand-purple:        #A88FE0;
    --brand-purple-ink:    #BCA8EC;
    --brand-purple-pastel: #A88FE0;
    --brand-green:         #5FD3A2;
    --brand-green-ink:     #7FE0B4;
    --brand-green-pastel:  #5FD3A2;

    --accent-soft: #1E222C;
    --on-accent:   #14161C;
    --green-soft:  #16241F;

    --rain-a: #A88FE0;
    --rain-b: #5FD3A2;
    --rain-opacity: 0.30;
  }
}

/* --- Manual override, if the visitor picks a mode -------------------------- */
:root[data-theme="dark"] {
  color-scheme: dark;

  --bg:          #0F1116;
  --surface:     #161921;
  --surface-2:   #1E222C;
  --line:        #2A2F3B;
  --line-strong: #3D4453;

  --ink:   #E8EAEF;
  --ink-2: #AEB4C2;
  --ink-3: #7C8394;

  --brand-purple:        #A88FE0;
  --brand-purple-ink:    #BCA8EC;
  --brand-purple-pastel: #A88FE0;
  --brand-green:         #5FD3A2;
  --brand-green-ink:     #7FE0B4;
  --brand-green-pastel:  #5FD3A2;

  --accent-soft: #1E222C;
  --on-accent:   #14161C;
  --green-soft:  #16241F;

  --rain-a: #A88FE0;
  --rain-b: #5FD3A2;
  --rain-opacity: 0.30;
}

/* --- Security context: swaps the working accent to green ------------------
   Applied narrowly (the security card, the security page's CTA) so it tips
   emphasis without turning a whole page one colour.
   -------------------------------------------------------------------------- */
[data-practice="security"] {
  --accent:        var(--brand-green);
  --accent-ink:    var(--brand-green-ink);
  --accent-pastel: var(--brand-green-pastel);
  --accent-soft:   var(--green-soft);
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; background: var(--bg); }

body {
  margin: 0;
  background: transparent;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.025em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1.1em; max-width: 68ch; }
p:last-child { margin-bottom: 0; }

a { color: var(--accent-ink); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { text-decoration-thickness: 2px; }

img { max-width: 100%; display: block; }

:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 3px; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--surface);
  color: var(--ink);
  padding: 0.75rem 1rem;
  z-index: 50;
  border: 1px solid var(--line-strong);
}
.skip:focus { left: 0; }

.label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0;
}

/* Verified / measured result — always green */
.ok {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.9em;
  letter-spacing: 0.01em;
  color: var(--brand-green-ink);
  white-space: nowrap;
}

.status-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  background: var(--brand-green);
  margin-right: 0.55rem;
  flex: none;
}

/* --- Binary rain background ------------------------------------------------ */
.rain {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  opacity: var(--rain-opacity);
  transition: opacity 400ms ease;
}
.rain[hidden] { display: none; }

main, .footer { position: relative; z-index: 1; }

.theme-toggle[aria-pressed="false"] { color: var(--ink-3); }
.theme-toggle[aria-pressed="false"] .theme-toggle__dot { background: var(--line-strong); }

/* --- Header --------------------------------------------------------------- */
.masthead {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line-strong);
}

.masthead__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 62px;
  padding-block: 0.5rem;
}

.wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.9375rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-right: auto;
}

/* The mark: hexagon inherits the ink colour, accents come from the brand pair */
.wordmark__mark {
  width: 22px;
  height: 22px;
  color: var(--ink);
  flex: none;
  overflow: visible;
}
.wordmark__hex   { stroke: currentColor; }
.wordmark__node  { stroke: var(--brand-purple); }
.wordmark__slash { stroke: var(--brand-green); }

.nav { display: flex; align-items: center; gap: 0.15rem; flex-wrap: wrap; }

.nav__link {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-decoration: none;
  padding: 0.55rem 0.7rem;
  border-bottom: 2px solid transparent;
}
.nav__link:hover { color: var(--ink); }
.nav__link[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--brand-purple-pastel);
}
.nav__link[data-practice="security"][aria-current="page"] {
  border-bottom-color: var(--brand-green-pastel);
}

.theme-toggle {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 0.45rem 0.7rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.theme-toggle:hover { border-color: var(--ink-3); color: var(--ink); }
.theme-toggle__dot {
  width: 7px; height: 7px;
  background: var(--brand-purple-pastel);
  flex: none;
}
[data-rain-toggle] .theme-toggle__dot { background: var(--brand-green-pastel); }

/* --- Sections ------------------------------------------------------------- */
.section { padding-block: clamp(3.5rem, 8vw, 5.5rem); }
.section--tight { padding-block: clamp(2.5rem, 5vw, 3.5rem); }
.section--edge { border-top: 1px solid var(--line); }

.section__head { margin-bottom: 2.5rem; max-width: 62ch; }
.section__head .label { margin-bottom: 0.8rem; }
.section__head h2 { font-size: clamp(1.5rem, 3.4vw, 2.125rem); }
.section__head p { margin-top: 0.9rem; color: var(--ink-2); }

/* --- Hero ----------------------------------------------------------------- */
.hero { padding-block: clamp(3.5rem, 9vw, 6rem) clamp(2rem, 5vw, 3rem); }
.hero .label { margin-bottom: 1.35rem; }

.hero h1 {
  font-size: clamp(2.375rem, 7vw, 4.5rem);
  max-width: 17ch;
  letter-spacing: -0.035em;
}
.hero h1 em { font-style: normal; }
.hero h1 .build { color: var(--brand-purple-ink); }
.hero h1 .break { color: var(--brand-green-ink); }
.hero h1 .lock  { color: var(--brand-green-ink); }

.hero__lede {
  margin-top: 1.5rem;
  font-size: clamp(1rem, 1.8vw, 1.125rem);
  color: var(--ink-2);
  max-width: 58ch;
}

/* --- Dual-track: the two practices, split by the accent spine -------------- */
.tracks {
  position: relative;
  display: grid;
  gap: 0;
  grid-template-columns: 1fr;
  margin-top: clamp(2.5rem, 6vw, 4rem);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.tracks::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--rule-h);
  z-index: 2;
}

.track {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  padding: clamp(1.75rem, 4vw, 2.25rem) clamp(1.5rem, 4vw, 2.25rem) clamp(1.5rem, 4vw, 2.25rem);
  text-decoration: none;
  color: inherit;
  transition: background 140ms ease;
}
.track + .track { border-top: 2px solid var(--accent-pastel); }
.track:hover { background: var(--accent-soft); }
.track h2 { font-size: clamp(1.375rem, 3vw, 1.75rem); }
.track p { color: var(--ink-2); font-size: 0.9375rem; margin: 0; }

.track__go {
  margin-top: auto;
  padding-top: 0.75rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-ink);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.track__arrow { transition: transform 140ms ease; }
.track:hover .track__arrow { transform: translateX(4px); }

@media (min-width: 46rem) {
  .tracks { grid-template-columns: 1fr 1fr; }
  .track + .track { border-top: 0; border-left: 2px solid var(--accent-pastel); }
}

/* --- Steps ---------------------------------------------------------------- */
.steps { display: grid; gap: 1.75rem; grid-template-columns: 1fr; list-style: none; margin: 0; padding: 0; }
@media (min-width: 44rem) { .steps { grid-template-columns: repeat(3, 1fr); gap: 2rem; } }

.step {
  padding-top: 1rem;
  background-image: var(--rule-h);
  background-size: 100% 3px;
  background-repeat: no-repeat;
  background-position: 0 0;
}
.step h3 { font-size: 1.0625rem; margin-bottom: 0.5rem; }
.step p { color: var(--ink-2); font-size: 0.9375rem; margin: 0; }
.step .label { margin-bottom: 0.6rem; }

/* --- Project record ------------------------------------------------------- */
.record {
  border-top: 1px solid var(--line);
  padding-block: clamp(1.75rem, 4vw, 2.5rem);
}
.record:last-child { border-bottom: 1px solid var(--line); }

.record__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.85rem;
}
.record__top h3 { font-size: clamp(1.25rem, 2.6vw, 1.5rem); }
.record__year {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--ink-3);
  letter-spacing: 0.1em;
}

.record__body { color: var(--ink-2); }

.record__spec {
  margin: 1.4rem 0 0;
  display: grid;
  gap: 0.5rem 1.25rem;
  grid-template-columns: 1fr;
  padding-left: 1.1rem;
  background-image: var(--rule-v);
  background-size: 3px 100%;
  background-repeat: no-repeat;
  background-position: 0 0;
}
@media (min-width: 40rem) {
  .record__spec { grid-template-columns: 7.5rem 1fr; align-items: baseline; }
}
.record__spec dt {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-top: 0.15rem;
}
.record__spec dd { margin: 0 0 0.35rem; font-size: 0.9375rem; color: var(--ink); }
@media (min-width: 40rem) { .record__spec dd { margin-bottom: 0; } }

/* --- Capability / skill columns ------------------------------------------ */
.cols { display: grid; gap: 2rem; grid-template-columns: 1fr; }
@media (min-width: 44rem) { .cols { grid-template-columns: repeat(2, 1fr); gap: 2.5rem; } }
@media (min-width: 60rem) { .cols--3 { grid-template-columns: repeat(3, 1fr); } }

.col h3 {
  font-size: 0.8125rem;
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 1rem;
  padding-bottom: 0.7rem;
  background-image: var(--rule-h);
  background-size: 100% 2px;
  background-repeat: no-repeat;
  background-position: 0 100%;
}

.ticklist { list-style: none; margin: 0; padding: 0; }
.ticklist li {
  position: relative;
  padding-left: 1.35rem;
  margin-bottom: 0.55rem;
  font-size: 0.9375rem;
  color: var(--ink-2);
}
.ticklist li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 9px;
  height: 3px;
  background: var(--brand-purple-pastel);
}
/* Alternate the ticks so a column of capabilities carries both accents */
.ticklist li:nth-child(even)::before { background: var(--brand-green-pastel); }

/* --- Callout -------------------------------------------------------------- */
.callout {
  background-color: var(--surface);
  background-image: var(--rule-v);
  background-size: 4px 100%;
  background-repeat: no-repeat;
  background-position: 0 0;
  border: 1px solid var(--line-strong);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: clamp(1.25rem, 3vw, 1.75rem) clamp(1.25rem, 3vw, 1.75rem) clamp(1.25rem, 3vw, 1.75rem) clamp(1.5rem, 3vw, 2rem);
}
.callout h3 {
  font-size: 0.8125rem;
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 0.75rem;
}
.callout p { color: var(--ink-2); font-size: 0.9375rem; }

/* --- Contact -------------------------------------------------------------- */
.contact {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: clamp(2rem, 5vw, 3rem) clamp(1.75rem, 5vw, 3rem) clamp(1.75rem, 5vw, 3rem);
  overflow: hidden;
}
.contact::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--rule-h);
}
.contact h2 { font-size: clamp(1.5rem, 3.4vw, 2.125rem); margin: 0.8rem 0 0.9rem; }
.contact p { color: var(--ink-2); }

.contact__links { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.5rem; }

.btn {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.85rem 1.35rem;
  border-radius: var(--radius);
  border: 1px solid var(--line-strong);
  color: var(--ink);
  background: transparent;
  transition: border-color 140ms ease, background 140ms ease, color 140ms ease;
}
.btn:hover { border-color: var(--brand-green); background: var(--green-soft); color: var(--ink); }

.btn--primary {
  background: var(--brand-purple);
  border-color: var(--brand-purple);
  color: var(--on-accent);
}
.btn--primary:hover {
  background: var(--brand-purple);
  border-color: var(--brand-purple);
  color: var(--on-accent);
  filter: brightness(1.12);
}

/* Green primary — used for the security page's call to action */
.btn--verify {
  background: var(--brand-green);
  border-color: var(--brand-green);
  color: var(--on-accent);
}
.btn--verify:hover {
  background: var(--brand-green);
  border-color: var(--brand-green);
  color: var(--on-accent);
  filter: brightness(1.12);
}

/* --- Pending button: profile links not live yet ---------------------------
   Same footprint as .btn, but visibly a status, not a link. The three dots
   pulse in sequence; with reduced motion they render as still dots.
   -------------------------------------------------------------------------- */
.btn--pending {
  cursor: default;
  color: var(--ink-3);
  border-style: dashed;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}
.btn--pending:hover { border-color: var(--line-strong); background: transparent; color: var(--ink-3); }

.pending-dots {
  display: inline-flex;
  gap: 4px;
  align-items: center;
}
.pending-dots i {
  width: 5px;
  height: 5px;
  background: var(--brand-purple-pastel);
  animation: pending-pulse 1.2s infinite ease-in-out;
}
.pending-dots i:nth-child(2) {
  background: var(--brand-green-pastel);
  animation-delay: 0.2s;
}
.pending-dots i:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes pending-pulse {
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
  40%           { opacity: 1;    transform: translateY(-2px); }
}

@media (prefers-reduced-motion: reduce) {
  .pending-dots i { animation: none; opacity: 0.6; }
}

/* --- Footer --------------------------------------------------------------- */
.footer {
  border-top: 1px solid var(--line-strong);
  padding-block: 2.5rem 3rem;
  margin-top: clamp(3rem, 7vw, 5rem);
}
.footer__inner {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: center;
}
.footer p {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0;
}
.footer a { color: var(--ink-2); }
.footer a[data-practice="security"] { color: var(--brand-green-ink); }

/* --- Scroll reveal -------------------------------------------------------- */
.reveal { opacity: 0; transform: translateY(12px); }
.reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 500ms ease, transform 500ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .reveal.is-in { opacity: 1; transform: none; transition: none; }
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}


/* --- Loading overlay ------------------------------------------------------
   The mark draws itself, the 50/50 rule sweeps beneath it. Three safety nets:
   a CSS failsafe that hides the overlay at 6s with no JS involved, a JS
   timeout at the same mark, and removal from the DOM once it has faded.
   -------------------------------------------------------------------------- */
html.is-loading { overflow: hidden; }

.loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: clamp(1.25rem, 4vw, 2rem);
  background: var(--bg);
  animation: loader-failsafe 400ms ease 6s forwards;
}
.loader.is-done { animation: loader-out 420ms cubic-bezier(0.4, 0, 0.2, 1) forwards; }

@keyframes loader-out     { to { opacity: 0; visibility: hidden; transform: scale(1.04); } }
@keyframes loader-failsafe { to { opacity: 0; visibility: hidden; } }

.loader__sr {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.loader__mark {
  width: clamp(84px, 22vw, 124px);
  height: clamp(84px, 22vw, 124px);
  color: var(--ink);
  overflow: visible;
  animation: loader-pulse 1.4s ease-in-out infinite;
}
@keyframes loader-pulse {
  0%, 100% { transform: scale(1)    rotate(0deg); }
  50%      { transform: scale(1.07) rotate(-2deg); }
}

.loader__hex,
.loader__node,
.loader__slash {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: loader-draw 1.4s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
.loader__hex   { stroke: currentColor; }
.loader__node  { stroke: var(--brand-purple); animation-delay: 0.12s; }
.loader__slash { stroke: var(--brand-green);  animation-delay: 0.24s; }

@keyframes loader-draw {
  0%   { stroke-dashoffset:  100; opacity: 0.2; }
  40%  { stroke-dashoffset:    0; opacity: 1; }
  70%  { stroke-dashoffset:    0; opacity: 1; }
  100% { stroke-dashoffset: -100; opacity: 0.2; }
}

.loader__bar {
  position: relative;
  width: clamp(110px, 28vw, 180px);
  height: 3px;
  background: var(--surface-2);
  overflow: hidden;
}
.loader__bar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--rule-h);
  animation: loader-sweep 1.4s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes loader-sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* --- Standing mark: the loader's draw, running inline on a page ------------
   Same hex / node / slash animation as the loading overlay, but as a
   permanent decorative element rather than a one-shot on page load.
   -------------------------------------------------------------------------- */
.markloop {
  display: grid;
  place-items: center;
  gap: clamp(1rem, 3vw, 1.5rem);
  margin: 0 0 clamp(1.75rem, 4vw, 2.5rem);
}
.markloop__svg {
  width: clamp(72px, 16vw, 104px);
  height: clamp(72px, 16vw, 104px);
  color: var(--ink);
  overflow: visible;
  animation: loader-pulse 1.4s ease-in-out infinite;
}
.markloop__hex,
.markloop__node,
.markloop__slash {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: loader-draw 1.4s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
.markloop__hex   { stroke: currentColor; }
.markloop__node  { stroke: var(--brand-purple); animation-delay: 0.12s; }
.markloop__slash { stroke: var(--brand-green);  animation-delay: 0.24s; }

.markloop__bar {
  position: relative;
  width: clamp(96px, 24vw, 150px);
  height: 3px;
  background: var(--surface-2);
  overflow: hidden;
}
.markloop__bar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--rule-h);
  animation: loader-sweep 1.4s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

/* Live-site link inside a project record */
.record__spec dd a { font-family: var(--font-mono); font-size: 0.875rem; }

@media (prefers-reduced-motion: reduce) {
  .loader { animation: loader-failsafe 1ms linear 500ms forwards; }
  .loader__mark,
  .loader__bar::after { animation: none; }
  .loader__hex,
  .loader__node,
  .loader__slash { animation: none; stroke-dashoffset: 0; opacity: 1; }

  .markloop__svg,
  .markloop__bar::after { animation: none; }
  .markloop__hex,
  .markloop__node,
  .markloop__slash { animation: none; stroke-dashoffset: 0; opacity: 1; }
}

/* --- Long-form article body ------------------------------------------------
   Used on build guides and posts. Wraps the measure and gives headings,
   lists, code and tables consistent rhythm without per-page inline styles.
   -------------------------------------------------------------------------- */
.prose { max-width: 68ch; }

.prose h2 {
  font-size: clamp(1.375rem, 3vw, 1.75rem);
  margin: 2.75rem 0 1rem;
  padding-top: 1rem;
  background-image: var(--rule-h);
  background-size: 100% 3px;
  background-repeat: no-repeat;
  background-position: 0 0;
}
.prose h2:first-child { margin-top: 0; }

.prose h3 {
  font-size: 1.0625rem;
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.06em;
  margin: 2rem 0 0.75rem;
}

.prose ul, .prose ol { margin: 0 0 1.1em; padding-left: 1.3rem; max-width: 68ch; }
.prose li { margin-bottom: 0.5rem; color: var(--ink-2); }
.prose li::marker { color: var(--accent-pastel); }
.prose li > ul, .prose li > ol { margin-top: 0.5rem; }

.prose > .callout,
.prose > .figure,
.prose > .bom-wrap { margin-block: 1.75rem; }

/* Inline code and blocks */
code {
  font-family: var(--font-mono);
  font-size: 0.875em;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.1em 0.35em;
  word-break: break-word;
}

pre {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  line-height: 1.7;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 0 var(--radius) var(--radius) 0;
  background-image: var(--rule-v);
  background-size: 4px 100%;
  background-repeat: no-repeat;
  background-position: 0 0;
  padding: 1rem 1rem 1rem 1.5rem;
  margin: 1.5rem 0;
  overflow-x: auto;
  color: var(--ink);
}
pre code { background: none; border: 0; padding: 0; font-size: inherit; }

/* --- Bill of materials ----------------------------------------------------- */
.bom-wrap { overflow-x: auto; }

.bom {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
  min-width: 34rem;
}
.bom caption {
  text-align: left;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-bottom: 0.7rem;
}
.bom th, .bom td {
  text-align: left;
  padding: 0.7rem 1rem 0.7rem 0;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.bom thead th {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-bottom: 2px solid var(--line-strong);
}
.bom tbody th {
  font-family: var(--font-body);
  font-weight: 600;
  color: var(--ink);
}
.bom td { color: var(--ink-2); }
.bom td:last-child, .bom th:last-child { padding-right: 0; }
.bom .bom__price {
  font-family: var(--font-mono);
  font-size: 0.875rem;
  color: var(--ink);
  white-space: nowrap;
}
.bom .bom__group th {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--surface-2);
  padding-left: 0.6rem;
  border-bottom: 1px solid var(--line-strong);
}

/* --- Figure / media placeholder -------------------------------------------- */
.figure { margin: 1.75rem 0; }
.figure__frame {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  aspect-ratio: 16 / 9;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 1.5rem;
}
.figure__frame video,
.figure__frame iframe,
.figure__frame img { width: 100%; height: 100%; object-fit: cover; border: 0; }
.figure figcaption {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-top: 0.7rem;
}

/* --- Affiliate / small print ----------------------------------------------- */
.disclosure {
  font-size: 0.8125rem;
  color: var(--ink-3);
  border-top: 1px solid var(--line);
  padding-top: 1rem;
  margin-top: 2.5rem;
  max-width: 68ch;
}

/* --- Series navigation on a guide ------------------------------------------ */
.series { margin-top: 2.5rem; }
.series ol { list-style: none; margin: 0; padding: 0; counter-reset: series; }
.series li {
  counter-increment: series;
  position: relative;
  padding-left: 2.4rem;
  margin-bottom: 0.7rem;
  font-size: 0.9375rem;
  color: var(--ink-2);
}
.series li::before {
  content: counter(series, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  color: var(--ink-3);
}
.series li[aria-current="true"] { color: var(--ink); font-weight: 600; }
.series li[aria-current="true"]::before { color: var(--accent-ink); }

/* --- Category group heading inside a section ------------------------------- */
.group__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 2.5rem 0 0.25rem;
  padding-bottom: 0.7rem;
  background-image: var(--rule-h);
  background-size: 100% 2px;
  background-repeat: no-repeat;
  background-position: 0 100%;
}
.group__head h3 {
  font-size: 0.8125rem;
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
}
.group__count {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  color: var(--ink-3);
}

/* Figure frame holding real media rather than a placeholder */
.figure__frame--media {
  padding: 0;
  overflow: hidden;
  background: #14161C;
}
.figure__frame--media video { display: block; }



/* ==========================================================================
   Header navigation — one row on wide screens, a drawer on narrow ones

   The full row (wordmark + five links + two toggles) needs roughly 1000px
   before it starts to crowd, so 62rem is where the drawer takes over. Above
   that breakpoint the burger is removed from the document entirely and the
   panel is a plain flex row, exactly as it always was.
   ========================================================================== */

.navpanel {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-left: auto;
}

.navpanel__tools {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.navburger { display: none; }

@media (max-width: 61.999rem) {

  .navburger {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 0.625rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-2);
    background: transparent;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    /* 44px minimum touch target */
    min-height: 44px;
    padding: 0.5rem 0.8rem;
    cursor: pointer;
  }
  .navburger:hover { color: var(--ink); border-color: var(--ink-3); }
  .navburger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

  .navburger__box {
    position: relative;
    width: 16px;
    height: 12px;
    flex: none;
  }
  .navburger__box i {
    position: absolute;
    left: 0;
    width: 100%;
    height: 2px;
    border-radius: 2px;
    background: var(--ink-2);
    transition: transform 0.22s ease, opacity 0.16s ease, background-color 0.2s ease;
  }
  .navburger__box i:nth-child(1) { top: 0; }
  .navburger__box i:nth-child(2) { top: 5px; }
  .navburger__box i:nth-child(3) { top: 10px; }

  /* The two brand colours split the mark when it becomes a close button. */
  .navburger[aria-expanded="true"] .navburger__box i:nth-child(1) {
    transform: translateY(5px) rotate(45deg);
    background: var(--brand-purple);
  }
  .navburger[aria-expanded="true"] .navburger__box i:nth-child(2) { opacity: 0; }
  .navburger[aria-expanded="true"] .navburger__box i:nth-child(3) {
    transform: translateY(-5px) rotate(-45deg);
    background: var(--brand-green);
  }

  .navpanel {
    position: fixed;
    top: var(--masthead-h, 62px);
    left: 0;
    right: 0;
    z-index: 19;
    display: block;
    margin-left: 0;
    padding: 0.5rem var(--gutter) 1.5rem;
    background: var(--bg);
    border-bottom: 1px solid var(--line-strong);
    box-shadow: 0 18px 40px -28px rgba(0, 0, 0, 0.55);

    /* Closed state: collapsed and inert, but still in the flow for animation. */
    visibility: hidden;
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0.2s;
    max-height: calc(100dvh - var(--masthead-h, 62px));
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  .navpanel.is-open {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s;
  }

  /* Stacked links, each a comfortable target, separated by hairlines. */
  .navpanel .nav {
    display: block;
    border-top: 1px solid var(--line);
  }
  .navpanel .nav__link {
    display: flex;
    align-items: center;
    min-height: 52px;
    padding: 0.5rem 0.25rem;
    font-size: 0.75rem;
    border-bottom: 1px solid var(--line);
    border-left: 2px solid transparent;
    padding-left: 0.75rem;
  }
  .navpanel .nav__link[aria-current="page"] {
    border-bottom-color: var(--line);
    border-left-color: var(--brand-purple-pastel);
    background: var(--surface-2);
  }
  .navpanel .nav__link[data-practice="security"][aria-current="page"] {
    border-left-color: var(--brand-green-pastel);
  }

  .navpanel__tools {
    margin-top: 1.1rem;
    gap: 0.6rem;
  }
  .navpanel__tools .theme-toggle { min-height: 44px; }

  .navscrim {
    position: fixed;
    inset: 0;
    z-index: 18;
    background: rgba(8, 9, 12, 0.42);
    backdrop-filter: blur(2px);
    border: 0;
  }

  /* Scroll lock while the drawer is open. */
  html.nav-open, html.nav-open body { overflow: hidden; }
}

@media (prefers-reduced-motion: reduce) {
  .navpanel { transition: none; }
  .navburger__box i { transition: none; }
}

/* --- Footer profile row --------------------------------------------------- */

.footer__social { display: flex; gap: 0.4rem; flex-wrap: wrap; align-items: center; }

/* --- Narrow-screen safety net --------------------------------------------
   Nothing below should ever be able to push the page sideways: long URLs,
   wide tables, and media all get a hard ceiling at the viewport width.
   -------------------------------------------------------------------------- */

html { overflow-x: hidden; }

img, video, svg, iframe { max-width: 100%; }

/* Long verification URLs and inline links wrap instead of overflowing. */
.record__spec dd, .record__spec dd a, .contact__links a[href^="mailto"] {
  overflow-wrap: anywhere;
}

@media (max-width: 30rem) {
  /* Stack full-width buttons so nothing is a cramped half-target. */
  .contact__links { flex-direction: column; align-items: stretch; }
  .contact__links .btn { justify-content: center; text-align: center; }
  .footer__inner { flex-direction: column; align-items: flex-start; gap: 0.6rem; }
}

/* --- Bill of materials on narrow screens ----------------------------------
   Below the table's natural minimum the three columns stop being a table and
   become one stacked card per part: name, notes, then a labelled price. The
   markup is unchanged, so the table stays a table for screen readers.
   -------------------------------------------------------------------------- */

@media (max-width: 37.5rem) {
  .bom-wrap { overflow-x: visible; }

  .bom { min-width: 0; display: block; }
  .bom thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .bom caption, .bom tbody { display: block; }

  .bom tbody tr {
    display: block;
    padding: 0.85rem 0 0.9rem;
    border-bottom: 1px solid var(--line);
  }
  .bom tbody th, .bom tbody td {
    display: block;
    padding: 0;
    border: 0;
  }
  .bom tbody th[scope="row"] { margin-bottom: 0.25rem; }
  .bom tbody td { margin-top: 0.3rem; }

  /* The group heading keeps its band and spans the full card width. */
  .bom tbody tr.bom__group { padding: 0; border-bottom: 0; }
  .bom .bom__group th {
    padding: 0.5rem 0.6rem;
    margin-top: 1.4rem;
    border-bottom: 1px solid var(--line-strong);
  }
  .bom tbody tr.bom__group:first-child th { margin-top: 0; }

  .bom .bom__price::before {
    content: "Price ";
    font-size: 0.6875rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-3);
  }
}

/* Single-line snippets (a URL, a settings path, a config line) wrap on narrow
   screens rather than hiding themselves behind a sideways scroll. */
@media (max-width: 37.5rem) {
  pre { white-space: pre-wrap; overflow-wrap: anywhere; }
}
