/* ============================================================
   5uj4n.com — shared stylesheet

   ONE file for the whole site. Every page links this and carries
   markup only. Before this existed the token block was pasted into
   each page, and mc.html silently drifted out of sync — different
   panel opacity, different blur, a cursor that stopped blinking.
   That is why this file exists. Do not copy it back into a page.

   Governed by DESIGN_BRIEF.md + DESIGN_SYSTEM.md in the repo root.
   Read those before changing anything here.

   ORDER: tokens · base · background · chrome · components ·
          page-scoped · motion
   ============================================================ */

/* ============================================================
   1. TOKENS
   ============================================================ */
:root {
  /* ---- Catppuccin Mocha — the source palette. Never introduce a
     hue from outside it; derive with color-mix() instead. ---- */
  --ctp-base:     #1e1e2e;
  --ctp-mantle:   #181825;
  --ctp-crust:    #11111b;
  --ctp-surface0: #313244;
  --ctp-surface1: #45475a;
  --ctp-surface2: #585b70;
  --ctp-overlay0: #6c7086;
  --ctp-overlay1: #7f849c;
  --ctp-text:     #cdd6f4;
  --ctp-subtext1: #bac2de;
  --ctp-subtext0: #a6adc8;
  --ctp-blue:     #89b4fa;
  --ctp-mauve:    #cba6f7;
  --ctp-green:    #a6e3a1;
  --ctp-peach:    #fab387;
  --ctp-sapphire: #74c7ec;
  --ctp-teal:     #94e2d5;
  --ctp-yellow:   #f9e2af;
  --ctp-red:      #f38ba8;

  /* ---- Semantic layer. Components reference ONLY these. ----
     Change --accent to reskin the site in one line. */
  --bg:             var(--ctp-base);
  --text:           var(--ctp-text);
  --text-secondary: var(--ctp-subtext1);
  --text-muted:     var(--ctp-subtext0);
  --text-dim:       var(--ctp-overlay1);
  --accent:         var(--ctp-blue);

  /* crust as raw components, so the veil and focus ring can vary
     alpha without hard-coding a hex outside this block */
  --veil-rgb: 17, 17, 27;

  /* ---- Surfaces ---- */
  --panel-bg:      rgba(49, 50, 68, 0.24);
  --panel-border:  rgba(205, 214, 244, 0.10);
  --panel-blur:    24px;
  --card-bg:       rgba(17, 17, 27, 0.28);
  --card-bg-hover: rgba(17, 17, 27, 0.42);
  --card-border:   rgba(205, 214, 244, 0.08);

  /* ---- Type ---- */
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, Consolas, monospace;

  /* ---- Type scale. Six steps. Thirteen ad-hoc values collapsed into
     these; --fs-xs is the floor, chosen so nothing renders below
     ~11.5px. Use a token, never a literal. ---- */
  --fs-xs:   0.72rem;   /* smallest chrome: pills, captions, badges, annotations */
  --fs-sm:   0.78rem;   /* labels: eyebrows, footers, tags, chips, back link     */
  --fs-md:   0.85rem;   /* descriptions, spec tables, meta lines, CTAs           */
  --fs-lg:   0.95rem;   /* component names                                       */
  --fs-body: 1.02rem;   /* prose                                                 */
  --fs-xl:   1.05rem;   /* index card names, photo-essay section headings        */

  --maxw:    44rem;   /* the reading column */
  --measure: 68ch;    /* prose cap; effectively lets the panel govern */

  /* ---- Spacing. ONE scale, everything derives from --sp. ----
     Generalised from miata.html, which was the only page that had it. */
  --sp:       clamp(1rem, 3vh, 1.5rem);   /* blocks within a section */
  --sp-tight: 0.5rem;                     /* caption to its image    */
  --gap:      0.5rem;                     /* gallery gutter          */

  /* Section rhythm on photo-essay pages. The one knob to turn if the
     gap above a section heading looks wrong. 1 = flush with the rest
     of the site, 2 = airy, 2.5 = too much. Fractions are fine. */
  --sp-section-mult: 1.5;
  --sp-section: calc(clamp(1rem, 3vh, 1.5rem) * var(--sp-section-mult));

  /* ---- Radius. Five steps, each with a job. No one-offs. ---- */
  --r-panel: 16px;
  --r-card:  12px;
  --r-tile:  10px;
  --r-chip:   6px;
  --r-pill:  999px;

  /* ---- Motion. One hover grammar for the whole site. ---- */
  --t: 0.18s ease;
  --lift: -2px;

  color-scheme: dark;
}

