/* rex-skin.css — the new system, applied over the existing pages.
 *
 * This does NOT restyle components. Every page keeps its own layout and its own
 * class names; this only retargets the tokens they already declare, and adds
 * the two new pieces: the lattice ribbon and the decode-on-hover text.
 *
 * Load rex-tokens.css FIRST, then this AFTER the page's own <style>
 * so the token block wins.
 */

:root{
  /* The palette lives in rex-tokens.css. These are the names the EXISTING
     pages already declare, aliased onto it — that aliasing is the whole
     mechanism: nothing here restyles a component. */
  --field:var(--p-ground); --paper:var(--p-surface); --soft:var(--p-chamber);
  --ink:var(--p-ink); --ink-soft:var(--p-ink-soft);
  --muted:var(--p-ink-muted); --faint:var(--p-ink-muted);
  --line:var(--p-line);
  --accent:var(--p-accent); --accent-text:var(--p-accent);
  /* the rainbow is gone. Anything still asking for --grad gets flat ink so it
     degrades to legible rather than to transparent. */
  --grad:none;
  /* loadout declares its own namespace */
  --dex-bg:var(--p-ground); --dex-panel:var(--p-chamber); --dex-ink:var(--p-ink-soft);
  --dex-line:rgba(30,30,28,.16); --dex-grad:none;
  /* loadout declares more of its namespace than the five above, and these four
     were missed — which is most of why that page stayed on the old cobalt. */
  --dex-ink-soft:rgba(26,26,25,.7); /* .6 was 4.4:1 on the ground; .7 clears AA */ --dex-mark:rgba(26,26,25,.85);
  --dex-navy:var(--p-ink-rgb); --dex-warm:rgba(26,26,25,.8);

  /* --navy was the biggest miss. It is not a background token, so it did not
     look like part of the palette — but it colours every link, the brand and
     the pills on three of these pages, so the old cobalt survived the reskin
     untouched. Consumed as a bare triple inside rgba(), so it stays a triple. */
  --navy:var(--p-ink-rgb);
}

/* ── residues ──────────────────────────────────────────────────────────
   Raw hex written into the pages' own rules, which no amount of retargeting
   reaches. Each one is a single declaration, listed rather than swept up by a
   broad selector so it stays obvious what is being overridden and why. */
.chip.hot{border-color:rgba(var(--p-accent-rgb),.4)}
#sitenav .links a[aria-current]{color:var(--accent)}
.boot-chapters b{color:var(--accent)}
.boot-skip:focus-visible{outline-color:var(--accent)}

/* the ground itself. background-color is set explicitly under the gradients:
   the shorthand alone leaves it transparent, and anything that fails to paint
   the gradient layers then falls through to black. */
body{
  background-color:var(--field);
  background-image:
    radial-gradient(60% 50% at 78% 12%, var(--g1), transparent 70%),
    radial-gradient(56% 48% at 8% 66%, var(--g2), transparent 72%),
    radial-gradient(76% 62% at 48% 102%, var(--g3), transparent 70%),
    linear-gradient(180deg, var(--soft), var(--field));
  background-attachment:fixed;
}

/* ── the lattice ribbon, behind everything ── */
#lattice{position:fixed;inset:0;z-index:0;pointer-events:none}
.frame,.sheet,main,header,footer,nav{position:relative;z-index:1}

/* ── kill the old look ──────────────────────────────────────────────────
   The hero headline was painted with the five-stop gradient and clipped to
   the text. With --grad:none that would render transparent, so the clip has
   to be undone explicitly rather than just changing the value. */
.hero h1, h1{
  background:none !important;
  -webkit-background-clip:border-box !important;
  background-clip:border-box !important;
  -webkit-text-fill-color:currentColor !important;
  color:var(--ink) !important;
  animation:none !important;
}
/* the ambient simulation host: it holds a canvas that no longer loads */
.sim{display:none !important}
/* the glyph confetti from accents.css, in case the link is still present */
.sheet::before,.sheet::after,.sec::before,.era::before{content:none !important}

/* accents.css is going away, but the page markup still depends on two of its
   rules. Dropping the stylesheet without these left the inline sigil SVG with
   no box at all, so it expanded to the SVG default and pushed the whole page
   down 538px. Anything the markup relies on has to be absorbed, not assumed. */
.sigil{display:inline-block;width:14px;height:14px;margin-right:.6rem;
  vertical-align:-2px;color:var(--accent);opacity:.75}
.sigil svg{display:block;width:100%;height:100%}

