/* ============================================================
   DREAMTEAM CRYPTO — core stylesheet
   Palette measured from Neon Hooded Dreamteam Hacker4k.png
   (15048x8469, sampled grid + adaptive quantize).
   No external fonts, no external assets, no third-party requests.
   ============================================================ */

:root {
  /* measured from the image */
  --bg:        #070416;   /* dominant base, ~46% of sampled pixels */
  --bg-2:      #051e58;   /* deep blue field */
  --ink:       #d6f6f4;   /* cyan-white, brightest cluster */
  --magenta:   #f10556;   /* neon red-pink, dominant hue 345-360 */
  --pink:      #fb1a8f;
  --rose:      #fd6190;
  --cyan:      #16e4fe;   /* neon cyan */
  --cyan-soft: #a2f5fe;
  --blue:      #0464e1;
  --purple:    #540a96;
  --amber:     #fee70a;   /* rare accent, use sparingly */

  --line:      rgba(84, 10, 150, .38);
  --line-hot:  rgba(22, 228, 254, .35);
  --panel:     rgba(7, 4, 22, .72);
  --muted:     #8fa7c8;

  --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --font-display: "Space Grotesk", "Inter", var(--font-mono);

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

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ---------- 1. THE BACKGROUND (the only thing visible first) ---------- */
.stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  opacity: 0;
  animation: stage-in 1200ms var(--ease) forwards;
}

/* Real img + srcset + sizes. The browser picks by actual viewport width,
   not by a guessed DPR. image-set with 1x/2x/3x picked the 640px file on a
   normal 1x display, which is what made the background look soft. */
.stage img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;
  z-index: 0;
}

/* Veil. Light during the intro so the picture reads clean.
   It darkens only when the page content arrives. */
.stage::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Lighter than before. Content sits top-left, and the top band of the image is
     already near-black (measured luminance about 2.9), so the text stays readable
     while the neon on the right reads clearly. */
  background:
    radial-gradient(120% 80% at 70% 45%, rgba(7,4,22,.12), rgba(7,4,22,.55) 70%),
    linear-gradient(180deg, rgba(7,4,22,.22), rgba(7,4,22,.62));
  z-index: 1;
  opacity: 0;
  /* Darkens slowly across the whole intro, so the picture reads clean first
     and only gets a proper text veil when the content arrives. */
  animation: veil-in 3500ms 1000ms var(--ease) forwards;
}

/* cyan light crossing the frame during the readout */
.stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(22,228,254,.14) 45%, transparent 60%);
  z-index: 2;
  transform: translateX(-100%);
  animation: sweep 2200ms 1200ms var(--ease) forwards;
}

@keyframes stage-in { to { opacity: 1; } }
@keyframes veil-in { to { opacity: 1; } }
@keyframes sweep { to { transform: translateX(100%); } }

.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .06;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

.grid {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 64px 64px;
  /* Masked to the right side, where the neon is. Before it was strongest at the top
     centre, which is exactly where the text now sits, so it competed with the heading. */
  mask-image: radial-gradient(120% 90% at 75% 45%, #000 20%, transparent 80%);
  opacity: 0;
  animation: veil-in 1000ms 2600ms var(--ease) forwards;
}

/* ---------- 2. THE INTRO READOUT (different metric) ---------- */
/* Smaller, uppercase, wide tracking, tabular numbers.
   Deliberately a different type system from the page body. */
.boot {
  position: fixed;
  inset: 0;
  z-index: 6;
  display: flex;
  /* Loading block centered on the screen, as asked. This also ends the overlap problem:
     the block no longer sits near the footer, so the bottom brackets are plain frame corners
     and nothing is drawn over the copyright line.
     On a 1080 viewport the block (about 79px tall) spans y 500 to 579. */
  align-items: center;
  padding: 40px;
  opacity: 0;
  transition: opacity 1200ms var(--ease);
  pointer-events: none;
}
.boot.show { opacity: 1; }
.boot.gone { opacity: 0; transition: opacity 900ms var(--ease); }

/* corner brackets, magenta */
.boot .bracket {
  position: absolute;
  width: 26px; height: 26px;
  border: 1px solid var(--magenta);
  opacity: .6;
}
.boot .bracket.tl { top: 26px; left: 26px; border-right: 0; border-bottom: 0; }
.boot .bracket.tr { top: 26px; right: 26px; border-left: 0; border-bottom: 0; }
/* The band between the readout bottom edge and the footer top edge is only 50px, and the
   bracket is 26px. So there is 24px of slack total. Any value that is not centred in that
   band presses the bracket against one edge or the other - that is why it kept touching
   the copyright line. 62px splits the slack: 12px below the readout, 12px above the footer.
   Bracket spans y 992-1018. Readout bottom edge 980, footer top edge 1030. */
/* Moved down as asked. The band between the readout and the footer is tight, so this is
   the lowest value that still keeps a positive gap on both sides. Below 44 the bracket
   lands on the copyright line.
   If you want it lower, change only this one number. Each 1px lower takes 1px off the gap
   above the copyright line.
   KNOB: bottom 44 -> bracket sits 44px above the footer bottom edge. */
.boot .bracket.bl { bottom: 44px; left: 26px; border-right: 0; border-top: 0; }
.boot .bracket.br { bottom: 44px; right: 26px; border-left: 0; border-top: 0; }

.boot-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
}