/* ============================================================
   2. BASE
   ============================================================ */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;

  /* ---- BACKGROUND PHOTOGRAPH — per-page, set below ----
     The photo is a GROUND, not a subject: a visitor should register
     texture and depth, not identify objects in it.

     VEIL. The only thing between the reader and the photograph.
     LOWER = more photo. HIGHER = darker, calmer. Keep the bottom
     higher than the top; pages get busier as you scroll.

     The rule is an OUTCOME, not a number. Photographs differ in
     brightness, so each page tunes its own values until all text
     sitting directly on the background is comfortably readable
     against the BRIGHTEST pixel of the veiled image inside the
     reading column. Measure it; do not guess.

     Practical form, no measurement needed: --text-secondary is the
     floor for readable text ANYWHERE — panels do not lift contrast.
     --panel-bg over the veiled background computes to a delta of
     exactly (0,0,0); a panel is a visual device, not a contrast one.
     --text-muted is fine for secondary labels inside a panel.
     --text-dim is DECORATION ONLY: chevrons, disabled states. */
  --bg-image:       url("background.jpg");
  --bg-veil-top:    0.78;
  --bg-veil-bottom: 0.87;
  --bg-pos:         50% 50%;
}

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(
      rgba(var(--veil-rgb), var(--bg-veil-top)),
      rgba(var(--veil-rgb), var(--bg-veil-bottom))
    ),
    var(--bg-image);
  background-position: center, var(--bg-pos);
  background-size: cover, cover;
  background-repeat: no-repeat, no-repeat;
}

.wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(3rem, 9vh, 6rem) clamp(1.25rem, 5vw, 2rem) 3rem;
  animation: rise 0.5s ease both;
}
@keyframes rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* ============================================================
   3. CHROME
   ============================================================ */

/* ---- back link ---- */
.back {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-secondary);   /* on the photo — see veil note */
  text-decoration: none;
  /* hit area: the visible text is only ~21px tall, so pad it out to ~45px
     and pull the padding back off with negative margin — the link does not
     move, but it becomes tappable. */
  padding: 0.75rem 0.6rem;
  margin: -0.75rem -0.6rem 0.75rem;
  transition: color var(--t);
}
.back:hover, .back:focus-visible { color: var(--accent); }
.back svg { width: 0.9rem; height: 0.9rem; }

/* ---- glass panels ---- */
.panel {
  background: var(--panel-bg);
  -webkit-backdrop-filter: blur(var(--panel-blur)) saturate(140%);
          backdrop-filter: blur(var(--panel-blur)) saturate(140%);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-panel);
  padding: clamp(1.5rem, 4vw, 2rem);
}
.panel + .panel { margin-top: var(--sp); }

/* if the browser can't frost, make panels near-opaque so text stays readable */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .panel { background: rgba(30, 30, 46, 0.92); }
}

/* ---- hero ---- */
.hero__mark {
  font-size: clamp(2rem, 6vw, 2.6rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  margin: 0;
  line-height: 1.1;
}
.hero__cursor {
  display: inline-block;
  width: 0.55ch;
  height: 1.05em;
  margin-left: 0.15em;
  background: var(--accent);
  vertical-align: -0.12em;
  animation: blink 1.2s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* Both sit on the photograph — --text-secondary is the floor there. */
.hero__meta {
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  color: var(--text-secondary);
  margin: 0.85rem 0 0;
  max-width: 80ch;
  letter-spacing: 0.01em;
}
.hero__tag {
  color: var(--text-secondary);
  font-size: var(--fs-lg);
  margin: 0.9rem 0 0;
  max-width: 80ch;
}
header + .panel, header + .sec { margin-top: var(--sp); }

/* Optional avatar. The HTML block is commented out in whoami.html as a
   documented "uncomment to use" affordance — keep this so it isn't a trap. */
.hero__row { display: flex; align-items: center; gap: 1.1rem; }
.avatar {
  flex: none;
  width: 3.75rem;
  height: 3.75rem;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--card-border);
}

/* ---- section label ---- */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 400;          /* it is an <h2>; do not let it go bold */
  color: var(--text-muted);
  letter-spacing: 0.04em;
  margin: 0 0 1rem;
}
.eyebrow::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}

