/* ==========================================================================
   A⁴ — the drawing sheet
   A civil engineer who spent five years being measured. The page is the
   artifact both halves share: a dimensioned drawing.
   ========================================================================== */

:root {
  --ground:  #0A0C0F;
  --panel:   #12161E;
  --raise:   #171D27;
  --ink:     #E8EBF1;
  --muted:   #8C94A3;
  --train:   #0DEEA0;
  --web:     #FDBF57;
  --rule:    #FFFFFF1F;   /* sheet linework */
  --rule-2:  #FFFFFF0F;   /* faint linework */

  --sheet-pad: clamp(16px, 3.2vw, 46px);
  --card-w:    580px;   /* the bio card and the gate row share one width */
  --gutter:    clamp(20px, 4vw, 64px);
  --measure:   64ch;

  --t-fast: 180ms;
  --ease:   cubic-bezier(.2,.7,.3,1);
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: Archivo, -apple-system, "Segoe UI", sans-serif;
  font-variation-settings: 'wdth' 100;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--train);
  outline-offset: 3px;
  border-radius: 2px;
}

/* --- shared type roles ------------------------------------------------- */
.mono {
  font-family: "DM Mono", ui-monospace, "SF Mono", monospace;
  font-size: 10.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}

.display {
  font-weight: 900;
  font-variation-settings: 'wdth' 68;   /* the axis nobody uses */
  letter-spacing: -.005em;
  line-height: .84;
  text-transform: uppercase;
  margin: 0;
}

.lede { color: var(--muted); font-size: 17px; max-width: 54ch; margin: 0; }
.lede strong { color: var(--ink); font-weight: 600; }

/* --- the sheet --------------------------------------------------------- */
/* --- page background: the "Sunset" ASCII field (js/ascii-bg.js) --------
   Fixed behind everything; the sheet is lifted one layer so copy stays on
   top. Element opacity is set by the script, from one config. */
.ascii-bg,
.neural-bg { position: fixed; inset: 0; z-index: 0; pointer-events: none; }

.sheet {
  position: relative; z-index: 1;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 var(--sheet-pad);
}
/* the ruled border of the drawing */
.sheet::before {
  content: "";
  position: fixed;
  inset: var(--sheet-pad);
  border: 1px solid var(--rule-2);
  pointer-events: none;
  z-index: 0;
}

/* --- top bar ----------------------------------------------------------- */
.bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px;
  padding: 18px 0 16px;
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: blur(9px);
  border-bottom: 1px solid var(--rule-2);
}
.bar-mark img { height: 30px; width: auto; }
.zones { display: flex; align-items: center; gap: 4px; }
.zone {
  display: inline-flex; align-items: baseline;
  padding: 7px 12px;
  font-family: "DM Mono", monospace; font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted);
  border: 1px solid transparent;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.zone:hover, .zone:focus-visible { color: var(--ink); border-color: var(--rule); }
.zone[aria-current="page"] { color: var(--ink); border-color: var(--line2);
  background: var(--panel); }
/* Training and Web are not published yet. They keep their place in the index so
   the shape of the site stays honest, but they are inert: rendered as spans, so
   there is nothing to click, and dimmed so it reads as deliberate. */
.zone.off { color: var(--muted); opacity: .4; cursor: default; }
.gate-link.off {
  --accent: var(--muted);
  color: var(--muted); opacity: .5; cursor: default;
  background: color-mix(in srgb, var(--panel) 60%, transparent);
}
.gate-link.off::before { display: none; }   /* no travelling beam on a dead door */
.gate-link.off .arr { color: var(--muted); }

/* --- section scaffold -------------------------------------------------- */
.band { position: relative; padding: clamp(52px, 5.6vw, 88px) 0; }
/* the portrait card and the two gates read as one unit with the hero, so
   they carry a tighter rhythm than a full section break */
.band-tight { padding: clamp(18px, 2.1vw, 28px) 0; }
.band + .band { border-top: 1px solid var(--rule-2); }

.band-head { display: flex; flex-direction: column; gap: 10px; margin-bottom: 34px; }
.band-head.center { align-items: center; text-align: center; }
.band-title { font-size: clamp(30px, 4.4vw, 48px); }

/* --- A · hero ---------------------------------------------------------- */
.hero { padding-top: clamp(44px, 5vw, 78px); padding-bottom: clamp(22px, 2.5vw, 38px); }
/* one centred column: the portrait was removed, so the name, the dimension
   line and the meta row stack on the sheet's axis */
.hero-grid {
  display: grid; gap: var(--gutter);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  text-align: center;
}
.hero-grid .hero-role { justify-content: center; }
.hero-name { font-size: clamp(64px, 14.2vw, 188px); }
.hero-name .l2 { display: block; }

.hero-role {
  display: flex; flex-wrap: wrap; gap: 8px 20px;
  margin: 26px 0 0;
}
.hero-role span { font-family: "DM Mono", monospace; font-size: 11px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.hero-role span b { color: var(--ink); font-weight: 500; }

/* --- the dimension line (signature) ------------------------------------ */
.dim { margin: 30px 0 0; }
.dim-body { position: relative; display: flex; align-items: center; gap: 0; }
.dim-run { flex: 1; display: flex; align-items: center; }
.dim-rule {
  flex: 1; height: 1px; background: var(--ink); opacity: .5;
  transform: scaleX(0); transform-origin: 0 50%;
  animation: draw .62s var(--ease) .3s forwards;
}
.dim-val {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  padding: 0 14px; background: var(--ground);
  font-family: "DM Mono", monospace; font-size: 11.5px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--ink); white-space: nowrap;
  opacity: 0;
  animation: fade .42s var(--ease) .88s forwards;
}

@keyframes draw { to { transform: scaleX(1); } }
@keyframes fade { to { opacity: 1; } }

/* --- B · the two doors ------------------------------------------------- */
.doors { display: grid; gap: 18px; grid-template-columns: repeat(2, minmax(0,1fr)); }
.door {
  --accent: var(--train);
  position: relative; display: flex; flex-direction: column; gap: 18px;
  padding: clamp(24px, 3vw, 38px);
  background: var(--panel);
  border: 1px solid var(--rule);
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.door.web { --accent: var(--web); }
.door:hover, .door:focus-visible { background: var(--raise); border-color: color-mix(in srgb, var(--accent) 46%, transparent); transform: translateY(-2px); }
/* the accent reads as a drawn edge, not a glow */
.door::before {
  content: ""; position: absolute; left: -1px; top: -1px; bottom: -1px;
  width: 3px; background: var(--accent);
}
.door-lock img { height: 27px; width: auto; }
.door-copy { flex: 1; }
.door h3 { margin: 0 0 8px; font-size: 22px; font-weight: 800;
  font-variation-settings: 'wdth' 88; }
.door p { margin: 0; color: var(--muted); font-size: 14.5px; max-width: 40ch; }
.door-meta { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.door-go {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--accent);
  /* a domain is one unbreakable token, so a long one (the old gridironhigh-
     schoolshowcase.netlify.app) ran past the card. `anywhere` also lowers the
     min-content width, which is what lets the flex item shrink at all. */
  flex-wrap: wrap; overflow-wrap: anywhere;
}
.door-go .arr { transition: transform var(--t-fast) var(--ease); }
.door:hover .door-go .arr { transform: translateX(5px); }

/* --- B · who — the portrait beside four labelled rows ------------------
   Square, like every other panel on the sheet. */
.bio { display: flex; align-items: center; gap: clamp(20px, 3vw, 34px);
  background: var(--panel); border: 1px solid var(--rule);
  padding: clamp(14px, 1.7vw, 18px);
  /* only as wide as the longest row of copy needs */
  max-width: var(--card-w); margin-inline: auto; }
.bio-frame { flex: none; width: 164px; height: 164px; }
.bio-img { width: 100%; height: 100%; border-radius: 50%;
  border: 2px solid var(--rule);
  object-fit: cover; object-position: 50% 6%; }
.bio-rows { flex: 1; min-width: 0; margin: 0;
  display: flex; flex-direction: column; gap: 6px; }
.bio-row { padding: 6px 16px;
  background: #FFFFFF08; border: 1px solid var(--rule-2);
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); }
.bio-row:hover { background: #FFFFFF0F;
  border-color: color-mix(in srgb, var(--train) 40%, transparent); }