/* the matrix column: cycling lines, neon cyan, monospace */
.matrix {
  font-size: 12px;
  line-height: 1.75;
  letter-spacing: .14em;
  color: var(--cyan);
  max-width: 420px;
  transition: opacity 700ms var(--ease);
}
.matrix.fade { opacity: 0; }

.matrix .line {
  opacity: 0;
  transform: translateY(5px);
  transition: opacity 400ms var(--ease), transform 400ms var(--ease);
  white-space: nowrap;
}
.matrix .line.on { opacity: 1; transform: none; }
.matrix .line.past { opacity: .38; }
.matrix .line.active {
  color: var(--cyan-soft);
  text-shadow: 0 0 14px rgba(22, 228, 254, .45);
}
.matrix .line .m { color: var(--magenta); margin-right: 8px; }

.boot-label {
  font-size: 11px;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--magenta);
  margin-bottom: 12px;
}

.boot-log {
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--cyan-soft);
  min-height: 90px;
}
.boot-log div { opacity: 0; animation: line-in 500ms var(--ease) forwards; }
@keyframes line-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.meter {
  position: relative;
  height: 2px;
  background: var(--line);
  margin: 16px 0 10px;
  overflow: hidden;
}
.meter i {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 0%;
  background: linear-gradient(90deg, var(--magenta), var(--cyan));
  box-shadow: 0 0 12px rgba(22,228,254,.5);
  transition: width 120ms linear;
}
.read {
  font-size: 11px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.read b { color: var(--cyan); font-weight: 600; }

.arrived-line {
  margin-top: 14px;
  font-size: 11px;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--magenta);
  opacity: 0;
}
.arrived-line.on { opacity: 1; }

.skip {
  position: absolute;
  /* Bracket.br spans from right 26 inward by its 26px width, so it occupies the band
     right 26 to right 52. Text at right 26px lands inside that band. right 64 puts the
     text right edge 12px clear of the bracket, matching the vertical clearance. */
  /* Frame corner text. With the block centered, these are plain corners, not a band.
     right 64 keeps the text clear of the bottom-right bracket, which spans right 26 to 52. */
  right: 64px;
  bottom: 44px;
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: .5;
}

/* ---------- 3. SHELL ---------- */
/* Left-aligned, not centred. Content column is 680px. On a 1920 viewport that leaves
   about 1216px of image visible, and the neon focal point sits right-of-centre in the
   lower half of the picture. Centring the column covered the focal point.
   The measured glow grid peaks at block row 3 col 5, so the right side must stay open. */
.wrap {
  position: relative;
  z-index: 2;
  max-width: 720px;
  margin: 0;
  padding: 0 24px;
}

/* ---------- 4. SPAWN SYSTEM (page content, after the readout) ---------- */
/* Only hidden when JS is present. No-JS visitors see the page at once. */
html.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 900ms var(--ease), transform 900ms var(--ease);
}
html.js .reveal.on { opacity: 1; transform: none; }