/* ---- prose ---- */
.prose {
  color: var(--text-secondary);
  font-size: var(--fs-body);
  max-width: var(--measure);
  margin: 0;
}
.prose + .prose { margin-top: 0.85rem; }
.prose em { color: var(--text); font-style: italic; }
.prose a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.prose a:hover, .prose a:focus-visible { border-bottom-color: currentColor; }

/* ---- footer ---- */
.foot {
  margin-top: var(--sp);
  padding: 0 clamp(1.5rem, 4vw, 2rem);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-secondary);   /* on the photo */
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.foot a { color: var(--text-secondary); text-decoration: none; }
.foot a:hover, .foot a:focus-visible { color: var(--accent); }
.foot .back { margin: -0.75rem -0.6rem; }

/* ============================================================
   4. COMPONENTS

   THE ONE HOVER GRAMMAR. Every interactive element uses exactly
   this: accent border, background lift, -2px rise, 0.18s. The rule
   is that there is ONE grammar — not that these are eternal
   numbers. Retune globally if you like; never add a second.
   ============================================================ */
.card,
a.row,
.lab__card,
.tile {
  transition: border-color var(--t), transform var(--t), background var(--t);
}
.card:hover, .card:focus-visible,
a.row:hover, a.row:focus-visible,
.lab__card:hover, .lab__card:focus-visible,
.tile:hover, .tile:focus-visible {
  border-color: var(--accent);
  transform: translateY(var(--lift));
  outline: none;
}
.card:hover, .card:focus-visible,
a.row:hover, a.row:focus-visible {
  background: var(--card-bg-hover);
}
/* one focus ring, readable over any background */
.card:focus-visible,
a.row:focus-visible,
.lab__card:focus-visible,
.tile:focus-visible {
  box-shadow: 0 0 0 2px rgba(var(--veil-rgb), 0.6), 0 0 0 4px var(--accent);
}

/* ---- chevron affordance (CSS-only, no asset) ---- */
.card::after,
a.row::after {
  content: "";
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-left: auto;
  background-color: var(--text-dim);
  -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23000" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 6 15 12 9 18"/></svg>') center / contain no-repeat;
          mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23000" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 6 15 12 9 18"/></svg>') center / contain no-repeat;
  transition: transform var(--t), background-color var(--t);
}
.card:hover::after, .card:focus-visible::after,
a.row:hover::after, a.row:focus-visible::after {
  background-color: var(--accent);
  transform: translateX(3px);
}

/* ---- grid of cards ---- */
.grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;   /* single column: full-width rows */
  gap: 0.75rem;
}

/* ---- .card — NAVIGATIONAL row. Links only. ---- */
.card {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  padding: 1.15rem 1.25rem;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--r-card);
  color: inherit;
  text-decoration: none;
}
.card__body { min-width: 0; }
.card__row { display: flex; align-items: center; gap: 0.5rem; }
.card__name { font-weight: 500; font-size: var(--fs-xl); }
.card__desc { font-size: var(--fs-md); color: var(--text-muted); margin-top: 0.15rem; }

/* Placeholders must visibly recede — signalling what's coming is
   friendly, letting it look shipped is misleading. Tokens do the
   work; no opacity hacks. Also needs tabindex="-1" in the markup. */
.card[aria-disabled="true"] { cursor: default; }
.card[aria-disabled="true"]:hover,
.card[aria-disabled="true"]:focus-visible {
  transform: none;
  border-color: var(--card-border);
  background: var(--card-bg);
  box-shadow: none;
}
.card[aria-disabled="true"]::after { display: none; }
.card[aria-disabled="true"] .icon {
  color: var(--text-dim);
  background: color-mix(in srgb, var(--text-dim) 14%, transparent);
}
.card[aria-disabled="true"] .card__name { color: var(--text-muted); }
.card[aria-disabled="true"] .card__desc { color: var(--text-dim); }

/* ---- icon tile ---- */
.icon {
  flex: none;
  width: 3rem;
  height: 3rem;
  border-radius: var(--r-card);
  display: grid;
  place-items: center;
  color: var(--ic, var(--accent));
  background: color-mix(in srgb, var(--ic, var(--accent)) 18%, transparent);
}
.icon svg { width: 1.5rem; height: 1.5rem; }