.bio-row dt { font-size: 15px; font-weight: 700; line-height: 1.25;
  font-variation-settings: 'wdth' 92; }
.bio-row dd { margin: 0; font-size: 13.5px; line-height: 1.35; color: var(--muted); }

/* --- two small gates: the doors reduced to a pair of buttons ------------
   The border is a travelling beam rather than a static rule. A conic gradient
   is spun by an animated <angle> custom property and then masked down to the
   1px frame, so one bright arc with a fading tail runs the perimeter. Where
   @property is unsupported the gradient simply holds still and the button
   reads as a plain outline; the reduced-motion block above freezes it too. */
@property --beam { syntax: "<angle>"; initial-value: 0deg; inherits: false; }

.gates { display: flex; flex-wrap: wrap; gap: 18px; justify-content: center;
  max-width: var(--card-w); margin-inline: auto; }
.gate-link {
  --accent: var(--train);
  position: relative; isolation: isolate;
  flex: 1 1 0; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 22px;
  padding: 11px 20px; line-height: 1.2; background: var(--panel);
  border: 1px solid var(--rule);
  font-family: "DM Mono", monospace; font-size: 19px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ink);
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease);
}
.gate-link.web { --accent: var(--web); }
.gate-link::before {
  content: ""; position: absolute; inset: -1px; z-index: -1;
  padding: 1px; pointer-events: none;
  background: conic-gradient(from var(--beam) at 50% 50%,
    transparent 0deg, transparent 268deg,
    color-mix(in srgb, var(--accent) 30%, transparent) 320deg,
    var(--accent) 356deg, transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: gate-beam 4.5s linear infinite;
}
/* the pair should not travel in lockstep */
.gate-link.web::before { animation-delay: -2.25s; }
@keyframes gate-beam { to { --beam: 360deg; } }

.gate-link .arr { color: var(--accent); transition: transform var(--t-fast) var(--ease); }
.gate-link:hover, .gate-link:focus-visible {
  background: var(--raise); color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 46%, transparent);
}
.gate-link:hover .arr { transform: translateX(5px); }

/* --- C · facts --------------------------------------------------------- */
.facts { display: grid; gap: 1px; background: var(--rule-2);
  grid-template-columns: repeat(3, minmax(0,1fr)); border: 1px solid var(--rule-2); }
.fact { background: var(--ground); padding: 26px clamp(18px,2.2vw,30px);
  display: flex; flex-direction: column; gap: 7px; }
.fact dt { font-size: 17px; font-weight: 700; font-variation-settings: 'wdth' 90; }
.fact dd { margin: 0; color: var(--muted); font-size: 14px; }

/* plates: photography enters the sheet as a bounded, captioned insert */
.door-plate { position:relative; border:1px solid var(--rule); overflow:hidden;
  aspect-ratio:16/7; background:var(--ground); }
.door-plate img { width:100%; height:100%; object-fit:cover; }
.door-plate figcaption { position:absolute; left:0; right:0; bottom:0; padding:6px 11px;
  background:color-mix(in srgb, var(--ground) 84%, transparent);
  border-top:1px solid var(--rule); }
.door:hover .door-plate img { transform:scale(1.03); }
.door-plate img { transition:transform .4s var(--ease); }

/* the web door shows the product itself rather than a stock photograph */
.mini { width:100%; height:100%; display:flex; flex-direction:column; background:var(--ground); }
.mini-chrome { display:flex; align-items:center; gap:5px; padding:7px 9px; background:var(--raise);
  border-bottom:1px solid var(--rule); }
.mini-dot { width:6px; height:6px; border-radius:50%; background:var(--line2); flex:none; }
.mini-url { flex:1; margin-left:5px; background:var(--ground); border-radius:999px; padding:3px 9px;
  font-family:"DM Mono", ui-monospace, monospace; font-size:8px; letter-spacing:.06em;
  color:var(--muted); }
.mini-body { flex:1; display:flex; flex-direction:column; justify-content:center; gap:7px;
  padding:0 clamp(12px,2.4vw,20px); }
.mini-name { font-weight:900; font-variation-settings:'wdth' 68; font-size:clamp(20px,3.2vw,30px);
  line-height:.84; text-transform:uppercase; letter-spacing:-.01em; }
.mini-rule { height:1px; background:var(--rule); }
.mini-row { display:flex; gap:6px; }
.mini-chip { height:7px; border-radius:999px; background:var(--line2); }

/* C · who — photo-led, so the page stops repeating one header shape */
.who { display:grid; gap:var(--gutter); align-items:center;
  grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr); }
.who-photo { position:relative; margin:0; border:1px solid var(--rule); overflow:hidden;
  aspect-ratio:4/5; background:var(--panel); }
.who-photo img { width:100%; height:100%; object-fit:cover; object-position:50% 18%; }
.who-photo figcaption { position:absolute; left:0; right:0; bottom:0; padding:8px 12px;
  background:color-mix(in srgb, var(--ground) 82%, transparent);
  border-top:1px solid var(--rule); }
.facts-stack { grid-template-columns:1fr; }

/* --- D · journey ------------------------------------------------------- */
/* The school marks are the strongest credibility here, so they become the
   nodes themselves rather than sitting in a 52px corner of a card. */
.tl { position:relative; max-width:900px; margin:0 auto; padding:0; list-style:none; }
.tl::before {
  content:""; position:absolute; left:50%; top:0; bottom:0; width:1px;
  transform:translateX(-.5px); opacity:.4;
  background:linear-gradient(180deg, var(--train), var(--train) 62%, var(--web));
}
.tl-item {
  position:relative; display:grid; grid-template-columns:1fr 86px 1fr;
  align-items:center; padding:12px 0;
}
.tl-node {
  grid-column:2; justify-self:center; width:66px; height:66px; border-radius:50%;
  background:#fff; border:2px solid var(--train); padding:9px; z-index:1;
  display:flex; align-items:center; justify-content:center;
  transition:transform var(--t-fast) var(--ease);
}
.tl-node img { max-width:100%; max-height:100%; object-fit:contain; }
.tl-item:hover .tl-node { transform:scale(1.07); }
.tl-item.fut .tl-node {
  background:var(--ground); border-color:var(--web); border-style:dashed; color:var(--web);
  font-family:"DM Mono", ui-monospace, monospace; font-size:24px;
}
.tl-txt { padding:0 26px; }
.tl-item.l .tl-txt { grid-column:1; text-align:right; }
.tl-item.r .tl-txt { grid-column:3; text-align:left; }
/* hairline leader from the node out to the type */
.tl-item.l .tl-txt::after,
.tl-item.r .tl-txt::after {
  content:""; position:absolute; top:50%; width:26px; height:1px; background:var(--rule);
}
.tl-item.l .tl-txt::after { left:calc(50% - 69px); }
.tl-item.r .tl-txt::after { right:calc(50% - 69px); }
.tl-d {
  display:block; margin-bottom:4px; color:var(--train);
  font-family:"DM Mono", ui-monospace, monospace; font-size:11px; letter-spacing:.14em;
}
.tl-item.fut .tl-d { color:var(--web); }
.tl-t { font-size:19px; font-weight:800; font-variation-settings:'wdth' 88; line-height:1.2; }
.tl-item.fut .tl-t { color:var(--muted); }
.tl-s { color:var(--muted); font-size:12.5px; margin-top:3px; }

