/* Self-hosted fonts (SIL Open Font License) — no third-party requests */
@font-face{font-family:"Chakra Petch";font-style:normal;font-weight:500;font-display:swap;src:url("fonts/chakra-petch-latin-500-normal.woff2") format("woff2")}
@font-face{font-family:"Chakra Petch";font-style:normal;font-weight:600;font-display:swap;src:url("fonts/chakra-petch-latin-600-normal.woff2") format("woff2")}
@font-face{font-family:"Chakra Petch";font-style:normal;font-weight:700;font-display:swap;src:url("fonts/chakra-petch-latin-700-normal.woff2") format("woff2")}
@font-face{font-family:"Chakra Petch";font-style:italic;font-weight:600;font-display:swap;src:url("fonts/chakra-petch-latin-600-italic.woff2") format("woff2")}
@font-face{font-family:"Instrument Sans";font-style:normal;font-weight:400;font-display:swap;src:url("fonts/instrument-sans-latin-400-normal.woff2") format("woff2")}
@font-face{font-family:"Instrument Sans";font-style:normal;font-weight:500;font-display:swap;src:url("fonts/instrument-sans-latin-500-normal.woff2") format("woff2")}
@font-face{font-family:"Instrument Sans";font-style:normal;font-weight:600;font-display:swap;src:url("fonts/instrument-sans-latin-600-normal.woff2") format("woff2")}
/* Layout: a calm sci-fi graphic novel. Splash panel hero (parallax skyline) → five story panels in an
   irregular comic grid (a true sequence, so chapters are numbered) → plain sections for skills,
   certifications, write-ups → "To be continued" contact panel. Day/night = light/dark theme. */
:root{
  --bg:#E8EFF1;
  --panel:#FAFCFD;
  --line:#0F2340;
  --text:#0E1F38;
  --muted:#475A77;
  --blue:#1B4F95;
  --teal:#0B827E;
  --purple:#6243D3;
  --green:#178F58;
  /* a warm accent, used sparingly: the sun, highlights, the hover "pop" */
  --amber:#F2A93B;
  /* the same hues, dark enough for small text on --panel and --bg (WCAG AA) */
  --green-text:#12744A; --teal-text:#086B67; --amber-text:#8F5300;
  /* scene colours */
  --sky-a:#C4E8EC; --sky-b:#A8D9E1; --orb:#FFE6A3; --cloud:#FFFFFF;
  --far:#8DBCD0; --mid:#4C88B0; --near:#1F4F80; --ground:#2B5F8E;
  --win:#EAF7F8; --star-o:0; --dots:rgba(15,35,64,.15);
  --glow:transparent; --btn-hover:var(--teal-text);
  --f-display:"Chakra Petch","Segoe UI",system-ui,sans-serif;
  --f-body:"Instrument Sans","Segoe UI",Roboto,system-ui,sans-serif;
  --frame:3px;
  --cut:22px;
}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
  --bg:#060C1A; --panel:#0D1730; --line:#93B4E4; --text:#E6EEF9; --muted:#9DB1CF;
  --blue:#7FB0F5; --teal:#4FE0D2; --purple:#B39BFF; --green:#62E8A6; --amber:#FFC46B;
  --green-text:#62E8A6; --teal-text:#4FE0D2; --amber-text:#FFC46B;
  --sky-a:#101C3A; --sky-b:#16264B; --orb:#F1F4FA; --cloud:#22345D;
  --far:#22355E; --mid:#1A2B4E; --near:#0B1530; --ground:#0E1A37;
  --win:#FFC46B; --star-o:1; --dots:rgba(147,180,228,.13);
  --glow:rgba(79,224,210,.18); --btn-hover:var(--teal);
  color-scheme:dark;
}}
:root[data-theme="dark"]{
  --bg:#060C1A; --panel:#0D1730; --line:#93B4E4; --text:#E6EEF9; --muted:#9DB1CF;
  --blue:#7FB0F5; --teal:#4FE0D2; --purple:#B39BFF; --green:#62E8A6; --amber:#FFC46B;
  --green-text:#62E8A6; --teal-text:#4FE0D2; --amber-text:#FFC46B;
  --sky-a:#101C3A; --sky-b:#16264B; --orb:#F1F4FA; --cloud:#22345D;
  --far:#22355E; --mid:#1A2B4E; --near:#0B1530; --ground:#0E1A37;
  --win:#FFC46B; --star-o:1; --dots:rgba(147,180,228,.13);
  --glow:rgba(79,224,210,.18); --btn-hover:var(--teal);
  color-scheme:dark;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--bg);color:var(--text);font:400 1.0625rem/1.62 var(--f-body);
  background-image:radial-gradient(var(--dots) 1px,transparent 1.3px);background-size:9px 9px;
  transition:background-color .5s,color .5s}
a{color:inherit}
:focus-visible{outline:3px solid var(--teal);outline-offset:3px}
.wrap{max-width:1160px;margin-inline:auto;padding-inline:clamp(16px,4vw,40px)}
h1,h2,h3{font-family:var(--f-display);text-wrap:balance}

/* frames: outer = line colour, inner = panel; both share the cut shape */
.frame{background:var(--line);padding:var(--frame);clip-path:var(--shape)}
.frame>.in{background:var(--panel);clip-path:var(--shape);height:100%;position:relative;overflow:hidden;transition:background-color .5s}
.cut-a{--shape:polygon(0 0,calc(100% - var(--cut)) 0,100% var(--cut),100% 100%,0 100%)}
.cut-b{--shape:polygon(var(--cut) 0,100% 0,100% calc(100% - var(--cut)),calc(100% - var(--cut)) 100%,0 100%,0 var(--cut))}
.cut-c{--shape:polygon(0 0,100% 0,100% 100%,var(--cut) 100%,0 calc(100% - var(--cut)))}

