/* =========================================================
   Badathala Jaisurya — AI security engineer & researcher
   Technical surface: dense panels, monospace structure,
   colour reserved for state and data.
   Chart/status colours are the validated steps from the
   data-viz reference palette, not picked by eye.
   ========================================================= */

:root{
  /* The browser paints the page scrollbar, the textarea and every form
     control from color-scheme, not from our tokens. Without it a dark
     page gets a light scrollbar down its edge. */
  color-scheme:dark;
  /* Monochrome, with one accent that is reserved for live state and for the
     single number on the page that deserves the eye. Every value below was
     solved against every surface it can land on (--bg, --s1, --s2 and its own
     tint), not against the background alone. */
  --bg:#0c0c0e; --s1:#141417; --s2:#1b1b1f;
  --line:rgba(255,255,255,.17); --line-2:rgba(255,255,255,.30);
  --line-strong:rgba(255,255,255,.27); --edge:rgba(255,255,255,.055);
  --ink:#f3f2ef; --ink-2:#b4b3bd; --ink-3:#8e8d98;
  --accent:#9b9fff; --accent-dim:rgba(155,159,255,.16);
  /* the partner hues a two-series chart needs; deliberately not a third and
     fourth brand colour */
  --accent-2:#9b9fff; --accent-3:#b4b3bd; --violet:#9b9fff;
  /* text on an accent fill; near-black scores 8.19:1 on this periwinkle,
     white only 2.5:1, so the dark theme inverts it */
  --on-accent:#0c0c0e;
  --good:#7bd88f; --warn:#f2c14e; --serious:#ffa657; --critical:#ff6b6b;
  --dot:rgba(255,255,255,.06);
  --wash-1:rgba(155,159,255,.12); --wash-2:rgba(255,255,255,.045); --wash-3:rgba(255,255,255,.035);
  --grain-o:.012;
  --tile:var(--s1); --tile-2:var(--s2);
  --maxw:1500px; --pad:clamp(20px,5vw,72px); --r:5px; --measure:66ch;
  --sans:"Inter",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --display:"Bricolage Grotesque","Inter",ui-sans-serif,system-ui,sans-serif;
  --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --ease:cubic-bezier(.16,1,.3,1)
}

:root[data-theme="light"]{
  color-scheme:light;
  --bg:#f4f3ef; --s1:#ffffff; --s2:#ebe9e3;
  --line:rgba(12,12,13,.17); --line-2:rgba(12,12,13,.32);
  --line-strong:rgba(12,12,13,.27); --edge:rgba(255,255,255,.9);
  --ink:#0c0c0d; --ink-2:#3d3d44; --ink-3:#676770;
  --accent:#3237e0; --accent-dim:rgba(50,55,224,.12);
  --accent-2:#3237e0; --accent-3:#3d3d44; --violet:#3237e0;
  /* and back again: white scores 7.61:1 on the deeper indigo */
  --on-accent:#ffffff;
  --good:#246328; --warn:#725100; --serious:#8a4408; --critical:#a2231b;
  /* Three textures stacked — dot grid, line grid, three washes — read as
     depth on a dark page and as smudges on a light one, because low-contrast
     texture hides in shadow and shows on paper. Light keeps one tinted wash
     and halves the rest; the grey washes go entirely. */
  --dot:rgba(12,12,13,.055);
  --wash-1:rgba(50,55,224,.06); --wash-2:transparent; --wash-3:transparent;
  --grain-o:.010;
  --tile:var(--s1); --tile-2:var(--s2)
}

@media (prefers-color-scheme: light){
  :root:not([data-theme]){
  color-scheme:light;
  --bg:#f4f3ef; --s1:#ffffff; --s2:#ebe9e3;
  --line:rgba(12,12,13,.17); --line-2:rgba(12,12,13,.32);
  --line-strong:rgba(12,12,13,.27); --edge:rgba(255,255,255,.9);
  --ink:#0c0c0d; --ink-2:#3d3d44; --ink-3:#676770;
  --accent:#3237e0; --accent-dim:rgba(50,55,224,.12);
  --accent-2:#3237e0; --accent-3:#3d3d44; --violet:#3237e0;
  /* and back again: white scores 7.61:1 on the deeper indigo */
  --on-accent:#ffffff;
  --good:#246328; --warn:#725100; --serious:#8a4408; --critical:#a2231b;
  /* Three textures stacked — dot grid, line grid, three washes — read as
     depth on a dark page and as smudges on a light one, because low-contrast
     texture hides in shadow and shows on paper. Light keeps one tinted wash
     and halves the rest; the grey washes go entirely. */
  --dot:rgba(12,12,13,.055);
  --wash-1:rgba(50,55,224,.06); --wash-2:transparent; --wash-3:transparent;
  --grain-o:.010;
  --tile:var(--s1); --tile-2:var(--s2)
}
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:var(--sans);font-size:15.5px;line-height:1.6;
  overflow-x:hidden;-webkit-tap-highlight-color:transparent;
  font-feature-settings:"kern" 1,"liga" 1,"cv05" 1;
}
img,svg{max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
p{margin:0}
ul,ol,dl,dd{margin:0;padding:0;list-style:none}
table{border-collapse:collapse}
[hidden]{display:none!important}
section[id]{scroll-margin-top:68px}
::selection{background:var(--accent);color:var(--on-accent)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}
code{font-family:var(--mono);font-size:.92em;color:var(--ink)}

h1,h2,h3,h4{margin:0;font-weight:600;letter-spacing:-.021em;line-height:1.15}
.mono{font-family:var(--mono);font-size:.85rem;letter-spacing:-.01em}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.skip-link{position:fixed;top:-60px;left:14px;z-index:300;background:var(--accent);color:var(--on-accent);padding:9px 15px;font-weight:600;border-radius:var(--r)}
.skip-link:focus{top:8px}
/* ==========================================================================
   BACKGROUND
   Three fixed, pointer-events-none layers behind everything: a fine dot
   grid, two very low-opacity accent washes, and a grain tile. All are
   painted once and never move, so scrolling costs nothing and there is no
   JavaScript, no canvas and no animation frame to drop.
   ========================================================================== */
.bg{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}

/* dot grid, dissolving toward the bottom so it never competes with content */
.bg::before{
  content:"";position:absolute;inset:0;
  background-image:radial-gradient(var(--dot) 1px,transparent 1px);
  background-size:26px 26px;background-position:-13px -13px;
  -webkit-mask-image:radial-gradient(120% 85% at 50% 0%,#000 0%,rgba(0,0,0,.55) 45%,transparent 78%);
  mask-image:radial-gradient(120% 85% at 50% 0%,#000 0%,rgba(0,0,0,.55) 45%,transparent 78%);
}
/* two off-centre washes: warmth behind the name, cool toward the work */
.bg::after{
  content:"";position:absolute;inset:-20%;
  background:
    radial-gradient(38% 30% at 18% 8%,var(--wash-1),transparent 70%),
    radial-gradient(42% 34% at 88% 22%,var(--wash-2),transparent 72%);
}
/* grain: one 160px tile of SVG noise, so the flat fills stop reading as plastic */
.grain{
  position:fixed;inset:0;z-index:1;pointer-events:none;opacity:var(--grain-o);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* everything that is not background sits above it */
.shell,header,main,footer,.rail,.scroll-progress,.to-top{position:relative;z-index:2}
.scroll-progress{position:fixed;top:0;left:0;right:0;height:2px;z-index:150}
.scroll-progress i{display:block;height:100%;width:0;background:var(--accent)}

/* ---------- type ---------- */
.display{font-size:clamp(2.5rem,5.6vw,4.2rem);line-height:1.02;letter-spacing:-.035em;font-weight:700}
.h-lg{font-size:clamp(1.55rem,3.1vw,2.35rem);letter-spacing:-.028em}
.h-xl{font-size:clamp(1.9rem,4vw,3rem);letter-spacing:-.03em}
[data-split] .l{display:block}
.display em,.h-lg em,.h-xl em{font-style:normal;color:var(--ink-2)}
/* Scroll reveal is opt-in: the hidden state applies only once the inline
   bootstrap has set html.js, so a browser without JS - or a crawler that
   never runs it - still sees every section. */
html.js [data-anim]{opacity:0;transition:opacity .45s var(--ease)}
html.js [data-anim].in{opacity:1}
@media (prefers-reduced-motion:reduce){html.js [data-anim]{opacity:1;transition:none}}

/* ---------- nav ---------- */
.nav{position:sticky;top:0;z-index:140;display:flex;align-items:center;gap:18px;padding:11px var(--pad);background:color-mix(in srgb,var(--bg) 88%,transparent);border-bottom:1px solid transparent;transition:border-color .25s}
.nav.stuck{border-bottom-color:var(--line)}
.brand{display:flex;align-items:center;gap:9px;font-family:var(--mono);font-weight:600;font-size:.92rem;letter-spacing:-.02em}
.brand-mark{display:grid;place-items:center;width:26px;height:26px;border-radius:var(--r);background:var(--accent);color:var(--on-accent)}
.brand-mark svg{width:15px;height:15px}
.nav-links{display:flex;gap:1px;margin-left:auto}
.nav-links a{position:relative;padding:6px 10px;border-radius:var(--r);font-size:.82rem;color:var(--ink-2);transition:color .18s,background .18s}
.nav-links a:hover{color:var(--ink);background:var(--s2)}
.nav-links a.current{color:var(--accent);background:var(--accent-dim)}
.nav-actions{display:flex;align-items:center;gap:6px}
.icon-btn,.kbtn,.lang-btn{display:flex;align-items:center;justify-content:center;gap:6px;height:30px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1);color:var(--ink-2);font-family:var(--mono);font-size:.81rem;transition:color .18s,background-color .18s,border-color .18s}
.icon-btn{width:30px}.kbtn{padding:0 9px}.lang-btn{padding:0 9px}
.icon-btn:hover,.kbtn:hover,.lang-btn:hover{border-color:var(--line-2);color:var(--ink);background:var(--s2)}
.icon-btn .i-moon{display:none}
:root[data-theme="light"] .icon-btn .i-sun{display:none}
:root[data-theme="light"] .icon-btn .i-moon{display:block}
kbd{font-family:var(--mono);font-size:.76rem;color:var(--ink-3)}
.lang{position:relative}
.lang-menu{position:absolute;right:0;top:calc(100% + 6px);min-width:200px;z-index:160;padding:4px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1);box-shadow:0 12px 32px -12px rgba(0,0,0,.6);max-height:min(64vh,420px);overflow-y:auto}
.lang-menu li{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:4px;font-size:.83rem;color:var(--ink-2);cursor:pointer}
.lang-menu li:hover{background:var(--s2);color:var(--ink)}
.lang-menu li[aria-selected="true"]{color:var(--accent)}
.lang-menu .lc{margin-left:auto;font-family:var(--mono);font-size:.76rem;color:var(--ink-3)}
.burger{display:none;flex-direction:column;gap:4px;width:30px;height:30px;border:1px solid var(--line);border-radius:var(--r);align-items:center;justify-content:center;background:var(--s1)}
.burger i{width:13px;height:1.5px;background:var(--ink-2);transition:transform .22s}
.burger[aria-expanded="true"] i:first-child{transform:translateY(2.7px) rotate(45deg)}
.burger[aria-expanded="true"] i:last-child{transform:translateY(-2.8px) rotate(-45deg)}
.mobile-menu{position:sticky;top:53px;z-index:135;display:grid;gap:1px;padding:8px var(--pad) 14px;background:var(--bg);border-bottom:1px solid var(--line)}
.mobile-menu a{padding:10px 11px;border-radius:var(--r);color:var(--ink-2);font-size:.95rem}
.mobile-menu a:hover{background:var(--s2);color:var(--ink)}

/* ---------- hero: the portrait plate ---------- */
.hero{padding:clamp(22px,2.6vw,38px) var(--pad) clamp(24px,2.6vw,38px)}
.hero-inner{max-width:var(--maxw);margin:0 auto}

.hero-top{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:12px;padding-bottom:clamp(16px,2vw,26px);border-bottom:1px solid var(--line)}
.hero-status{display:inline-flex;align-items:center;gap:9px;margin:0;
  font-family:var(--mono);font-size:.79rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-2)}
.hero-loc{margin:0;font-size:.79rem;letter-spacing:.06em;color:var(--ink-3)}

.hero-split{display:grid;align-items:center;
  grid-template-columns:minmax(0,1fr) minmax(280px,min(39vw,560px)) minmax(0,1fr);
  gap:clamp(16px,2.6vw,48px);margin-top:clamp(18px,2.4vw,34px)}

.hero-name{margin:0 0 clamp(14px,1.6vw,22px);font-family:var(--display);font-weight:700;
  letter-spacing:-.04em;line-height:.94;font-size:clamp(1.5rem,2.6vw,2.4rem);color:var(--ink-2)}
.hs-word{margin:0;font-family:var(--display);font-weight:700;letter-spacing:-.05em;
  line-height:.86;font-size:clamp(2rem,4.9vw,5.4rem);color:var(--ink)}
.hs-code::before{content:"<";color:var(--accent);margin-right:.04em}
.hs-code::after{content:">";color:var(--accent);margin-left:.04em}
.hs-sub{margin:16px 0 0;max-width:30ch;font-size:.94rem;line-height:1.55;color:var(--ink-2)}
.hs-r{text-align:right}
.hs-r .hs-sub{margin-left:auto}
.hs-tags{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;margin:18px 0 0;
  padding:0;list-style:none}
.hs-tags li{font-family:var(--mono);font-size:.75rem;letter-spacing:.06em;color:var(--ink-3);
  border:1px solid var(--line);border-radius:100px;padding:3px 10px}

/* The artwork's ground is retoned to the site's own blue-black and its edges
   are feathered to nothing, so there is no plate and no frame — it simply
   stops. The glow behind it is the page's accent, which ties the two together
   on either theme. */
.hs-portrait{position:relative;margin:0 0 -3%;isolation:isolate}
.hs-portrait img{display:block;width:100%;height:auto;position:relative;z-index:1}
.hs-glow{position:absolute;z-index:0;inset:-12% 0 -4%;pointer-events:none;
  background:
    radial-gradient(58% 46% at 50% 42%, var(--glow-1), transparent 72%),
    radial-gradient(46% 34% at 70% 70%, var(--glow-2), transparent 74%)}
:root{--glow-1:rgba(145,148,229,.20); --glow-2:rgba(145,148,229,.10)}
:root[data-theme="light"]{--glow-1:rgba(50,55,224,.14); --glow-2:rgba(50,55,224,.08)}

.hero-foot{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:clamp(16px,2.4vw,44px);align-items:center;margin-top:clamp(18px,2.2vw,30px);
  padding-top:clamp(18px,2.2vw,28px);border-top:1px solid var(--line)}
.hero-foot .lede{max-width:var(--measure);margin:0;font-size:1rem;color:var(--ink-2)}
.hero-foot .actions{display:flex;flex-direction:column;align-items:flex-end;gap:14px}
.hero-foot .cta{margin-top:0;justify-content:flex-end}
.hero-foot .socials{margin-top:0}

@media (max-width:1140px){
  .hero-split{grid-template-columns:1fr;gap:26px;justify-items:center;text-align:center}
  .hs-portrait{order:-1;width:min(80vw,450px);margin-bottom:0}
  .hs-r,.hs-l{text-align:center}
  .hs-sub{margin-inline:auto;max-width:40ch}
  .hs-tags{justify-content:center}
  .hs-word{font-size:clamp(2.6rem,12vw,4rem)}
  .hero-name{font-size:clamp(1.3rem,5vw,1.8rem)}
  .hero-foot{grid-template-columns:1fr;gap:20px}
  .hero-foot .actions{align-items:flex-start}
  .hero-foot .cta{justify-content:flex-start}
}

/* ---------- hero: compact, dense ---------- */

.pulse{width:6px;height:6px;border-radius:50%;background:var(--good)}
@keyframes blink{50%{opacity:0}}
.lede{margin-top:16px;max-width:var(--measure);color:var(--ink-2);font-size:1rem}
.cta{display:flex;flex-wrap:wrap;gap:10px;margin-top:24px}
.btn{display:inline-flex;align-items:center;gap:8px;padding:9px 16px;border:1px solid var(--line-2);border-radius:var(--r);font-size:.86rem;font-weight:500;color:var(--ink);background:var(--s1);transition:color .2s,background-color .2s,border-color .2s,filter .2s}
.btn:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-dim)}
.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.btn-primary:hover{background:var(--accent);color:var(--on-accent);filter:brightness(1.08)}
.btn svg{width:13px;height:13px}
.socials{display:flex;gap:8px;margin-top:22px}
.socials a{display:grid;place-items:center;width:32px;height:32px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1);color:var(--ink-2);transition:color .2s,border-color .2s}
.socials a:hover{color:var(--accent);border-color:var(--accent)}