/* --- E · connect ------------------------------------------------------- */
.connect { display: grid; gap: var(--gutter);
  grid-template-columns: minmax(0,1fr) minmax(0,1fr); align-items: start; }
.links { display: flex; flex-direction: column; gap: 1px;
  background: var(--rule-2); border: 1px solid var(--rule-2); }
.link {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  background: var(--ground); padding: 17px 20px;
  transition: background var(--t-fast) var(--ease), padding-left var(--t-fast) var(--ease);
}
.link:hover, .link:focus-visible { background: var(--panel); padding-left: 26px; }
.link-l { font-size: 15.5px; font-weight: 600; font-variation-settings: 'wdth' 92; }

/* --- title block ------------------------------------------------------- */
.title-block {
  margin: 0 0 var(--sheet-pad);
  border: 1px solid var(--rule);
  display: flex; flex-wrap: wrap;
}
/* cells share the row the way the old fr track list did, but the count is no
   longer fixed: pages carry two or three cells and each still fills the rule. */
.tb-cell { flex: 1 1 0; padding: 15px 18px; border-right: 1px solid var(--rule-2);
  display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.tb-cell:last-child { border-right: 0; }
.tb-v { font-size: 14px; font-weight: 600; font-variation-settings: 'wdth' 92;
  overflow-wrap: anywhere; }
.tb-cell.brand { flex: 1.5 1 0; display: flex; flex-direction: row; align-items: center; gap: 13px; }
.tb-cell.brand img { height: 30px; width: auto; }
.tb-brand-t { display: flex; flex-direction: column; gap: 3px; }

/* --- responsive -------------------------------------------------------- */
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; align-items: start; }
  .bio { flex-direction: column; }
  .bio-rows { width: 100%; }
  .who { grid-template-columns: 1fr; }
  .who-photo { max-width: 320px; aspect-ratio: 1/1; }
  .doors, .connect { grid-template-columns: 1fr; }
  .facts { grid-template-columns: 1fr; }
  .tb-cell, .tb-cell.brand { flex: 1 1 50%; border-bottom: 1px solid var(--rule-2); }
  /* keep navigation on small screens: labels stay, sheet numbers drop, and the
     index scrolls sideways rather than truncating. */
  .zone { padding: 7px 7px; font-size: 9.5px; letter-spacing: .07em; }
  .zones { gap: 0; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; }
  .zones::-webkit-scrollbar { display: none; }
  .bar { gap: 12px; }
  .bar-mark img { height: 26px; }
}
@media (max-width: 640px) {
  .dim-val { font-size: 9.5px; letter-spacing: .12em; padding: 0 9px; }
  /* a 16:10 site screenshot is unreadable at phone width and costs a scroll of
     its own, so the website cards drop their preview. The app screens and the
     EdgeNotes stage are legible small and stay. */
  .shelf.web .proj-shot { display: none; }
  /* tighter tracking keeps most URLs on one line at phone width. A URL that
     still has to wrap reads better as running text than as flex items: as a
     flex child the arrow could not share a line with a two-line label and got
     stranded on a third line of its own. */
  .door-go { display: block; font-size: 10.5px; letter-spacing: .08em; }
  .door-go .arr { display: inline-block; margin-left: 7px; }
}

/* Below ~560px the pair no longer has the room for 19px mono at .18em tracking:
   the label and its arrow ran past the 20px padding and sat on the border. The
   doors stack instead of shrinking, so the type keeps its designed size and each
   gate gets a full-width tap target. */
@media (max-width: 560px) {
  .gates { flex-direction: column; gap: 12px; }
  .gate-link { flex: 0 0 auto; width: 100%; padding: 13px 18px; }
}
@media (max-width: 520px) {
  .tb-cell, .tb-cell.brand { flex: 1 1 100%; }
  .hero-name { font-size: clamp(52px, 17vw, 96px); }
}

/* the journey collapses to a single left-aligned column */
@media (max-width: 720px) {
  .tl::before { left: 24px; }
  .tl-item { grid-template-columns: 48px 1fr; padding: 10px 0; }
  /* grid auto-placement is sparse and never backtracks, so a left-side item
     (text before node in the DOM) would push the node to the next row. Both
     children get an explicit row. */
  .tl-node { grid-column: 1; grid-row: 1; width: 48px; height: 48px; padding: 6px;
    justify-self: start; font-size: 18px; }
  .tl-item.l .tl-txt, .tl-item.r .tl-txt {
    grid-column: 2; grid-row: 1; text-align: left; padding: 0 0 0 18px;
  }
  .tl-item.l .tl-txt::after, .tl-item.r .tl-txt::after { display: none; }
  .tl-t { font-size: 17px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-delay: 0ms !important;
    transition-duration: .001ms !important;
  }
  .dim-rule { transform: scaleX(1); }
  .dim-val { opacity: 1; }
}

/* ==========================================================================
   SHEET 2 · TRAINING
   The hero inverts the home sheet: image as canvas, type in the safe area.
   ========================================================================== */
.canvas {
  position: relative; margin: 0 0 clamp(52px,5.6vw,88px);
  border: 1px solid var(--rule); overflow: hidden;
  min-height: clamp(360px, 52vw, 620px); display: flex; align-items: flex-end;
}
.canvas-img { position: absolute; inset: 0; }
.canvas-img img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 42%; }
/* tonal wash, palette-matched, keeps the type readable without a glow */
.canvas-img::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--ground) 52%, transparent) 0%,
    color-mix(in srgb, var(--ground) 22%, transparent) 34%,
    color-mix(in srgb, var(--ground) 88%, transparent) 82%,
    var(--ground) 100%);
}
.canvas-body { position: relative; padding: clamp(24px,3.4vw,52px); width: 100%; }
.canvas-title { font-size: clamp(52px,10vw,132px); }
.canvas-title em { font-style: normal; color: var(--train); }
.canvas-sub { margin: 18px 0 0; max-width: 46ch; font-size: 17px; color: var(--ink); opacity: .88; }
.canvas-meta { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-top: 20px; }

/* programmes */
.progs { display: grid; gap: 16px; grid-template-columns: repeat(3, minmax(0,1fr)); }
.prog {
  display: flex; flex-direction: column; gap: 14px; padding: clamp(22px,2.6vw,32px);
  background: var(--panel); border: 1px solid var(--rule); position: relative;
  transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.prog:hover { transform: translateY(-3px); border-color: color-mix(in srgb, var(--train) 45%, transparent); }
.prog.lead { border-color: color-mix(in srgb, var(--train) 52%, transparent); background: var(--raise); }
.prog.lead::before {
  content: ""; position: absolute; left: -1px; top: -1px; bottom: -1px; width: 3px;
  background: var(--train);
}
.prog-t { margin: 0; font-size: 20px; font-weight: 800; font-variation-settings: 'wdth' 88; }
.prog p { margin: 0; color: var(--muted); font-size: 14px; flex: 1; }
.prog-tag {
  align-self: flex-start; font-family: "DM Mono", ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--train);
  border: 1px solid color-mix(in srgb, var(--train) 40%, transparent);
  border-radius: 999px; padding: 5px 10px;
}
.prog.lead .prog-tag { background: color-mix(in srgb, var(--train) 14%, transparent); }
.note-line { margin: 18px 0 0; color: var(--muted); font-size: 13px; }

/* facility — a deliberately quiet section between two dense ones */
.facility { display: grid; gap: var(--gutter); grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  align-items: start; }
.facility-stat { display: flex; flex-direction: column; gap: 3px; }
.facility-stat b { font-size: 17px; font-weight: 700; font-variation-settings: 'wdth' 90; }
.facility-list { display: flex; flex-direction: column; gap: 1px; background: var(--rule-2);
  border: 1px solid var(--rule-2); }