/* ---- slim card variant ---- */
.card--sub { gap: 0.9rem; padding: 0.85rem 1rem; margin-top: 0.75rem; }
.card--sub .icon { width: 2.25rem; height: 2.25rem; border-radius: var(--r-tile); }
.card--sub .icon svg { width: 1.15rem; height: 1.15rem; }
.card--sub .card__name { font-size: var(--fs-lg); }
.card--sub .card__desc { font-size: var(--fs-md); }
.card--sub::after { display: none; }   /* replaced by the Explore CTA */

/* ---- featured card (accent spotlight) ---- */
.lab__card {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.85rem 1rem;
  background: var(--card-bg);
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 8px 28px -14px color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: var(--r-card);
  color: inherit;
  text-decoration: none;
}
.lab__card:hover {
  box-shadow: 0 12px 36px -12px color-mix(in srgb, var(--accent) 70%, transparent);
}
.lab__icon {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--r-tile);
  display: grid;
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
}
.lab__icon svg { width: 1.15rem; height: 1.15rem; }
.lab__body { min-width: 0; }
.lab__name { display: block; font-size: var(--fs-lg); font-weight: 600; letter-spacing: -0.01em; }
.lab__pitch { display: block; font-size: var(--fs-md); color: var(--text-secondary); margin-top: 0.15rem; }

.lab__cta {
  flex: none;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  color: var(--accent);
  white-space: nowrap;
}
.lab__cta svg { width: 1rem; height: 1rem; transition: transform var(--t); }
.lab__card:hover .lab__cta svg,
.card--sub:hover .lab__cta svg,
.card--sub:focus-visible .lab__cta svg { transform: translateX(4px); }

/* ---- pill ---- */
.pill {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-dim);
  border: 1px solid var(--card-border);
  border-radius: var(--r-pill);
  padding: 0.05rem 0.5rem;
}

/* ---- .row — INFORMATIONAL row. Cards navigate, rows inform. ---- */
.stack { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.75rem; }
.row {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  padding: 0.95rem 1rem;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--r-card);
}
.row__icon {
  flex: none;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: var(--r-tile);
  display: grid;
  place-items: center;
  color: var(--ic, var(--accent));
  background: color-mix(in srgb, var(--ic, var(--accent)) 18%, transparent);
}
.row__icon svg { width: 1.25rem; height: 1.25rem; }
.row__body { min-width: 0; }
/* block, or the name and description run together on one line */
.row__name { display: block; font-weight: 500; font-size: var(--fs-lg); }
.row__desc { display: block; font-size: var(--fs-md); color: var(--text-muted); margin-top: 0.15rem; }

/* link variant */
a.row { align-items: center; color: inherit; text-decoration: none; }

/* ---- tags ---- */
.tags { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tag {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--r-pill);
  padding: 0.3rem 0.75rem;
}

/* ---- stats ---- */
.stats {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: 0.75rem;
}
.stat {
  padding: 1rem;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--r-card);
}
.stat__num {
  font-size: clamp(1.5rem, 4vw, 1.9rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--sc, var(--accent));
}
.stat__unit { font-size: 0.6em; }
.stat__label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  letter-spacing: 0.03em;
  margin-top: 0.5rem;
}

/* ---- tech stack strip ---- */
.techstack { display: grid; gap: 0.6rem; }
.tcat { display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
.tcat__label {
  flex: none;
  width: 8.5rem;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: 0.03em;
  color: var(--text-muted);
  text-transform: uppercase;
}
.tcat__chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.tchip {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--r-chip);
  padding: 0.2rem 0.55rem;
}
@media (max-width: 30rem) {
  .tcat { flex-direction: column; gap: 0.3rem; }
  .tcat__label { width: auto; }
}

/* ---- photographs ---- */
figure { margin: 0; }
.shot { margin-top: var(--sp); }
.shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-card);
  border: 1px solid var(--card-border);
}
.shot figcaption {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin-top: var(--sp-tight);
}
.panel > .shot:first-child { margin-top: 0; }