/* summary panel */
.chip{padding:0}
.chip.live{display:inline-flex;align-items:center;gap:6px;color:var(--good)}
.ring-mid strong{display:block;font-family:var(--mono);font-size:2.2rem;font-weight:600;letter-spacing:-.04em;line-height:1;color:var(--ink)}
.ring-mid small{display:block;margin-top:6px;font-family:var(--mono);font-size:.78rem;color:var(--ink-3)}
.mini-stats{margin-top:18px;border-top:1px solid var(--line)}
.mini-stats li{display:flex;gap:12px;padding:9px 0;border-bottom:1px solid var(--line);font-size:.82rem;color:var(--ink-2)}
.mini-stats li:last-child{border-bottom:0}
.mini-stats b{font-family:var(--mono);font-size:.8rem;font-weight:500;color:var(--accent);min-width:42px}

.stat{background:var(--bg);padding:16px 18px}
.stat b{display:block;font-family:var(--mono);font-size:clamp(1.3rem,2.4vw,1.75rem);font-weight:600;letter-spacing:-.03em;word-spacing:-.16em;color:var(--ink)}
.stat span{display:block;margin-top:4px;font-size:.76rem;color:var(--ink-3)}

/* ---------- at a glance ---------- */
.glance{border-block:1px solid var(--line);background:var(--s1)}
.glance-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:20px 32px}
.glance-grid dt{font-family:var(--mono);font-size:.76rem;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);margin-bottom:6px}
.glance-grid dd{font-size:.9rem;line-height:1.5}
.glance-cta{display:flex;flex-wrap:wrap;gap:10px;margin-top:24px}

/* ---------- sections ---------- */
.section{max-width:var(--maxw);margin:0 auto;padding:clamp(52px,6.5vw,92px) var(--pad)}
.sec-head{margin-bottom:clamp(26px,3.4vw,42px)}
.eyebrow{display:flex;align-items:center;gap:12px;font-family:var(--mono);font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);margin-bottom:16px}
.eyebrow .idx{color:var(--accent)}
.eyebrow::after{content:"";flex:1;height:1px;background:var(--line)}
.sec-sub{margin-top:14px;color:var(--ink-2);max-width:var(--measure);font-size:.97rem}

/* ---------- work ---------- */
/* the research card's label + link (the only survivors of the old
   project-row markup; the project tiles are .t.link now) */
.ptag{color:var(--accent);text-transform:uppercase;letter-spacing:.08em}
.plink{grid-column:4;justify-self:end;margin-top:0}
.plink:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-dim)}

/* ---------- live lab ---------- */
.lab-wrap{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--s1)}
.lab-io{display:grid;grid-template-columns:1fr 1fr}
.lab-panel{display:flex;flex-direction:column;border-right:1px solid var(--line)}
.lab-panel:last-child{border-right:0}
.panel-bar{display:flex;align-items:center;gap:9px;padding:9px 14px;border-bottom:1px solid var(--line);background:var(--s2);font-family:var(--mono);font-size:.78rem;color:var(--ink-3)}
.dots{display:flex;gap:4px}
.dots i{width:7px;height:7px;border-radius:50%;background:var(--line-2)}
#probe{flex:1;width:100%;min-height:180px;resize:vertical;border:0;outline:none;background:none;color:var(--ink);font-family:var(--mono);font-size:.78rem;line-height:1.7;padding:14px}
#probe::placeholder{color:var(--ink-3)}
.samples{display:flex;flex-wrap:wrap;align-items:center;gap:6px;padding:11px 14px;border-top:1px solid var(--line);font-family:var(--mono);font-size:.79rem;color:var(--ink-3)}
.pill{padding:3px 9px;border:1px solid var(--line);border-radius:999px;font-family:var(--mono);font-size:.78rem;color:var(--ink-2);transition:color .18s,background-color .18s,border-color .18s}
.pill:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-dim)}
.verdict{display:flex;align-items:flex-start;gap:20px;padding:16px 14px 8px}
.gauge{display:none}
.score-line{display:flex;align-items:baseline;gap:7px;margin-bottom:8px}
.score-line b{font-family:var(--mono);font-size:2.1rem;font-weight:600;letter-spacing:-.04em;line-height:1}
.score-line small{font-family:var(--mono);font-size:.76rem;color:var(--ink-3)}
.badge{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;border-radius:4px;font-family:var(--mono);font-size:.79rem;font-weight:600;letter-spacing:.08em;border:1px solid currentColor}
#verdict[data-level="allow"] .badge{color:var(--good)}
#verdict[data-level="warn"] .badge{color:var(--warn)}
#verdict[data-level="block"] .badge{color:var(--critical)}
#verdictText{margin-top:9px;font-size:.87rem;color:var(--ink-2)}
.conf{margin-top:7px;font-family:var(--mono);font-size:.78rem;color:var(--ink-3)}
.findings{display:grid;gap:6px;padding:0 14px 14px;max-height:280px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--line-2) transparent}
.findings::-webkit-scrollbar{width:8px}
.findings::-webkit-scrollbar-track{background:transparent}
.findings::-webkit-scrollbar-thumb{background:var(--line-2);border-radius:4px;border:2px solid var(--s1)}
/* Fade the last row only while there is more to scroll to, so a clipped
   card reads as "more below" rather than as a broken one. */
.findings.more{-webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 34px),transparent);mask-image:linear-gradient(to bottom,#000 calc(100% - 34px),transparent)}
.finding{display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:start;padding:9px 11px;border:1px solid var(--line);border-radius:var(--r);background:var(--bg)}
.finding .sev{width:6px;height:6px;border-radius:50%;margin-top:6px}
.finding.high .sev{background:var(--critical)}
.finding.med .sev{background:var(--serious)}
.finding.low .sev{background:var(--warn)}
.finding.clean{grid-template-columns:auto 1fr;border-color:var(--good)}
.finding.clean .sev{background:var(--good)}
.finding h5{margin:0;font-size:.82rem;font-weight:600}
.finding p{margin-top:2px;font-family:var(--mono);font-size:.79rem;color:var(--ink-3);word-break:break-word}
.finding .note{font-family:var(--sans);font-size:.76rem;color:var(--ink-2)}
.finding .w{font-family:var(--mono);font-size:.78rem;color:var(--ink-3)}
.lab-note{margin-top:14px;font-family:var(--mono);font-size:.79rem;color:var(--ink-3);line-height:1.75;max-width:var(--measure)}
.lab-note a{color:var(--accent);border-bottom:1px solid var(--accent)}

/* ---------- research ---------- */
.res-wrap{display:grid;gap:clamp(18px,2.4vw,30px)}
.res-q{border:1px solid var(--line);border-radius:var(--r);background:var(--s1);padding:clamp(20px,2.6vw,32px)}
.res-q .ptag{display:block;font-family:var(--mono);font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;color:var(--accent);margin-bottom:12px}
.res-q h3{font-size:clamp(1.25rem,2.4vw,1.8rem);max-width:28ch}
.res-q>p{margin-top:12px;color:var(--ink-2);max-width:var(--measure);font-size:.95rem}
.res-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:18px;margin-top:22px;padding-top:18px;border-top:1px solid var(--line)}
.res-meta b{display:block;font-family:var(--mono);font-size:1.35rem;font-weight:600;color:var(--ink)}
.res-meta sup{font-size:.58em}
.res-meta span{display:block;margin-top:4px;font-size:.85rem;color:var(--ink-3)}
.res-q .plink{margin-top:20px}

/* figure */
.res-fig{margin:0;border:1px solid var(--line);border-radius:var(--r);background:var(--s1);padding:clamp(18px,2.4vw,28px)}
.res-fig figcaption h4{font-size:1rem;margin-bottom:8px}
.res-fig figcaption p{font-size:.88rem;color:var(--ink-2);max-width:var(--measure)}
.fig{display:block;width:100%;height:auto;margin:22px 0 4px;overflow:visible}
.fig .grid{stroke:var(--line);stroke-width:1}
.fig .yt,.fig .xt{font-family:var(--mono);font-size:10px;fill:var(--ink-3)}
/* The SVG scales down with the column, so its text scales with it.
   Below the desktop width, size the labels up in viewBox units to keep
   them legible once rendered. */
@media (max-width:880px){.fig .yt,.fig .xt{font-size:15px}}
@media (max-width:560px){.fig .yt,.fig .xt{font-size:19px}}
.fig .yt{text-anchor:end}
.fig .xt{text-anchor:middle}
.fig .mark{fill:var(--accent);transition:fill .15s}
.fig .bar[data-ident="true"] .mark{fill:var(--good)}
.fig .hit{fill:transparent;cursor:pointer}
.fig .bar:hover .mark,.fig .bar.on .mark{filter:brightness(1.25)}
.fig .bar{outline:none}
.fig .bar:focus-visible .hit{stroke:var(--ink-2);stroke-width:1.5;stroke-dasharray:3 3}
.fig-leg{display:flex;flex-wrap:wrap;gap:16px;margin:10px 0 0;padding:0;list-style:none}
.fig-leg li{display:flex;align-items:center;gap:7px;font-family:var(--mono);font-size:.79rem;color:var(--ink-2)}
.fig-leg .sw{width:10px;height:10px;border-radius:2px;flex:none}
.sw-good{background:var(--good)}
.sw-acc{background:var(--accent)}
.fig-axis{margin-top:4px;font-size:.78rem;color:var(--ink-3);display:flex;gap:10px}
.fig-table{margin-top:16px;border-top:1px solid var(--line);padding-top:12px}
.fig-table summary{font-family:var(--mono);font-size:.81rem;color:var(--ink-2);cursor:pointer}
.fig-table table{margin-top:10px;font-family:var(--mono);font-size:.83rem}
.fig-table th,.fig-table td{padding:3px 18px 3px 0;text-align:left;color:var(--ink-2)}
.fig-table th{color:var(--ink-3);font-weight:500;border-bottom:1px solid var(--line)}
.fig-tip{position:fixed;z-index:200;pointer-events:none;padding:6px 9px;border:1px solid var(--line-2);border-radius:4px;background:var(--s1);font-family:var(--mono);font-size:.79rem;color:var(--ink);white-space:nowrap;opacity:0;transition:opacity .12s}
.fig-tip.on{opacity:1}