.facility-list > div { background: var(--ground); padding: 15px 18px; }

/* booking form */
.book { display: grid; gap: var(--gutter); grid-template-columns: minmax(0,.9fr) minmax(0,1.1fr);
  align-items: start; }
.field { display: flex; flex-direction: column; gap: 7px; margin-bottom: 14px; }
.field label { font-family: "DM Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.field input, .field select, .field textarea {
  background: var(--panel); border: 1px solid var(--rule); color: var(--ink);
  font-family: Archivo, sans-serif; font-size: 15px; padding: 12px 14px; border-radius: 0;
  width: 100%; transition: border-color var(--t-fast) var(--ease);
}
.field textarea { resize: vertical; min-height: 104px; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--train);
}
.field select { cursor: pointer; }
.submit {
  width: 100%; padding: 17px 20px; background: var(--train); color: #06251A;
  border: 1px solid var(--train); font-family: Archivo, sans-serif; font-size: 15px;
  font-weight: 700; font-variation-settings: 'wdth' 90; cursor: pointer;
  transition: opacity var(--t-fast) var(--ease);
}
.submit:hover { opacity: .88; }
.submit[data-state="sending"] { opacity: .6; cursor: wait; }
.submit[data-state="error"] { background: #FF6B6B; border-color: #FF6B6B; color: #2A0808; }
.form-note { margin: 12px 0 0; color: var(--muted); font-size: 12.5px; }

/* vault entry */
.vault-cta { display: flex; align-items: center; justify-content: space-between; gap: 20px;
  flex-wrap: wrap; padding: 22px 26px; border: 1px dashed var(--line2); background: var(--panel); }
.vault-cta p { margin: 0; color: var(--muted); font-size: 14px; max-width: 56ch; }
.vault-cta b { color: var(--ink); font-weight: 600; }

@media (max-width: 900px) {
  .progs { grid-template-columns: 1fr; }
  .facility, .book { grid-template-columns: 1fr; }
}

/* ==========================================================================
   SHEET 3 · WEB DESIGN — pricing
   ========================================================================== */
.tiers { display: grid; gap: 16px; grid-template-columns: repeat(3, minmax(0,1fr)); align-items: stretch; }
.tier {
  display: flex; flex-direction: column; gap: 16px; padding: clamp(22px,2.6vw,32px);
  background: var(--panel); border: 1px solid var(--rule); position: relative;
  transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.tier:hover { transform: translateY(-3px); border-color: color-mix(in srgb, var(--web) 45%, transparent); }
.tier.lead { background: var(--raise); border-color: color-mix(in srgb, var(--web) 52%, transparent); }
.tier.lead::before {
  content: ""; position: absolute; left: -1px; top: -1px; bottom: -1px; width: 3px; background: var(--web);
}
.tier-tag {
  align-self: flex-start; font-family: "DM Mono", ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--web);
  border: 1px solid color-mix(in srgb, var(--web) 40%, transparent);
  border-radius: 999px; padding: 5px 10px;
}
.tier.lead .tier-tag { background: color-mix(in srgb, var(--web) 14%, transparent); }
.tier-name { margin: 0; font-size: 21px; font-weight: 800; font-variation-settings: 'wdth' 88; }
.tier-price { display: flex; align-items: baseline; gap: 9px; }
.tier-price b { font-size: clamp(34px,4.4vw,46px); font-weight: 900;
  font-variation-settings: 'wdth' 74; letter-spacing: -.02em; line-height: 1; }
.tier-desc { margin: 0; color: var(--muted); font-size: 14px; }
.tier-feats { list-style: none; margin: 0; padding: 16px 0 0; border-top: 1px solid var(--rule);
  display: flex; flex-direction: column; gap: 10px; flex: 1; }
.tier-feats li { display: flex; gap: 11px; font-size: 14px; align-items: baseline; }
.tier-feats li::before { content: "—"; color: var(--web); flex: none; }
.tier-cta {
  display: block; text-align: center; padding: 14px 18px; border: 1px solid var(--web);
  color: var(--web); font-size: 14px; font-weight: 700; font-variation-settings: 'wdth' 90;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tier.lead .tier-cta { background: var(--web); color: #2A1C02; }
.tier-cta:hover { background: var(--web); color: #2A1C02; }

/* ==========================================================================
   SHEET 4 · PROJECTS
   ========================================================================== */
/* auto-fill, not auto-fit: a section holding one project keeps a card-sized
   card instead of stretching it across the sheet */
.projs { display: grid; gap: 16px;
  /* min() so the track collapses to the drawer's width on a phone: a bare
     320px minimum is wider than the sheet once padding is taken out, and the
     cards overflowed to the right. */
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); }
.proj {
  --proj-pad: clamp(20px,2.4vw,28px);
  display: flex; flex-direction: column; gap: 13px; padding: var(--proj-pad);
  background: var(--panel); border: 1px solid var(--rule);
  transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.proj:hover { transform: translateY(-3px); border-color: var(--line2); }

/* the preview runs full-bleed to the card edge, so it reads as the card's
   own header rather than a picture sitting inside a box */
.proj-shot {
  position: relative; overflow: hidden; aspect-ratio: 16 / 10;
  background: var(--ground); border-bottom: 1px solid var(--rule);
  margin: calc(-1 * var(--proj-pad)) calc(-1 * var(--proj-pad)) 2px;
}
.proj-shot img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 0;
  transition: transform .4s var(--ease); }
.proj:hover .proj-shot img { transform: scale(1.03); }

/* app screens: a scrollable row of phone-shaped shots */
.proj-screens { display: flex; gap: 9px; overflow-x: auto; padding-bottom: 3px;
  scrollbar-width: thin; }
.proj-screen { flex: none; width: 124px; aspect-ratio: 9 / 19.5; overflow: hidden;
  background: var(--ground); border: 1px solid var(--rule); }
.proj-screen img { width: 100%; height: 100%; object-fit: cover; }

/* placeholder skeletons — deliberate, so a missing asset does not read as a
   broken image. Swap in a real <img> and the skeleton goes away. */
.shot-skel, .screen-skel { width: 100%; height: 100%; display: flex;
  flex-direction: column; gap: 6px; padding: 12px; background: var(--ground); }
.screen-skel { padding: 7px; gap: 4px; }
.skel-bar { height: 6px; background: var(--rule); flex: none; }
.skel-bar.w60 { width: 60%; } .skel-bar.w40 { width: 40%; } .skel-bar.w80 { width: 80%; }
.skel-fill { flex: 1; background: var(--rule-2); }
.proj-note { font-family: "DM Mono", ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }

.proj-top { display: flex; align-items: center; gap: 11px; }
.proj-top .proj-t { flex: 1; min-width: 0; }
/* an app icon should read as an app icon: big, squircle-cornered, no frame */
.proj-logo.app { width: 64px; height: 64px; border: 0; border-radius: 22.4%;
  box-shadow: 0 2px 10px rgba(0,0,0,.45); }
.proj-logo.app img { padding: 0; object-fit: cover; }

/* the App Store call to action */
.app-cta {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  margin-top: 2px; padding: 13px 16px;
  background: var(--ink); color: var(--ground);
  border: 1px solid var(--ink);
  font-family: "DM Mono", ui-monospace, monospace; font-size: 10.5px;
  letter-spacing: .13em; text-transform: uppercase; font-weight: 500;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.app-cta svg { width: 15px; height: 15px; flex: none; fill: currentColor; }
.app-cta:hover, .app-cta:focus-visible {
  background: var(--train); border-color: var(--train); color: #04140D;
}
/* the same app on the web: sits under the App Store button, outlined so the
   store stays the primary action. A domain is one long token, so let it wrap. */
.app-cta.web { margin-top: -5px; background: transparent; color: var(--ink);
  border-color: var(--rule); text-transform: none; letter-spacing: .06em;
  overflow-wrap: anywhere; }
.app-cta.web svg { fill: none; stroke: currentColor; stroke-width: 1.6; }

.proj-logo { flex: none; width: 48px; height: 48px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  font-family: "DM Mono", ui-monospace, monospace; font-size: 13px;
  letter-spacing: .04em; color: var(--muted); }
.proj-logo img { width: 100%; height: 100%; object-fit: contain; }
/* only the initials fallbacks need a frame to read as a mark */
.proj-logo.tile { background: var(--ground); border: 1px solid var(--rule); }
.proj-status {
  font-family: "DM Mono", ui-monospace, monospace; font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; padding: 4px 9px; border-radius: 999px; white-space: nowrap;
  border: 1px solid currentColor;
}
.st-live { color: var(--train); } .st-open { color: var(--train); }
.st-build { color: var(--web); } .st-off { color: var(--muted); }
.proj-t { margin: 0; font-size: 19px; font-weight: 800; font-variation-settings: 'wdth' 88; }
.proj p { margin: 0; color: var(--muted); font-size: 14px; flex: 1; }
.tags { display: flex; flex-wrap: wrap; gap: 7px; }
.tags span {
  font-family: "DM Mono", ui-monospace, monospace; font-size: 9.5px; letter-spacing: .1em;
  color: var(--muted); border: 1px solid var(--rule); padding: 4px 9px; border-radius: 999px;
}

/* --- the three drawers ------------------------------------------------
   Apps, Websites, Software: each a collapsed row with a line-drawn device on
   the left. The header is one <button>; js/projects.js toggles .is-open and
   the rest is CSS. Height animates with grid-template-rows (0fr -> 1fr), so
   nothing is measured, and the cards inside enter on a stagger driven by an
   --i index the script writes onto each card. Without JS (html.no-js) every
   drawer sits open so nothing is hidden. */
.shelves { display: flex; flex-direction: column; gap: 14px; }
.shelf {
  --accent: var(--train);
  position: relative; background: var(--panel); border: 1px solid var(--rule);
  transition: border-color .3s var(--ease);
}
.shelf.web  { --accent: var(--web); }
.shelf.soft { --accent: var(--ink); }
/* the drawn edge (see .door::before) grows in from the top as the drawer opens */
.shelf::before {
  content: ""; position: absolute; left: -1px; top: -1px; bottom: -1px; width: 3px;
  background: var(--accent); transform: scaleY(0); transform-origin: 50% 0;
  transition: transform .5s var(--ease);
}
.shelf:hover::before, .shelf.is-open::before { transform: scaleY(1); }
.shelf.is-open { border-color: color-mix(in srgb, var(--accent) 46%, transparent); }

.shelf-h { margin: 0; font: inherit; }
.shelf-btn {
  display: grid; grid-template-columns: auto 1fr auto auto; align-items: center;
  gap: clamp(16px, 2.6vw, 36px); width: 100%;
  padding: clamp(18px, 2.2vw, 26px) clamp(20px, 2.6vw, 32px);
  background: none; border: 0; color: inherit; font: inherit; text-align: left;
  cursor: pointer; -webkit-appearance: none; appearance: none;
  transition: background var(--t-fast) var(--ease);
}
.shelf-btn:hover, .shelf.is-open .shelf-btn { background: var(--raise); }
.shelf-btn:focus-visible { outline-offset: -4px; outline-color: var(--accent); }

/* the device: muted linework at rest, lit in the accent on hover and open */
.dev { width: 132px; height: 99px; color: var(--muted); transition: color .3s var(--ease); }
.dev svg { width: 100%; height: 100%; overflow: visible; }
.shelf-btn:hover .dev, .shelf.is-open .dev { color: var(--accent); }
.dev-screen { fill: transparent; transition: fill .45s var(--ease); }
.shelf.is-open .dev-screen { fill: color-mix(in srgb, var(--accent) 12%, transparent); }
/* phone: the app tiles pop in one after another */
.dev-apps rect { transform-box: fill-box; transform-origin: 50% 50%; transform: scale(0);
  transition: transform .32s var(--ease); }
.dev-apps rect:nth-child(2) { transition-delay: 45ms; }
.dev-apps rect:nth-child(3) { transition-delay: 90ms; }
.dev-apps rect:nth-child(4) { transition-delay: 135ms; }
.dev-apps rect:nth-child(5) { transition-delay: 180ms; }
.dev-apps rect:nth-child(6) { transition-delay: 225ms; }
.shelf-btn:hover .dev-apps rect, .shelf.is-open .dev-apps rect { transform: scale(1); }
/* browser and terminal: the page draws itself in, line by line */
.dev-lines line, .dev-lines path { stroke-dasharray: 100; stroke-dashoffset: 100;
  transition: stroke-dashoffset .55s var(--ease); }
.dev-lines .l2 { transition-delay: 90ms; }
.dev-lines .l3 { transition-delay: 180ms; }
.shelf-btn:hover .dev-lines line, .shelf-btn:hover .dev-lines path,
.shelf.is-open .dev-lines line, .shelf.is-open .dev-lines path { stroke-dashoffset: 0; }
.dev-hero { fill: transparent; transition: fill .5s var(--ease) .2s; }
.shelf-btn:hover .dev-hero, .shelf.is-open .dev-hero { fill: color-mix(in srgb, currentColor 28%, transparent); }
.dev-cursor { animation: dev-blink 1.1s steps(2, start) infinite; }
@keyframes dev-blink { 50% { opacity: 0; } }

.shelf-txt { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.shelf-k { transition: color .3s var(--ease); }
.shelf.is-open .shelf-k { color: var(--accent); }
.shelf-t {
  font-weight: 900; font-variation-settings: 'wdth' 68; text-transform: uppercase;
  font-size: clamp(30px, 4.2vw, 48px); line-height: .9; letter-spacing: -.005em;
}
.shelf-s { color: var(--muted); font-size: 14.5px; max-width: 48ch; margin-top: 4px; }
.shelf-n { font-size: 10.5px; white-space: nowrap; padding: 5px 11px;
  border: 1px solid var(--rule); border-radius: 999px; }
.shelf-x { display: flex; align-items: center; gap: 12px; color: var(--muted);
  transition: color .3s var(--ease); }
.shelf-xl::after { content: "Open"; }
.shelf.is-open .shelf-xl::after { content: "Close"; }
.shelf.is-open .shelf-x { color: var(--accent); }
/* the plus that turns into a cross */
.plus { position: relative; width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--rule); transition: transform .45s var(--ease), border-color .3s var(--ease); }
.plus::before, .plus::after { content: ""; position: absolute; left: 50%; top: 50%;
  width: 12px; height: 1.5px; background: currentColor; transform: translate(-50%, -50%); }
.plus::after { transform: translate(-50%, -50%) rotate(90deg); }
.shelf-btn:hover .plus { border-color: var(--rule); }
.shelf.is-open .plus { transform: rotate(45deg); border-color: var(--accent); }

/* the body: measured by the grid, not by JS */
.shelf-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .6s var(--ease); }
.shelf.is-open .shelf-body { grid-template-rows: 1fr; }
.shelf-in { min-height: 0; overflow: hidden; visibility: hidden; transition: visibility 0s .6s; }
.shelf.is-open .shelf-in { visibility: visible; transition-delay: 0s; }
.shelf-in > .projs { padding: 8px clamp(20px, 2.6vw, 32px) clamp(22px, 2.6vw, 32px);
  border-top: 1px solid var(--rule-2); }
/* cards rise out of the drawer in order; backwards fill holds them invisible
   through the delay, then hands back to the normal (hover-able) styles */
.shelf.is-open .proj { animation: proj-in .6s var(--ease) backwards;
  animation-delay: calc(120ms + var(--i, 0) * 85ms); }
@keyframes proj-in { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }
/* a drawer opened from the URL on load skips the theatre */
.shelf-instant .shelf-body, .shelf-instant .shelf-in { transition: none; }
.shelf-instant .proj { animation: none; }
/* no script: everything open, nothing to click for */
.no-js .shelf-body { grid-template-rows: 1fr; }
.no-js .shelf-in { visibility: visible; }
.no-js .shelf-x { display: none; }

/* cards inside a drawer take that drawer's accent */
.shelf .proj:hover { border-color: color-mix(in srgb, var(--accent) 46%, transparent); }
.proj .door-go { color: var(--accent); margin-top: auto; }
.proj .door-go.off { color: var(--muted); }
.proj:hover .door-go .arr { transform: translateX(5px); }
/* a site that is also an app: the App Store link sits under the domain. Only
   the first link takes the auto margin, so the pair stays together at the foot. */
.proj .door-go + .door-go { margin-top: -5px; }
/* the global reset makes every svg a block, which strands the logo on its own
   line once .door-go turns block at phone width; the flex gap spaces it above that */
.door-go.store svg { display: inline-block; width: 12px; height: 12px; flex: none;
  fill: currentColor; vertical-align: -1px; }
@media (max-width: 640px) { .door-go.store svg { margin-right: 8px; } }
.shelf.apps .app-cta:hover, .shelf.apps .app-cta:focus-visible {
  background: var(--accent); border-color: var(--accent); color: #04140D; }

/* app cards: copy on the left, the phone screens filling the rest */
.projs-apps { grid-template-columns: 1fr; }
.proj-app { display: grid; grid-template-columns: minmax(260px, 360px) 1fr;
  gap: clamp(18px, 2.6vw, 36px); align-items: start; }
.proj-app-copy { display: flex; flex-direction: column; gap: 13px; min-width: 0; }
.proj-app .proj-screens { min-width: 0; gap: 10px; }
.proj-app .proj-screen { width: 150px; }
@media (max-width: 760px) {
  .proj-app { grid-template-columns: 1fr; }
  .proj-app .proj-screen { width: 124px; }
}

@media (max-width: 720px) {
  .shelf-btn { grid-template-columns: auto 1fr auto; gap: 14px; }
  /* the sheet number costs more width than it earns once the column narrows */
  .shelf-no { display: none; }
  .shelf-k { white-space: nowrap; }
  .dev { width: 84px; height: 63px; }
  .shelf-n { display: none; }
  .shelf-x .mono { display: none; }
  .shelf-s { font-size: 13.5px; }
  .shelf-t { font-size: clamp(26px, 8vw, 36px); }
}

/* --- EdgeNotes ---------------------------------------------------------
   The card carries the app's own demo rather than a picture of it. The demo
   is a self-contained page (embed/edgenotes-deck.html, copied from the
   project's portfolio folder) and runs in an iframe for two reasons: its
   class names are generic enough to collide with this stylesheet, and inside
   its own document the deck's 320pt coordinate space and ghost-cursor
   keyframes work exactly as written, with no rescaling here.

   The stage is 640 x 704 and sizes itself to the frame's width, so the frame
   only has to hold that ratio. */
.projs-soft { grid-template-columns: 1fr; }
.proj-ed {
  display: grid; grid-template-columns: minmax(240px, 340px) 1fr;
  gap: clamp(18px, 2.6vw, 36px); align-items: start;
}
.proj-ed-copy { display: flex; flex-direction: column; gap: 13px; min-width: 0; }
.proj-ed-copy p { flex: 1; }
/* iOS Safari ignores an iframe's declared height and grows it to its content,
   so the ratio is held by a wrapper that clips, and the frame just fills it */
.ed-stage {
  position: relative; width: 100%; max-width: 640px;
  aspect-ratio: 640 / 704; overflow: hidden;
}
.ed-frame {
  position: absolute; inset: 0; width: 100%; height: 100%;
  border: 0; display: block; background: transparent;
  color-scheme: light;   /* the demo draws a Mac screen, not a dark panel */
}

/* the icon art already carries its own corners and shadow */
.proj-logo.app.bare { border-radius: 0; box-shadow: none; }
.proj-logo.app.bare img { object-fit: contain; }

@media (max-width: 760px) {
  .proj-ed { grid-template-columns: 1fr; }
}

/* ==========================================================================
   SHEET 5 · THE VAULT — measured, not claimed
   ========================================================================== */
.gate { max-width: 460px; margin: 0 auto; text-align: center;
  display: flex; flex-direction: column; gap: 18px; align-items: center; }
.gate .field { width: 100%; text-align: left; margin-bottom: 0; }
.gate-err { color: #FF6B6B; font-size: 13px; min-height: 19px; margin: 0; }
/* discrete cards, not a hairline grid: nine records never divide evenly into
   the column count, and empty grid cells were rendering as lit panels. */
.prs { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(210px,1fr)); }
.pr { background: var(--panel); border: 1px solid var(--rule); padding: 20px 22px;
  display: flex; flex-direction: column; gap: 6px; }
.pr.empty { background: none; border-style: dashed; }
.pr-l { font-family: "DM Mono", ui-monospace, monospace; font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); }
.pr-v { font-size: clamp(26px,3vw,34px); font-weight: 900; font-variation-settings: 'wdth' 74;
  letter-spacing: -.02em; line-height: 1; font-variant-numeric: tabular-nums; }
.pr.empty .pr-v { color: var(--muted); opacity: .5; }
.pr-u { font-family: "DM Mono", ui-monospace, monospace; font-size: 11px; color: var(--muted); }
.log { width: 100%; border-collapse: collapse; }
.log th { text-align: left; padding: 0 16px 11px 0; border-bottom: 1px solid var(--rule);
  font-family: "DM Mono", ui-monospace, monospace; font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); font-weight: 400; }
.log td { padding: 14px 16px 14px 0; border-bottom: 1px solid var(--rule-2); font-size: 14.5px;
  color: var(--muted); }
.log td.d { font-family: "DM Mono", ui-monospace, monospace; font-size: 12px; white-space: nowrap; }
.log td.n { color: var(--ink); font-weight: 600; font-variation-settings: 'wdth' 92; }
.log td.v { color: var(--ink); font-family: "DM Mono", ui-monospace, monospace;
  font-variant-numeric: tabular-nums; text-align: right; }

@media (max-width: 900px) { .tiers { grid-template-columns: 1fr; } }

/* ==========================================================================
   CAREER — the game log
   ========================================================================== */
/* --- career stat block --------------------------------------------------
   Seven facts of two kinds. Counts stand alone; records were set against a
   team, so that team's mark is set beside the figure at full size rather than
   tucked underneath it. A fixed three-track grid, because auto-fit chose a
   different column count at every width and seven tiles never filled it —
   which left a hole three cells wide on a large screen. */
.stats { display: grid; gap: 1px; background: var(--rule-2);
  border: 1px solid var(--rule-2); margin-bottom: 30px;
  grid-template-columns: repeat(3, minmax(0, 1fr)); }
.stat { background: var(--ground); padding: 24px clamp(18px, 2vw, 26px);
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(14px, 1.6vw, 20px); min-width: 0; }
.stat-txt { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.stat-v { font-size: clamp(28px,3.2vw,38px); font-weight: 900; font-variation-settings: 'wdth' 74;
  letter-spacing: -.02em; line-height: 1; font-variant-numeric: tabular-nums; }
/* a value carrying both units is twice the characters, so it steps down a size
   rather than wrapping mid-figure */
.stat-v.dual { font-size: clamp(21px,2.3vw,27px); }
.stat-l { font-family: "DM Mono", ui-monospace, monospace; font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); }

/* The opponent a record was set against, sitting to the right of the figure.
   No chip — the mark is on the sheet, with a hairline halo so the darker crests
   keep an edge. --k is the per-mark size correction from games.js: without it a
   tall crest fills the box and reads much heavier than a wide, flat one. */
.stat-mark { flex: none; width: clamp(44px, 4.6vw, 58px); height: clamp(44px, 4.6vw, 58px);
  display: grid; place-items: center; }
.stat-mark img, .stat-team img {
  max-width: calc(100% * var(--k, 1)); max-height: calc(100% * var(--k, 1));
  width: auto; height: auto;
  filter: drop-shadow(0 0 1.5px #FFFFFF59) drop-shadow(0 1px 4px #00000080); }

/* the streak takes the full width, and its six marks are spread across it
   rather than crowded against the right edge */
.stat.wide { grid-column: 1 / -1; }
.stat.wide .stat-teams { flex: 1; display: flex; align-items: center;
  justify-content: space-evenly; gap: 10px; padding-left: clamp(20px, 4vw, 60px); }
.stat-team { flex: none; width: clamp(38px, 3.8vw, 52px); height: clamp(38px, 3.8vw, 52px);
  display: grid; place-items: center; }

@media (max-width: 820px) {
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 520px) {
  .stats { grid-template-columns: 1fr; }
  .stat.wide { flex-wrap: wrap; }
  .stat.wide .stat-teams { width: 100%; flex-basis: 100%; padding-left: 0;
    justify-content: space-between; }
}

.filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; align-items: center; }
.chip {
  font-family: "DM Mono", ui-monospace, monospace; font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted); background: none;
  border: 1px solid var(--rule); padding: 8px 13px; cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.chip:hover { color: var(--ink); border-color: var(--line2); }
.chip[aria-pressed="true"] { color: var(--ground); background: var(--ink); border-color: var(--ink); }
.filter-sep { width: 1px; height: 20px; background: var(--rule); margin: 0 6px; }

/* the log is wider than a phone, so its wrapper is the thing that scrolls.
   Without this the table simply overflowed and body's overflow-x:hidden cut
   the last columns off with no way to reach them. */
.scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: thin; }
.scroll:focus-visible { outline-offset: 2px; }
.games { width: 100%; border-collapse: collapse; min-width: 720px; }
.games th { text-align: left; padding: 0 14px 11px 0; border-bottom: 1px solid var(--rule);
  font-family: "DM Mono", ui-monospace, monospace; font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); font-weight: 400; white-space: nowrap; }
.games td { padding: 13px 14px 13px 0; border-bottom: 1px solid var(--rule-2);
  color: var(--muted); font-size: 14px; vertical-align: baseline; }
.games tr:hover td { background: color-mix(in srgb, var(--panel) 60%, transparent); }
.games .g-d { font-family: "DM Mono", ui-monospace, monospace; font-size: 11.5px; white-space: nowrap; }
.games .g-o { color: var(--ink); font-weight: 600; font-variation-settings: 'wdth' 92; }
.games .g-s { font-family: "DM Mono", ui-monospace, monospace; font-variant-numeric: tabular-nums;
  color: var(--ink); white-space: nowrap; }
.games .g-r { font-family: "DM Mono", ui-monospace, monospace; font-weight: 500; width: 1%; }
.g-r.w { color: var(--train); } .g-r.l { color: var(--muted); }
.games .g-a { text-align: right; font-family: "DM Mono", ui-monospace, monospace;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.g-ha { font-family: "DM Mono", ui-monospace, monospace; font-size: 10px; letter-spacing: .12em;
  color: var(--muted); border: 1px solid var(--rule); padding: 2px 7px; }
.games-empty { padding: 34px 0; color: var(--muted); font-size: 14px; }

/* --- the career map ----------------------------------------------------- */
.map-wrap { display: grid; gap: 16px; grid-template-columns: minmax(0,1.55fr) minmax(0,.95fr);
  align-items: stretch; margin-bottom: 34px; }
.globe-box { position: relative; border: 1px solid var(--rule); background: var(--panel);
  min-height: 440px; overflow: hidden; }
#globeViz { position: absolute; inset: 0; }
.globe-hint { position: absolute; left: 14px; bottom: 12px; z-index: 2; pointer-events: none; }
.globe-fallback, .globe-loading { position: absolute; inset: 0; display: none;
  flex-direction: column; gap: 10px; align-items: center; justify-content: center;
  text-align: center; padding: 30px; }
/* the globe itself is hidden, so nothing paints until the boundaries land —
   without this the box just sits empty and reads as broken */
.globe-box[data-state="loading"] .globe-loading { display: flex; }
.globe-box[data-state="loading"] .globe-loading .mono { animation: pulse 1.4s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: .45 } 50% { opacity: 1 } }
@media (prefers-reduced-motion: reduce) {
  .globe-box[data-state="loading"] .globe-loading .mono { animation: none; opacity: .8; }
}
.globe-box[data-state="failed"] .globe-fallback { display: flex; }
.globe-box[data-state="failed"] #globeViz,
.globe-box[data-state="failed"] .globe-hint { display: none; }

.map-card { --lamp: #FFA31A;
  border: 1px solid var(--rule); background: var(--panel); padding: 22px 24px;
  display: flex; flex-direction: column; gap: 14px; }
.map-card .mc-city { font-size: clamp(24px,2.8vw,32px); font-weight: 900;
  font-variation-settings: 'wdth' 78; letter-spacing: -.015em; line-height: 1; margin: 0; }
.mc-venue { margin: 0; color: var(--muted); font-size: 13.5px; }
.mc-list { display: flex; flex-direction: column; gap: 1px; background: var(--rule-2);
  border: 1px solid var(--rule-2); max-height: 300px; overflow-y: auto; }
/* every game at a venue is a board of its own, at row height: the same lamps
   the full game board uses, so the card and the dialog read as one object.
   The whole row opens that game's board. */
.mc-g { width: 100%; text-align: left; font: inherit; border: 0; cursor: pointer;
  background: var(--ground); padding: 9px 14px; display: grid;
  grid-template-columns: 1fr auto auto; gap: 14px; align-items: center;
  transition: background var(--t-fast) var(--ease); }
.mc-g:hover, .mc-g:focus-visible { background: var(--raise); }
.mc-g:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
.mc-g .o { color: var(--ink); font-size: 14px; font-weight: 600;
  font-variation-settings: 'wdth' 92; min-width: 0; overflow-wrap: anywhere; }
.mc-lamps { display: flex; align-items: center; gap: 9px; }
.mc-win { display: flex; gap: 3px; padding: 4px 5px; background: #04060A;
  box-shadow: inset 0 0 0 1px #FFFFFF0D; }
.mc-win svg { height: 19px; width: auto; display: block; }
.mc-g .r { font-family: "DM Mono", ui-monospace, monospace; font-size: 12px;
  font-weight: 500; width: 1ch; }
.mc-g .r.w { color: var(--lamp, #FFA31A); } .mc-g .r.l { color: var(--muted); }
/* the score is drawn, so give a screen reader the plain numbers */
.vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.mc-empty { color: var(--muted); font-size: 14px; margin: 0; }
@media (max-width: 900px) {
  .map-wrap { grid-template-columns: 1fr; }
  .globe-box { min-height: 330px; }
}

/* The map and the log read as one stack. At their seam three separate spaces
   were stacking — the wrapper's trailing margin plus a full band's padding on
   each side — for 138px of nothing between the venue card and the heading. */
.map-wrap:last-child { margin-bottom: 0; }
.band-seam { padding-bottom: clamp(22px, 2.4vw, 32px); }
.band-seam + .band { padding-top: clamp(20px, 2.2vw, 30px); }

/* --- the game board ----------------------------------------------------
   A stadium scoreboard, drawn rather than typeset. The digits are real
   seven-segment lamps: the segments that are not lit stay faintly visible,
   which is the thing that makes a board read as a board instead of as orange
   text in a box. Below the lamps the point margin is set as an engineer's
   dimension line — the same device the home page opens with, doing real work
   here, since the margin is literally the distance between the two numbers.
   Native <dialog>, so Esc, focus trapping and the backdrop are the browser's. */
.games tbody tr { cursor: pointer; }
.games tbody tr:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }

.gm {
  --lamp: #FFA31A;
  width: min(486px, calc(100vw - 26px)); padding: 0; border: 0; color: var(--ink);
  background: linear-gradient(176deg, #141922 0%, #0E1116 42%, #0A0D12 100%);
  box-shadow: 0 0 0 1px #FFFFFF1A, 0 1px 0 #FFFFFF12 inset, 0 38px 90px #000000BF;
}
.gm::backdrop { background: color-mix(in srgb, #04060A 84%, transparent); }

/* marquee: what the board is bolted to, and what state it is in */
.sb-marquee {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 13px 52px 13px 18px; border-bottom: 1px solid #FFFFFF14;
  font-family: "DM Mono", ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .2em; text-transform: uppercase; color: var(--muted);
}
.sb-state { display: inline-flex; align-items: center; gap: 7px; color: var(--ink); }
.sb-state::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--lamp); box-shadow: 0 0 8px var(--lamp);
}
.sb-x {
  position: absolute; top: 7px; right: 7px; width: 32px; height: 32px; line-height: 1;
  background: none; border: 1px solid transparent; color: var(--muted);
  font-size: 18px; cursor: pointer; z-index: 2;
}
.sb-x:hover, .sb-x:focus-visible { color: var(--ink); border-color: #FFFFFF26; }

/* the two lamp windows */
.sb-lamps { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; padding: 20px 18px 4px; }
.sb-side { display: flex; flex-direction: column; align-items: center; gap: 10px; min-width: 0; }
.sb-slot { font-family: "DM Mono", ui-monospace, monospace; font-size: 8.5px;
  letter-spacing: .3em; text-transform: uppercase; color: #7A8290; }
.sb-window {
  width: 100%; display: flex; justify-content: center; gap: 10px;
  padding: 11px 10px; background: #04060A;
  box-shadow: inset 0 0 0 1px #FFFFFF0F, inset 0 3px 14px #000000B3;
}
.sb-window svg { height: 72px; width: auto; display: block; }
.sg { fill: var(--lamp); fill-opacity: .07; transition: fill-opacity .18s linear; }
.sg.on { fill-opacity: 1; filter: drop-shadow(0 0 7px #FFA31A80); }
/* power-on: every segment strikes before the score settles, the way a real
   board runs its lamp test */
.gm.warm .sg { fill-opacity: .4; }
.gm.warm .sg.on { filter: none; }

/* the name plate under each window */
.sb-plate { display: flex; align-items: baseline; gap: 8px; max-width: 100%; }
.sb-team {
  font-family: Archivo, sans-serif; font-weight: 800; font-variation-settings: 'wdth' 72;
  font-size: 15px; line-height: 1.15; letter-spacing: .015em; text-transform: uppercase;
  text-align: center; overflow-wrap: anywhere;
}
.sb-res { font-family: "DM Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .1em; color: var(--muted); }
.sb-res.w { color: var(--lamp); }

/* the margin, set as a dimension */
.sb-margin { position: relative; display: flex; align-items: center;
  margin: 16px 18px 20px; }
.sb-dim { flex: 1; height: 1px; background: var(--ink); opacity: .34; }
.sb-margin::before, .sb-margin::after {
  content: ""; position: absolute; top: 50%; width: 0; height: 0;
  border-block: 3px solid transparent; opacity: .34;
}
.sb-margin::before { left: 0; border-right: 6px solid var(--ink); transform: translateY(-50%); }
.sb-margin::after { right: 0; border-left: 6px solid var(--ink); transform: translateY(-50%); }
.sb-dim-val {
  padding: 0 12px; font-family: "DM Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .2em; text-transform: uppercase; color: var(--muted); white-space: nowrap;
}

/* the facts band */
.sb-rail { margin: 0; display: grid; grid-template-columns: repeat(3, minmax(0,1fr));
  gap: 1px; background: #FFFFFF0F; border-block: 1px solid #FFFFFF0F; }
.sb-foot { border-top: 0; }
.sb-cell { background: #0B0E13; padding: 13px 16px; display: flex;
  flex-direction: column; gap: 5px; min-width: 0; }
.sb-cell dt { font-family: "DM Mono", ui-monospace, monospace; font-size: 8.5px;
  letter-spacing: .18em; text-transform: uppercase; color: #7A8290; }
.sb-cell dd { margin: 0; font-size: 13px; font-weight: 600;
  font-variation-settings: 'wdth' 88; overflow-wrap: anywhere; }

/* footer: the box-score link, flanked by the pager when the board was opened
   from a set — a venue's games, or whatever the log's filters are showing */
.sb-foot { display: grid; grid-template-columns: 52px 1fr 52px; }
.sb-foot.solo { grid-template-columns: 1fr; }
.sb-foot.solo .sb-nav { display: none; }
.sb-nav {
  background: none; border: 0; border-inline: 1px solid #FFFFFF0F; cursor: pointer;
  color: var(--muted); font-size: 20px; line-height: 1; padding: 0;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.sb-nav:first-child { border-left: 0; }
.sb-nav:last-child { border-right: 0; }
.sb-nav:hover:not(:disabled), .sb-nav:focus-visible { color: var(--lamp); background: #FFA31A0F; }
.sb-nav:disabled { color: #3A4049; cursor: default; }
.sb-head-r { display: inline-flex; align-items: center; gap: 12px; }
.sb-pos { font-variant-numeric: tabular-nums; color: #7A8290; }

.sb-link {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 14px 18px; font-family: "DM Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
}
.sb-link:hover, .sb-link:focus-visible { color: var(--lamp); background: #FFA31A0F; }
.sb-link .arr { transition: transform var(--t-fast) var(--ease); }
.sb-link:hover .arr { transform: translateX(4px); }

@media (max-width: 440px) {
  .sb-window { gap: 7px; padding: 12px 8px; }
  .sb-window svg { height: 50px; }
  .sb-team { font-size: 13px; }
  .sb-cell { padding: 11px 12px; }
  .sb-cell dd { font-size: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .gm.warm .sg { fill-opacity: .07; }
  .gm.warm .sg.on { fill-opacity: 1; }
}

/* --- the enquiry form, opened from the Projects call to action -----------
   Same square panel language as the game board: a native <dialog>, so Esc,
   focus trapping and the backdrop come from the browser. */
button.gate-link { cursor: pointer; }

.cf {
  width: min(460px, calc(100vw - 26px)); padding: 0; color: var(--ink);
  background: var(--panel); border: 1px solid var(--rule);
  box-shadow: 0 34px 84px #000000BF;
}
.cf::backdrop { background: color-mix(in srgb, #04060A 82%, transparent); }
.cf-in { padding: 26px clamp(20px, 3vw, 30px) 24px; }
.cf-t { margin: 7px 0 20px; font-size: clamp(23px, 2.8vw, 29px); font-weight: 900;
  font-variation-settings: 'wdth' 80; letter-spacing: -.015em; line-height: 1.1; }
.cf-x {
  position: absolute; top: 7px; right: 7px; width: 32px; height: 32px; line-height: 1;
  background: none; border: 1px solid transparent; color: var(--muted);
  font-size: 18px; cursor: pointer; z-index: 1;
}
.cf-x:hover, .cf-x:focus-visible { color: var(--ink); border-color: var(--rule); }
.cf .form-note { margin: 12px 0 0; }
/* the projects enquiry button takes the amber of this sheet, not the green the
   shared .submit carries for the training form */
.cf .submit { background: var(--web); border-color: var(--web); color: #2A1C02; }