/* ---- spec list ---- */
.spec { margin: 0; font-family: var(--font-mono); font-size: var(--fs-md); line-height: 1.6; }
.spec div {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 0.5rem 1rem;
  padding: 0.5rem 0;
  border-top: 1px solid var(--card-border);
}
.spec div:first-child { border-top: 0; padding-top: 0; }
.spec dt { color: var(--text-muted); }   /* --text-dim measured 3.31:1 here */
.spec dd { margin: 0; color: var(--text-secondary); }
/* a spec table followed by explanatory prose needs the block gap */
.spec + .prose { margin-top: var(--sp); }
/* tag list nested in a spec value (e.g. required mods) */
.spec dd > .tags { margin: 0.15rem 0; }
@media (max-width: 30rem) {
  .spec div { grid-template-columns: 1fr; gap: 0.1rem; padding: 0.6rem 0; }
}

/* ============================================================
   5. PHOTO-ESSAY PAGES
   Section heading floats on the background, photographs lead,
   a panel of prose sits beneath them.
   ============================================================ */
.sec { margin-top: var(--sp-section); }
.sec:first-of-type { margin-top: var(--sp); }

/* A heading, not a label: steps up in size and to full --text. */
.sec > .eyebrow {
  font-size: var(--fs-xl);
  font-weight: 600;
  color: var(--text);
  letter-spacing: 0.01em;
  margin: 0 0 1rem;
}
.sec > .eyebrow::before { width: 7px; height: 7px; }

.group { margin-top: 0; }
.group .shot { margin-top: 0; }
.group .shot + .shot { margin-top: var(--sp); }
.group + .panel,
.panel + .group { margin-top: var(--sp); }

/* ---- gallery (CSS columns masonry) ----
   No cropping — tall shots keep their height and carry their column.
   Reading order runs down each column, which is accepted. */
.gallery { column-count: 3; column-gap: var(--gap); margin-top: var(--sp); }
@media (max-width: 44rem) { .gallery { column-count: 2; } }
.gallery figure { break-inside: avoid; margin: 0 0 var(--gap); }
.tile {
  display: block;
  border-radius: var(--r-tile);
  overflow: hidden;
  border: 1px solid var(--card-border);
}
.tile img { display: block; width: 100%; height: auto; }

/* ---- lightbox ----
   Progressive enhancement. With JS off a tile is a plain link to the
   full image and still works. Native <dialog> handles Escape, focus
   trapping and the backdrop. */
.lb {
  border: 0;
  padding: 0;
  background: transparent;
  max-width: 100vw;
  max-height: 100vh;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.lb::backdrop { background: rgba(var(--veil-rgb), 0.92); }
.lb__inner {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: clamp(0.75rem, 4vw, 3rem);
}
.lb img { max-width: 100%; max-height: 100%; width: auto; height: auto; border-radius: var(--r-tile); }
.lb__close {
  position: fixed;
  top: 1rem;
  right: 1rem;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--card-border);
  background: rgba(var(--veil-rgb), 0.7);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  cursor: pointer;
}
.lb__close:hover { border-color: var(--accent); color: var(--accent); }
.lb__close:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 2px rgba(var(--veil-rgb), 0.6), 0 0 0 4px var(--accent);
}

/* ============================================================
   6. ARCHITECTURE DIAGRAM  (lab.html)
   Branched, mobile-first. Trust level is carried by --zc.
   ============================================================ */
.diagram { margin-top: 0.25rem; }

.dgm-tier { display: flex; justify-content: center; }
.dgm-node {
  width: 100%;
  max-width: 30rem;
  text-align: center;
  padding: 0.85rem 1rem;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--r-card);
}
.dgm-node--net {                        /* Internet = untrusted */
  border-color: color-mix(in srgb, var(--ctp-red) 45%, transparent);
  background: color-mix(in srgb, var(--ctp-red) 8%, var(--card-bg));
}
.dgm-node--fw { border-color: color-mix(in srgb, var(--text-muted) 40%, transparent); }
.dgm-node__name { font-weight: 600; font-size: var(--fs-lg); }
.dgm-node__meta {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin-top: 0.25rem;
  letter-spacing: 0.02em;
}

/* spine connector with downward arrowhead */
.dgm-link {
  position: relative;
  width: 2px;
  height: 1.6rem;
  background: var(--ctp-overlay1);
  margin: 0.4rem auto;
}
.dgm-link::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -1px;
  transform: translateX(-50%);
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--ctp-overlay1);   /* points down = inbound */
}