.res-method{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:10px}
.rm{padding:18px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1)}
.rm-n{display:block;font-family:var(--mono);font-size:.78rem;color:var(--accent);margin-bottom:10px}
.rm h4{font-size:.95rem;margin-bottom:6px}
.rm p{font-size:.85rem;color:var(--ink-2)}

.ledger{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--s1)}
.ledger-head{padding:18px clamp(16px,2vw,24px);border-bottom:1px solid var(--line)}
.ledger-head h3{font-size:1.08rem}
.ledger-head p{margin-top:7px;font-size:.88rem;color:var(--ink-2);max-width:var(--measure)}
.ledger-rows li{display:grid;grid-template-columns:38px minmax(0,1fr) auto;gap:14px;align-items:center;padding:11px clamp(16px,2vw,24px);border-bottom:1px solid var(--line)}
.ledger-rows li:last-child{border-bottom:0}
.hid{font-family:var(--mono);font-size:.83rem;color:var(--ink-3)}
.hdesc{font-size:.88rem;color:var(--ink-2)}
.hstat{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);font-size:.78rem;padding:2px 8px;border-radius:4px;border:1px solid currentColor;white-space:nowrap}
.hstat::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor}
.hstat.live{color:var(--good)}
.hstat.dead{color:var(--critical)}
.hstat.warn{color:var(--warn)}

/* ablation study — the ledger pattern, reused so the two research findings
   read as one system rather than two one-offs */
.abl-claim{max-width:var(--measure);margin-top:10px;font-size:1.02rem;line-height:1.55;
  color:var(--ink)}
.abl-claim strong{font-weight:600}
.abl .abl-rows{margin:22px 0 0;border:1px solid var(--line);border-radius:var(--r);
  background:var(--s1);overflow:hidden}
.abl .abl-m{margin-top:18px;gap:28px}
.abl-foot{max-width:var(--measure);margin-top:18px;font-size:.86rem;color:var(--ink-3)}
@media (max-width:720px){
  .abl .abl-rows li{grid-template-columns:30px minmax(0,1fr);row-gap:8px}
  .abl .abl-rows .hstat{grid-column:2;justify-self:start}
}
.ledger-foot{padding:14px clamp(16px,2vw,24px);border-top:1px solid var(--line);font-family:var(--mono);font-size:.79rem;color:var(--ink-3);line-height:1.75}

/* ---------- focus ---------- */
.focus-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(255px,1fr));gap:10px}
.fcard{display:block;padding:20px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1);transition:border-color .22s}
.fcard:hover{border-color:var(--line-2)}
.fnum{display:block;font-family:var(--mono);font-size:.78rem;color:var(--accent);margin-bottom:12px}
.ficon{display:none}
.fcard h3{font-size:1rem;margin-bottom:8px}
.fcard p{color:var(--ink-2);font-size:.86rem}
.ftags{display:flex;flex-wrap:wrap;gap:5px;margin-top:14px}
.ftags li{font-family:var(--mono);font-size:.76rem;color:var(--ink-3);padding:2px 7px;border:1px solid var(--line);border-radius:4px}

/* ---------- capabilities ---------- */
.skills-shell{border:1px solid var(--line);border-radius:var(--r);background:var(--s1);overflow:hidden}
.tabs{display:flex;gap:4px;padding:10px;border-bottom:1px solid var(--line);background:var(--s2);overflow-x:auto;scrollbar-width:none;max-width:100%;-webkit-overflow-scrolling:touch}
.tabs::-webkit-scrollbar{display:none}
/* The strip scrolls sideways when the tabs do not fit; fade the right
   edge so it is visible that there is more to reach. */
.tabs{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 24px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 24px),transparent)}
@media (min-width:700px){.tabs{-webkit-mask-image:none;mask-image:none}}
.tabs::-webkit-scrollbar{display:none}
.tab{padding:6px 12px;border-radius:var(--r);font-size:.8rem;color:var(--ink-3);white-space:nowrap;transition:color .18s,background-color .18s}
.tab:hover{color:var(--ink-2)}
.tab.active{background:var(--accent);color:var(--on-accent);font-weight:500}
.tabpanel{padding:20px}
.caps{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:0 28px}
.caps li{padding:8px 0;border-bottom:1px solid var(--line);font-size:.88rem;color:var(--ink-2)}
.chipset{display:flex;flex-wrap:wrap;gap:5px;margin-top:20px;padding-top:16px;border-top:1px solid var(--line)}
.chipset span{font-family:var(--mono);font-size:.78rem;color:var(--ink-3);padding:3px 8px;border:1px solid var(--line);border-radius:4px}

/* ---------- experience ---------- */
.timeline{display:grid;gap:10px}
.timeline::before,.tl-dot{display:none}
.tl-card{padding:20px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1);transition:border-color .22s}
.tl-card:hover{border-color:var(--line-2)}
.tl-head{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px;align-items:baseline}
.tl-head h3{font-size:1.04rem}
.tl-when{font-family:var(--mono);font-size:.79rem;color:var(--ink-3)}
.tl-org{margin-top:4px;font-size:.85rem;color:var(--accent)}
.tl-card ul{margin-top:12px;display:grid;gap:7px;max-width:var(--measure)}
.tl-card li{padding-left:16px;position:relative;font-size:.88rem;color:var(--ink-2)}
.tl-card li::before{content:"";position:absolute;left:0;top:.66em;width:7px;height:1px;background:var(--line-2)}
.tl-tags{display:flex;flex-wrap:wrap;gap:5px;margin-top:14px}
.tl-tags span{font-family:var(--mono);font-size:.76rem;color:var(--ink-3);padding:2px 7px;border:1px solid var(--line);border-radius:4px}

/* ---------- credentials ---------- */
.cert-layout{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,.7fr);gap:14px;align-items:start}
.cert-grid{display:grid;gap:8px}
.cert{display:flex;align-items:center;gap:13px;padding:12px 16px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1)}
.cert-ic{flex:0 0 auto;display:grid;place-items:center;min-width:42px;height:26px;border-radius:4px;background:var(--accent-dim);color:var(--accent);font-family:var(--mono);font-size:.78rem;font-weight:600}
.cert h4{font-size:.9rem;font-weight:500}
.cert p{margin-top:1px;font-size:.76rem;color:var(--ink-3)}
.cert .ok{margin-left:auto;color:var(--good);font-size:.8rem}
.cert .wip{margin-left:auto;font-family:var(--mono);font-size:.76rem;color:var(--warn);padding:2px 7px;border:1px solid currentColor;border-radius:4px}
.cert.prog .cert-ic{background:rgba(250,178,25,.12);color:var(--warn)}
.achieve{padding:20px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1)}
.achieve h3{font-size:1rem;margin-bottom:14px}
.achieve ul{display:grid;gap:11px}
.achieve li{padding-left:16px;position:relative;font-size:.87rem;color:var(--ink-2)}
.achieve li::before{content:"";position:absolute;left:0;top:.66em;width:7px;height:1px;background:var(--accent)}
.achieve b{color:var(--ink);font-weight:600}
.langs{margin-top:18px;padding-top:14px;border-top:1px solid var(--line)}
.langs>.mono{font-size:.76rem;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}
.langs div{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.langs span:not(.mono){font-size:.78rem;color:var(--ink-2);padding:2px 8px;border:1px solid var(--line);border-radius:4px}

/* ---------- contact ---------- */
.contact{padding-bottom:clamp(48px,6vw,84px)}
.contact-inner{max-width:880px}
.contact-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:24px}
/* (the old contact-card grid that lived here is gone; its .ccard rules were
   bleeding padding into the credential cards, which reuse the class name) */

.footer{border-top:1px solid var(--line);padding:22px var(--pad)}
.footer-big{display:none}
.footer-row{max-width:var(--maxw);margin:0 auto;display:flex;flex-wrap:wrap;gap:10px;justify-content:space-between;font-family:var(--mono);font-size:.79rem;color:var(--ink-3)}
.to-top{position:fixed;right:18px;bottom:18px;z-index:130;display:grid;place-items:center;width:34px;height:34px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1);color:var(--ink-2);transition:color .2s,border-color .2s}
.to-top:hover{color:var(--accent);border-color:var(--accent)}

/* ---------- rail ---------- */
.rail{position:fixed;left:max(12px,calc((100vw - var(--maxw)) / 2 - 70px));top:50%;z-index:90;transform:translateY(-50%);opacity:0;pointer-events:none;transition:opacity .4s}
.rail.on{opacity:1;pointer-events:auto}
.rail a{display:flex;align-items:center;gap:9px;padding:4px 0;font-family:var(--mono);font-size:.76rem;color:var(--ink-3);transition:color .2s}
.rail i{font-style:normal}
.rail a span{opacity:0;transition:opacity .25s;font-family:var(--sans);font-size:.81rem}
.rail a:hover{color:var(--ink-2)}
.rail a:hover span,.rail a.current span{opacity:1}
.rail a.current{color:var(--accent)}
/* The rail lives in the left gutter, whose width is
   (100vw - maxw)/2 - 70. Below ~1600px that gutter is narrower than the
   rail, so it printed over the first column instead of beside it. */
@media (max-width:1599px){.rail{display:none}}

/* ---------- palette ---------- */
.palette{position:fixed;inset:0;z-index:200;display:grid;place-items:start center;padding:11vh 16px 16px;background:rgba(0,0,0,.6);backdrop-filter:blur(3px)}
.palette-box{width:min(600px,100%);border:1px solid var(--line-2);border-radius:var(--r);background:var(--s1);box-shadow:0 24px 60px -20px rgba(0,0,0,.7);overflow:hidden}
.palette-input{display:flex;align-items:center;gap:11px;padding:13px 15px;border-bottom:1px solid var(--line);color:var(--ink-3)}
.palette-input input{flex:1;background:none;border:0;outline:none;color:var(--ink);font-size:.92rem;font-family:var(--sans)}
.palette-list{max-height:330px;overflow-y:auto;padding:5px}
.palette-list li{display:flex;align-items:center;gap:11px;padding:8px 11px;border-radius:4px;cursor:pointer;font-size:.86rem;color:var(--ink-2)}
.palette-list li .pk{margin-left:auto;font-family:var(--mono);font-size:.75rem;color:var(--ink-3)}
.palette-list li[aria-selected="true"]{background:var(--accent);color:var(--on-accent)}
.palette-list li[aria-selected="true"] .pk{color:rgba(255,255,255,.7)}
.palette-list .empty{justify-content:center;color:var(--ink-3);cursor:default}
.palette-foot{display:flex;gap:16px;padding:10px 15px;border-top:1px solid var(--line);font-family:var(--mono);font-size:.76rem;color:var(--ink-3)}
.toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%,10px);z-index:250;padding:9px 16px;border:1px solid var(--accent);border-radius:var(--r);background:var(--s1);color:var(--ink);font-size:.82rem;opacity:0;transition:opacity .22s,transform .22s}
.toast.show{opacity:1;transform:translate(-50%,0)}

/* ---------- responsive ---------- */
@media (max-width:1020px){
  .cert-layout{grid-template-columns:1fr}
}
/* The link row is as wide as whatever language is loaded. 1020px clears
   English; navFit() in main.js measures the rest and adds .nav-compact,
   because Portuguese and Telugu need nearly 200px more. */
html.nav-compact .nav-links{display:none}
html.nav-compact .burger{display:flex}
html.nav-compact .kbtn{display:none}
@media (max-width:1020px){
  .nav-links{display:none}
  .burger{display:flex}
  .kbtn{display:none}
}
@media (max-width:880px){
  .lab-io{grid-template-columns:1fr}
  .lab-panel{border-right:0;border-bottom:1px solid var(--line)}
  .caps{grid-template-columns:1fr}
}
@media (max-width:560px){
  .ledger-rows li{grid-template-columns:32px minmax(0,1fr);row-gap:6px}
  .ledger-rows .hstat{grid-column:2;justify-self:start}
  /* the longest verdicts ("falsified - 0 of 37 decisions changed") are wider
     than a phone, so the pill wraps rather than running under the border.
     The dot holds the first line instead of centring on the block. */
  .hstat{white-space:normal;align-items:flex-start}
  .hstat::before{flex:0 0 5px;margin-top:.44em}
  .res-meta{grid-template-columns:1fr 1fr}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important;scroll-behavior:auto!important}
}

