/* ─────────────────────────────────────────────────────────────────────────
   abraar.me
   A printed field notebook that happens to be a website.
   Warm paper, madder red, river teal. Every diagram drawn in SVG.
   ───────────────────────────────────────────────────────────────────────── */

:root{
  /* the palette is lifted from a gamosa — the woven Assamese cloth that is
     cream with a red border. it is his, and no generator reaches for it. */
  --paper:   #F2ECE1;
  --paper-2: #EAE1D1;
  --paper-3: #E0D5C0;
  --ink:     #17130F;
  --ink-2:   #4E453B;
  --ink-3:   #7A6E60;
  --red:     #B3251C;
  --red-2:   #8E1A13;
  --river:   #1F6B70;
  --gold:    #B98A22;
  --line:    #CBBFA9;
  --line-2:  #DDD3C0;

  --measure: 34rem;
  --gutter:  clamp(20px, 5vw, 72px);

  --disp: "Fraunces", Georgia, "Times New Roman", serif;
  --text: "Newsreader", Georgia, "Times New Roman", serif;
}

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

html{
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  overflow-x:clip;
}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }

body{
  margin:0;
  /* the portrait's registration rings hang a little past the trim, the way
     a plate overruns the page edge. clip rather than let the page slide. */
  overflow-x:clip;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--text);
  font-optical-sizing:auto;
  font-size:clamp(17px,1.05rem + .2vw,19px);
  line-height:1.62;
  /* a faint laid-paper tooth. two repeating gradients, no image file. */
  background-image:
    repeating-linear-gradient(90deg, rgba(23,19,15,.016) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg,  rgba(23,19,15,.013) 0 1px, transparent 1px 4px);
}

p{margin:0 0 1.05em}
a{color:var(--red-2); text-underline-offset:.18em; text-decoration-thickness:.06em}
a:hover{color:var(--red)}
strong,b{font-weight:650}
em,i{font-style:italic}

:focus-visible{
  outline:2.5px solid var(--river);
  outline-offset:3px;
  border-radius:1px;
}

.skip{
  position:absolute; left:-9999px; top:0; z-index:99;
  background:var(--ink); color:var(--paper);
  padding:12px 20px; font-family:var(--disp); text-decoration:none;
}
.skip:focus{left:0}

/* ── brand glyphs ───────────────────────────────────────────────────────
   painted from icons.js at runtime. --ic-w widens for wordmark-shaped
   marks that would otherwise be illegible squeezed into a square. */