/* ── decode-on-hover ──────────────────────────────────────────────────
   LAYOUT-TRANSPARENT, deliberately. The prototype pinned each .sx to the
   wider of its proportional and monospace widths so the box could not judder.
   On real content that is actively harmful: an inline-block cannot participate
   in its parent's line breaking, and a min-width set from the mono measurement
   is wider than the proportional text, so any title near its container width
   was forced onto a second line. Measured: "Cotswold Sauna" min-width 295px in
   a 295px parent, height 38px -> 77px, and every card below it shifted down.

   So no display change, no min-width, and no font swap. The glyphs substitute
   in the page's own face, which means the box can only vary by the width
   difference between two characters of the same font — far too small to change
   a wrap, and the effect is over in 460ms. Geometry is preserved exactly. */
.sx{}
.sx .sx-vis{font-variant-numeric:tabular-nums}
/* rex-skin.js injects a .sr-only twin of every scrambled string so assistive
   tech reads a stable value instead of the churn. That class is styled in the
   prototype's stylesheet, which these pages do not load — so without this rule
   the twin renders VISIBLY, doubling every card title and forcing headings
   onto a second line. Second time a dependency had to be absorbed rather than
   assumed; check what the script emits, not just what the markup contains. */
.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ── status line ──
   NOT applied on this pass. Replacing the page's eyebrow with a channel
   readout is a CONTENT change, and the brief is that content stays put; it
   also shifted the whole page 25px because .hero p (0,1,1) outranks a bare
   class and the readout inherited the hero paragraph size. Kept here so the
   styling exists when the copy change is actually agreed. */
p.rex-status{font-family:var(--mono);font-size:.75rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted);margin:1rem 0;max-width:none}
p.rex-status .odd{color:var(--accent)}

/* ── gradient-clipped text ─────────────────────────────────────────────
   These pages paint some headings by clipping a gradient to the glyphs:
   background-image:var(--grad) + background-clip:text + a transparent fill.
   Setting --grad to none removes the gradient but NOT the transparent fill,
   so the text is still there, still measurable, and completely invisible.

   The h1 case was already handled. This is the one that was missed: the
   typewriter word on the about page, which is the only visible content of that
   whole section — it read as a blank gap with a blinking cursor in it. */
h1, .hero h1, .word, #tw-word{
  background-image:none !important;
  -webkit-background-clip:border-box !important;
  background-clip:border-box !important;
  -webkit-text-fill-color:currentColor !important;
  color:var(--ink);
}

/* ── the backdrop ──────────────────────────────────────────────────────
   Option C: the card goes.

   Every inner page sat on .sheet — an opaque white surface running the full
   height of the page and nearly its full width. The lattice is fixed BEHIND
   that at z-index 0, so all it ever showed was a ~28px strip down each edge.
   These pages read as the old site in new colours because structurally that is
   what they were: the same white card, repainted.

   Only the background is removed. Content width is set by .wrap (max 1180px),
   not by the sheet, so deleting the surface moves nothing — which is the point,
   and what the baseline checks. The radius and the overflow clip are left
   alone: with nothing painted they cost nothing, and overflow:hidden is still
   doing work for anything inside that overhangs. */
.sheet{background:none}

/* With no surface to sit on, the sections have to carry their own separation.
   The hairline is the system's own device, so this is not a new idea being
   introduced — it is the one already used on the homepage. */
.sec + .sec, .sec{border-top:1px solid var(--line)}
.sec:first-of-type{border-top:0}

/* loadout is deliberately NOT given this treatment. Its #stage is a fixed
   cinema panel that the video layers render into — the card IS the content
   there, not a wrapper around it, and making it transparent would break the
   thing that page does. It gets the palette instead of the deletion, so the
   lattice reads in the inset gutter around the screen rather than through it. */
#stage{background:var(--dex-panel)}

/* ── the experience rows ───────────────────────────────────────────────
   .job was already structurally the system's own .rec component — a date
   column, a content column, a hairline between rows — just written in the old
   language. This moves it into the new one WITHOUT touching the markup:

     .rec  →  3rem | 1fr | 9rem   with an index, a hover indent, a mono date
     .job  →  15rem | 1fr          with a bold heading and an accent-coloured org

   Changes here are deliberate and WILL move geometry, unlike everything else
   in this pass. The date column drops from 15rem to 10rem because 15 was sized
   for a label that turned out to be two short mono lines, and the 5rem it
   gives back goes to the prose. */
.job{
  /* 10rem. Measured with a Range across all six rows, because <b> is a block
     and its box always reports the full column width: the widest date TEXT is
     142px, so this leaves 18px of headroom rather than the none it looks like. */
  grid-template-columns:10rem 1fr;
  transition:padding-left .25s;
  counter-increment:jobrow;
}
/* the indent is the system's own hover: the row steps aside rather than
   lighting up, which is quieter and survives on a monochrome palette where a
   colour change would not read */
.job:hover{padding-left:.75rem}