/* ==========================================================================
   BENTO LAYER
   One tile system for the whole page. Every panel is a .t on a 12-column
   grid; hierarchy comes from how many columns and rows a tile spans, not
   from giving each section its own treatment. Section chrome is a single
   small label - the tiles carry the page.
   ========================================================================== */

.section{max-width:var(--maxw);margin:0 auto;padding:clamp(34px,4vw,54px) var(--pad)}

/* --- section label: replaces the old eyebrow + 2-line headline + subtitle --- */
.lbl{display:flex;align-items:center;gap:12px;margin-bottom:16px;
     font-family:var(--mono);font-size:.79rem;letter-spacing:.15em;
     text-transform:uppercase;color:var(--ink-3)}
.lbl .idx{color:var(--accent)}
.lbl::after{content:"";flex:1;height:1px;background:var(--line)}
.lbl a{margin-left:auto;color:var(--ink-3);text-transform:none;letter-spacing:.02em}
.lbl a:hover{color:var(--accent)}

/* --- the grid --- */
.bento{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));
       gap:var(--tgap,14px);align-items:stretch}
.c3{grid-column:span 3}.c4{grid-column:span 4}.c5{grid-column:span 5}
.c6{grid-column:span 6}.c7{grid-column:span 7}.c8{grid-column:span 8}
.c9{grid-column:span 9}.c12{grid-column:span 12}
.r2{grid-row:span 2}.r3{grid-row:span 3}

/* --- the tile --- */
.t{display:flex;flex-direction:column;min-width:0;
   padding:clamp(18px,1.7vw,24px);
   border:1px solid var(--line);border-radius:14px;background:var(--tile);
   transition:border-color .2s,background .2s}
.t.link:hover{border-color:var(--line-2);background:var(--tile-2)}
.t.flush{padding:0;overflow:hidden}
.t.quiet{background:transparent}
.t.fill{background:var(--tile-2)}

/* tile head: a mono kicker on the left, an optional meta on the right */
.t-k{display:flex;align-items:center;gap:9px;margin-bottom:10px;
     font-family:var(--mono);font-size:.76rem;letter-spacing:.1em;
     text-transform:uppercase;color:var(--accent)}
.t-k .meta{margin-left:auto;color:var(--ink-3);letter-spacing:.02em;text-transform:none}
.t h3{font-size:1.06rem;letter-spacing:-.01em;margin:0}
.t h4{font-size:.92rem;margin:0}
.t > p{margin-top:8px;color:var(--ink-2);font-size:.88rem;line-height:1.62}
.t-foot{margin-top:auto;padding-top:14px}

/* metric strip inside a tile */
.t-m{display:flex;flex-wrap:wrap;gap:20px;margin:14px 0 0;padding:0;list-style:none}
.t-m b{display:block;font-family:var(--mono);font-size:.98rem;font-weight:600;color:var(--ink)}
.t-m span{font-size:.81rem;color:var(--ink-3)}

/* stack tags */
.t-s{display:flex;flex-wrap:wrap;gap:6px;margin:14px 0 0;padding:0;list-style:none}
.t-s li{font-family:var(--mono);font-size:.76rem;color:var(--ink-3);
        padding:2px 7px;border:1px solid var(--line);border-radius:5px}

/* a tile that is entirely a link */
a.t{color:inherit}
a.t h3{transition:color .2s}
a.t:hover h3{color:var(--accent)}
.t-go{display:inline-flex;align-items:center;gap:5px;margin-top:auto;padding-top:14px;
      font-family:var(--mono);font-size:.79rem;color:var(--ink-3)}
a.t:hover .t-go{color:var(--accent)}

/* compact list of secondary work */
.t-list{margin:0;padding:0;list-style:none}
.t-list li + li{border-top:1px solid var(--line)}
.t-list a{display:flex;align-items:baseline;gap:10px;padding:11px 0;color:var(--ink-2);font-size:.86rem}
.t-list a:hover{color:var(--accent)}
.t-list .n{font-family:var(--mono);font-size:.76rem;color:var(--ink-3);flex:none}
.t-list .tag{margin-left:auto;font-family:var(--mono);font-size:.75rem;color:var(--ink-3);flex:none}

@media (max-width:980px){
  .c3,.c4,.c5{grid-column:span 6}
  .c7,.c8,.c9{grid-column:span 12}
  .r2,.r3{grid-row:auto}
}
@media (max-width:620px){
  .bento{gap:12px}
  /* small tiles stay two-up so a phone does not scroll past five of them */
  .c3{grid-column:span 6}
  .c4,.c5,.c6,.c7,.c8,.c9{grid-column:span 12}
  /* except in contact, where the two small tiles carry prose rather than a
     numeral: half a phone width turns a role list into a column of fragments */
  #contact .t.c3{grid-column:span 12}
}

/* --- hero, as bento tiles --- */

.intro{justify-content:center;gap:0}
.intro .display{font-size:clamp(2.1rem,5.2vw,3.6rem);line-height:1.02;letter-spacing:-.04em;
                font-weight:700;margin:14px 0 0}
.status{display:inline-flex;align-items:center;gap:8px;align-self:flex-start;
        font-family:var(--mono);font-size:.78rem;color:var(--ink-2);
        padding:5px 11px;border:1px solid var(--line);border-radius:100px}
.intro .role{display:flex;align-items:center;gap:10px;margin-top:14px;
             font-family:var(--mono);font-size:.82rem;color:var(--accent)}
.intro .lede{margin-top:14px;max-width:58ch;color:var(--ink-2);font-size:.97rem;line-height:1.65}
.intro .cta{display:flex;flex-wrap:wrap;gap:9px;margin-top:20px}
.intro .socials{display:flex;gap:8px;margin:18px 0 0;padding:0;list-style:none}

/* posture tile */
.ring-mid{margin-top:4px}
.ring-mid strong{display:block;font-family:var(--mono);font-size:clamp(1.8rem,3.4vw,2.4rem);
                 font-weight:600;letter-spacing:-.03em;line-height:1}
.ring-mid small{display:block;margin-top:5px;font-family:var(--mono);font-size:.78rem;color:var(--ink-3)}
.mini-stats{margin:16px 0 0;padding:0;list-style:none;display:grid;gap:9px}
.mini-stats li{display:flex;align-items:baseline;gap:11px;padding-top:9px;border-top:1px solid var(--line)}
.mini-stats b{font-family:var(--mono);font-size:.84rem;color:var(--accent);flex:none;min-width:34px}
.mini-stats span{font-size:.8rem;color:var(--ink-2)}

/* stat tiles */
.t.stat{justify-content:flex-end;min-height:104px}
.t.stat b{display:block;font-family:var(--mono);font-size:clamp(1.25rem,2.2vw,1.6rem);
          font-weight:600;letter-spacing:-.03em;word-spacing:-.16em;color:var(--ink)}
.t.stat span{margin-top:5px;font-size:.76rem;color:var(--ink-3);line-height:1.4}
.t-list.cols{columns:2;column-gap:38px}
.t-list.cols li{break-inside:avoid}
.t-list.cols li:first-child{border-top:0}
@media (max-width:760px){.t-list.cols{columns:1}}

/* --- research tiles --- */
.res-q{gap:0}
.res-method{gap:0;justify-content:flex-start}
.res-method .rm{padding:12px 0;border-top:1px solid var(--line)}
.res-method .rm:first-of-type{border-top:0;padding-top:0}
.res-method .rm-n{display:block;font-size:.75rem;color:var(--accent);margin-bottom:4px}
.res-method .rm h4{font-size:.88rem}
.res-method .rm p{margin-top:4px;font-size:.82rem;color:var(--ink-2);line-height:1.55}
.res-fig{margin:0}
.res-fig figcaption h4{font-size:.98rem}
.ledger{gap:0}

/* --- experience / credentials tiles --- */
.t .lbl{margin:22px 0 14px;padding-top:18px;border-top:1px solid var(--line)}
.t .lbl .idx{display:none}
.t .timeline{margin:0}
.t .cert-layout{display:block}

/* --- "at a glance" facts row --- */
.glance-s{padding-top:0}
.t.gl{background:transparent}
.t.gl .t-k{color:var(--ink-3)}
.t.gl > p{margin-top:0;font-size:.85rem;color:var(--ink-2);line-height:1.55}

/* --- contact --- */
.contact .c-h{font-size:clamp(1.25rem,2.4vw,1.75rem);letter-spacing:-.02em;line-height:1.2}
.contact-actions{display:flex;flex-wrap:wrap;gap:9px;margin-top:auto;padding-top:20px}
.contact .t h4{font-size:.95rem;font-weight:500;color:var(--ink);line-height:1.4}

/* --- research tiles: drop the pre-bento box treatment so nothing nests --- */
.t.res-q{border-radius:14px}
.t.res-q h3{font-size:1.06rem;max-width:none}
.t.res-q > p{font-size:.88rem;max-width:none}
.t.res-q .plink{align-self:flex-start;margin-top:auto}
.t.res-method .rm{padding:14px 0;border:0;border-top:1px solid var(--line);
                  border-radius:0;background:transparent}
.t.res-method .rm:first-of-type{border-top:0;padding-top:0}
.t.res-method{justify-content:flex-start}

/* --- inside a tile, nothing gets its own box: rows are separated by rules --- */
.t .timeline{gap:0}
.t .tl-card{padding:16px 0;border:0;border-top:1px solid var(--line);
            border-radius:0;background:transparent}
.t .tl-item:first-child .tl-card{border-top:0;padding-top:0}
.t .tl-dot{display:none}
.t .cert{padding:11px 0;border:0;border-top:1px solid var(--line);
         border-radius:0;background:transparent}
.t .cert-list > .cert:first-child{border-top:0;padding-top:0}
/* a label that opens a tile needs no divider above it */
.t > .lbl:first-child{margin-top:0;padding-top:0;border-top:0}
.t .cert-layout{display:block}
.t .cert-grid > .cert:first-child{border-top:0;padding-top:0}

/* Full width, when there is no gallery beside it, the list would otherwise be
   one tall thin column with dead space to the right. */
#certListCard.c12 .cert-grid{grid-template-columns:repeat(2,minmax(0,1fr));
  column-gap:34px}
#certListCard.c12 .cert-grid > .cert:nth-child(2){border-top:0;padding-top:0}
@media (max-width:760px){
  #certListCard.c12 .cert-grid{grid-template-columns:1fr}
  #certListCard.c12 .cert-grid > .cert:nth-child(2){border-top:1px solid var(--line)}
}
.t .achieve{padding:18px 0 0;margin-top:18px;border:0;border-top:1px solid var(--line);
            border-radius:0;background:transparent}
.t .achieve h3{font-size:.92rem}
.t .achieve{padding:0;margin:0;border:0}
.t .achieve .langs{margin-top:16px;padding-top:13px}
.col{display:flex;flex-direction:column;gap:var(--tgap,14px);min-width:0}
.col > .t{flex:0 0 auto}
.col > .t:last-child{flex:1 1 auto}

/* The custom cursor was removed: it is the system cursor people know, and a
   portfolio is not the place to retrain it. Pointer/text affordances stay. */
a,button,summary,label,select,[role="button"],.t.link{cursor:pointer}
input,textarea,[contenteditable]{cursor:text}
:disabled,[aria-disabled="true"]{cursor:not-allowed}

/* --- the thirty-second case: three claims, each with its own evidence --- */
.proof .proof-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
                   gap:0;margin:4px 0 0;padding:0;list-style:none;counter-reset:pf}
.proof .proof-list li{counter-increment:pf;padding:0 26px;border-left:1px solid var(--line)}
.proof .proof-list li:first-child{padding-left:0;border-left:0}
.proof .proof-list li::before{content:counter(pf,decimal-leading-zero);
    display:block;margin-bottom:7px;font-family:var(--mono);font-size:.75rem;color:var(--accent)}
.proof h4{font-size:.94rem;letter-spacing:-.01em}
.proof p{margin-top:6px;font-size:.84rem;color:var(--ink-2);line-height:1.6}
@media (max-width:900px){
  .proof .proof-list{grid-template-columns:1fr;gap:18px}
  .proof .proof-list li{padding:18px 0 0;border-left:0;border-top:1px solid var(--line)}
  .proof .proof-list li:first-child{padding-top:0;border-top:0}
}

/* ==========================================================================
   READING DEPTH
   Two audiences read this page: someone scanning for thirty seconds, and
   someone who wants the workings. Quick mode folds away the deep material -
   research method, the hypothesis ledger, secondary work, older roles - so
   the first reader is not made to scroll past it.

   Full is the default, so a visitor with no JavaScript, and any crawler or
   assistant reading the page, always receives the complete document.
   ========================================================================== */
.depth-btn{display:inline-flex;align-items:center;gap:0;padding:2px;
  border:1px solid var(--line);border-radius:100px;background:var(--s1);
  font-family:var(--mono);font-size:.75rem;letter-spacing:.06em;text-transform:uppercase}