/* Cloudflare is an edge annotation — name resolution, not a hop */
.dgm-annot {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-align: center;
  margin: 0 auto 0.4rem;
  max-width: 30rem;
}

/* elbow: gateway spine (centre) out to the segment trunk (left) */
.dgm-fork { position: relative; height: 1.9rem; margin: 0.1rem 0 0; }
.dgm-fork::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 2px;
  height: 100%;
  background: var(--ctp-overlay1);
  transform: translateX(-1px);
}
.dgm-fork::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: calc(0.5rem + 1px);
  width: calc(50% - 0.5rem - 1px);
  height: 2px;
  background: var(--ctp-overlay1);
}

.zones {
  list-style: none;
  margin: 0 0 0 0.5rem;
  padding: 1rem 0 0 1.25rem;
  display: grid;
  grid-template-columns: 1fr;                  /* always one column — no reflow warp */
  gap: 0.75rem;
  border-left: 2px solid var(--ctp-overlay1);  /* the trunk */
}
.zone {
  position: relative;
  padding: 0.9rem 1rem;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-left: 3px solid var(--zc, var(--accent));   /* trust rail */
  border-radius: var(--r-tile);
}
.zone::before {                                /* tick from trunk to card */
  content: "";
  position: absolute;
  left: -1.25rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1.25rem;
  height: 2px;
  background: var(--ctp-overlay1);
}
.zone::after {                                 /* inbound arrowhead */
  content: "";
  position: absolute;
  left: -0.5rem;
  top: 50%;
  transform: translateY(-50%);
  width: 0;
  height: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 6px solid var(--ctp-overlay1);
}
/* air-gapped: dashed on the 3 non-rail sides, and no inbound arrow */
.zone--isolated { border-top-style: dashed; border-right-style: dashed; border-bottom-style: dashed; }
.zone--isolated::before { background: none; height: 0; border-top: 2px dashed var(--ctp-overlay1); }
.zone--isolated::after { display: none; }

.zone__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.35rem 0.5rem;
}
.zone__name { font-weight: 600; font-size: var(--fs-lg); }
.zone__trust {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  color: var(--zc, var(--accent));
  border: 1px solid color-mix(in srgb, var(--zc, var(--accent)) 40%, transparent);
  border-radius: var(--r-pill);
  padding: 0.1rem 0.5rem;
  white-space: nowrap;
}
.zone__desc { font-size: var(--fs-md); color: var(--text-muted); margin: 0.45rem 0 0; }

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  justify-content: center;
  margin: 1.1rem 0 0;
}
.legend__item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.legend__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--zc, var(--accent)); flex: none; }

.dgm-caption {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin: 0.9rem 0 0;
  text-align: center;
}

/* ============================================================
   7. PAGE-SCOPED OVERRIDES
   Per-page background photographs. Each page's veil is tuned so
   on-background text stays readable against that photograph —
   see the veil note in §2. Verified by measurement, not guessed.
   ============================================================ */

/* miata: golden-hour shot of the car.
   Measured across six window sizes; --text-secondary reads 5.3:1
   against the brightest veiled pixel in the column. Do not drop
   --bg-veil-top below 0.74 — this photo has direct sun on silver
   paint, and the captions fail underneath it. */
body.page-miata {
  --bg-image: url("miata-img/bg.jpg");
  /* This plate has blown-out highlights (direct sun on silver paint), so it
     needs a heavier veil than background.jpg to clear the same floor. Raised
     0.78 -> 0.80 when --text-muted entered panels via .spec dt: at 0.78 that
     token measured 4.27:1 here, at 0.80 it is 4.54:1. Do NOT go below 0.74. */
  --bg-veil-top:    0.80;
  --bg-veil-bottom: 0.89;
}

/* ============================================================
   8. MOTION
   Motion confirms an interaction; it never performs. Every
   animation on the site is listed here — add new ones in the
   same edit that introduces them.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .wrap { animation: none; }
  .hero__cursor { animation: none; }
  .card, .card::after,
  a.row, a.row::after,
  .lab__card, .lab__cta svg,
  .tile, .back { transition: none; }
  .card:hover, a.row:hover, .lab__card:hover, .tile:hover,
  .card:focus-visible, a.row:focus-visible, .lab__card:focus-visible, .tile:focus-visible { transform: none; }
}