/* Headings join the reveal set. JS adds the class, so no-JS keeps them visible.
   Keep opacity and transform here too. A bare `transition: color` on a more
   specific selector would override the reveal transition and kill the slide. */
html.js section.band h2 {
  transition: opacity 900ms var(--ease), transform 900ms var(--ease), color 500ms var(--ease);
}

/* Jump target must clear the sticky nav */
section.band { scroll-margin-top: 64px; }

/* Section you just navigated to gets a brief highlight */
section.band.arriving h2 { color: var(--cyan); }

/* The mark is a link now, so it must look like one */
nav.top a.mark { color: var(--cyan-soft); font-weight: 700; letter-spacing: .1em; }

/* ---------- 5. TYPE ---------- */
h1 {
  font-family: var(--font-display);
  /* Each line is its own block and never wraps mid-line. 86px was too wide for
     "We keep it clean." inside a 720px column, so it wrapped and orphaned "clean." */
  font-size: clamp(30px, 5vw, 64px);
  line-height: 1.15;
  margin: 0;
  letter-spacing: -.03em;
  color: var(--cyan-soft);
  text-shadow: 0 0 24px rgba(22,228,254,.35), 0 0 60px rgba(241,5,86,.25);
  /* Gap between the heading block and the terminal. */
  margin: 0 0 20px;
}
h1 .ln { display: block; white-space: nowrap; }
h2 {
  font-size: 13px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 18px;
}
h3 { font-size: 17px; margin: 0 0 10px; color: var(--ink); }
p { margin: 0 0 14px; color: #b9c8de; }
a { color: var(--cyan); text-decoration: none; }
a:hover { color: var(--pink); }

.kicker {
  color: var(--magenta);
  font-size: 12px;
  letter-spacing: .22em;
  text-transform: uppercase;
  margin-bottom: 14px;
}

/* ---------- 6. HERO ---------- */
/* Budget for a 1080 viewport:
   nav 50 + hero content 719 + hero padding 80 + footer 64 = 913. Fits, no scroll.
   The old hero used min-height 100svh plus 80px padding, which pushed the total to
   1128 and forced scrolling to reach the footer.
   Top-aligned, left-aligned. The image focal point sits right-of-centre, lower half,
   so keeping content on the left leaves the neon visible. */
.hero {
  /* Footer is 49px of content plus the 1px border-top = 50px. Using 49 here left the
     page 1px taller than the viewport, which is a 1px scroll. 50 makes it exact. */
  min-height: calc(100svh - 50px - 50px);
  display: flex;
  align-items: flex-start;
  padding: 40px 0;
}
/* 680, not 640. "We keep it clean." is 17 monospace chars, and at 64px that needs
   about 653px. A 640px column would wrap it again and orphan the word. */
.hero .hero-inner { max-width: 680px; }
/* Two fixed lines, not a wrapped paragraph. Each line is its own block, so the
   break is where you wrote it, not where the column happens to cut. */
.tagline {
  font-size: 16px;
  color: #cfe0f0;
  margin: 18px 0 0;   /* gap after the terminal */
}
.tagline .ln { display: block; }

.term {
  border: 1px solid var(--line-hot);
  background: var(--panel);
  padding: 14px 16px;
  border-radius: 4px;
  font-size: 13px;
  color: var(--cyan-soft);
  /* Fixed size. The box never grows or shrinks as lines land, so nothing jumps. */
  width: 620px;
  max-width: 100%;
  /* head 36 + panel 220 + log 164 = 420. Trimmed from 460 so the whole page fits
     a 1080 viewport without scrolling to the footer. */
  height: 420px;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.term-head {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  flex: 0 0 auto;
}
.term-head .tname { color: var(--cyan-soft); font-weight: 700; }
.term-head .tmode {
  color: var(--magenta);
  border: 1px solid var(--line);
  padding: 2px 8px;
  border-radius: 3px;
}
.term-head .spacer { flex: 1; }
.term-head .tuptime b { color: var(--cyan); font-variant-numeric: tabular-nums; font-weight: 600; }

/* Two zones.
   Static panel: fixed height, lines land once and never move. It is the screen.
   Log column: the only part that grows. It appends and scrolls inside its own box,
   so the panel above it never shifts. */
/* 8 lines at 12px * 1.7 + 3px margin = 23.4px each, plus 24px padding = 211px.
   220px gives headroom so the last line is never clipped. */
.term-static {
  flex: 0 0 auto;
  height: 220px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  overflow: hidden;
  font-size: 12px;
  line-height: 1.7;
}

.term-log {
  flex: 1;
  padding: 10px 14px;
  overflow: auto;
  font-size: 11px;
  line-height: 1.6;
  scrollbar-width: thin;
  scrollbar-color: var(--purple) transparent;
}
.term-log .tline { color: var(--muted); }
.term-log .tline .t { color: var(--purple); margin-right: 8px; }
.term-log .tline.hist { color: var(--cyan); }
/* The class sits on the line itself, not on a container. A selector written as
   `.term .out .tline` would never match and the fade-in would not fire. */
.term .tline {
  margin-bottom: 3px;
  white-space: pre;
  opacity: 0;
  transition: opacity 300ms var(--ease);
}
.term .tline.on { opacity: 1; }
.term .tline.cmd { color: var(--cyan-soft); }
.term .tline.cmd .p { color: var(--magenta); margin-right: 8px; }
.term .tline.ok { color: var(--cyan); }
.term .tline.head { color: var(--cyan-soft); font-weight: 700; }
/* No .log class here. Log lines live in .term-log and are styled by
   `.term-log .tline`. A rule for `.term .tline.log` would be dead code. */
/* No .demo class any more. The honesty line was removed, so this rule would be
   dead code. */
.term .dots { color: var(--purple); }
.term .caret {
  display: inline-block;
  width: 8px; height: 12px;
  background: var(--cyan);
  vertical-align: -2px;
  margin-left: 4px;
  animation: blink 1.1s steps(2) infinite;
}
.caret {
  display: inline-block;
  width: 8px; height: 14px;
  background: var(--cyan);
  vertical-align: -2px;
  animation: blink 1.1s steps(2) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* ---------- 7. NAV ---------- */
nav.top {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  align-items: center;
  padding: 14px 24px;
  border-bottom: 1px solid var(--line);
  background: rgba(7,4,22,.78);
  backdrop-filter: blur(10px);
}

nav.top .mark { color: var(--cyan-soft); font-weight: 700; letter-spacing: .1em; }
nav.top a { color: var(--muted); font-size: 13px; }
nav.top a:hover { color: var(--cyan); }
nav.top .spacer { flex: 1; }
nav.top .live { font-size: 11px; color: var(--magenta); letter-spacing: .12em; }

/* Nav must not exist during the intro. Only the picture, then the readout. */
html.js nav.top { opacity: 0; transition: opacity 700ms var(--ease); }
html.js nav.top.on { opacity: 1; }
.dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--magenta);
  box-shadow: 0 0 10px var(--magenta);
  animation: pulse 2.4s ease-in-out infinite;
}
@keyframes pulse { 50% { opacity: .35; transform: scale(.85); } }

/* ---------- 8. SECTIONS ---------- */
section.band {
  position: relative;
  z-index: 2;
  padding: 70px 0;
  border-top: 1px dashed var(--line);
}
section.band:first-of-type { border-top: 0; }

.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }

.card {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 18px;
  transition: border-color 200ms, transform 200ms;
}
.card:hover { border-color: var(--line-hot); transform: translateY(-3px); }

.card::before, .card::after {
  content: "";
  position: absolute;
  width: 12px; height: 12px;
  border: 1px solid var(--cyan);
  opacity: .5;
}
.card::before { top: 8px; left: 8px; border-right: 0; border-bottom: 0; }
.card::after { bottom: 8px; right: 8px; border-left: 0; border-top: 0; }

/* ---------- 9. TABLE ---------- */
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); }
th { color: var(--muted); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; font-size: 11px; }
td.num { font-variant-numeric: tabular-nums; color: var(--cyan-soft); }

/* ---------- 10. FOOTER ---------- */
/* Compact. One line, about 49px tall, so the page ends inside the first screen.
   The old footer used 40px top and 60px bottom, which alone was 100px and pushed
   the total past a 1080 viewport. */
footer {
  position: relative; z-index: 2;
  padding: 16px 24px;
  border-top: 1px solid var(--line);
  font-size: 11px;
  letter-spacing: .08em;
  color: var(--muted);
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  align-items: center;
}
footer .copy { color: var(--cyan-soft); }
footer .sep { color: var(--purple); }

/* ---------- 11. ACCESSIBILITY / MOTION ---------- */
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }

/* Reduced motion: fade only, no movement. The intro still happens.
   Add html.force (from ?intro=1) to get the full motion version back. */
@media (prefers-reduced-motion: reduce) {
  html:not(.force) *, html:not(.force) *::before, html:not(.force) *::after {
    animation: none !important;
    transform: none !important;
    transition-property: opacity !important;
    transition-duration: 600ms !important;
  }
  html:not(.force) .stage { opacity: 1; }
  html:not(.force) .stage::before { display: none; }   /* no sweep */
  /* Animations are off, so anything that used one must be set to its end state
     by hand, or the veil and grid would stay invisible. */
  html:not(.force) .stage::after { opacity: 1; }
  html:not(.force) .grid { opacity: .5; }
  html:not(.force) .caret, html:not(.force) .dot { animation: none !important; }
  html:not(.force) .matrix .line { transition-property: opacity !important; }
}

@media (max-width: 640px) {
  h1 { font-size: 34px; }
  .hero { padding: 40px 0; }
  .boot-inner { grid-template-columns: 1fr; }
  .matrix { max-width: none; }
  .matrix .line { white-space: normal; }
  /* Centered here too. The block stacks to one column, so it is taller (about 130px),
     but it is centred, so it no longer sits near the footer. Brackets can stay visible as
     plain frame corners because nothing is drawn near the footer any more. */
  .boot { padding: 24px; }
  .skip { right: 24px; bottom: 24px; }
  .boot .bracket.bl, .boot .bracket.br { display: block; }
  /* nowrap can overflow a 320px viewport, so allow wrapping here */
  h1 .ln { white-space: normal; }
  /* Keep white-space: pre. The mining columns only line up if lines do not wrap.
     Device lines are 74 characters, so both zones scroll sideways instead of
     breaking the columns. Panel needs 211px for 8 lines, so total must stay above it. */
  /* 380 = head 36 + panel 220 + log 124, so the log still shows about 5 lines. */
  .term { height: 380px; }
  .term-static, .term-log { overflow-x: auto; }
  .term-head { flex-wrap: wrap; gap: 8px; }
}

/* ---------- 5. CONTENT PAGES ---------- */

/* Nav links. main.css already has `nav.top a` and `nav.top a:hover`, so this block
   only adds what those rules do not cover: no underline, and the current-page marker.
   Do not re-declare nav.top a here or the two rules fight over specificity. */
/* Content pages have no intro, so nothing ever adds .on to the nav. Without this the
   nav would stay at opacity 0 and be invisible. */
html.no-intro nav.top { opacity: 1; }

nav.top a { text-decoration: none; }
nav.top a[aria-current="page"] { color: var(--cyan-soft); }

/* Typography V3 (2026-10-29): sub-page text raised to match the Mining report size,
   column widened, width adapts to small screens. */
.page { position: relative; z-index: 2; max-width: min(1240px, 100%); margin: 0 auto; padding: 48px clamp(20px, 4vw, 48px) 64px; font-size: 15px; line-height: 1.7; }
.page h1 { font-size: clamp(32px, 5vw, 40px); margin: 24px 0 18px; }
/* text-transform removed so project names render as written, in Title Case. */
.page h2 { font-size: 16px; letter-spacing: .18em; color: var(--magenta); margin: 28px 0 12px; }

.row {
  display: flex;
  gap: 14px;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
  font-size: 14px;
}
.row .k { color: var(--muted); min-width: 120px; letter-spacing: .1em; text-transform: uppercase; font-size: 12px; }
.row a { color: var(--cyan); text-decoration: none; word-break: break-all; }
.row .v { color: var(--cyan-soft); }