.depth-btn span{padding:5px 10px;border-radius:100px;color:var(--ink-3);transition:color .18s,background-color .18s}
.depth-btn .df{background:var(--accent);color:var(--on-accent)}
html[data-depth="quick"] .depth-btn .df{background:transparent;color:var(--ink-3)}
html[data-depth="quick"] .depth-btn .dq{background:var(--accent);color:var(--on-accent)}
html[data-depth="quick"] [data-deep]{display:none}
@media (max-width:880px){.depth-btn{display:none}}

/* Fixed background layers confuse full-page capture and waste ink; drop them
   for print and for anything asking to save paper. */
@media print{
  .bg,.grain{display:none !important}
  .t{background:#fff !important;border-color:#ddd !important}
}

/* ==========================================================================
   V5 — panels with real edges, big display type, one accent
   An earlier pass removed every box; structure came only from type size and
   colour. Read back, the page had no readable module boundaries. The tiles
   are panels again: one hairline, one surface, generous padding — the
   structure the reference work has — while the display type stays.
   ========================================================================== */

/* display type everywhere a heading appears */
h1,h2,h3,.display,.t h3,.t h4,.name,.stat b,.t-m b,.fig b{font-family:var(--display)}
.display{font-weight:800;letter-spacing:-.045em;line-height:.88}
h2,h3{font-weight:600;letter-spacing:-.03em}

/* The drifting colour field.
   A radial gradient is already soft, so no blur filter is needed - and that
   matters: a blurred layer must be re-rasterised whenever it moves, which
   measured 133ms per frame full-screen and still 50ms once split into layers.
   Gradient-filled blobs animate at a locked 60fps because moving them is a
   pure composite. Each is promoted so the paint happens once. */
/* These were promoted, animated layers. Measured: with them the page drops a
   median of 60-100 frames per scroll; without, zero and a 16.7ms p95. The
   cost is the promotion itself, not the animation — a 56vw compositing layer
   is re-composited on every frame. They are plain painted washes now, and the
   movement the page needed has moved to the pointer instead. */
.bg .blob{position:absolute;display:block}
.bg .b1{width:56vw;height:56vw;left:-14%;top:-16%;
        background:radial-gradient(closest-side,var(--wash-1),transparent 72%)}
.bg .b2{width:48vw;height:48vw;right:-12%;top:-2%;
        background:radial-gradient(closest-side,var(--wash-2),transparent 72%)}
.bg .b3{width:44vw;height:44vw;left:34%;top:48%;
        background:radial-gradient(closest-side,var(--wash-3),transparent 72%)}
@keyframes d1{0%,100%{transform:translate3d(0,0,0) scale(1)}
              50%{transform:translate3d(7vw,6vh,0) scale(1.15)}}
@keyframes d2{0%,100%{transform:translate3d(0,0,0) scale(1.08)}
              50%{transform:translate3d(-8vw,8vh,0) scale(.9)}}
@keyframes d3{0%,100%{transform:translate3d(0,0,0) scale(.95)}
              50%{transform:translate3d(6vw,-7vh,0) scale(1.18)}}

/* tiles are panels: one hairline, one surface */
.t{padding:clamp(20px,2vw,28px);border:1px solid var(--line);border-radius:var(--r);
   background:var(--s1);
   box-shadow:inset 0 1px 0 var(--edge), 0 1px 2px rgba(0,0,0,.04), 0 8px 24px -18px rgba(0,0,0,.35)}
:root[data-theme="light"] .t,
:root[data-theme="light"] .t.flush,
:root[data-theme="light"] .lab-wrap,
:root[data-theme="light"] .skills-shell,
:root[data-theme="light"] .ledger{
  box-shadow:0 1px 2px rgba(12,12,13,.05), 0 14px 30px -22px rgba(12,12,13,.32)}
@media (prefers-color-scheme:light){
  :root:not([data-theme="dark"]) .t,
  :root:not([data-theme="dark"]) .t.flush,
  :root:not([data-theme="dark"]) .lab-wrap,
  :root:not([data-theme="dark"]) .skills-shell,
  :root:not([data-theme="dark"]) .ledger{
    box-shadow:0 1px 2px rgba(12,12,13,.05), 0 14px 30px -22px rgba(12,12,13,.32)}
}
.t:hover{border-color:var(--line-strong)}
.t.fill{background:var(--s2)}
/* the posture card is twice the height of a figure tile, so it spans both
   rows and the four figures sit beside it as a tidy 2x2 rather than
   stretching into mostly-empty panels */
/* The card used to span two grid rows with nothing ever placed in the second
   one, so half the width of that row was empty. It takes its natural height
   now and the figures beside it fill the row with it. */
.posture-card{grid-row:auto}
.t.quiet{background:transparent;border-color:transparent;padding-inline:0}
.bento{--tgap:clamp(14px,1.5vw,20px);row-gap:clamp(14px,1.5vw,20px)}

/* a work card: a real panel that lifts and takes the accent edge on hover */
a.t.link{position:relative;
  transition:border-color .22s,background .22s,transform .22s var(--ease)}
a.t.link:hover{border-color:var(--accent);background:var(--s2);transform:translateY(-2px)}
a.t.link h3{font-size:clamp(1.25rem,1.9vw,1.6rem);line-height:1.1;transition:color .22s;
  margin-top:10px}
a.t.link:hover h3{color:var(--accent)}
.t-k{color:var(--accent)}
.t-go{color:var(--ink-3)}

/* figures: big numerals inside their panel */
.t.stat{min-height:0;justify-content:center}
.t.stat b{font-size:clamp(1.9rem,3.8vw,3rem);font-weight:700;letter-spacing:-.04em;line-height:1}
.t.stat span{margin-top:7px;font-family:var(--mono);font-size:.78rem;
             letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3)}

/* the panels that still need a surface keep one, quietly */
.t.flush,.lab-wrap,.skills-shell{border:1px solid var(--line);border-radius:var(--r);
                                 background:var(--s1);overflow:hidden}
.t.gl{border-top:1px solid var(--line);padding-top:16px}

/* section labels */
.lbl{font-size:.81rem;letter-spacing:.2em;color:var(--ink-3)}
.lbl .idx{color:var(--accent)}

/* the hero */
.intro .display{font-size:clamp(2.6rem,9vw,8rem)}
.intro .role{color:var(--accent)}
.btn-primary{background:var(--accent);color:var(--on-accent);border:0}
.btn-primary:hover{filter:brightness(1.08)}
.proof .proof-list li::before{color:var(--accent)}
.proof h4{font-family:var(--display);font-size:1rem}

/* entrance: reveal rises rather than only fading */
html.js [data-anim]{opacity:0;transform:translateY(18px);
                    transition:opacity .6s var(--ease),transform .6s var(--ease)}
html.js [data-anim].in{opacity:1;transform:none}
html.js [data-anim][data-d="1"]{transition-delay:.06s}
html.js [data-anim][data-d="2"]{transition-delay:.12s}
html.js [data-anim][data-d="3"]{transition-delay:.18s}
html.js [data-anim][data-d="4"]{transition-delay:.24s}
@media (prefers-reduced-motion:reduce){
  .bg .blob{animation:none}
  html.js [data-anim]{opacity:1;transform:none;transition:none}
}

/* the name: two masked lines, the surname carrying the accent gradient */
.intro .display .ln{display:block;overflow:hidden}
.intro .display em{font-style:normal;
  background:var(--ink);
  -webkit-background-clip:text;background-clip:text;color:transparent}
html.js .intro .display .ln > *,
html.js .intro .display .ln{will-change:transform}
html.js .intro .display em{display:block;transform:translateY(105%);
  animation:wipe .95s var(--ease) .08s forwards}
html.js .intro .display .ln:first-child{--_d:0s}
@keyframes wipe{to{transform:translateY(0)}}

/* tighter hero rhythm now that the boxes are gone */

.intro{gap:0}
.intro .display{margin:10px 0 0}
.intro .role{margin-top:12px}
.intro .lede{margin-top:12px}
.intro .cta{margin-top:18px}
.intro .socials{margin-top:14px}
.hero .bento{row-gap:clamp(20px,3vw,36px)}

/* figures cycle through the four accents by their own order */
.t.stat b{color:var(--ink)}

/* ==========================================================================
   ACCESSIBILITY PASS
   Token contrast measured against each theme's own surface, not eyeballed:
   --ink-3 was 3.71:1 on dark and 3.75:1 on light, and all three light-mode
   accents sat between 3.48 and 4.24:1. Every one now clears WCAG AA 4.5:1
   for normal text.
   ========================================================================== */

/* No mono label below 12px. The depth switch was rendering at 9.9px, which
   is under the body-text floor regardless of how decorative it looks. */
.depth-btn{font-size:.75rem}
.kbtn kbd{font-size:.83rem}
.rail i{font-size:.83rem}

/* A focus ring on every operable control, including the ones inside the
   palette dialog - the rule is "every", and a custom cursor is no substitute. */
a:focus-visible,button:focus-visible,summary:focus-visible,
input:focus-visible,textarea:focus-visible,select:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible{
  outline:2px solid var(--accent);outline-offset:3px;border-radius:3px}
/* These three explicitly cleared their outline; keyboard users still need one. */
#probe:focus-visible,.palette-input input:focus-visible,.fig .bar:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px}
.palette a:focus-visible,.palette button:focus-visible,
.palette input:focus-visible{outline-color:var(--accent)}

/* Adjacent targets keep an 8px gap so neighbours are not mis-tapped. */
.socials{gap:10px}
.cta{gap:12px}

/* The skip link has to be readable the moment it is focused. */
.skip-link:focus{background:var(--accent);color:var(--on-accent);outline:2px solid var(--ink)}

/* Every accent-filled control takes the per-theme on-accent ink. */
.btn-primary{background:var(--accent);color:var(--on-accent);border:0}
.btn-primary:hover{filter:brightness(1.08)}
.depth-btn .df,html[data-depth="quick"] .depth-btn .dq{color:var(--on-accent)}
.skip-link,.skip-link:focus{background:var(--accent);color:var(--on-accent)}

/* Mono labels sit on raised panels, not the page, where --ink-3 measured
   4.36:1. On a panel they use the brighter ink. */
.panel-bar .mono,.kbtn kbd,.lab-note{color:var(--ink-2)}

/* WCAG 2.2 Target Size: every control at least 24px tall. Three inline links
   sat at 16-19px - tall enough to read, too short to hit reliably. Padding
   rather than font-size, so nothing reflows around them. */
.lab-note a,.fig-table summary,.tl-card a{display:inline-block;padding-block:4px;min-height:24px}
.fig-table summary{padding-block:5px}

/* ==========================================================================
   CERTIFICATE GALLERY + LIGHTBOX
   An editorial grid rather than equal cards: tiles span one or two columns
   by position, so the rhythm varies without the data having to describe it.
   Images are contained, never cropped - a cropped certificate loses the
   text that makes it worth showing.
   ========================================================================== */
.cert-filters{display:flex;flex-wrap:wrap;gap:7px;margin:0 0 16px}
.cert-filter{padding:6px 13px;min-height:32px;border:1px solid var(--line);border-radius:100px;
             background:transparent;color:var(--ink-3);font-family:var(--mono);font-size:.79rem;
             letter-spacing:.04em;transition:color .2s,border-color .2s,background .2s}
.cert-filter:hover{color:var(--ink);border-color:var(--line-2)}
.cert-filter.on{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}

.cert-shots{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:14px;margin-top:4px}
.cert-shot{grid-column:span 2;display:flex;flex-direction:column;
           border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--s1);
           transition:border-color .22s,transform .22s var(--ease)}
/* a varied but deterministic rhythm: every fourth tile is wider */
.cert-shot:nth-child(7n+1){grid-column:span 3}
.cert-shot:nth-child(7n+4){grid-column:span 3}
.cert-shot:hover{border-color:var(--accent);transform:translateY(-3px)}
.cert-shot img{display:block;width:100%;aspect-ratio:4/3;object-fit:contain;
               background:var(--s2);padding:10px}
.cert-pdf{display:grid;place-items:center;width:100%;aspect-ratio:4/3;background:var(--s2);
          font-family:var(--mono);font-size:.81rem;color:var(--ink-3)}
.cert-none{display:grid;place-items:center;gap:8px;width:100%;aspect-ratio:4/3;background:var(--s2)}
.cert-none-mark{display:grid;place-items:center;width:42px;height:42px;border-radius:10px;
                border:1px solid var(--line-2);font-family:var(--display);font-size:1.2rem;color:var(--ink-3)}
.cert-none-txt{font-family:var(--mono);font-size:.75rem;color:var(--ink-3)}
.cert-meta{display:block;padding:11px 13px;border-top:1px solid var(--line)}
.cert-meta b{display:block;font-size:.86rem;color:var(--ink);line-height:1.35}
.cert-meta span{display:block;margin-top:3px;font-family:var(--mono);font-size:.78rem;color:var(--ink-3)}
.cert-wip{display:inline-block;margin-top:6px;font-family:var(--mono);font-size:.75rem;font-style:normal;
          color:var(--warn);border:1px solid currentColor;border-radius:4px;padding:1px 6px}
.cert-empty{margin-top:4px;font-size:.84rem;color:var(--ink-3)}