.job .when{
  font-size:.75rem;letter-spacing:.14em;
  font-variant-numeric:tabular-nums;color:var(--muted);
}
/* the index numeral, from a counter rather than markup — the system signs its
   records and these had no number to sign them with */
.job .when::before{
  content:counter(jobrow,decimal-leading-zero);
  display:block;color:var(--faint);letter-spacing:.2em;margin-bottom:.5rem;
}
.job .when b{color:var(--ink);font-weight:400}

/* heading weight and the org line both come back to the system: 400 not 600,
   and the org in muted rather than the accent. The accent is one colour used
   sparingly for signal; every job having one made it decoration. */
.job h3{font-weight:400}
.job .org{color:var(--muted);font-size:.8125rem}

/* ── the accents ───────────────────────────────────────────────────────
   The system's diegetic furniture existed on the homepage and nowhere else,
   which is most of why the inner pages read as a different site wearing the
   same colours. Two pieces, both real markup rather than CSS content: a
   stylesheet-injected numeral is invisible to anything that reads the document
   instead of painting it, and these are meant to be furniture, not text. */

/* the hero has to establish a containing block for the numeral, and this is
   the only line in this block that can move anything — checked against the
   baseline for exactly that reason */
.hero{position:relative}

/* the channel number, huge and at 4% ink. It sits behind the hero rather than
   beside it: legible if you look for it, invisible if you are reading. */
.ghostnum{position:absolute;right:0;top:2.5rem;z-index:0;
  font-size:clamp(6rem,14vw,11rem);line-height:1;color:var(--ink);opacity:.04;
  font-variant-numeric:tabular-nums;pointer-events:none;user-select:none}
.hero > *:not(.ghostnum){position:relative;z-index:1}

/* a dot and a hairline, closing the hero. The dot is the one place the accent
   appears on these pages by default, which is what keeps it reading as signal. */
.noderule{display:flex;align-items:center;gap:.5rem;margin:2rem 0 0}
.noderule i{width:5px;height:5px;border-radius:50%;background:var(--accent);flex:none}
.noderule span{flex:1;height:1px;background:var(--line)}

/* ── the status line ───────────────────────────────────────────────────
   The homepage rail styles its own .chan; the inner pages need it too, and
   they have less room, so it goes early and hides before the menu does. */
.chan{font-family:var(--mono);font-size:.75rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap;margin-left:auto}
.chan .odd{color:var(--accent)}
@media(max-width:1100px){.nav .chan{display:none}}

/* ── the experience spine ──────────────────────────────────────────────
   Experience and education merged into two eras on one line, because the
   degrees belong in the years they happened in rather than in a list
   underneath. Replaces .job entirely. */
.era{margin:0 0 var(--s-8,2rem)}
.era-head{display:flex;align-items:baseline;gap:.75rem;margin:0 0 1.25rem}
.era-head .n{font-family:var(--mono);font-size:.75rem;letter-spacing:.2em;color:var(--accent)}
.era-head .t{font-family:var(--mono);font-size:.75rem;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ink)}
.era-head .r{flex:1;height:1px;background:rgba(30,30,28,.22)}
.era-head .span{font-family:var(--mono);font-size:.75rem;letter-spacing:.14em;
  color:var(--muted);font-variant-numeric:tabular-nums}

.spine{position:relative;padding-left:2.5rem}
.spine::before{content:"";position:absolute;left:5px;top:.55rem;bottom:.9rem;
  width:1px;background:rgba(30,30,28,.22)}
.spine .node{position:relative;padding:0 0 1.9rem}
.spine .node:last-child{padding-bottom:.2rem}
.spine .node::before{content:"";position:absolute;left:-2.5rem;top:.42rem;
  width:11px;height:11px;border-radius:50%;background:var(--field);
  border:1px solid rgba(30,30,28,.28);z-index:1}
.spine .node.now::before{background:var(--accent);border-color:var(--accent)}
/* one shape change carries work-vs-study without a legend, and without
   spending the accent on it */
.spine .node.study::before{border-radius:0;transform:rotate(45deg);
  width:8px;height:8px;left:-2.42rem;top:.55rem}
/* a project inside a longer engagement, not a job beside it */
.spine .node.sub{padding-left:1.25rem;border-left:1px solid var(--line);margin-left:.1rem}
.spine .node.sub::before{width:7px;height:7px;left:-2.35rem;top:.6rem}

.spine .when{font-family:var(--mono);font-size:.75rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted);display:block;margin-bottom:.25rem;
  font-variant-numeric:tabular-nums}
/* measured: a hairline token used as text reads at 1.61:1. This is the
   lightest warm grey still clearing 4.5:1 on the ground. */