/* A row whose URL was never filled in. Shown as not set, never as a guessed link. */
/* JS writes the text "not set", so no ::after content here. A ::after rule would
   print the words twice. The class is on .v, not on the row. */
.v.missing { color: var(--magenta); font-size: 12px; letter-spacing: .12em; }

.audit {
  border: 1px solid var(--line);
  border-left: 3px solid var(--purple);
  padding: 14px 16px;
  margin-bottom: 14px;
  font-size: 14px;
}
.audit h3 { margin: 0 0 6px; font-size: 15px; color: var(--cyan-soft); }
.audit .meta { font-size: 12px; color: var(--muted); letter-spacing: .08em; margin-bottom: 8px; }
.audit code { color: var(--cyan); font-size: 13px; }
.audit p { margin: 6px 0; color: #cfe0f0; }

.note { font-size: 14px; color: var(--muted); margin-top: 20px; }

/* ---------- 6. PROJECT OVERVIEW AND AUDIT PAGES ---------- */

/* Overview rows. Name, one quick summary line, link to the full audit.
   .audit already has the card box, so .proj only adds what .audit does not have. */
.proj h3 { margin: 0 0 6px; font-size: 15px; color: var(--cyan-soft); }
.proj .sum { font-size: 14px; color: #cfe0f0; margin: 6px 0 8px; }
.proj .go { font-size: 14px; }
.proj .link { color: var(--cyan); text-decoration: none; }
.proj .link:hover { color: var(--cyan-soft); }

/* Upcoming: name only, no link, because no audit exists yet. */
.upcoming { border: 1px dashed var(--line); padding: 12px 16px; margin-bottom: 12px; }
.upcoming h3 { margin: 0; font-size: 15px; color: var(--muted); }
.upcoming .sum { font-size: 14px; color: var(--muted); margin-top: 6px; }

/* A row with no audit page yet. Shown as not audited, never as a broken link. */
.nolink { color: var(--muted); font-size: 14px; }

/* Full audit page. It reuses .page, .page h1, .page h2 and .note, so nothing is
   re-declared here. Only the parts .page does not already cover are added. */
/* The audit report gets the widest field. Long tables need it, but the field must
   shrink with the viewport, never overflow it. */
main.page.report { max-width: min(1320px, 100%); }

/* ==== REPORT STYLES (appended by patch2.js, safe to re-run) ==== */
.audit-page .meta { font-size: 14px; color: var(--muted); letter-spacing: .06em; margin-bottom: 20px; }
.audit-page .score { font-size: 15px; color: var(--muted); margin-bottom: 20px; }
.audit-page .back { font-size: 14px; margin-top: 26px; }
.audit-page .back a { color: var(--cyan); text-decoration: none; }
.report h3{margin:1.6em 0 .5em;font-size:1.05rem}
.report h4{margin:1.2em 0 .4em;font-size:.95rem;opacity:.85}
.report p{margin:.85em 0;line-height:1.65}
.report ul,.report ol{margin:.85em 0 .85em 1.25em;padding:0}
.report li{margin:.5em 0;line-height:1.6}
.report code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.86em;
  background:rgba(255,255,255,.07);padding:.12em .38em;border-radius:4px;word-break:break-word}
.report pre{background:rgba(0,0,0,.42);border:1px solid rgba(255,255,255,.1);
  border-radius:10px;padding:.9em 1em;overflow-x:auto;margin:1.1em 0}
.report pre code{background:none;padding:0;font-size:.82rem;line-height:1.55;white-space:pre}
.report a{color:#16e4fe;text-decoration:none;border-bottom:1px solid rgba(22,228,254,.35)}
.report a:hover{border-bottom-color:#16e4fe}
.report hr{border:0;border-top:1px solid rgba(255,255,255,.12);margin:2.2em 0}
.report blockquote{margin:1.1em 0;padding:.2em 0 .2em 1em;
  border-left:2px solid rgba(241,5,86,.6);opacity:.92}
.report h2{margin:2.2em 0 .7em;font-size:1.35rem;letter-spacing:.02em}
.report th,.report td{border:1px solid rgba(255,255,255,.13);padding:.55em .7em;
  text-align:left;vertical-align:top}
.report th{background:rgba(255,255,255,.06);font-weight:600;white-space:nowrap}
.report tbody tr:nth-child(even) td{background:rgba(255,255,255,.022)}
.report .score{margin:1.1em 0 1.6em;padding:.6em .85em;border-radius:8px;
  background:rgba(22,228,254,.08);border-left:2px solid #16e4fe;font-weight:600}
@media (max-width:640px){.report table{font-size:.78rem}.report th,.report td{padding:.42em .5em}}

.report table{display:block;width:100%;overflow-x:auto;border-collapse:collapse;
  margin:1.2em 0;font-size:.9rem;line-height:1.6}
.report p { margin: 1.15em 0; line-height: 1.72; }
.report h2 { margin: 2.8em 0 1em; font-size: 1.4rem; }
.report h3 { margin: 2em 0 .7em; font-size: 1.12rem; }
.report h4 { margin: 1.5em 0 .5em; }
.report ul, .report ol { margin: 1.15em 0 1.15em 1.4em; }
.report li { margin: .7em 0; line-height: 1.7; }
.report table { margin: 1.6em 0; font-size: .9rem; line-height: 1.6; }
.report th, .report td { padding: .7em .9em; }
.report pre { margin: 1.5em 0; }

/* Blurred copy of the front-page picture behind every sub-page, so the dark
   pages read as the same site instead of a plain black background. */
body.page-only::before {
  content: "";
  position: fixed;
  inset: -60px;
  z-index: 0;
  background: url("../assets/hero-1920.webp") center 35% / cover no-repeat;
  filter: blur(20px) saturate(.8) brightness(.5);
  transform: scale(1.08);
}
/* Veil over the blur so body text keeps contrast. */
body.page-only::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(7,4,22,.74), rgba(7,4,22,.88));
}

@media (max-width: 820px) {
  .page { padding: 36px 20px 56px; }
  body.page-only::before { filter: blur(14px) saturate(.8) brightness(.5); inset: -40px; }
}

/* Stronger veil: the audit is long text, so the picture must stay clearly
   behind it. Raise these two alphas to push it further back. */
body.page-only::before{filter:blur(26px) saturate(.7) brightness(.42)}
body.page-only::after{background:linear-gradient(180deg,rgba(7,4,22,.86),rgba(7,4,22,.93))}

/* Safety net: nothing may paint outside the reading column. */
.page{overflow-x:clip}
.report pre,.report .tw{max-width:100%}

/* ==== PROJECT GRID (appended by build; safe to re-run) ==== */
/* The overview used to be six full-width rows. With the page now centred and wide,
   the audit cards become real cards: two across on a laptop, one on a phone. */
.proj-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  align-items: stretch;
  gap: 18px;
  margin: 20px 0 8px;
}
.proj-grid .proj {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 18px 20px;
  background: var(--panel);
}
.proj-grid .proj.audit {
  display: flex;
  flex-direction: column;
  min-height: 388px;
}
.proj-grid .proj h3 { margin: 0 0 8px; font-size: 15px; }
.proj-grid .audit-date,
.audit-page .audit-date {
  margin: 0 0 8px;
  color: var(--cyan-soft);
  font-size: 11px;
  letter-spacing: .04em;
}
.freshness-note {
  margin: 12px 0;
  padding: 10px 12px;
  border-left: 2px solid var(--magenta);
  background: rgba(241,5,86,.07);
  color: #d9c8da;
  font-size: 12px;
  line-height: 1.55;
}
.proj-grid .proj .sum { margin: 0 0 12px; line-height: 1.6; }
.proj-grid .score-panel {
  margin: auto 0 14px;
  padding: 12px;
  border: 1px solid var(--line-hot);
  border-radius: 7px;
  background: linear-gradient(135deg, rgba(22,228,254,.08), rgba(84,10,150,.12));
}
.proj-grid .score-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
  color: var(--muted);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.proj-grid .score-heading .verdict {
  padding: 3px 8px;
  border: 1px solid rgba(22,228,254,.35);
  border-radius: 999px;
  background: rgba(22,228,254,.08);
  color: var(--cyan-soft);
  font-size: 10px;
  letter-spacing: .08em;
}
.proj-grid .score-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.proj-grid .score-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  padding: 8px 9px;
  border: 1px solid rgba(143,167,200,.16);
  border-radius: 5px;
  background: rgba(7,4,22,.44);
}
.proj-grid .score-item span { color: var(--muted); font-size: 10px; }
.proj-grid .score-item strong { color: var(--ink); font-size: 17px; line-height: 1.2; }
.proj-grid .proj .go { margin-top: 2px; }
@media (max-width: 700px) {
  .proj-grid { grid-template-columns: 1fr; gap: 14px; }
  .proj-grid .proj.audit { min-height: 388px; }
}