/* --- lightbox --- */
.cert-box{position:fixed;inset:0;z-index:300;display:grid;place-items:center;padding:clamp(12px,3vw,40px);
          background:rgba(6,4,14,.82);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.cert-box[hidden]{display:none}
.cb-panel{position:relative;display:grid;grid-template-columns:minmax(0,1.6fr) minmax(260px,.9fr);
          gap:0;width:min(1100px,100%);max-height:88vh;overflow:hidden;
          border:1px solid var(--line-2);border-radius:16px;background:var(--s1)}
.cb-figure{display:grid;place-items:center;gap:14px;padding:clamp(14px,2vw,26px);background:var(--s2);min-height:0}
.cb-figure img{max-width:100%;max-height:74vh;object-fit:contain;border-radius:6px}
.cb-pdf{width:100%;height:70vh;border:0;border-radius:6px;background:#fff}
.cb-none{font-family:var(--mono);font-size:.76rem;color:var(--ink-3)}
.cb-info{display:flex;flex-direction:column;padding:clamp(18px,2.4vw,28px);min-width:0;overflow-y:auto}
.cb-title{font-family:var(--display);font-size:clamp(1.1rem,2vw,1.5rem);line-height:1.2;margin:0}
.cb-sub{margin:7px 0 0;font-family:var(--mono);font-size:.83rem;color:var(--ink-3)}
.cb-extra{display:flex;flex-direction:column;align-items:flex-start;gap:12px;margin-top:18px}
.cb-id{display:flex;flex-wrap:wrap;align-items:center;gap:9px;margin:0;font-size:.76rem;color:var(--ink-3)}
.cb-id code{font-family:var(--mono);font-size:.85rem;color:var(--ink);
            padding:3px 8px;border:1px solid var(--line);border-radius:5px}
.cb-copy{min-height:28px;padding:3px 10px;border:1px solid var(--line);border-radius:5px;
         background:transparent;color:var(--ink-2);font-family:var(--mono);font-size:.78rem}
.cb-copy:hover{border-color:var(--accent);color:var(--accent)}
.cb-nav{display:flex;align-items:center;gap:12px;margin-top:auto;padding-top:20px}
.cb-prev,.cb-next,.cb-close{display:grid;place-items:center;width:36px;height:36px;
        border:1px solid var(--line);border-radius:9px;background:transparent;color:var(--ink-2);transition:color .2s,background-color .2s,border-color .2s}
.cb-prev:hover,.cb-next:hover,.cb-close:hover{border-color:var(--accent);color:var(--accent)}
.cb-prev:disabled,.cb-next:disabled{opacity:.35}
.cb-close{position:absolute;top:10px;right:10px;z-index:2;background:var(--s1)}
.cb-count{font-family:var(--mono);font-size:.79rem;color:var(--ink-3)}

@media (max-width:860px){
  .cert-shots{grid-template-columns:repeat(2,minmax(0,1fr))}
  .cert-shot,.cert-shot:nth-child(7n+1),.cert-shot:nth-child(7n+4){grid-column:span 1}
  .cb-panel{grid-template-columns:1fr;max-height:92vh}
  .cb-figure img{max-height:44vh}
  .cb-pdf{height:44vh}
}
@media (max-width:420px){.cert-shots{grid-template-columns:1fr}}

/* ---------- brand mark ---------- */
.brand-mark{display:grid;place-items:center;width:32px;height:32px;color:var(--on-accent);
            border:1px solid var(--line);border-radius:8px;transition:border-color .22s,color .22s}
.brand:hover .brand-mark{border-color:var(--accent);color:var(--accent)}

/* ---------- about ---------- */
.about-lead{font-size:clamp(1rem,1.5vw,1.16rem);color:var(--ink);line-height:1.6}
#about .t > p{margin-top:14px;max-width:62ch}
.about-list{margin:4px 0 0;padding:0;list-style:none}
.about-list li{display:grid;grid-template-columns:96px minmax(0,1fr);gap:14px;
               padding:13px 0;border-top:1px solid var(--line);align-items:baseline}
.about-list li:first-child{border-top:0;padding-top:0}
.about-list b{font-family:var(--mono);font-size:.78rem;letter-spacing:.09em;
              text-transform:uppercase;color:var(--accent);font-weight:500}
.about-list span{font-size:.86rem;color:var(--ink-2);line-height:1.55}
@media (max-width:560px){.about-list li{grid-template-columns:1fr;gap:4px}}

/* --ink-3 measures 4.07-4.36:1 on a raised panel rather than on the page.
   Anything sitting on --s1/--s2 takes the brighter ink. */
.cert-meta span,.cert-none-txt,.cert-pdf{color:var(--ink-2)}

/* ==========================================================================
   FEATURED CASE STUDY
   One project gets editorial weight rather than a fifth identical card.
   The pipeline figure is the repository's own architecture, drawn rather
   than described — five detectors, a risk engine feeding a policy engine,
   five decisions.
   ========================================================================== */
/* the featured card is a panel like the rest: .t draws its hairline on all
   four sides, so it needs inline padding too - without it the copy sat
   flush against the border. */
.feature{padding:clamp(26px,3vw,40px) clamp(22px,2.6vw,40px)}
.feat-head{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:20px}
.feature .feat-title{font-family:var(--display);font-size:clamp(2rem,5vw,3.4rem);font-weight:700;
            letter-spacing:-.04em;line-height:1;margin:10px 0 0}
.feat-thesis{margin:14px 0 0;max-width:62ch;font-size:clamp(.95rem,1.3vw,1.08rem);
             color:var(--ink-2);line-height:1.6}
.feat-cta{flex:none}
.feat-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
           gap:clamp(20px,3vw,48px);margin-top:clamp(24px,3vw,38px)}
.feature .feat-col h4,.feature .feat-ev h4{font-family:var(--mono);font-size:.78rem;letter-spacing:.14em;
                         text-transform:uppercase;color:var(--accent);margin:0 0 9px}
.feat-col p{margin:0;font-size:.9rem;color:var(--ink-2);line-height:1.65}

/* --- pipeline figure --- */
.pipe{margin:clamp(26px,3.4vw,44px) 0 0}
.pipe-cap{margin:0 0 14px;font-size:.82rem;color:var(--ink-3);max-width:70ch}
.pipe-svg{display:block;width:100%;height:auto;overflow:visible}
.pipe-svg .pn rect{fill:var(--s1);stroke:var(--line-2);stroke-width:1}
.pipe-svg .pn text{fill:var(--ink);font-family:var(--sans);font-size:13px;
                   font-weight:500;text-anchor:middle}
.pipe-svg .pn text.sm{fill:var(--ink-2);font-family:var(--mono);font-size:11.5px;font-weight:400}
.pipe-svg .pn-out rect{stroke:var(--accent)}
.pipe-svg .pn-out text{fill:var(--ink)}
.pipe-svg .pn-out text.sm{fill:var(--accent)}
.pipe-svg .pe path{fill:none;stroke:var(--line-2);stroke-width:1.5}
.pipe-svg .pe-dim path{stroke-dasharray:3 3;opacity:.8}
.pipe-svg .pe-lab{fill:var(--ink-3);font-family:var(--mono);font-size:11px}
/* the figure is a wide diagram; on narrow screens it scrolls rather than
   shrinking its labels below legibility */
@media (max-width:900px){
  .feat-grid{grid-template-columns:1fr}
  .pipe{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .pipe-svg{min-width:760px}
}

/* --- evidence --- */
.feat-ev{margin-top:clamp(26px,3.4vw,44px);padding-top:clamp(20px,2.4vw,30px);
         border-top:1px solid var(--line)}
.ev-rows{display:flex;flex-wrap:wrap;gap:clamp(22px,4vw,64px);margin:0;padding:0;list-style:none}
.ev-rows b{display:block;font-family:var(--display);font-size:clamp(1.5rem,3vw,2.2rem);
           font-weight:700;letter-spacing:-.035em;line-height:1}
.ev-rows li b{color:var(--ink)}
.ev-rows li:nth-child(2) b{color:var(--accent)}
.ev-rows li:nth-child(2) b{color:var(--accent)}

.ev-rows span{display:block;margin-top:6px;font-family:var(--mono);font-size:.78rem;
              letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.ev-note{margin:20px 0 0;max-width:78ch;font-size:.86rem;color:var(--ink-2);line-height:1.65}

/* the hero figure now carries two numbers */
.ring-mid .slash{color:var(--ink-3);font-weight:400}
.ring-mid .u{font-size:.6em}

/* --- project cards: enough substance to judge the work from the card --- */
.p-pts{margin:14px 0 0;padding:0;list-style:none;display:grid;gap:7px}
.p-pts li{position:relative;padding-left:16px;font-size:.82rem;line-height:1.5;color:var(--ink-2)}
.p-pts li::before{content:"";position:absolute;left:0;top:.62em;width:6px;height:1px;
  background:var(--accent)}
/* a fixed three-up keeps the figures on one line in every card, so the cards
   line up instead of one of them wrapping to a second row */
.pcard .t-m{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;
  margin-top:16px;padding-top:14px;border-top:1px solid var(--line)}
.pcard .t-m span{display:block;line-height:1.35}
.pcard .t-s{margin-top:14px}
/* the cards are equal height, so the foot of each - figures, stack, link -
   is pushed down as one block. That lines the three figure rows up with each
   other instead of letting a card with one extra line of copy drift. */
.pcard .p-pts{margin-bottom:auto;padding-bottom:16px}
.pcard .t-go{margin-top:0;padding-top:16px}
.sub-head{margin:clamp(12px,1.6vw,22px) 0 0;font-family:var(--mono);font-size:.78rem;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.scard h4{margin-top:8px;font-size:1rem;letter-spacing:-.01em}
.scard > p{margin-top:8px;font-size:.82rem;color:var(--ink-3);line-height:1.5}
.scard .t-go{margin-top:auto;padding-top:14px}
@media (max-width:1100px){
  .pcard{grid-column:span 6}
  .scard{grid-column:span 6}
}
@media (max-width:720px){
  .pcard,.scard{grid-column:span 12}
}

/* the card carries no padding of its own so the plate can reach the edge;
   the body and foot bring their own */
.cert-card{gap:0;position:relative;padding:0;overflow:hidden}
.cert-card.has-shot{cursor:pointer}
.cert-card .cert-body,.cert-card .cert-foot,.cert-card .cert-verify{
  padding-inline:clamp(16px,1.5vw,20px)}
.cert-card .cert-body{padding-top:clamp(14px,1.3vw,18px)}
.cert-card .cert-foot{padding-bottom:clamp(14px,1.3vw,18px)}
.cert-plate{display:grid;place-items:center;aspect-ratio:16/10;
  border-bottom:1px solid var(--line);background:var(--accent-dim);overflow:hidden}
.cert-plate b{font-family:var(--mono);font-size:clamp(1.4rem,2.4vw,2rem);font-weight:600;
  letter-spacing:.02em;color:var(--accent)}
.cert-plate img{width:100%;height:100%;object-fit:contain;background:var(--s2)}
.cert-card .cert-body h4{font-size:1rem;letter-spacing:-.01em;line-height:1.25}
.cert-card .cert-body p{margin-top:5px;font-size:.82rem;color:var(--ink-3)}
.cert-foot{display:flex;align-items:center;justify-content:flex-end;gap:12px;
  margin-top:auto;padding-top:14px}
.cert-foot .cy{margin-right:auto;font-size:.81rem;color:var(--ink-3);letter-spacing:.04em}
.cert-foot .cy:empty{display:none}
.cs{font-family:var(--mono);font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;
  padding:3px 9px;border-radius:100px;border:1px solid currentColor}
.cs.ok{color:var(--good)}
.cs.wip{color:var(--warn)}
.cert-card.prog .cert-plate{background:color-mix(in srgb,var(--warn) 12%,transparent)}
.cert-card.prog .cert-plate b{color:var(--warn)}
.cert-verify{margin-top:12px;font-family:var(--mono);font-size:.79rem;color:var(--accent);
  border-bottom:1px solid currentColor;align-self:flex-start}
.cert-card.has-shot:hover{border-color:var(--accent);transform:translateY(-2px)}
.cert-card{transition:border-color .22s,transform .22s var(--ease)}
.cert-note{max-width:var(--maxw);margin:clamp(14px,1.8vw,22px) auto 0;
  font-family:var(--mono);font-size:.79rem;color:var(--ink-3)}
@media (max-width:1000px){.cert-card{grid-column:span 6}}
@media (max-width:640px){.cert-card{grid-column:span 12}}

/* ==========================================================================
   Interaction layer
   Pointer-driven, rAF-throttled, pointer devices only, and every value falls
   back to a resting default so nothing is stuck mid-gesture.
   ========================================================================== */
.t.link,.cert-card,.t.feature{--mx:50%;--my:50%;--rx:0deg;--ry:0deg}
.btn,.icon-btn,.kbtn,.lang-btn,.socials a,.to-top{--tx:0px;--ty:0px}

/* the light follows the pointer across the card */
.t.link::after,.cert-card.has-shot::after,.t.feature::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  opacity:0;transition:opacity .3s;z-index:0;
  background:radial-gradient(300px circle at var(--mx) var(--my),
             color-mix(in srgb,var(--accent) 18%,transparent), transparent 60%)}
.t.link:hover::after,.cert-card.has-shot:hover::after,.t.feature:hover::after{opacity:1}
.t.link,.cert-card,.t.feature{position:relative;isolation:isolate}
.t.link > *,.cert-card > *,.t.feature > *{position:relative;z-index:1}

/* a slight tilt toward the pointer */
html.fx .t.link,html.fx .cert-card.has-shot{
  transform:perspective(900px) rotateX(var(--rx)) rotateY(var(--ry));
  transition:transform .35s var(--ease),border-color .22s,box-shadow .35s}
html.fx .t.link:hover,html.fx .cert-card.has-shot:hover{
  box-shadow:inset 0 1px 0 var(--edge), 0 18px 44px -22px rgba(0,0,0,.55)}

/* buttons lean toward the cursor before it arrives */
html.fx .btn,html.fx .icon-btn,html.fx .kbtn,html.fx .lang-btn,
html.fx .socials a,html.fx .to-top{
  transform:translate3d(var(--tx),var(--ty),0);
  transition:transform .28s var(--ease),color .18s,background-color .18s,border-color .18s}



/* frosted, over real content. The nav re-blurs on every scroll frame because
   what is behind it moves. Measured over five runs each: blur(14px) with
   saturate() drops a median of 2 frames and up to 7; blur(8px) drops 1; none
   drops 0. 8px still reads as glass, so that is what it keeps. */
.nav{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
/* Overlays lock the page behind them, so nothing moves under the blur and a
   wider radius is free here. */
.cert-box{backdrop-filter:blur(18px) saturate(130%);-webkit-backdrop-filter:blur(18px) saturate(130%)}
.palette{backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}

.hs-portrait{transition:transform .6s var(--ease)}
@media (hover:hover){.hs-portrait:hover{transform:translateY(-6px) scale(1.012)}}

@media (prefers-reduced-motion:reduce){
  .t.link::after,.cert-card.has-shot::after,.t.feature::after{display:none}
  html.fx body::after{display:none}
  html.fx .t.link,html.fx .cert-card.has-shot,html.fx .btn,html.fx .icon-btn,
  html.fx .kbtn,html.fx .lang-btn,html.fx .socials a,html.fx .to-top,
  .hs-portrait{transform:none!important;transition:none}
  .hs-portrait:hover{transform:none}
}


/* Depth, re-added only after the compositing problem above was fixed, and
   measured again with it in place. A fine grid that fades out top and bottom,
   painted once into the fixed background layer. */
.bg::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to bottom, var(--bg), transparent 18%, transparent 74%, var(--bg)),
    linear-gradient(var(--grid-line) 1px, transparent 1px) 0 0/78px 78px,
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px) 0 0/78px 78px}
:root{--grid-line:rgba(255,255,255,.030)}
:root[data-theme="light"]{--grid-line:rgba(12,12,13,.020)}

/* A light that follows the cursor. A gradient painted at a moving position
   repaints the viewport every frame; this is a fixed-size layer that is
   translated, so it is rasterised once and each move is a composite. */
.cursor-glow{position:fixed;top:0;left:0;width:720px;height:720px;margin:-360px 0 0 -360px;
  z-index:0;pointer-events:none;opacity:0;will-change:transform;
  transform:translate3d(-999px,-999px,0);transition:opacity .5s;
  background:radial-gradient(closest-side,
    color-mix(in srgb,var(--accent) 10%,transparent), transparent 70%)}
html.fx .cursor-glow{opacity:1}
@media (prefers-reduced-motion:reduce){.cursor-glow{display:none}}

/* --- credentials: cards. The scan is the point of a credential card, so it
   gets the top of the card at a readable size instead of an 88px chip; the
   whole card opens the same zoom dialog the badges use. --- */
.crows{list-style:none;margin:10px 0 0;padding:0;
  display:grid;gap:clamp(14px,1.6vw,20px);
  grid-template-columns:repeat(auto-fill,minmax(min(100%,300px),1fr))}
.ccard{position:relative;display:grid;grid-template-rows:auto 1fr;min-width:0;
  border:1px solid var(--line);border-radius:calc(var(--r) + 5px);background:var(--s1);
  overflow:hidden;
  box-shadow:inset 0 1px 0 var(--edge), 0 1px 2px rgba(0,0,0,.05), 0 12px 28px -22px rgba(0,0,0,.5);
  transition:border-color .22s,transform .22s var(--ease),box-shadow .22s}
.ccard:hover,.ccard:focus-within{border-color:var(--line-2);transform:translateY(-3px);
  box-shadow:inset 0 1px 0 var(--edge), 0 2px 4px rgba(0,0,0,.07), 0 20px 40px -24px rgba(0,0,0,.62)}
/* a certificate is a landscape document, so the slot it sits in is one too */
.cc-shot{position:relative;display:grid;place-items:center;aspect-ratio:16/10;
  background:var(--s2);border-bottom:1px solid var(--line);overflow:hidden;
  font-family:var(--mono);font-size:1.5rem;font-weight:600;letter-spacing:.08em;color:var(--ink-3)}
/* Absolutely positioned, because height:100% cannot resolve against a box
   sized by aspect-ratio: it falls back to the image's own ratio, overflows
   the slot and is clipped, which looks exactly like object-fit:cover. */
.cc-shot img{position:absolute;inset:0;width:100%;height:100%;display:block;
  transition:transform .45s var(--ease)}
/* A certificate is a document, and the point of showing it is that it can be
   read as one — cropping to fill the slot cuts the signature line off the
   bottom. It is contained whole, on the deeper surface so the paper edge
   still reads against the card. */
.cc-shot.is-scan img{object-fit:contain;padding:8px}
.cc-shot.is-badge{background:var(--s1)}
.cc-shot.is-badge img{object-fit:contain;padding:14px}
.ccard:hover .cc-shot img,.ccard:focus-within .cc-shot img{transform:scale(1.035)}
/* the zoom cue: always faintly present so the card reads as openable on a
   touch screen too, and it brightens on hover rather than appearing */
.cc-zoom{position:absolute;right:9px;bottom:9px;display:grid;place-items:center;
  width:28px;height:28px;border-radius:50%;
  background:color-mix(in srgb,var(--bg) 72%,transparent);
  border:1px solid var(--line);color:var(--ink-2);opacity:.75;
  transition:opacity .2s,background .2s,border-color .2s,color .2s}
.ccard:hover .cc-zoom,.ccard:focus-within .cc-zoom{opacity:1;color:var(--on-accent);
  background:var(--accent);border-color:var(--accent)}
.cc-body{display:grid;align-content:start;gap:3px;padding:13px 14px 12px}
.cc-title{display:block;font-size:.95rem;font-weight:600;letter-spacing:-.01em;line-height:1.3;
  color:var(--ink);transition:color .2s}
/* The card's hit area is a bare button laid over the whole card, so the
   target is the card itself and not a 20px line of text. It carries the
   credential's name as its label, and the verify chip sits above it. */
.cc-open{position:absolute;inset:0;z-index:0;cursor:pointer;
  border:0;padding:0;background:none;border-radius:inherit;appearance:none}
.ccard:hover .cc-title,.ccard:focus-within .cc-title{color:var(--accent)}
.cc-open:focus-visible{outline:2px solid var(--accent);outline-offset:-3px}
.cc-issuer{font-size:.79rem;color:var(--ink-2)}
/* issued / number / expiry, in the mono face so the id reads as an id */
.cc-facts{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:5px;
  font-family:var(--mono);font-size:.76rem;letter-spacing:.02em;color:var(--ink-3)}
.cc-facts .sep{font-style:normal;opacity:.5}
.cc-foot{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px}
/* the chip is also a 24px tap target when it is a verification link, and it
   sits above the card button so it can still be clicked on its own */
.cplat{position:relative;z-index:1;display:inline-flex;align-items:center;min-height:24px;
  font-family:var(--mono);font-size:.75rem;letter-spacing:.06em;color:var(--ink-3);
  border:1px solid var(--line);border-radius:100px;padding:2px 10px;white-space:nowrap}
a.cplat.is-link{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 40%,transparent)}
a.cplat.is-link:hover{background:var(--accent-dim);border-color:var(--accent)}
.cplat-none{display:none}
/* status reads by icon and word, not by colour alone. "Earned" is the
   resting state of a credentials list, so it reads as a check and the word
   goes to screen readers only; the pill is spent on the exception. */