/* svg scene paint */
.sky-a{fill:var(--sky-a)} .sky-b{fill:var(--sky-b)} .orb{fill:var(--orb)} .cloud{fill:var(--cloud)}
.far{fill:var(--far)} .mid{fill:var(--mid)} .near{fill:var(--near)} .ground{fill:var(--ground)}
.win{fill:var(--win)} .ink{stroke:var(--line);stroke-width:2.5;stroke-linejoin:round}
.ink-thin{stroke:var(--line);stroke-width:1.5}
.f-teal{fill:var(--teal)} .f-purple{fill:var(--purple)} .f-green{fill:var(--green)} .f-panel{fill:var(--panel)}
.s-green{stroke:var(--green)} .s-teal{stroke:var(--teal)}
.star{fill:var(--orb);opacity:var(--star-o);transition:opacity .6s}
.dots{fill:url(#halftone)}
svg *{transition:fill .5s,stroke .5s}
.sfx{font:italic 600 22px var(--f-display);fill:var(--purple)}

/* nav */
.nav{position:sticky;top:env(safe-area-inset-top,0px);z-index:30;background:color-mix(in srgb,var(--bg) 86%,transparent);-webkit-backdrop-filter:blur(10px) saturate(1.3);backdrop-filter:blur(10px) saturate(1.3);border-bottom:var(--frame) solid var(--line);transition:background-color .5s}
.nav .wrap{display:flex;align-items:center;gap:20px;padding-block:10px}
.brand{font:700 1.2rem/1 var(--f-display);text-decoration:none;letter-spacing:.02em}
.nav ul{display:flex;gap:clamp(12px,2.4vw,26px);list-style:none;margin:0 0 0 auto;padding:0}
.nav ul a{font:600 1rem/1 var(--f-display);text-decoration:none;color:var(--muted)}
.nav ul a:hover{color:var(--text)}
.brand,.nav ul a{white-space:nowrap}
@media (max-width:1000px){.nav .wrap{gap:12px}.nav ul{gap:12px}.nav ul a{font-size:.92rem}}
@media (max-width:760px){
  .nav .wrap{flex-wrap:wrap;row-gap:6px}
  .nav ul{order:3;flex:1 0 100%;margin:0 calc(-1 * clamp(16px,4vw,40px));padding:2px clamp(16px,4vw,40px) 4px;overflow-x:auto;scrollbar-width:none;
    -webkit-mask:linear-gradient(90deg,transparent,#000 16px,#000 calc(100% - 24px),transparent);mask:linear-gradient(90deg,transparent,#000 16px,#000 calc(100% - 24px),transparent)}
  .nav ul::-webkit-scrollbar{display:none}
  .lang{margin-inline-start:auto}
}
.toggle{display:inline-flex;align-items:center;gap:8px;border:2px solid var(--line);background:var(--panel);color:var(--text);
  font:600 .95rem/1 var(--f-display);padding:7px 12px;cursor:pointer;clip-path:polygon(8px 0,100% 0,100% calc(100% - 8px),calc(100% - 8px) 100%,0 100%,0 8px)}
.toggle svg{width:16px;height:16px}

/* buttons */
.btns{display:flex;flex-wrap:wrap;gap:12px}
.btn{--b:var(--text);display:inline-flex;align-items:center;gap:9px;text-decoration:none;cursor:pointer;
  font:600 1.02rem/1 var(--f-display);letter-spacing:.02em;padding:13px 20px 12px;
  background:var(--text);color:var(--bg);border:0;
  clip-path:polygon(0 0,calc(100% - 12px) 0,100% 12px,100% 100%,12px 100%,0 calc(100% - 12px));
  transition:background-color .2s,translate .2s cubic-bezier(.3,1.6,.5,1)}
.btn:hover{background:var(--btn-hover);color:var(--bg)}
.btn.ghost{background:transparent;color:var(--text);box-shadow:inset 0 0 0 2px var(--line)}
.btn.ghost:hover{background:var(--panel);box-shadow:inset 0 0 0 2px var(--teal)}
.btn svg{width:17px;height:17px;flex:none}

/* hero splash */
.hero{padding-block:clamp(18px,3vw,32px) 0}
.splash{--cut:44px}
.splash .in{min-height:clamp(440px,58vw,600px);display:grid;align-items:start}
.splash svg.scene{position:absolute;inset:0;width:100%;height:100%}
.layer{will-change:transform}
.hero-copy{position:relative;z-index:2;padding:clamp(28px,5vw,64px);max-width:640px;display:grid;gap:18px;justify-items:start}
.caption{font:600 .98rem/1.3 var(--f-display);background:var(--panel);border:2px solid var(--line);padding:7px 12px;color:var(--text);transition:background-color .5s}
.hero h1{margin:0;font-weight:700;font-size:clamp(3.4rem,10vw,7.4rem);line-height:.88;letter-spacing:-.015em;color:var(--text);
  text-shadow:.045em .045em 0 var(--teal)}
.hero-card{display:grid;gap:16px;background:var(--panel);border:2px solid var(--line);padding:16px 18px 18px;
  box-shadow:6px 6px 0 var(--teal);transition:background-color .5s}
.hero .lede{margin:0;font-size:clamp(1.1rem,1.8vw,1.3rem);font-weight:500;max-width:34ch;line-height:1.4}

/* section heads */
.sec{padding-block:clamp(64px,9vw,112px) 0}
.sec-head{display:grid;gap:8px;margin-bottom:28px;max-width:62ch}
.sec-head h2{margin:0;font-weight:700;font-size:clamp(2rem,4.6vw,3.1rem);line-height:1;letter-spacing:-.01em}
.sec-head p{margin:0;color:var(--muted)}

/* story grid */
.story{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:16px}
.p1{grid-column:span 4}.p2{grid-column:span 2}.p3{grid-column:span 3}.p4{grid-column:span 3}.p5{grid-column:span 6}
.panel .in{display:flex;flex-direction:column}
.panel .art{position:relative;border-bottom:var(--frame) solid var(--line)}
.panel .art svg{display:block;width:100%;height:auto}
.chap{position:absolute;left:14px;top:14px;font:700 .95rem/1 var(--f-display);background:var(--panel);border:2px solid var(--line);padding:6px 10px;transition:background-color .5s}
.panel .txt{padding:16px 20px 20px;display:grid;gap:6px;align-content:start;flex:1}
.panel h3{margin:0;font-weight:700;font-size:1.45rem;line-height:1.15}
.panel p{margin:0;color:var(--muted);max-width:58ch}
.p2 .art svg{aspect-ratio:400/330}
.meter{margin-top:10px;display:grid;gap:6px}
.meter-top{display:flex;justify-content:space-between;font:600 .9rem/1 var(--f-display)}
.bar{height:12px;border:2px solid var(--line);position:relative;overflow:hidden;transform:skewX(-20deg)}
.bar i{position:absolute;inset:0 auto 0 0;width:var(--p,0%);background:var(--teal);transition:width 1.2s cubic-bezier(.2,.8,.2,1)}

/* reveal: panels are fully visible at rest; JS only makes the ones below the fold settle in as they arrive */
.reveal{transition:transform .9s cubic-bezier(.2,.8,.2,1),translate .25s ease,background-color .25s}
.reveal.wait{transform:translateY(26px) rotate(-.4deg)}

/* accent colour for skill groups and certification badges */
.c-teal{--c:var(--teal)} .c-blue{--c:var(--blue)} .c-purple{--c:var(--purple)} .c-green{--c:var(--green)} .c-muted{--c:var(--muted)}

/* skills */
.skills{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.skill-col .in{padding:20px 20px 22px;display:grid;gap:12px;align-content:start}
.skill-col h3{margin:0;font-size:1.25rem;display:flex;align-items:center;gap:10px}
.skill-col h3 i{width:12px;height:12px;background:var(--c);transform:rotate(45deg);flex:none}
.skill-col p{margin:0;color:var(--muted);font-size:.95rem}
.chips{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0;padding:0}
.chips li{font:600 .95rem/1 var(--f-display);padding:8px 11px;border:2px solid var(--c);color:var(--text)}

/* certifications */
.certs{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}
.cert .in{padding:20px;display:grid;grid-template-columns:72px 1fr;gap:16px;align-items:center}
.cert svg{width:72px;height:80px}
.cert h3{margin:0;font-size:1.1rem;line-height:1.2}
.cert p{margin:4px 0 0;font:600 .9rem/1.2 var(--f-display);color:var(--c)}
.cert.earned p{color:var(--teal-text)}
.cert .hex{stroke:var(--c);stroke-width:3;fill:transparent}
.cert.earned .hex{fill:var(--c)}
.cert.progress .hex{stroke-dasharray:10 6}
.cert.planned .hex{stroke-dasharray:3 6}
.cert .hex-t{font:700 15px var(--f-display);fill:var(--c);text-anchor:middle}
.cert .hex-t.long{font-size:13px}
.cert .hex-t.longer{font-size:11px}
.verify{color:inherit;text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:2px}
.verify:hover{text-decoration-color:var(--teal)}
.cert.earned .hex-t{fill:var(--panel)}

/* write-ups */
.posts{display:grid;gap:14px}
.post{display:grid;grid-template-columns:auto 1fr auto;gap:18px;align-items:baseline;text-decoration:none;padding:16px 20px;border:2px solid var(--line);background:var(--panel)}
.post:hover{border-color:var(--teal)}
.post time{font:600 .9rem/1 var(--f-display);color:var(--muted);font-variant-numeric:tabular-nums}
.post h3{margin:0;font-size:1.15rem}
.post p{margin:4px 0 0;color:var(--muted);font-size:.95rem}
.post .tag{font:600 .85rem/1 var(--f-display);color:var(--purple)}
.empty .in{padding:28px clamp(20px,4vw,36px);display:grid;grid-template-columns:minmax(0,1fr) 200px;gap:24px;align-items:center}
.empty h3{margin:0 0 6px;font-size:1.4rem}
.empty p{margin:0;color:var(--muted);max-width:54ch}
.empty svg{width:100%;height:auto}

/* ending */
.ending{padding-block:clamp(72px,10vw,120px) clamp(40px,6vw,64px)}
.end-panel{--cut:40px}
.end-panel .in{padding:clamp(32px,6vw,72px);display:grid;gap:20px;justify-items:start;
  background:linear-gradient(var(--panel),var(--panel)) padding-box}
.end-panel .in::before{content:"";position:absolute;inset:0;background:radial-gradient(var(--dots) 1.2px,transparent 1.5px);background-size:8px 8px;
  mask:linear-gradient(110deg,transparent 40%,#000);-webkit-mask:linear-gradient(110deg,transparent 40%,#000);pointer-events:none}
.end-panel h2{margin:0;font-weight:700;font-style:italic;font-size:clamp(2.6rem,8vw,5.6rem);line-height:.95;text-shadow:.045em .045em 0 var(--purple);position:relative}
.end-panel p{margin:0;max-width:52ch;font-size:1.1rem;color:var(--muted);position:relative}
.end-panel .btns{position:relative}
footer{color:var(--muted);font:500 .95rem/1.4 var(--f-display)}
footer .wrap{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px;padding-block:22px 34px;border-top:2px solid var(--line)}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .reveal{transform:none;transition:none}
  .bar i{transition:none}
}
@media (max-width:900px){
  .p1,.p2,.p3,.p4{grid-column:span 6}
  .p2 .art svg{aspect-ratio:400/250}
  .skills{grid-template-columns:1fr}
}
@media (max-width:640px){
  .empty .in{grid-template-columns:1fr}
  .empty svg{max-width:180px}
  .post{grid-template-columns:1fr}
  .splash{--cut:28px}
  .hero-copy{padding-bottom:180px}
}
.defs{position:absolute;width:0;height:0;overflow:hidden}
[hidden]{display:none!important}

/* ---------- hidden flags ---------- */
.b64{font:500 9px/1 ui-monospace,Consolas,monospace;fill:var(--muted);letter-spacing:.02em}
code{font:500 .92em/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;background:color-mix(in srgb,var(--line) 10%,transparent);padding:.1em .35em}
.ctf{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px}
.ctf .in{padding:22px 22px 24px;display:grid;gap:14px;align-content:start}
.ctf h3{margin:0;font-size:1.3rem}
.hints{margin:0;padding:0;list-style:none;counter-reset:h;display:grid;gap:10px}
.hints li{counter-increment:h;display:grid;grid-template-columns:30px 1fr;gap:12px;align-items:start;color:var(--muted)}
.hints li::before{content:counter(h);display:grid;place-items:center;width:28px;height:28px;border:2px solid var(--line);font:700 .9rem/1 var(--f-display);color:var(--text)}
.hints li.done span{text-decoration:line-through;text-decoration-color:var(--teal);text-decoration-thickness:2px}
.hints li.done::before{content:"✓";background:var(--teal);border-color:var(--teal);color:var(--panel)}
.flag-form{display:grid;gap:8px}
.flag-form label{font:600 .95rem/1 var(--f-display)}
.flag-row{display:flex;gap:10px;flex-wrap:wrap}
.flag-row input{flex:1 1 200px;min-width:0;font:500 1rem/1 ui-monospace,Consolas,monospace;padding:12px 14px;border:2px solid var(--line);background:var(--bg);color:var(--text)}
.flag-row input:focus-visible{outline:3px solid var(--teal);outline-offset:2px}
.flag-row .btn{border:0}
.flag-msg{margin:0;color:var(--muted);min-height:3em}
.flag-msg[data-state="ok"]{color:var(--green-text)}
.flag-msg[data-state="bad"]{color:var(--purple)}
.flag-progress{display:flex;align-items:center;gap:12px;font:600 .95rem/1 var(--f-display)}
.pips{display:flex;gap:6px}
.pips i{width:18px;height:18px;border:2px solid var(--line);transform:rotate(45deg);transition:background-color .3s}
.pips i.on{background:var(--teal);border-color:var(--teal)}

/* ---------- sub pages (write-ups, CV, 404) ---------- */
.page-head{padding-block:clamp(40px,7vw,80px) clamp(24px,4vw,40px);display:grid;gap:14px;justify-items:start}
.page-head h1{margin:0;font-weight:700;font-size:clamp(2.4rem,7vw,4.6rem);line-height:.95;letter-spacing:-.015em;text-shadow:.045em .045em 0 var(--teal)}
.page-head .lede{margin:0;max-width:56ch;font-size:clamp(1.05rem,1.6vw,1.2rem);color:var(--muted)}
.back{font:600 1rem/1 var(--f-display);text-decoration:none;color:var(--muted)}
.back:hover{color:var(--text)}
.strip figure{margin:0}
.strip{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.strip .in{display:flex;flex-direction:column}
.strip svg{display:block;width:100%;height:auto;border-bottom:var(--frame) solid var(--line)}
.strip .cap{padding:14px 18px 18px;display:grid;gap:4px}
.strip .cap b{font:700 1.15rem/1.2 var(--f-display)}
.strip .cap span{color:var(--muted);font-size:.97rem}
.mono-t{font:600 15px ui-monospace,Consolas,monospace}
.prose{max-width:70ch;padding-block:clamp(40px,6vw,72px) 0}
.prose h2{font-size:clamp(1.5rem,3vw,2rem);line-height:1.15;margin:2.2em 0 .5em}
.prose h2:first-child{margin-top:0}
.prose p,.prose li{color:var(--text)}
.prose p{margin:0 0 1em}
.prose ul,.prose ol{padding-left:1.3em;margin:0 0 1em;display:grid;gap:.4em}
.prose pre{margin:0 0 1.2em;padding:14px 16px;overflow-x:auto;background:var(--panel);border:2px solid var(--line);font:500 .88rem/1.55 ui-monospace,SFMono-Regular,Consolas,monospace}
.prose pre code{background:none;padding:0;font:inherit}
.tbl{overflow-x:auto;margin:0 0 1.2em;border:2px solid var(--line);background:var(--panel)}
.tbl table{border-collapse:collapse;width:100%;min-width:520px;font-size:.95rem}
.tbl th,.tbl td{text-align:left;padding:10px 12px;border-bottom:1px solid color-mix(in srgb,var(--line) 30%,transparent);vertical-align:top}
.tbl th{font:700 .95rem/1.2 var(--f-display)}
.tbl tr:last-child td{border-bottom:0}
.ok{color:var(--green-text);font-weight:600}
.next{margin-top:40px}
.next .in{padding:22px 24px;display:grid;gap:8px}
.next h3{margin:0;font-size:1.25rem}
.next p{margin:0;color:var(--muted)}

/* CV: one printable sheet in the style of Jake's Resume. Black on white in both themes, like paper.
   No letter-spacing or small caps anywhere on it: both come out of a PDF as split words ("git hub",
   "E ducation"), which breaks ATS keyword matching. Headings are uppercase instead. */
.cv-page{padding-block:clamp(24px,4vw,40px) clamp(40px,6vw,72px);display:grid;gap:18px;justify-items:center}
.sheet{--ink:#111;--ink-2:#3a3a3a;box-sizing:border-box;width:100%;max-width:210mm;background:#fff;color:var(--ink);
  padding:clamp(20px,5vw,14mm) clamp(16px,5vw,15mm);box-shadow:0 0 0 1px var(--line),10px 10px 0 var(--teal);
  font:400 10.2pt/1.34 var(--f-body);letter-spacing:normal}
.sheet *{letter-spacing:normal}
.sheet a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}
.sheet a:hover{text-decoration-thickness:2px}
.sheet-head{text-align:center;margin-bottom:6pt}
.sheet h1{margin:0;font:700 22pt/1.1 var(--f-body);text-shadow:none}
.sheet-headline{margin:2pt 0 0;font-style:italic;color:var(--ink-2)}
.sheet-contact{margin:3pt 0 0;font-size:9.5pt;text-wrap:balance}
.sheet-contact a,.sheet-contact span:not(.sep){white-space:nowrap}
.sheet-personal{margin:1pt 0 0;font-size:9.5pt}
.sheet h2{margin:8pt 0 3pt;padding-bottom:1pt;border-bottom:1px solid var(--ink);font:600 11pt/1.2 var(--f-body);text-transform:uppercase;text-wrap:wrap}
.sheet section>p{margin:0}
.sheet .entry{margin:0 0 4pt}
.sheet .entry:last-child{margin-bottom:0}
.sheet .row{display:flex;flex-wrap:wrap;justify-content:space-between;gap:0 12pt}
.sheet .row>span:last-child:not(:first-child){font-variant-numeric:tabular-nums}
.sheet .row.sub{font-size:9.5pt;font-style:italic}
.sheet .note{margin:1pt 0 0;font-size:9.6pt;color:var(--ink-2)}
.sheet ul{display:block;margin:2pt 0 0;padding-left:14pt}
.sheet li{margin:0 0 .5pt;font-size:9.6pt}
.sheet .skills{margin:0;padding:0;list-style:none}
.sheet .skills li{margin:0}
@media (max-width:900px){.strip{grid-template-columns:1fr}.ctf{grid-template-columns:1fr}}

/* print: the CV prints as a clean one-pager */
@media print{
  @page{size:A4;margin:11mm 13mm}
  :root,:root[data-theme]{--bg:#fff;--panel:#fff;--line:#000;--text:#000;--muted:#333;--teal:#000}
  body{background:#fff;font-size:10.5pt;line-height:1.45}
  .nav,footer,.no-print,.back{display:none!important}
  .frame{background:none;padding:0;clip-path:none}
  .frame>.in{clip-path:none;padding:0!important}
  .page-head{padding:0 0 10pt}
  .page-head h1{text-shadow:none;font-size:26pt}
  .cv-page{display:block;padding:0;max-width:none}
  .sheet{max-width:none;padding:0;box-shadow:none}
  a{color:#000}
}

/* 404 */
.notfound{margin-block:clamp(24px,5vw,56px)}
.notfound .in{display:grid}
.notfound svg{display:block;width:100%;height:auto;border-bottom:var(--frame) solid var(--line)}
.nf-copy{padding:clamp(22px,4vw,40px);display:grid;gap:12px;justify-items:start}
.nf-copy h1{margin:0;font-size:clamp(2.2rem,6vw,3.6rem);line-height:1;text-shadow:.045em .045em 0 var(--purple)}
.nf-copy p{margin:0;color:var(--muted)}
.nav a[aria-current="page"]{color:var(--text);text-decoration:underline;text-decoration-color:var(--teal);text-decoration-thickness:2px;text-underline-offset:6px}

/* ---------- Chapter 1: courses dialog ---------- */
.panel.clickable{cursor:pointer}
.panel.clickable:hover .in{background:color-mix(in srgb,var(--teal) 6%,var(--panel))}
.courses-btn{justify-self:start;margin-top:8px}
.courses-dialog{padding:0;border:0;background:transparent;color:var(--text);width:min(1040px,calc(100vw - 32px));max-height:calc(100dvh - 32px);overflow:visible}
.courses-dialog::backdrop{background:color-mix(in srgb,var(--bg) 55%,rgba(0,0,0,.55));backdrop-filter:blur(2px)}
.dlg-frame{--cut:30px;max-height:calc(100dvh - 32px);display:flex}
.dlg-frame>.in{overflow:auto;padding:clamp(20px,4vw,36px);display:grid;gap:20px;align-content:start;flex:1}
.dlg-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}
.dlg-head>div{display:grid;gap:8px;justify-items:start;min-width:0}
.dlg-head h2{margin:0;font-weight:700;font-size:clamp(1.9rem,4vw,2.6rem);line-height:1;text-shadow:.045em .045em 0 var(--teal)}
.dlg-head p{margin:0;color:var(--muted)}
.dlg-close{flex:none}
.dlg-summary{display:flex;flex-wrap:wrap;gap:8px 22px;font:500 1rem/1.3 var(--f-display);color:var(--muted)}
.dlg-summary b{color:var(--text);font-weight:700;font-size:1.25rem;font-variant-numeric:tabular-nums}
.semesters{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:14px}
.sem{border:2px solid var(--line);padding:14px 16px 12px;display:grid;gap:10px;align-content:start;background:var(--bg)}
.sem.current{border-color:var(--teal);box-shadow:4px 4px 0 var(--teal)}
.sem.upcoming{border-style:dashed}
.sem-head{display:flex;justify-content:space-between;align-items:baseline;gap:8px}
.sem-head h3{margin:0;font-size:1.1rem}
.sem-state{font:600 .82rem/1 var(--f-display);color:var(--muted)}
.sem.completed .sem-state{color:var(--green-text)}
.sem.abroad{border-color:var(--purple);box-shadow:4px 4px 0 var(--purple)}
.sem-abroad{margin:0;display:flex;align-items:center;gap:8px;padding:6px 10px;border-left:4px solid var(--purple);background:color-mix(in srgb,var(--purple) 16%,var(--bg));font:600 .88rem/1.25 var(--f-display);color:var(--text)}
.sem-abroad svg{flex:none;width:16px;height:16px;color:var(--purple)}
.sem.current .sem-state{color:var(--teal-text)}
.sem-list{list-style:none;margin:0;padding:0;display:grid;gap:6px}
.sem-list li{display:flex;justify-content:space-between;gap:10px;font-size:.95rem;line-height:1.3}
.sem-list .ects{flex:none;font:600 .82rem/1.3 var(--f-display);color:var(--muted);font-variant-numeric:tabular-nums}
.sem-total{margin:0;padding-top:8px;border-top:1px solid color-mix(in srgb,var(--line) 35%,transparent);font:600 .85rem/1 var(--f-display);color:var(--muted);text-align:right}
@media (max-width:560px){.dlg-head{flex-direction:column}}
/* courses dialog: the inner panel is the scroller (fix: it used to grow and get clipped) */
.dlg-frame>.in{min-height:0;max-height:calc(100dvh - 32px - 2*var(--frame));overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;scrollbar-gutter:stable}
@supports not (height:100dvh){.dlg-frame>.in{max-height:calc(100vh - 38px)}}

/* ================= animations =================
   Light by design. The clouds are separate small layers moved with transform, so the GPU
   handles them without repainting anything. Loops inside the drawings run in a few
   "comic" steps per second instead of every frame, which keeps repaints rare. Everything
   pauses off screen (.anim-gate without .live) and is off for reduced-motion users. */
.hero-clouds{position:absolute;inset:0;z-index:1;pointer-events:none;overflow:hidden}
.hc{position:absolute;height:auto;overflow:visible}
.hc1{width:clamp(110px,16.5%,200px);left:54%;top:31%}
.hc2{width:clamp(90px,14%,170px);left:81.5%;top:42%}
@media (max-width:640px){.hc1{left:58%;top:6%}.hc2{left:80%;top:14%}}
@media (prefers-reduced-motion:no-preference){
  /* 1. page load: the name is inked in left to right, then the caption box drops in */
  .hero h1{animation:ink-wipe .9s cubic-bezier(.7,0,.2,1) .1s both}
  .hero .caption{animation:pop .45s cubic-bezier(.3,1.6,.5,1) .05s both}
  .hero-card{animation:rise .6s cubic-bezier(.2,.8,.2,1) .75s both}

  /* 2. hero: clouds drift (GPU only), data lines pulse, windows flicker at night */
  .hc1{animation:drift 18s ease-in-out infinite alternate}
  .hc2{animation:drift 26s ease-in-out -8s infinite alternate}
  .pulse{stroke-dasharray:14 10;animation:march-line 2.4s steps(12) infinite}
  .hero .win rect:nth-child(4n+1){animation:flicker 7s steps(1) infinite}
  .hero .win rect:nth-child(5n+2){animation:flicker 11s steps(1) -3s infinite}

  /* 3. stars twinkle, only at night (in daylight they're invisible, so they don't animate) */
  :root[data-theme="dark"] .star circle{animation:twinkle 3.6s steps(4) infinite}
  :root[data-theme="dark"] .star circle:nth-child(2n){animation-duration:4.8s;animation-delay:-1.5s}
  :root[data-theme="dark"] .star circle:nth-child(3n){animation-duration:6s;animation-delay:-3s}

  /* 4. Chapter 3: as the panel arrives, the wires light up and the padlock clicks shut (plays once) */
  .js .p3 .shackle{transform:translateY(-14px);transition:transform .35s cubic-bezier(.5,0,.3,1.6) 1.1s}
  .js .p3.seen .shackle{transform:none}
  .js .p3 .wires path{stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset .9s ease-out .2s}
  .js .p3.seen .wires path{stroke-dashoffset:0}
  .js .p3 .nodes circle{opacity:0;transition:opacity .3s 1s}
  .js .p3.seen .nodes circle{opacity:1}
  .js .p3 .sfx{opacity:0;transform:scale(.4);transform-box:fill-box;transform-origin:center;transition:opacity .2s 1.4s,transform .35s cubic-bezier(.3,1.8,.5,1) 1.4s}
  .js .p3.seen .sfx{opacity:1;transform:none}

  /* 5. Chapter 4: the flag waves; Chapter 5: the road rolls toward you */
  .flag{transform-box:fill-box;transform-origin:left center;animation:wave 2.6s steps(8) infinite}
  .road{stroke-dasharray:6 8;animation:roll 1.6s steps(7) infinite}

  /* 6. in-progress certification badge: its dashed edge keeps moving */
  .cert.progress .hex{animation:march-hex 2.4s steps(16) infinite}

  /* pause everything that's off screen */
  .js .anim-gate:not(.live) :is(.pulse,.star circle,.win rect,.flag,.road,.hex,.hc){animation-play-state:paused}
}
@keyframes ink-wipe{from{clip-path:inset(-15% 100% -15% -5%)}to{clip-path:inset(-15% -10% -15% -5%)}}
@keyframes pop{from{opacity:0;transform:scale(.6) rotate(-6deg)}to{opacity:1;transform:none}}
@keyframes rise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
@keyframes drift{from{transform:translateX(-18px)}to{transform:translateX(22px)}}
@keyframes march-line{to{stroke-dashoffset:-48}}
@keyframes march-hex{to{stroke-dashoffset:-32}}
@keyframes flicker{0%,100%{opacity:1}48%{opacity:.35}52%{opacity:1}53%{opacity:.5}55%{opacity:1}}
@media (prefers-reduced-motion:no-preference) and (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .star circle{animation:twinkle 3.6s steps(4) infinite}
  :root:not([data-theme="light"]) .star circle:nth-child(2n){animation-duration:4.8s;animation-delay:-1.5s}
  :root:not([data-theme="light"]) .star circle:nth-child(3n){animation-duration:6s;animation-delay:-3s}
}
@keyframes twinkle{0%,100%{opacity:1}50%{opacity:.25}}
@keyframes wave{0%,100%{transform:skewY(0) scaleX(1)}50%{transform:skewY(7deg) scaleX(.92)}}
@keyframes roll{to{stroke-dashoffset:-28}}

/* job-fair cards (card.html): 85 × 55 mm business cards, black on white like the CV; ten print on an A4 page */
.cards-page{padding-block:clamp(24px,4vw,40px) clamp(40px,6vw,72px);display:grid;gap:22px;justify-items:center;text-align:center}
.cards-head{display:grid;gap:12px;justify-items:center}
.cards-head h1{margin:0;font-size:clamp(2rem,5vw,3rem);line-height:1}
.cards-head .lede{margin:0;max-width:52ch;color:var(--muted)}
.cards{display:grid;justify-content:center;page:cards}
.card{box-sizing:border-box;width:85mm;height:55mm;padding:5mm;display:grid;grid-template-columns:1fr 25mm;gap:3mm;align-items:center;
  background:#fff;color:#111;text-align:left;font:400 7.5pt/1.3 var(--f-body);letter-spacing:normal;box-shadow:0 0 0 1px var(--line),8px 8px 0 var(--teal)}
.card *{letter-spacing:normal}
.card-name{margin:0;font:700 12pt/1.15 var(--f-body)}
.card-role{margin:1.5mm 0 2.5mm;font-style:italic;color:#3a3a3a}
.card-contact{margin:0;padding:0;list-style:none;display:grid;gap:.6mm}
.card-contact li{white-space:nowrap}
.card-qr{margin:0;display:grid;justify-items:center;gap:1mm}
.card-qr img{display:block;width:25mm;height:25mm}
.card-qr figcaption{font:600 6.5pt/1 var(--f-body)}
.card.extra{display:none}
@page cards{size:A4;margin:10mm}
@media print{
  .cards-head{display:none}
  .cards-page{display:block;padding:0}
  .cards{grid-template-columns:repeat(2,85mm);gap:0}
  .card,.card.extra{display:grid;box-shadow:none;border:.2mm dashed #888}
}

/* Languages: the language switch, the Arabic fonts and right-to-left layout. The home page also exists in
   Spanish (/es/) and Arabic (/ar/); Spanish needs nothing beyond the Latin fonts above. */
@font-face{font-family:"Noto Kufi Arabic";font-style:normal;font-weight:600;font-display:swap;src:url("fonts/noto-kufi-arabic-arabic-600-normal.woff2") format("woff2")}
@font-face{font-family:"Noto Kufi Arabic";font-style:normal;font-weight:700;font-display:swap;src:url("fonts/noto-kufi-arabic-arabic-700-normal.woff2") format("woff2")}
@font-face{font-family:"Noto Sans Arabic";font-style:normal;font-weight:400;font-display:swap;src:url("fonts/noto-sans-arabic-arabic-400-normal.woff2") format("woff2")}
@font-face{font-family:"Noto Sans Arabic";font-style:normal;font-weight:600;font-display:swap;src:url("fonts/noto-sans-arabic-arabic-600-normal.woff2") format("woff2")}
.lang{display:flex;gap:2px;margin-inline-start:-6px}
.lang a{font:600 .85rem/1 var(--f-display);color:var(--muted);text-decoration:none;padding:7px 6px 5px;border-bottom:3px solid transparent}
.lang a:hover{color:var(--text)}
.lang a[aria-current="true"]{color:var(--text);border-bottom-color:var(--teal)}
html[lang="ar"]{--f-display:"Noto Kufi Arabic","Chakra Petch","Segoe UI",system-ui,sans-serif;--f-body:"Noto Sans Arabic","Instrument Sans","Segoe UI",system-ui,sans-serif}
html[lang="ar"] body{line-height:1.8}
html[lang="ar"] *{letter-spacing:0!important;font-style:normal!important}
/* the hero's skyline isn't mirrored, so its text stays on the left side */
html[dir="rtl"] .hero-copy{margin-left:0;margin-right:auto}
svg .mono-t{direction:ltr}
/* code and tables of code stay left to right inside a right-to-left page */
html[dir="rtl"] pre,html[dir="rtl"] pre code{direction:ltr;text-align:left}

/* ================= polish: hover, focus and motion details =================
   Everything here is decoration on top of the layout above. Movement uses the separate `translate`,
   `rotate` and `scale` properties, so it never fights the `transform` the reveal and the drawings use. */
::selection{background:var(--amber);color:#0E1F38}

/* nav: the current section is underlined (main.js marks it), and a thin bar shows how far down the page you are */
.nav ul a{position:relative;padding-block:6px;transition:color .2s}
.nav ul a::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:var(--teal);transform:scaleX(0);transform-origin:left;transition:transform .3s cubic-bezier(.2,.8,.2,1)}
.nav ul a:hover::after,.nav ul a.on::after{transform:scaleX(1)}
.nav ul a.on{color:var(--text)}
.nav a[aria-current="page"]{text-decoration:none}
.nav a[aria-current="page"]::after{transform:scaleX(1)}
.nav::after{content:"";position:absolute;left:0;right:0;bottom:calc(-1 * var(--frame));height:var(--frame);background:var(--amber);transform:scaleX(0);transform-origin:left;pointer-events:none}
.toggle{transition:background-color .2s,border-color .2s}
.toggle:hover{border-color:var(--teal)}
.toggle svg{transition:rotate .5s cubic-bezier(.3,1.6,.5,1)}
.toggle:hover svg{rotate:-25deg}

/* buttons lift a little under the pointer and press down when clicked */
.btn:hover{translate:0 -2px}
.btn:active{translate:0 1px}

/* cards: the outline takes the card's colour and the card lifts */
:is(.panel,.skill-col,.cert,.ctf .frame,.next){transition:translate .25s ease,background-color .25s}
.panel:hover,.ctf .frame:hover,.next:hover{background:var(--teal)}
:is(.skill-col,.cert):hover{background:var(--c)}
:is(.skill-col,.cert):hover>.in{background:color-mix(in srgb,var(--c) 9%,var(--panel))}
.panel:hover>.in,.next:hover>.in{background:color-mix(in srgb,var(--teal) 6%,var(--panel))}
.cert svg{transition:rotate .4s cubic-bezier(.3,1.6,.5,1),scale .4s cubic-bezier(.3,1.6,.5,1)}
.cert:hover svg{rotate:-10deg;scale:1.08}
.chips li{transition:background-color .2s,translate .2s}
.chips li:hover{background:color-mix(in srgb,var(--c) 16%,transparent);translate:0 -2px}

/* write-ups: a comic "pop" with a hard shadow */
.post{transition:border-color .2s,translate .2s ease,box-shadow .2s ease}
.post:hover{translate:-3px -3px;box-shadow:6px 6px 0 var(--teal)}
.post h3{transition:color .2s}
.post:hover h3{color:var(--teal-text)}

/* section titles get a skewed bar under them, like the progress meters */
.sec-head h2::after{content:"";display:block;width:72px;height:7px;margin-top:14px;background:var(--teal);transform:skewX(-20deg);transform-origin:left}
#skills .sec-head h2::after{background:var(--blue)}
#certs .sec-head h2::after{background:var(--green)}
#writeups .sec-head h2::after{background:var(--purple)}
#flags .sec-head h2::after{background:var(--purple)}

/* the sun glows at night */
.orb{filter:drop-shadow(0 0 22px var(--glow))}

/* hidden-flag pips pop when one is found */
.pips i.on{animation:pip .45s cubic-bezier(.3,1.8,.5,1)}

@media (hover:none){
  .btn:hover,.chips li:hover,.post:hover{translate:none}
}

@media (prefers-reduced-motion:no-preference){
  /* the hero name gets its shadow after the ink wipe */
  .hero h1{animation:ink-wipe .9s cubic-bezier(.7,0,.2,1) .1s both,shadow-in .45s cubic-bezier(.3,1.6,.5,1) .95s both}
  :is(.panel,.skill-col,.cert):hover{translate:0 -5px}
  .ctf .frame:hover,.next:hover{translate:0 -3px}

  /* scroll-driven touches, where the browser supports them (transform only: content never fades out) */
  @supports (animation-timeline:view()){
    .nav::after{animation:grow linear both;animation-timeline:scroll(root)}
    .sec-head h2::after{animation:grow-skew linear both;animation-timeline:view();animation-range:entry 10% cover 30%}
    :is(.skill-col,.cert,.post,.ctf .frame){animation:settle linear both;animation-timeline:view();animation-range:entry 0% entry 70%}
    .skills>:nth-child(2),.certs>:nth-child(2){animation-range:entry 5% entry 80%}
    .skills>:nth-child(3),.certs>:nth-child(3){animation-range:entry 10% entry 90%}
    .certs>:nth-child(4){animation-range:entry 15% entry 100%}
  }

  /* switching day and night: the new theme spreads out from the button (see main.js) */
  ::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal}
  ::view-transition-new(root){animation:theme-reveal .65s cubic-bezier(.4,0,.2,1)}
}
.theme-switching,.theme-switching *{transition:none!important}
@keyframes shadow-in{from{text-shadow:0 0 0 var(--teal)}to{text-shadow:.045em .045em 0 var(--teal)}}
@keyframes grow{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes grow-skew{from{transform:skewX(-20deg) scaleX(0)}to{transform:skewX(-20deg) scaleX(1)}}
@keyframes settle{from{transform:translateY(28px) scale(.97)}to{transform:none}}
@keyframes pip{0%{scale:.4}60%{scale:1.25}100%{scale:1}}
@keyframes theme-reveal{from{clip-path:circle(0 at var(--vt-x,100%) var(--vt-y,0))}to{clip-path:circle(150vmax at var(--vt-x,100%) var(--vt-y,0))}}