/* ==== HIDDEN AUDIT TEASERS ==== */
/* A hidden audit must not reveal the project name. CSS blur alone is not enough,
   because view-source still shows the real text. So the build writes a block mask
   into the HTML instead of the name, and the blur is the visual layer on top.
   The real name never reaches projects.html while publish is false. */
.proj.teaser { border-style: dashed; }
.proj.teaser .tag {
  font-size: 11px;
  letter-spacing: .12em;
  color: var(--muted);
  margin-bottom: 8px;
}
.proj.teaser .redacted {
  filter: blur(5px);
  user-select: none;
  letter-spacing: .12em;
  line-height: 1.6;
}
.proj.teaser h3.redacted { color: var(--cyan-soft); margin-bottom: 8px; }
.proj.teaser .sum.redacted { color: #cfe0f0; margin-bottom: 12px; }

/* ==== TABLE RULES (appended by build; safe to re-run) ==== */
/* The class is atable, never grid. base.css owns a fixed full-screen .grid
   overlay, and a table wearing that class gets pulled out of the page and
   painted over the background. That collision caused the bleed. */
.report .tw{overflow-x:auto;max-width:100%;margin:1.6em 0;border:1px solid var(--line);border-radius:8px}
.report table.atable{display:table;width:100%;border-collapse:collapse;margin:0;font-size:.84rem;line-height:1.55}
.report .atable th,.report .atable td{border:1px solid var(--line);padding:.6em .7em;text-align:left;vertical-align:top;overflow-wrap:anywhere}
.report .atable th{background:rgba(255,255,255,.06);font-size:.68rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);font-weight:600}
.report .atable td code{font-size:.78rem;word-break:break-all}
.report .atable .c-num{width:46px;text-align:center}
.report .atable .c-file{width:200px}
.report .atable .c-reach{width:104px}
.report .atable .c-ded{width:76px;text-align:center}
.report .atable .c-applies{width:100px}
.report .atable .c-field{width:180px}
.report .atable .c-what{width:140px}
.report .atable .c-status{width:140px}
.report .atable .c-link{word-break:break-all}
/* Fixed layout: widths come from the header row, never from content. */
.report table.atable{table-layout:fixed}
.report .atable .c-finding{width:auto}
.report .atable .c-value{width:auto}
.report .atable .c-ded{width:96px}
.report .atable .c-applies{width:126px}
.report .atable .c-reach{width:112px}
.report .atable .c-first{width:34%}
.report .atable .c-status{width:auto}

/* ==== Homepage mining fleet image (added 2026-10-29) ==== */
/* The hero stays the first thing seen. The fleet dashboard image sits inside the
   hero column as a framed panel, matching the card treatment used on the site. */
.fleet-image {
  margin: 22px 0 0;
}
.fleet-image img {
  display: block;
  width: 100%;
  max-width: 1200px;
  height: auto;
  border: 1px solid rgba(22, 228, 254, .28);
  border-radius: 12px;
  background: var(--panel);
}
.fleet-image figcaption {
  margin-top: 8px;
  color: var(--cyan-soft);
  font-size: 12px;
  letter-spacing: .04em;
}

/* mining page banner — CSP blocks inline style attributes, so rules live here */
.fleet-fig { margin: 0 0 1.4em; }
.fleet-img { max-width: 100%; height: auto; border: 1px solid rgba(22,228,254,.28); border-radius: 12px; }