.cs{display:inline-flex;align-items:center;gap:5px;font-family:var(--mono);font-size:.75rem;
  letter-spacing:.06em;text-transform:uppercase;white-space:nowrap;margin-left:auto}
.cs i{font-style:normal;font-size:.83rem;line-height:1}
.cs.ok{color:var(--good);border:0;background:none;padding:0;min-height:24px}
.cs.ok > span{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}
.cs.ok i{font-size:.95rem;line-height:1}
.cs.wip{color:var(--warn)}
.cert-note{margin-top:16px;font-family:var(--mono);font-size:.78rem;color:var(--ink-3)}

/* ---------- credentials: badge wall, ledger, platforms ---------- */

/* Badges are issued in their own shapes — hexagon, shield, disc — so they
   are never plated, cropped or forced square. The tile is a square box and
   the artwork is contained inside it at whatever aspect it really has. */
.bwall-wrap{margin-bottom:clamp(14px,1.6vw,20px)}
.bwall-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:12px;margin-bottom:14px}
.bwall{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));
  gap:clamp(16px,1.8vw,24px);margin:0;padding:0;list-style:none}
/* titles run to three or four lines, so the tiles take a common height
   and pack their content to the top rather than ending ragged */
.bwall li{min-width:0;display:grid}
/* No plate. A badge is minted as a hexagon, a shield or a disc, and a card
   drawn around it hides the one thing that identifies it on sight. Without
   the box the silhouette is the tile, so the lift and the title carry the
   hover instead of a border. */
/* artwork, then a title that takes whatever height it needs, then the issuer
   pinned to the bottom row — without the plate to square them off, a ragged
   last line is the thing the eye catches */
.bwall .btile{display:grid;grid-template-rows:auto 1fr auto;justify-items:center;gap:10px;
  height:100%;padding:4px 2px 2px;text-align:center;border-radius:var(--r);
  transition:transform .25s var(--ease)}
.bwall a.btile:hover,.bwall a.btile:focus-visible{transform:translateY(-3px)}
.bwall .bart{position:relative;display:block;
  width:clamp(74px,7.2vw,98px);height:clamp(74px,7.2vw,98px)}
.bwall .bart img{display:block;width:100%;height:100%;object-fit:contain;
  filter:drop-shadow(0 4px 9px rgba(0,0,0,.42))}
/* The gleam is masked with the artwork itself, at the same size and position
   the image is laid out with, so it travels across the badge and stops at its
   real edge rather than sweeping a square. */
.bwall .bshine{position:absolute;inset:0;pointer-events:none;
  -webkit-mask-image:var(--art);mask-image:var(--art);
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  background:linear-gradient(104deg,transparent 41%,rgba(255,255,255,.80) 50%,transparent 59%);
  background-size:260% 100%;background-position:170% 0;opacity:0}
/* one pass as the wall appears, then again on hover or keyboard focus */
.bwall .btile.cert-enter .bshine{opacity:1;
  animation:bsheenIn 1.15s var(--ease) both;
  animation-delay:calc(var(--stagger,0ms) + 300ms)}
.bwall a.btile:hover .bshine,.bwall a.btile:focus-visible .bshine{
  opacity:1;animation:bsheen .95s var(--ease)}
@keyframes bsheen{from{background-position:170% 0}to{background-position:-70% 0}}
@keyframes bsheenIn{from{background-position:170% 0}to{background-position:-70% 0}}
@media (prefers-reduced-motion:reduce){.bwall .bshine{display:none}}
.bwall .btile b{display:block;font-size:.76rem;font-weight:600;line-height:1.28;letter-spacing:-.01em;
  overflow-wrap:anywhere}
.bwall .btile span{display:block;font-family:var(--mono);font-size:.75rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3)}
.bwall a.btile:hover b,.bwall a.btile:focus-visible b{color:var(--accent)}
/* on paper the dark lift reads as grime under the artwork, so the badge keeps
   a shadow but a much lighter one — same split the panels already use */
:root[data-theme="light"] .bwall .bart img{
  filter:drop-shadow(0 3px 8px rgba(12,12,13,.22))}
@media (prefers-color-scheme:light){
  :root:not([data-theme="dark"]) .bwall .bart img{
    filter:drop-shadow(0 3px 8px rgba(12,12,13,.22))}
}

/* The monogram plate. Only the CTF cards still use it now that credentials
   are cards, but it keeps its own base so those marks do not depend on a
   rule that belongs to another component. */
.cmark{display:grid;place-items:center;border-radius:7px;overflow:hidden;
  background:var(--s2);border:1px solid var(--line);color:var(--ink-3);
  font-family:var(--mono);font-size:.8rem;font-weight:600;letter-spacing:.06em}

/* platforms: two panels, each with its figures and the issuer's own badge */
.plat-band{margin-top:clamp(14px,1.6vw,20px)}
.ctf-list{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));
  gap:var(--tgap,14px);grid-column:1/-1}