.spine .when .dur{color:#6b6a64}
.spine h3{font-size:1.0625rem;font-weight:400;letter-spacing:-.01em;margin:0 0 .1rem}
.spine .org{font-size:.8125rem;color:var(--muted);margin-bottom:.4rem}
.spine p{font-size:.9rem;color:var(--ink-soft);margin:0;max-width:56ch}
.spine .win{font-family:var(--mono);font-size:.75rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);border-left:1px solid var(--accent);
  padding-left:.65rem;margin-top:.6rem;max-width:52ch;line-height:1.5}
.spine .win b{color:var(--ink);font-weight:400}
.spine .ev{display:inline-block;font-family:var(--mono);font-size:.75rem;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  border-bottom:1px solid rgba(30,30,28,.28);padding-bottom:.1rem;margin-top:.7rem}
.spine .ev:hover{color:var(--ink);border-bottom-color:var(--accent)}
.kind{font-family:var(--mono);font-size:.75rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);border:1px solid var(--line);
  padding:.18rem .45rem;margin-left:.5rem;white-space:nowrap;vertical-align:.12em}

/* ── the to-scale bars ── */
.gantt{margin-top:var(--s-8,2rem);border-top:1px solid rgba(30,30,28,.22);padding-top:1.5rem}
.gantt .grow{display:grid;grid-template-columns:11rem 1fr;gap:1rem;align-items:center;
  margin-bottom:.42rem}
.gantt .lbl{font-size:.8125rem;color:var(--ink);text-align:right;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.gantt .grow.indent .lbl{color:var(--muted);font-size:.75rem}
.gantt .track{position:relative;height:14px}
.gantt .seg{position:absolute;top:3px;height:8px;background:var(--ink-soft)}
.gantt .seg.study{background:none;border:1px solid rgba(30,30,28,.28)}
.gantt .seg.now{background:var(--accent)}
.gantt .seg.startup{background:rgba(30,30,28,.28)}
/* hatched: a solid four-year bar beside two solid employment bars would read
   as a claim to three simultaneous full-time jobs */
.gantt .seg.free{background:repeating-linear-gradient(90deg,rgba(30,30,28,.32) 0 3px,transparent 3px 6px)}
.gantt .axis{position:relative;height:1.4rem;margin-left:12rem;
  border-top:1px solid var(--line);margin-top:.6rem}
.gantt .axis span{position:absolute;top:.3rem;font-family:var(--mono);font-size:.75rem;
  letter-spacing:.14em;color:var(--muted);transform:translateX(-50%)}
.gantt .axis i{position:absolute;top:0;width:1px;height:4px;background:rgba(30,30,28,.28)}
/* annotation on the data, rather than a key pointing at it */
.gantt .anno{position:absolute;top:1px;font-family:var(--mono);font-size:.75rem;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted);white-space:nowrap}
.gantt .anno.accent{color:var(--accent)}
.gantt-note{margin-top:1rem;font-size:.75rem}
@media(max-width:720px){
  .gantt .grow{grid-template-columns:7rem 1fr}
  .gantt .axis{margin-left:8rem}
  .gantt .lbl{font-size:.75rem}
}

/* ── the capability index ──────────────────────────────────────────────
   Replaces the chip wall. A claim with its evidence beside it is a different
   kind of statement from a claim on its own, and it is the only version of
   this section that does anything for someone deciding whether to call. */
.cap-index{width:100%;border-collapse:collapse;font-size:.9375rem;margin-top:var(--s-6,1.5rem)}
.cap-index th{font-family:var(--mono);font-size:.75rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);font-weight:400;text-align:left;
  padding:0 .75rem .6rem 0;border-bottom:1px solid rgba(30,30,28,.22)}
.cap-index td{padding:.68rem .75rem .68rem 0;border-bottom:1px solid var(--line);
  vertical-align:baseline}
.cap-index tr:hover td{background:rgba(30,30,28,.02)}
.cap-index .n{font-family:var(--mono);font-size:.75rem;letter-spacing:.14em;
  color:var(--muted);font-variant-numeric:tabular-nums;width:2.75rem}
.cap-index .cap{color:var(--ink)}
.cap-index .proof{width:14rem;font-size:.8125rem}
.cap-index .proof a{color:var(--muted);border-bottom:1px solid rgba(30,30,28,.28);
  padding-bottom:.1rem}
.cap-index .proof a:hover{color:var(--ink);border-bottom-color:var(--accent)}
@media(max-width:620px){
  .cap-index{font-size:.875rem}
  .cap-index .proof{width:auto}
  .cap-index thead{display:none}
  .cap-index tr{display:grid;grid-template-columns:2.25rem 1fr;gap:0 .5rem;
    padding:.6rem 0;border-bottom:1px solid var(--line)}
  .cap-index td{border:0;padding:0}
  .cap-index .n{grid-row:1/3}
  .cap-index .proof{margin-top:.15rem}
}