.ic{
  display:inline-flex; align-items:center; justify-content:center;
  width:var(--ic-w,18px); height:18px; flex:none;
  vertical-align:-.2em;
}
.ic svg{width:100%; height:100%; display:block}
.ic--sprout{color:#3F6E33; fill:currentColor}
@media (max-width:520px){ .ic{max-width:60px} }


/* ══ MASTHEAD ═════════════════════════════════════════════════════════ */

.masthead{
  padding:clamp(38px,7vw,84px) var(--gutter) 0;
  max-width:1180px; margin:0 auto;
}

/* the three-rule head ornament: thick, thin, thick — letterpress habit */
.masthead__rule,.colophon__rule{display:grid; gap:3px; margin-bottom:26px}
.masthead__rule span:nth-child(1),.colophon__rule span:nth-child(1){height:4px; background:var(--red)}
.masthead__rule span:nth-child(2),.colophon__rule span:nth-child(2){height:1px; background:var(--ink)}
.masthead__rule span:nth-child(3),.colophon__rule span:nth-child(3){height:2px; background:var(--ink)}

.masthead__top{
  display:grid;
  grid-template-columns:minmax(0,1fr) clamp(280px,33vw,440px);
  gap:clamp(24px,4vw,60px);
  align-items:start;
}

.masthead__kicker{
  font-family:var(--disp);
  font-size:.78rem; letter-spacing:.13em; text-transform:uppercase;
  font-weight:600; color:var(--ink-2); margin-bottom:clamp(18px,3vw,34px);
}

.masthead__name{
  font-family:var(--disp);
  font-variation-settings:"SOFT" 22,"WONK" 1,"opsz" 144;
  font-weight:760;
  font-size:clamp(2.9rem,9.4vw,7.4rem);
  line-height:.85;
  letter-spacing:-.028em;
  margin:0 0 .28em;
  display:grid;
}
.masthead__name .n2{color:var(--red); font-style:italic; font-weight:600}
.masthead__name .n3{font-size:.53em; letter-spacing:-.012em; color:var(--ink-2); font-weight:600}

.masthead__alias{
  font-family:var(--disp); font-size:1.02rem; color:var(--ink-2);
  letter-spacing:.02em; margin-bottom:1.2em;
}
.masthead__alias em{
  color:var(--ink); font-weight:700; font-style:normal;
  border-bottom:2px solid var(--gold); padding-bottom:1px;
}

.masthead__line{
  max-width:var(--measure);
  font-size:1.14em; line-height:1.5; color:var(--ink-2);
  margin-bottom:1.4em;
}

.masthead__tags{
  list-style:none; margin:0 0 clamp(26px,4vw,44px); padding:0;
  display:flex; flex-wrap:wrap; gap:8px 22px;
}
.masthead__tags li{
  display:inline-flex; align-items:center; gap:9px;
  font-family:var(--disp); font-weight:600; font-size:.82rem;
  letter-spacing:.03em; color:var(--ink-2);
}
.dot{width:9px; height:9px; border-radius:50%; flex:none}
.dot--red{background:var(--red)} .dot--river{background:var(--river)} .dot--gold{background:var(--gold)}

/* ── Plate I: the portrait, printed two-colour and slightly out of register */
.port{margin:0; position:relative}
.port__plate{position:relative; isolation:isolate}
.port__pic,.port__pic img{display:block; width:100%; height:auto}
.port__pic img{
  position:relative; z-index:2;
  filter:contrast(1.06) brightness(1.02);
}
/* the second impression: a flat madder-red silhouette printed a few
   thousandths off the black plate, so only the fringe shows. it is masked
   by the same file the portrait uses, so it is free — no extra decode. */
.port__ghost{display:none}
@supports ((mask-image:url(#a)) or (-webkit-mask-image:url(#a))){
  .port__ghost{
    display:block; position:absolute; inset:0;
    z-index:1; pointer-events:none;
    background:var(--red); opacity:.42;
    transform:translate(12px,-12px);
    -webkit-mask-image:url(/assets/img/abraar.webp);
            mask-image:url(/assets/img/abraar.webp);
    -webkit-mask-size:100% 100%;  mask-size:100% 100%;
    -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  }
}
.port__rings{
  position:absolute; left:-9%; right:-9%; bottom:4%; width:118%; height:auto;
  z-index:0; overflow:visible;
}
.pr__ring{fill:none; stroke:var(--line); stroke-width:1.2}
.pr__ring--dash{stroke-dasharray:2 9; stroke:var(--ink-3); opacity:.55}
.pr__ring--red{stroke:var(--red); opacity:.28}
.pr__ticks line{stroke:var(--ink-3); stroke-width:1.4}
.pr__arc{fill:none; stroke:var(--gold); stroke-width:2.4; stroke-linecap:round; opacity:.7}
.pr__spin{transform-origin:200px 200px; animation:spin 90s linear infinite}
@keyframes spin{ to{transform:rotate(360deg)} }
@media (prefers-reduced-motion:reduce){ .pr__spin{animation:none} }

.port__cap{
  font-family:var(--disp); font-size:.76rem; letter-spacing:.07em;
  color:var(--ink-3); margin-top:14px; text-align:right; font-weight:500;
}
.port__cap span{
  text-transform:uppercase; letter-spacing:.15em; font-weight:700;
  color:var(--red); margin-right:.5em;
}

/* ── the braid ── */
.braid{margin:clamp(26px,4vw,48px) 0 clamp(34px,6vw,72px)}
.braid svg{display:block; width:100%; height:clamp(120px,17vw,200px)}
.braid__bed path{fill:none; stroke:var(--line); stroke-width:1.4}
.braid__flow path{
  fill:none; stroke:var(--river); stroke-width:2.4; stroke-linecap:round;
  stroke-dasharray:96 1400; stroke-dashoffset:1496;
  animation:flow 7s linear infinite;
}
.braid__flow path:nth-child(2){animation-duration:9s; animation-delay:-2.2s; stroke:var(--red)}
.braid__flow path:nth-child(3){animation-duration:11s; animation-delay:-5s; stroke:var(--gold)}
@keyframes flow{ to{stroke-dashoffset:0} }
.braid__nodes circle{fill:var(--paper); stroke:var(--ink); stroke-width:1.6}
/* squeezing 1200 units into 375 thins every stroke to a hair, so the river
   is drawn heavier and taller on a phone or it disappears. */
@media (max-width:640px){
  .braid svg{height:150px}
  .braid__bed path{stroke-width:2.4}
  .braid__flow path{stroke-width:4}
  .braid__nodes circle{stroke-width:2.6; r:7}
}

.braid figcaption,.plate figcaption{
  font-family:var(--disp);
  font-size:.79rem; letter-spacing:.045em; color:var(--ink-3);
  margin-top:12px; font-weight:500;
}


/* ══ CHAPTERS ═════════════════════════════════════════════════════════ */

.ch{padding:clamp(52px,8vw,110px) var(--gutter)}
.ch--alt{background:var(--paper-2); border-block:1px solid var(--line-2)}
.ch--feature{background:var(--ink); color:var(--paper)}

.ch__inner{max-width:1180px; margin:0 auto}
.ch__inner--split{
  display:grid; gap:clamp(34px,5vw,68px);
  grid-template-columns:minmax(0,1.08fr) minmax(0,.92fr);
  align-items:center;
}
.ch__inner--flip .ch__col{order:2}

.ch__num{
  font-family:var(--disp); font-weight:700;
  font-size:1.02rem; letter-spacing:.05em; color:var(--red);
  margin-bottom:.5em;
}
.ch__num span{
  color:var(--ink-3); font-weight:500; letter-spacing:.16em;
  text-transform:uppercase; font-size:.68rem; margin-right:.7em;
}
.ch--feature .ch__num span{color:#9C9184}

.ch__title{
  font-family:var(--disp);
  font-variation-settings:"SOFT" 18,"WONK" 1,"opsz" 96;
  font-weight:640;
  font-size:clamp(2.05rem,5.4vw,3.9rem);
  line-height:1.02; letter-spacing:-.02em;
  margin:0 0 .62em; max-width:16ch;
}
.ch--feature .ch__title{max-width:20ch}

.ch__body{max-width:var(--measure)}
.ch__body--wide{max-width:46rem}
.ch__body p{color:var(--ink-2)}
.ch--feature .ch__body p{color:#C9BFB0}
.ch--feature .ch__body strong{color:var(--paper)}

.lede{
  font-size:1.2em; line-height:1.45; color:var(--ink) !important;
  font-weight:420;
}
.ch--feature .lede{color:var(--paper) !important}
.lede::first-line{ letter-spacing:.005em }

.cue{
  font-family:var(--disp); font-weight:600; font-style:italic;
  color:var(--gold) !important; font-size:1.06em;
}

/* ── institutional crests ───────────────────────────────────────────── */
.crest{
  display:flex; align-items:center; gap:16px;
  margin:0 0 clamp(20px,3vw,30px);
  padding:13px 18px 13px 13px;
  border:1px solid var(--line);
  background:rgba(255,255,255,.42);
  max-width:var(--measure);
}
.crest img{
  display:block; width:56px; height:auto; flex:none;
  filter:saturate(.92);
}
.crest__inst{
  font-family:var(--disp); font-weight:660; font-size:.98rem;
  line-height:1.22; margin:0 0 3px; color:var(--ink);
}
.crest__note{
  font-family:var(--disp); font-size:.72rem; letter-spacing:.05em;
  color:var(--ink-3); margin:0; line-height:1.35;
}


/* ══ PLATES (the SVG figures) ═════════════════════════════════════════ */

.plate{margin:clamp(30px,5vw,52px) 0 0}
.plate svg{display:block; width:100%; height:auto}
.plate--trace{max-width:820px}
.plate--dial,.plate--train{margin:0}
.plate--dial svg{max-width:300px; margin-inline:auto}
.plate--train svg{max-width:460px; margin-inline:auto}
.plate--surface{max-width:880px}

.plate__bar{
  display:flex; align-items:center; gap:18px; flex-wrap:wrap;
  margin-top:16px; padding-top:14px; border-top:1px solid var(--line);
}
.plate__bar--stack{flex-direction:column; align-items:stretch; gap:14px}
.plate__btns{display:flex; align-items:center; gap:18px; flex-wrap:wrap}
.plate__out{
  margin:0; font-family:var(--disp); font-size:.86rem; color:var(--ink-2);
  font-variant-numeric:tabular-nums; flex:1 1 240px; line-height:1.4;
}

/* traceroute */
.trace__wire path{fill:none; stroke:var(--line); stroke-width:1.5}
.trace__lit path{
  fill:none; stroke:var(--red); stroke-width:2.4; stroke-linecap:round;
  stroke-dasharray:0 4000;
}
.trace__hops circle{fill:var(--paper); stroke:var(--ink); stroke-width:1.8;
  transition:fill .2s ease, stroke .2s ease}
.trace__hops .is-end circle{fill:var(--red); stroke:var(--red-2)}
.trace__hops g.lit circle{fill:var(--river); stroke:var(--river)}
.trace__hops text{
  font-family:var(--disp); font-size:12.5px; font-weight:600;
  fill:var(--ink-2); text-anchor:middle; letter-spacing:.02em;
}
.trace__hops .ms{fill:var(--red); font-size:11px; font-weight:700; font-style:italic}
.trace__pkt{fill:var(--gold); stroke:var(--ink); stroke-width:1.4; opacity:0}
.trace__pkt.on{opacity:1}

/* on a phone the wire runs down the page and the hops read as a listing,
   which is what a traceroute actually looks like in a terminal anyway. */
.plate--trace.is-vert .trace__hops text{font-size:17.5px; text-anchor:start}
.plate--trace.is-vert .trace__hops .ms{font-size:15px; text-anchor:end}
.plate--trace.is-vert .trace__wire path,
.plate--trace.is-vert .trace__lit path{stroke-width:3}
.plate--trace.is-vert .trace__hops circle{r:11px; stroke-width:2.6}
.plate--trace.is-vert .trace__pkt{r:8px}

/* the 24-hour dial */
.dial__face{fill:none; stroke:var(--line); stroke-width:1.4}
.dial__ticks line{stroke:var(--ink-3); stroke-width:1.4}
.dial__arcs circle{
  fill:none; stroke-width:13; transform:rotate(-90deg);
  transform-origin:130px 130px; stroke-linecap:butt;
}
/* circumference at r=98 is ~615.75 */
.dial__arcs .a1{stroke:var(--red);   stroke-dasharray:64 552; stroke-dashoffset:-128}
.dial__arcs .a2{stroke:var(--river); stroke-dasharray:128 488; stroke-dashoffset:-192}
.dial__arcs .a3{stroke:var(--gold);  stroke-dasharray:77 539; stroke-dashoffset:-436}
.dial__arcs .a4{stroke:var(--ink);   stroke-dasharray:154 462; stroke-dashoffset:-513}
.dial__hub{
  font-family:var(--disp); font-size:27px; font-weight:700;
  fill:var(--ink); text-anchor:middle;
}
.dial__sub{
  font-family:var(--disp); font-size:11px; font-weight:600; letter-spacing:.14em;
  text-transform:uppercase; fill:var(--ink-3); text-anchor:middle;
}
.plate--dial figcaption{display:flex; flex-wrap:wrap; gap:6px 18px; justify-content:center}
.plate--dial figcaption span{display:inline-flex; align-items:center; gap:7px}
.sw{width:11px; height:11px; border-radius:50%; display:block}
.sw--1{background:var(--red)} .sw--2{background:var(--river)}
.sw--3{background:var(--gold)} .sw--4{background:var(--ink)}

/* ── the classifier that actually trains ────────────────────────────── */
.tr__axes line{stroke:var(--ink); stroke-width:1.5}
.tr__grid line{stroke:var(--line); stroke-width:1; stroke-dasharray:2 5}
.tr__shade polygon{fill:var(--river); opacity:.09}
.tr__pts circle{stroke:var(--paper); stroke-width:.8}
.tr__pts .c0{fill:var(--red)}
.tr__pts .c1{fill:var(--river)}
.tr__pts .wrong{stroke:var(--ink); stroke-width:1.4}
.tr__bound{
  stroke:var(--ink); stroke-width:2.6; stroke-linecap:round;
}
.tr__inset rect{fill:var(--paper); stroke:var(--line); stroke-width:1}
.tr__inset text{
  font-family:var(--disp); font-size:9px; font-weight:600; letter-spacing:.1em;
  text-transform:uppercase; fill:var(--ink-3);
}
#tLoss{fill:none; stroke:var(--gold); stroke-width:1.8; stroke-linejoin:round}
.tr__ax{
  font-family:var(--disp); font-size:11.5px; font-weight:600;
  fill:var(--ink-3); text-anchor:middle; letter-spacing:.07em;
}
.tr__ax--y{transform:rotate(-90deg); transform-origin:18px 132px}
/* the plate scales down to about 0.84 on a phone, so the type has to
   scale up to meet it in the middle. */
@media (max-width:640px){
  .tr__ax{font-size:14.5px}
  .tr__inset text{font-size:13.5px}
  .tr__pts circle{stroke-width:1}
}

.train__stats{
  display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin:0;
}
.train__stats dt{
  font-family:var(--disp); font-size:.62rem; letter-spacing:.15em;
  text-transform:uppercase; color:var(--ink-3); font-weight:650; margin-bottom:2px;
}
.train__stats dd{
  margin:0; font-family:var(--disp); font-weight:700; font-size:1.35rem;
  line-height:1.1; color:var(--ink); font-variant-numeric:tabular-nums;
}

/* ── the attack surface ─────────────────────────────────────────────── */
.sf__box rect{fill:var(--paper); stroke:var(--ink-3); stroke-width:1.4}
.sf__box .sf__box--core{stroke:var(--ink); stroke-width:2}
.sf__flow path{
  fill:none; stroke:var(--line); stroke-width:2; stroke-linecap:round;
  stroke-dasharray:6 6;
}
.sf__lab text{
  font-family:var(--disp); font-size:14px; font-weight:660;
  fill:var(--ink); text-anchor:middle;
}
.sf__lab .sf__sub{
  font-size:10px; font-weight:600; font-style:italic;
  fill:var(--ink-3); letter-spacing:.03em;
}
.hs{cursor:pointer}
.hs circle{
  fill:var(--paper); stroke:var(--red); stroke-width:2;
  transition:fill .16s ease, r .16s ease;
}
.hs text{
  font-family:var(--disp); font-size:14px; font-weight:700;
  fill:var(--red); text-anchor:middle; pointer-events:none;
  transition:fill .16s ease;
}
/* one plate or the other, never both. `.plate svg` also sets display, so
   these carry the extra class weight to beat it. */
.plate svg.sf--tall{display:none}
@media (max-width:640px){
  .plate svg.sf--wide{display:none}
  .plate svg.sf--tall{display:block}
  .sf--tall .sf__lab text{text-anchor:start; font-size:19px}
  .sf--tall .sf__lab .sf__sub{font-size:14px}
  .sf--tall .hs text{font-size:21px}
  .sf--tall .hs circle{r:20px}
  .sf--tall .sf__flow path{stroke-width:2.4}
}
.hs:hover circle,.hs:focus circle{fill:var(--red)}
.hs:hover text,.hs:focus text{fill:var(--paper)}
.hs.on circle{fill:var(--red); stroke:var(--ink)}
.hs.on text{fill:var(--paper)}
.hs:focus{outline:none}
.hs:focus circle{stroke:var(--ink); stroke-width:3}

.sf__note{
  margin-top:18px; padding:16px 20px;
  border-left:3px solid var(--red); background:rgba(255,255,255,.45);
  max-width:46rem; min-height:6.4em;
}
.sf__t{
  font-family:var(--disp); font-weight:700; font-size:1.06rem;
  margin:0 0 .25em; color:var(--ink);
}
.sf__d{margin:0; color:var(--ink-2); font-size:.98em; line-height:1.5}


/* ══ THE GROVE (chapter four's game) ══════════════════════════════════ */

.grove{
  display:grid; gap:clamp(26px,4vw,54px);
  grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr);
  align-items:center;
  margin:clamp(30px,5vw,52px) 0 26px;
  padding:clamp(22px,3.4vw,40px);
  border:1px solid #3A322A;
  background:#1E1912;
}

.grove__stage{text-align:center}
.tree{display:block; width:100%; max-width:330px; margin-inline:auto; height:auto}
.tree__ground{stroke:#4A4034; stroke-width:1.5}

.lyr{opacity:0; transition:opacity .5s ease}
.lyr.on{opacity:1}
@media (prefers-reduced-motion:reduce){ .lyr{transition:none} }

/* the unearned tree, showing through */
.ghost{opacity:.06}
.ghost circle{fill:var(--paper)}
.ghost path{fill:none; stroke:var(--paper); stroke-width:8; stroke-linecap:round}

.seed{fill:var(--gold)}
.stem,.trunk,.bough,.root{
  fill:none; stroke:#8A6B45; stroke-linecap:round;
}
.stem{stroke:#5E8C3A; stroke-width:3.4}
.trunk{stroke-width:9} .trunk--sm{stroke-width:5.5}
.bough{stroke-width:4}
.root{stroke-width:3; stroke:#6E563A; opacity:.8}
.leaf{fill:#5E8C3A}
/* one opaque fill for every canopy circle, so the overlaps read as a single
   mass instead of a pile of translucent discs */
.canopy circle{fill:#3F6E33}
.canopy--sm circle{fill:#34592B}
.halo{fill:none; stroke:var(--gold); stroke-width:1.4; opacity:.5}
.fruit circle{fill:var(--gold)}

.grove__stagename{
  font-family:var(--disp); font-weight:700; font-size:1.32rem;
  color:var(--paper); margin:16px 0 0; letter-spacing:.01em;
}

/* the ledger — one square per submission, in order, forever */
.ledger{
  display:flex; flex-wrap:wrap; gap:4px; justify-content:center;
  margin:16px auto 0; max-width:250px; min-height:13px;
}
.ledger i{
  width:13px; height:13px; display:block; background:#332B22;
  border:1px solid #453B2F; font-style:normal;
  animation:pop .28s cubic-bezier(.2,1.4,.4,1);
}
.ledger i.ok{background:#4C7A3C; border-color:#5E8C3A}
.ledger i.part{background:#7A6120; border-color:var(--gold)}
.ledger i.bad{background:#7A2E27; border-color:#D9776C}
@keyframes pop{ from{transform:scale(.2); opacity:0} }
@media (prefers-reduced-motion:reduce){ .ledger i{animation:none} }

.grove__stats{
  display:grid; grid-template-columns:repeat(3,1fr);
  gap:14px; margin:0 0 24px;
  border-block:1px solid #3A322A; padding:16px 0;
}
.grove__stats div{text-align:left}
.grove__stats dt{
  font-family:var(--disp); font-size:.66rem; letter-spacing:.15em;
  text-transform:uppercase; color:#9C9184; font-weight:600; margin-bottom:4px;
}
.grove__stats dd{
  margin:0; font-family:var(--disp); font-weight:700;
  font-size:1.7rem; line-height:1; color:var(--paper);
  font-variant-numeric:tabular-nums;
}
.grove__stats small{font-size:.5em; color:#9C9184; font-weight:500; letter-spacing:.06em}
#verified{color:#7FB069} #rejected{color:#D9776C}

.grove__claim{margin-bottom:18px}
.grove__claim label{
  display:block; font-family:var(--disp); font-size:.68rem;
  letter-spacing:.15em; text-transform:uppercase; color:#9C9184;
  font-weight:600; margin-bottom:8px;
}
#claimSel{
  width:100%; font-family:var(--text); font-size:1rem;
  background:#171209; color:var(--paper);
  border:1px solid #4A4034; padding:11px 13px; border-radius:0;
}

.btn{
  display:inline-flex; align-items:center; gap:12px;
  font-family:var(--disp); font-weight:700; font-size:1.02rem;
  letter-spacing:.01em;
  background:var(--red); color:#FFF3EA;
  border:none; padding:15px 26px; cursor:pointer;
  transition:background .18s ease, transform .1s ease;
}
.btn:hover{background:var(--red-2)}
.btn:active{transform:translateY(1px)}
.btn[disabled]{background:#4A4034; color:#9C9184; cursor:progress}
.btn--sm{font-size:.9rem; padding:11px 20px; gap:10px}
.btn--ink{background:var(--ink); color:var(--paper)}
.btn--ink:hover{background:var(--red-2)}
.btn--ink[disabled]{background:var(--line); color:var(--ink-3)}
.btn__lens{
  width:15px; height:15px; border-radius:50%; flex:none;
  border:2.5px solid currentColor; position:relative;
}
.btn__lens::after{
  content:""; position:absolute; inset:3px; border-radius:50%;
  background:currentColor; opacity:.35;
}
.btn.is-shooting .btn__lens::after{animation:shutter .42s ease}
@keyframes shutter{ 50%{opacity:1; transform:scale(.3)} }
.btn__arrow{
  width:16px; height:2px; background:currentColor; flex:none; position:relative;
}
.btn__arrow::after{
  content:""; position:absolute; right:-1px; top:-3px;
  border-left:6px solid currentColor;
  border-block:4px solid transparent;
}
@media (prefers-reduced-motion:reduce){ .btn.is-shooting .btn__lens::after{animation:none} }

.grove__verdict{
  min-height:4.5em; margin:20px 0 0;
  font-size:1.02rem; line-height:1.5;
}
.grove__hint{color:#8C8175; font-style:italic}
.grove__verdict b{display:block; font-family:var(--disp); font-size:1.1em; margin-bottom:2px}
.v-ok b{color:#7FB069} .v-part b{color:var(--gold)} .v-bad b{color:#D9776C}
.grove__verdict span:not(.grove__hint){color:#C9BFB0}

.grove__reset{margin:14px 0 0}
.linkbtn{
  background:none; border:none; padding:0; cursor:pointer;
  font-family:var(--disp); font-size:.8rem; letter-spacing:.05em;
  color:#9C9184; text-decoration:underline; text-underline-offset:.2em;
}
.linkbtn:hover{color:var(--paper)}
.linkbtn--ink{color:var(--ink-3)}
.linkbtn--ink:hover{color:var(--red-2)}
/* a finger is not a cursor: give the small text controls a real hit area
   without moving the ink they sit on. */
@media (max-width:640px){
  .linkbtn{padding:11px 0; margin:-11px 0}
  .stack__foot .ext{display:inline-block; padding:9px 0}
}

.grove__legend{
  max-width:46rem; color:#A79C8E; font-size:.97em;
  border-left:2px solid var(--gold); padding-left:18px;
  margin-bottom:clamp(34px,5vw,60px);
}
.grove__legend b{color:var(--paper); font-weight:600}


/* ══ STACKS & CHIPS ═══════════════════════════════════════════════════ */

.stack__h{
  font-family:var(--disp); font-weight:660;
  font-size:clamp(1.24rem,2.4vw,1.65rem); letter-spacing:-.01em;
  margin:clamp(30px,5vw,52px) 0 22px;
  padding-bottom:10px; border-bottom:2px solid currentColor;
  display:inline-block;
}

.stack__grid{
  display:grid; gap:26px clamp(24px,4vw,48px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,230px),1fr));
}
.stack__grid--two{grid-template-columns:repeat(auto-fit,minmax(min(100%,265px),1fr))}

.stack__lab{
  font-family:var(--disp); font-size:.69rem; font-weight:650;
  letter-spacing:.15em; text-transform:uppercase;
  color:var(--ink-3); margin-bottom:12px;
  padding-bottom:8px; border-bottom:1px solid var(--line);
}
.ch--feature .stack__lab{color:#9C9184; border-bottom-color:#3A322A}

.chips{list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:8px}
.chips li{
  display:inline-flex; align-items:center; gap:8px;
  font-family:var(--disp); font-weight:560; font-size:.86rem;
  padding:7px 12px 7px 10px;
  border:1px solid var(--line);
  background:var(--paper);
  line-height:1.15;
}
.ch--alt .chips li{background:var(--paper)}
.ch--feature .chips li{background:#241E16; border-color:#3E362C; color:#DDD3C4}

.stack__foot{
  margin-top:24px; color:#A79C8E; font-size:.95em;
}
.stack__foot .ext{color:var(--gold); font-weight:600}


/* ══ CERTIFICATIONS ═══════════════════════════════════════════════════ */

.certs{
  list-style:none; margin:0; padding:0;
  display:grid; gap:10px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,330px),1fr));
}
.cert{
  display:flex; align-items:center; gap:14px;
  padding:14px 16px;
  border:1px solid var(--line); background:var(--paper);
  border-left:3px solid var(--line);
}
.cert--held{border-left-color:var(--river)}
/* wordmarks (ISC2, CompTIA) are far wider than they are tall; cap them so
   they cannot elbow the certificate name off its own card. */
.cert .ic{margin-top:1px; max-width:34px}
.cert__txt{display:grid; min-width:0; flex:1}
.cert__txt b{font-weight:650; line-height:1.3; font-size:.98rem}
.cert__txt small{color:var(--ink-3); font-size:.75rem; letter-spacing:.05em; margin-top:2px}
.cert__pill{
  font-family:var(--disp); font-size:.63rem; font-weight:700;
  letter-spacing:.13em; text-transform:uppercase;
  padding:5px 9px; border:1px solid var(--line); color:var(--ink-3);
  white-space:nowrap; flex:none;
}
.cert__pill--held{
  background:var(--river); border-color:var(--river); color:#F2ECE1;
}


/* ══ COLOPHON ═════════════════════════════════════════════════════════ */

.colophon{
  padding:clamp(52px,8vw,100px) var(--gutter) clamp(38px,5vw,64px);
  background:var(--paper-3);
  border-top:1px solid var(--line);
}
.colophon__h{
  font-family:var(--disp);
  font-variation-settings:"SOFT" 18,"WONK" 1;
  font-weight:660; font-size:clamp(2rem,5vw,3.4rem);
  line-height:1.02; letter-spacing:-.02em; margin:0 0 .3em;
}
.colophon__sub{max-width:var(--measure); color:var(--ink-2); margin-bottom:2em}

.colophon__links{
  list-style:none; margin:0 0 clamp(34px,5vw,56px); padding:0;
  display:flex; flex-wrap:wrap; gap:12px;
}
.colophon__links a{
  display:inline-flex; align-items:center; gap:10px;
  font-family:var(--disp); font-weight:620; font-size:.95rem;
  text-decoration:none; color:var(--ink);
  border:1px solid var(--ink); padding:11px 18px;
  transition:background .16s ease, color .16s ease;
}
.colophon__links a:hover{background:var(--ink); color:var(--paper)}
.colophon__links a:hover .ic svg{fill:var(--paper) !important}

.colophon__fine{
  max-width:44rem; font-size:.9rem; color:var(--ink-3); line-height:1.55;
  margin-top:20px;
}
.colophon__fine--last{
  font-family:var(--disp); letter-spacing:.06em; font-weight:600;
  color:var(--ink-2);
}


/* ══ REVEAL ═══════════════════════════════════════════════════════════
   transform + opacity only, one-shot, unobserved after firing. */
.rv{opacity:0; transform:translateY(16px); will-change:opacity,transform}
.rv.in{
  opacity:1; transform:none;
  transition:opacity .62s cubic-bezier(.2,.7,.3,1), transform .62s cubic-bezier(.2,.7,.3,1);
}
@media (prefers-reduced-motion:reduce){
  .rv{opacity:1 !important; transform:none !important; transition:none !important}
  .braid__flow path{animation:none; stroke-dashoffset:0; stroke-dasharray:none; opacity:.5}
}


/* ══ NARROW ═══════════════════════════════════════════════════════════ */

@media (max-width:980px){
  .masthead__top{grid-template-columns:1fr; gap:clamp(20px,4vw,34px)}
  .port{max-width:300px; margin-left:auto}
  .port__cap{text-align:right}
}

@media (max-width:860px){
  .ch__inner--split{grid-template-columns:1fr}
  .ch__inner--flip .ch__col{order:0}
  .grove{grid-template-columns:1fr}
  .plate--dial,.plate--train{margin-top:8px}
}

@media (max-width:560px){
  .masthead__name .n3{font-size:.44em; line-height:1.05}
  .port{max-width:230px}
  .grove__stats{grid-template-columns:1fr 1fr 1fr; gap:8px}
  .grove__stats dd{font-size:1.35rem}
  .btn{width:100%; justify-content:center}
  .plate__btns .btn{width:auto}
  .cert{flex-wrap:wrap; row-gap:10px}
  .cert__txt{flex:1 1 150px}
  .cert__pill{margin-left:auto}   /* if it wraps, it wraps to the right edge */
  /* the flex items are the list items, not the anchors inside them */
  .colophon__links li{flex:1 1 100%}
  .colophon__links a{justify-content:center}

  /* the small tracked capitals are a device, not a place to save space.
     Under about 11px on a phone they stop being read and start being
     texture, so every one of them goes up a point. */
  .stack__lab,.crest__note,.cert__txt small{font-size:.72rem}
  .cert__pill{font-size:.7rem}
  .train__stats dt,.grove__stats dt,.colophon dt{font-size:.7rem}
}


/* ══ PRINT — this page is also the CV ═════════════════════════════════ */

@media print{
  :root{--paper:#fff}
  body{background:#fff; background-image:none; color:#000; font-size:11pt}
  .braid,.plate--trace,.plate--dial,.plate--train,.grove,.skip,
  .grove__reset,.grove__legend,.port__rings,.port__ghost,.plate__bar{display:none}
  /* paper is wide: print the whiteboard drawing, never the phone one */
  .plate svg.sf--tall{display:none}
  .plate svg.sf--wide{display:block; max-width:520px}
  .port{max-width:150px; float:right; margin:0 0 12pt 12pt}
  .ch,.ch--alt,.ch--feature,.colophon{
    background:#fff !important; color:#000 !important;
    padding:18pt 0; border:none; break-inside:avoid;
  }
  .ch--feature .ch__body p,.ch--feature .lede,.ch--feature .chips li{color:#000 !important}
  .ch--feature .chips li{background:#fff !important; border-color:#999 !important}
  .rv{opacity:1 !important; transform:none !important}
  .masthead__name{font-size:30pt}
  .ch__title{font-size:17pt}
  a{color:#000; text-decoration:underline}
  .colophon__links a{border-color:#000}
  .cert__pill--held{background:#fff; color:#000; border-color:#000}
}