.ctf{gap:0}
.ctf-top{display:flex;align-items:center;gap:13px;margin-bottom:14px}
.ctf-top .cmark{width:52px;height:52px;font-size:.76rem;
  background:var(--accent-dim);border-color:transparent;color:var(--accent)}
.ctf-top > b{font-size:1.02rem;font-weight:600;letter-spacing:-.01em;transition:color .2s}
.ctf > p{margin:12px 0 0;font-size:.85rem;color:var(--ink-3);line-height:1.55}
/* TryHackMe mints this strip at 249px and no larger, so displaying it at
   249 CSS px is exactly 1x — half-resolution on a 2x screen. Held to 168px
   it has 1.48x device pixels to draw with and reads sharp. */
.ctf-live{display:block;width:168px;max-width:100%;height:auto;margin-top:16px;
  border:1px solid var(--line);border-radius:6px}
.plat-note{margin-top:14px;font-family:var(--mono);font-size:.76rem;letter-spacing:.06em;
  color:var(--ink-3);grid-column:1/-1}
@media (max-width:760px){
  .ctf-list{grid-template-columns:1fr}
  .ctf{grid-column:1/-1}
}

/* --- CTF & labs --- */
/* the two platforms sit centred in their panel rather than stacked at the
   top with the leftover height pooling underneath */
.ctf-list{display:grid;gap:0;margin-top:6px;flex:1;align-content:center}

.ctf-body > b{display:block;font-size:.94rem;font-weight:600;letter-spacing:-.01em}
.ctf-body > p{margin-top:6px;font-size:.8rem;color:var(--ink-3);line-height:1.5}
.ctf-stats{display:flex;flex-wrap:wrap;gap:20px;margin:9px 0 0;padding:0;list-style:none}
.ctf-stats b{display:block;font-family:var(--mono);font-size:1.05rem;font-weight:600;
  letter-spacing:-.02em;color:var(--ink)}
.ctf-stats span{font-size:.79rem;color:var(--ink-3)}
/* a platform with a profile is the whole card, so the hit area is the row
   rather than a small link at the end of it */
a.ctf{color:inherit;transition:background .2s}
a.ctf:hover{background:var(--s2)}
a.ctf:hover .ctf-body > b{color:var(--accent)}
.ctf-body > b{transition:color .2s}
.ctf-handle{margin-left:8px;font-family:var(--mono);font-size:.79rem;font-weight:400;
  letter-spacing:.02em;color:var(--ink-3)}
.ctf-go{display:inline-flex;align-items:center;gap:5px;margin-top:10px;
  font-family:var(--mono);font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);transition:color .2s}
.ctf-go::after{content:"\2197"}
a.ctf:hover .ctf-go{color:var(--accent)}
a.ctf:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r)}

/* the badge wall the Credly rows verify against */
.cert-wall{display:inline-flex;align-self:flex-start;align-items:center;gap:7px;margin-top:14px;
  padding:7px 13px;border:1px solid var(--line-2);border-radius:var(--r);
  font-family:var(--mono);font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-2);transition:color .2s,border-color .2s,background-color .2s}
.cert-wall:hover{color:var(--accent);border-color:var(--accent);background:var(--s2)}

@keyframes certIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.cert-enter{animation:certIn .45s var(--ease) both;animation-delay:var(--stagger,0ms)}
@media (prefers-reduced-motion:reduce){.cert-enter{animation:none}}
@media (max-width:560px){
  /* one card per row on a phone, and a shorter preview so the title and the
     facts are still above the fold of the card */
  .crows{grid-template-columns:1fr}
  .cc-shot{aspect-ratio:16/9}
}

/* =========================================================
   Highlights. One accent on near-black reads as plain, so the accent gets a
   second, cooler hue to run into: the hero word and the headline figures go
   periwinkle into cyan, section rules pick the accent up and fade it out, and
   the ambient light behind the page carries a little of both.
   Every gradient endpoint is solved against every surface it can land on —
   dark #9b9fff 8.19:1 and #5ce1e6 12.44:1, light #3237e0 6.86:1 and #0369a1
   5.34:1 — because the contrast gate skips text with a transparent fill and
   cannot check gradient text for itself.
   ========================================================= */
:root{--hi:#5ce1e6;--hi-dim:rgba(92,225,230,.12);
  --grad:linear-gradient(100deg,var(--accent) 0%,var(--hi) 100%);
  /* these still carried the previous accent's RGB */
  --glow-1:rgba(155,159,255,.20);--glow-2:rgba(92,225,230,.09);
  --wash-2:rgba(92,225,230,.06)}
:root[data-theme="light"]{--hi:#0369a1;--hi-dim:rgba(3,105,161,.10);
  --glow-1:rgba(50,55,224,.13);--glow-2:rgba(3,105,161,.07);--wash-2:rgba(3,105,161,.03)}
@media (prefers-color-scheme:light){:root:not([data-theme]){--hi:#0369a1;--hi-dim:rgba(3,105,161,.10);
  --glow-1:rgba(50,55,224,.13);--glow-2:rgba(3,105,161,.07);--wash-2:rgba(3,105,161,.03)}}

@supports ((-webkit-background-clip:text) or (background-clip:text)){
  /* fit-content, so the gradient spans the glyphs and not the empty column */
  .hs-code,.ring-mid strong,.t.stat b{width:fit-content;
    background:var(--grad);-webkit-background-clip:text;background-clip:text;
    -webkit-text-fill-color:transparent;color:transparent}
  .ring-mid .slash{-webkit-text-fill-color:var(--ink-3)}
}
/* Windows high-contrast drops backgrounds; a transparent fill would vanish */
@media (forced-colors:active){
  .hs-code,.ring-mid strong,.t.stat b{background:none;
    -webkit-text-fill-color:CanvasText;color:CanvasText}
}

/* The gradient sits on top of a solid accent fill, so anything measuring
   the label against its background measures it against the lower-contrast
   end of the gradient rather than against nothing. */
.btn-primary{background-color:var(--accent);background-image:var(--grad);border:0}
.btn-primary:hover{filter:brightness(1.07) saturate(1.06)}

/* section rules take the accent and let it fade, instead of a flat hairline */
.lbl::after{background:linear-gradient(90deg,
  color-mix(in srgb,var(--accent) 65%,transparent) 0%,
  color-mix(in srgb,var(--hi) 30%,transparent) 32%,
  var(--line) 58%, transparent 100%)}

/* work cards and credentials light up on hover rather than only lifting */
a.t.link:hover,.ccard:hover,.ccard:focus-within{
  box-shadow:inset 0 1px 0 var(--edge),
    0 0 0 1px color-mix(in srgb,var(--accent) 34%,transparent),
    0 24px 50px -30px color-mix(in srgb,var(--accent) 60%,transparent)}

/* ---- the status line: a compact pill, not a banner ----
   It was 12.6px uppercase mono at .1em tracking across a full-width band with
   a rule under it, which made the first thing under the nav the loudest. Sentence
   case in the text face, inside a pill tinted by the same green as its dot. */
.hero-top{border-bottom:0;padding-bottom:clamp(10px,1.2vw,16px);gap:10px 16px}
.hero-status{font-family:var(--sans);font-size:.78rem;font-weight:500;
  letter-spacing:0;text-transform:none;color:var(--ink);
  padding:5px 13px 5px 11px;border-radius:100px;
  border:1px solid color-mix(in srgb,var(--good) 34%,transparent);
  background:color-mix(in srgb,var(--good) 9%,transparent)}
.hero-loc{font-size:.75rem;letter-spacing:.02em}
/* a fit-content block ignores text-align, so the right-hand hero word has to
   be pushed over explicitly — and centred once the hero stacks */
.hs-r .hs-code{margin-left:auto}
@media (max-width:1140px){.hs-r .hs-code{margin-inline:auto}}

/* =========================================================
   Credentials, as a showcase. The panel that boxed the cards is gone — it put
   cards inside a card under a second "Certifications" heading inside the first —
   the grid fills the row instead of leaving forty per cent of it empty, and each
   preview is a lit stage: the document floats on soft accent and cyan light with
   a real shadow beneath it, and lifts toward you on hover.
   ========================================================= */
:root{--doc-shadow:drop-shadow(0 18px 26px rgba(0,0,0,.52))}
:root[data-theme="light"]{--doc-shadow:drop-shadow(0 14px 22px rgba(12,12,13,.22))}
@media (prefers-color-scheme:light){:root:not([data-theme]){--doc-shadow:drop-shadow(0 14px 22px rgba(12,12,13,.22))}}

.cert-panel,.cert-panel:hover{background:none;border:0;padding:0;box-shadow:none}
.crows{grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr));margin-top:4px}

.cc-shot,.cc-shot.is-scan,.cc-shot.is-badge{aspect-ratio:16/9;
  background:
    radial-gradient(70% 85% at 50% 118%,var(--hi-dim),transparent 70%),
    radial-gradient(75% 90% at 50% -18%,var(--accent-dim),transparent 72%),
    var(--s2)}
.cc-shot.is-scan img{padding:clamp(14px,2.2vw,26px);filter:var(--doc-shadow)}
.cc-shot.is-badge img{padding:clamp(18px,2.6vw,32px);filter:var(--doc-shadow)}
.ccard:hover .cc-shot img,.ccard:focus-within .cc-shot img{transform:translateY(-5px) scale(1.035)}

/* the monogram stands in for missing artwork, in the same gradient */
.cc-mono{font-family:var(--mono);font-size:clamp(1.6rem,3vw,2.2rem);font-weight:600;letter-spacing:.1em}
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .cc-mono{background:var(--grad);-webkit-background-clip:text;background-clip:text;
    -webkit-text-fill-color:transparent}}

/* earned / in progress, on the preview where the eye lands first */
.cc-state{position:absolute;top:12px;left:12px;z-index:2;display:inline-flex;align-items:center;gap:6px;
  padding:4px 10px 4px 8px;border-radius:100px;
  font-family:var(--mono);font-size:.75rem;letter-spacing:.08em;text-transform:uppercase;
  color:var(--good);background:color-mix(in srgb,var(--bg) 72%,transparent);
  border:1px solid color-mix(in srgb,var(--good) 40%,transparent);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.cc-state.wip{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 40%,transparent)}
.cc-state i{font-style:normal}

.cc-body{padding:16px 18px 18px}
.cc-title{font-size:1.02rem}
.cc-issuer{font-size:.84rem;color:var(--ink-2)}
/* issued / id / renews as labelled values in a row, not a dot-joined run */
.cc-facts{display:flex;flex-wrap:wrap;gap:12px 28px;margin:14px 0 0;padding-top:13px;
  border-top:1px solid var(--line)}
.cc-fact{display:grid;gap:3px;min-width:0}
.cc-fact dt{font-family:var(--mono);font-size:.75rem;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
.cc-fact dd{margin:0;font-family:var(--mono);font-size:.84rem;color:var(--ink);overflow-wrap:anywhere}

.cc-foot{margin-top:16px}
.cc-verify{position:relative;z-index:1;display:inline-flex;align-items:center;gap:8px;min-height:34px;
  padding:6px 14px;border-radius:100px;font-size:.84rem;font-weight:500;color:var(--accent);
  border:1px solid color-mix(in srgb,var(--accent) 42%,transparent);background:var(--accent-dim);
  transition:background .2s,border-color .2s}
.cc-verify:hover,.cc-verify:focus-visible{border-color:var(--accent);
  background:color-mix(in srgb,var(--accent) 24%,transparent)}
.cc-via{font-family:var(--mono);font-size:.75rem;color:var(--ink-2)}
.cc-via::before{content:"\00b7";margin-right:7px;color:var(--ink-3)}
.cc-go{display:inline-grid}

/* the count moved out of the duplicate inner heading into the section label */
.lbl-n{font-family:var(--mono);font-size:.75rem;letter-spacing:.04em;color:var(--accent);
  padding:1px 9px;border-radius:100px;background:var(--accent-dim);
  border:1px solid color-mix(in srgb,var(--accent) 40%,transparent)}
.lbl-n:empty{display:none}

/* the zoom dialog gets the same stage, so opening a card feels like the card */
.cb-figure{background:
  radial-gradient(70% 80% at 50% 112%,var(--hi-dim),transparent 70%),
  radial-gradient(70% 80% at 50% -12%,var(--accent-dim),transparent 72%),var(--s2)}
.cb-figure img{filter:var(--doc-shadow)}

/* the two figure tiles were lit only by their numerals; a corner of the cyan
   gives the space under them somewhere to fall */
.t.stat{background-image:radial-gradient(100% 80% at 100% 100%,var(--hi-dim),transparent 62%)}
/* the light theme lifts every panel with a shadow at :root[data-theme] .t
   specificity; the unboxed credentials panel has to out-rank it to stay flat */
:root .t.cert-panel,:root[data-theme] .t.cert-panel{box-shadow:none;background:none;border:0}
@media (max-width:560px){
  /* on a phone the document fills the width and ran under the EARNED pill;
     it drops below the pill instead of the pill sitting on its corner */
  .cc-shot.is-scan img,.cc-shot.is-badge img{padding-top:48px}
}
