:root{
  --bg:#ffffff;--ink:#111111;--muted:#737373;--rule:#e7e7e7;--hl:#f3d36b;
  --serif:'Spectral',Georgia,'Times New Roman',serif;
  --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --colw:min(540px,38vw);
  --mainx:clamp(440px,55vw,calc(100vw - var(--colw) - 72px)); /* where the content column starts */
}
[data-theme=dark]{--bg:#0b0b0b;--ink:#ececec;--muted:#8b8b8b;--rule:#252525;--hl:#8a6d12}
*{box-sizing:border-box}
html,body{margin:0;background:var(--bg);color:var(--ink)}
body{font-family:var(--serif);font-weight:300;-webkit-font-smoothing:antialiased;transition:background-color .3s,color .3s}
a{color:inherit;text-decoration:none}
a:hover{opacity:.6}
button{all:unset;cursor:pointer}
a:focus-visible,button:focus-visible{outline:1px dashed var(--muted);outline-offset:3px}
.u{text-decoration:underline;text-underline-offset:4px;text-decoration-color:var(--rule)}
.d{font-family:var(--mono);font-size:12px;color:var(--muted)}

/* ---------- header ---------- */
header{position:fixed;top:0;left:0;right:0;z-index:3;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:30px 48px 36px;font-size:15px;font-weight:400;background:linear-gradient(var(--bg) 60%,transparent);pointer-events:none;transition:background .3s}
header>*{pointer-events:auto}
.hrow{display:contents}
.brand{display:flex;align-items:center;gap:14px}
.nameblk{display:flex;flex-direction:column;gap:2px}
.name{font-size:17px}
.updated{font-family:var(--mono);font-size:10.5px;color:var(--muted);min-height:1.2em}
#gz{width:56px;height:44px;display:block;margin:-12px 0}
nav{display:flex;align-items:center;gap:clamp(14px,2.2vw,28px);white-space:nowrap}
nav a{color:var(--muted);transition:color .3s}
nav a.on{color:var(--ink)}
.theme{width:13px;height:13px;border-radius:50%;border:1px solid var(--ink);background:linear-gradient(90deg,var(--ink) 50%,transparent 50%);margin-left:4px;flex:none}
.theme-m{display:none}

/* ---------- the curve ---------- */
.stage{position:fixed;inset:0;z-index:0}
#m{width:100%;height:100%;display:block;touch-action:pan-y;user-select:none;-webkit-user-select:none}
#shapes{position:absolute;left:44px;bottom:22px;z-index:4;display:flex;gap:2px;align-items:center;flex-wrap:wrap;font-family:var(--mono);font-size:11px;color:var(--muted)}
#shapes .pill{position:absolute;left:0;top:0;width:0;height:0;border-radius:6px;background:var(--rule);pointer-events:none;transition:left .45s cubic-bezier(.3,.7,.2,1),top .45s cubic-bezier(.3,.7,.2,1),width .45s cubic-bezier(.3,.7,.2,1)}
#shapes button{position:relative;padding:4px 9px;border-radius:6px;transition:color .3s}
#shapes button:hover,#shapes button.on{color:var(--ink)}
#coord{position:fixed;left:0;top:0;z-index:1;white-space:nowrap;font-family:var(--mono);font-size:11px;color:var(--muted);pointer-events:none}
.hello{position:fixed;left:48px;bottom:64px;z-index:1;pointer-events:none}
.hello p{margin:0;font-size:19px;line-height:1.65;white-space:nowrap}
.hello a{pointer-events:auto;text-decoration:underline;text-underline-offset:5px;text-decoration-color:var(--muted)}

/* ---------- content column ---------- */
main{position:relative;z-index:1;width:var(--colw);margin-left:var(--mainx);padding:100vh 0 45vh;pointer-events:none}
.sec{pointer-events:auto;display:flex;flex-direction:column;gap:20px;padding-bottom:22vh}
.sec h2{margin:0 0 8px;font-weight:400;font-size:42px;line-height:1.05;letter-spacing:-.01em}
.sec p{margin:0;font-size:18px;line-height:1.65;text-wrap:pretty}
.meta{font-family:var(--mono);font-size:11px;color:var(--muted);margin-bottom:-6px;min-height:1.3em}
.btn{font-family:var(--mono);font-size:12px;color:var(--muted);border:1px solid var(--rule);border-radius:6px;padding:4px 9px;white-space:nowrap;line-height:1.3}
.btn:hover{border-color:var(--muted);color:var(--ink);opacity:1}

/* about */
.idrow{display:grid;grid-template-columns:128px 1fr;gap:22px;align-items:end;padding-bottom:22px;border-bottom:1px solid var(--rule);margin-bottom:4px}
.portrait{width:128px;height:160px;object-fit:cover;object-position:50% 40%;background:var(--rule);display:block;border-radius:6px;filter:grayscale(.15)}
.portrait.mono{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;font-style:italic;font-size:44px;color:var(--muted);filter:none}
.portrait.mono small{font-family:var(--mono);font-style:normal;font-size:9.5px}
.idlinks{display:flex;flex-direction:column;gap:8px;font-family:var(--mono);font-size:12px;color:var(--muted)}
.idlinks a{display:flex;justify-content:space-between;gap:12px;border-bottom:1px solid var(--rule);padding-bottom:6px}
.idlinks a:hover{color:var(--ink);opacity:1}
.bio{display:flex;flex-direction:column;gap:16px}
.bio p{font-size:17.5px;line-height:1.7}

/* lists (news, cv) */
.sub{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);padding-bottom:10px;border-bottom:1px solid var(--rule);margin-top:8px}
.list{display:flex;flex-direction:column;gap:18px}
.row{display:grid;grid-template-columns:78px 1fr;gap:16px;align-items:baseline}
.row .m{font-size:18px;line-height:1.4;font-weight:400}
.row .s{display:block;font-size:15.5px;line-height:1.45;color:var(--muted);margin-top:2px}
.row.news .m{font-weight:300}
.inline{font-size:16.5px;line-height:1.7;color:var(--muted)}
.inline b{font-weight:400;color:var(--ink)}

/* collections (projects, reading list) */
.empty{font-style:italic;color:var(--muted);font-size:18px}
.devnote{font-family:var(--mono);font-size:11px;line-height:1.55;color:var(--muted);border:1px dashed var(--rule);border-radius:6px;padding:8px 10px}
.stack{display:flex;flex-direction:column;gap:20px}
.bar{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-top:-8px}
.bar .d{font-size:11.5px}
.btns{display:flex;gap:6px;flex:none}
.allbtn{font-family:var(--mono);font-size:11.5px;color:var(--ink);border:1px solid var(--rule);border-radius:6px;padding:5px 10px;white-space:nowrap}
.allbtn:hover{border-color:var(--muted)}
.filters{display:flex;flex-direction:column;gap:8px;margin-top:-6px}
.chips{display:flex;flex-wrap:wrap;gap:6px}
.chips:empty{display:none}
.chip{font-family:var(--mono);font-size:11px;color:var(--muted);border:1px solid var(--rule);border-radius:6px;padding:3px 8px;line-height:1.3;transition:color .2s,border-color .2s,background .2s}
.chip:hover{color:var(--ink);border-color:var(--muted)}
.chip.on{color:var(--bg);background:var(--ink);border-color:var(--ink)}
.chip.clear{border-color:transparent;text-decoration:underline;text-underline-offset:3px}
.emb{width:100%;height:clamp(220px,34vh,320px);display:block;border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);touch-action:pan-y}
.cap2{font-size:14px;color:var(--muted);margin-top:-8px;display:flex;gap:4px 16px;flex-wrap:wrap;align-items:baseline;text-wrap:pretty}
.cap2 .lg{font-family:var(--mono);font-size:11px;display:flex;gap:12px}
.entry{display:grid;grid-template-columns:78px 1fr;gap:16px;align-items:baseline;padding:18px 0;border-top:1px solid var(--rule);transition:opacity .2s}
.entry:last-child{border-bottom:1px solid var(--rule)}
.entry.wide{grid-template-columns:1fr}
.entry.ph{opacity:.5}
.entry.ph:hover,.entry.ph.hl{opacity:.8}
.et{font-size:19px;line-height:1.35;font-weight:400;text-wrap:pretty}
a.et:hover{opacity:1;text-decoration:underline;text-underline-offset:4px;text-decoration-color:var(--muted)}
.entry.hl .et{text-decoration:underline;text-underline-offset:4px;text-decoration-color:var(--muted)}
.es{display:block;font-size:15.5px;line-height:1.5;color:var(--muted);margin-top:6px;text-wrap:pretty}
.ea{display:block;font-size:14.5px;color:var(--muted);margin-top:4px;font-style:italic}
.meta2{display:block;font-family:var(--mono);font-size:11px;color:var(--muted);margin-top:6px}
.lk{display:flex;flex-wrap:wrap;gap:4px 12px;font-family:var(--mono);font-size:11px;color:var(--muted);margin-top:8px}
.lk button{color:var(--ink);text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--rule)}
.lk button:hover{text-decoration-color:var(--ink)}
.none{font-style:italic;color:var(--muted);font-size:16px;padding:14px 0}

/* the Projects terminal: one session, each project a command whose output is its title as a banner, what
   it is, and its live demo. Every .l is a line, numbered in the gutter by site.js. Black in both themes. */
.term{
  --bg:#0a0a0a;--ink:#e6e6e6;--muted:#878787;--rule:#262626;--gut:#4a4a4a;
  --lh:22px;--gw:46px;--padr:16px;--c1:calc(var(--colw) - var(--gw) - var(--padr) - 2px);
  container-type:inline-size;position:relative;width:100%;padding:12px var(--padr) 12px var(--gw);
  background:var(--bg);color:var(--ink);border:1px solid var(--bg);border-radius:6px;color-scheme:dark;
  font:400 12px/var(--lh) var(--mono);font-variant-ligatures:none;text-align:left
}
[data-theme=dark] .term{--bg:#000;border-color:#1f1f1f}
/* a project opened fully (docs.js): the terminal moves left over the curve, keeping its right edge. Its
   titles, descriptions and demos keep the column's width (--c1), so only the space beside them grows. */
.term{transition:margin-left .48s cubic-bezier(.3,.7,.2,1),width .48s cubic-bezier(.3,.7,.2,1)}
.term.max{margin-left:calc(48px - var(--mainx));width:calc(100% + var(--mainx) - 48px)}
.term .entry>.p{max-width:var(--c1)}
.term button{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;cursor:pointer;line-height:inherit;text-align:inherit}
.term h2,.term h3,.term p,.term figure{margin:0;font:inherit;letter-spacing:0}
.term a,.term .u{text-decoration:underline;text-underline-offset:4px;text-decoration-color:var(--muted)}
.term .mu,.term .m,.term .ps{color:var(--muted)}
.term .r{text-align:right}
.term .sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.term .l{position:relative;min-height:var(--lh);display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;column-gap:2ch}
.term .l::before{content:attr(data-ln);position:absolute;top:0;left:calc(-1 * var(--gw) - var(--pad,0px));width:calc(var(--gw) - 16px);text-align:right;white-space:pre;font:10px/var(--lh) var(--mono);color:var(--gut);pointer-events:none;-webkit-user-select:none;user-select:none}
.term .l.c{justify-content:center;text-align:center}
.term .p{display:block;color:#bdbdbd;text-wrap:pretty}
.term .p code{font:inherit;color:var(--ink)}
.term .kv{display:grid;grid-template-columns:13ch minmax(0,1fr);column-gap:2ch}
.term .kv3{display:grid;grid-template-columns:13ch minmax(0,1fr) auto;column-gap:2ch}
.term .kv3>span:first-child{margin-left:-.5ch}
.term .divider{color:var(--muted)}
.term .divider>span{flex:1 1 auto;min-width:0;overflow:hidden;white-space:nowrap}
.term .divider>span::after{content:'========================================================================================================================================================================'}
/* bracket buttons */
.term .t{padding:0 .5ch;white-space:nowrap}
.term .t:hover{outline:1px solid var(--ink);outline-offset:-1px}
.term .t[aria-pressed=true]{background:var(--ink);color:var(--bg)}
.term .t:disabled,.term .t:disabled:hover{color:var(--muted);cursor:default;outline:none}
.term .l>.t:first-child,.term .l>span>.t:first-child{margin-left:-.5ch}
/* a project: the command, then its banner. The banner's cells are twice as tall as wide (as in figlet.js),
   and every banner shares one cell size (--B columns fill the column); its line rounds up to whole lines.
   With a demo, the banner is a button that opens it. */
.term .entry{display:block;padding:0;border:0}
.term .entry.hl .cmd>span{text-decoration:underline;text-underline-offset:4px;text-decoration-color:var(--muted)}
.term .fig{align-items:center;height:calc(var(--c1) * var(--rows) * 2 / var(--B));height:round(up,var(--c1) * var(--rows) * 2 / var(--B),var(--lh))}
.term .fig svg{display:block;flex:none;width:calc(var(--c1) * var(--cols) / var(--B));height:auto;overflow:visible}
.term .fig button{display:block}
.term .fig .bk{fill:var(--ink);transition:fill .2s}
.term .fig .sh{fill:none;stroke:var(--muted);stroke-width:1px;vector-effect:non-scaling-stroke;transition:stroke .2s}
.term .fig button:hover .bk{fill:#fff}
.term .fig button:hover .sh{stroke:var(--ink)}
.term .cur{display:inline-block;width:.62em;height:1.15em;vertical-align:-.22em;background:currentColor;animation:term-blink 1.1s steps(1) infinite}
@keyframes term-blink{50%{opacity:0}}
.flash{animation:flash 1.8s ease}
@keyframes flash{0%,35%{background:var(--rule)}100%{background:transparent}}

/* contact */
.mail{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;font-size:19px;font-weight:400}
.form{display:flex;flex-direction:column;gap:14px;margin-top:4px}
.form label{display:flex;flex-direction:column;gap:6px;font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.form input,.form textarea{all:unset;box-sizing:border-box;width:100%;font-family:var(--serif);font-size:17px;font-weight:300;color:var(--ink);letter-spacing:0;text-transform:none;border-bottom:1px solid var(--rule);padding:6px 0;transition:border-color .2s}
.form textarea{min-height:110px;resize:vertical;line-height:1.55}
.form input:focus,.form textarea:focus{border-color:var(--ink)}
.send{align-self:flex-start;font-family:var(--mono);font-size:12px;color:var(--bg);background:var(--ink);border-radius:6px;padding:8px 14px;margin-top:4px}
.send:hover{opacity:.8}
.links{display:flex;gap:24px;flex-wrap:wrap;font-size:16px;color:var(--muted)}

/* drawer */
.drawer{position:fixed;z-index:5;top:0;right:0;bottom:0;width:min(620px,50vw);background:var(--bg);border-left:1px solid var(--rule);border-radius:8px 0 0 8px;padding:28px 24px 40px;overflow:auto;transform:translateX(100%);visibility:hidden;transition:transform .45s cubic-bezier(.2,.7,.2,1),visibility .45s}
.drawer.on{transform:none;visibility:visible}
.dh{display:flex;justify-content:space-between;align-items:baseline;gap:16px;margin-bottom:20px}
.dh h3{margin:0;font-weight:400;font-size:22px}
.dh button{font-family:var(--mono);font-size:12px;color:var(--muted)}
.dfilter{all:unset;box-sizing:border-box;width:100%;font-family:var(--mono);font-size:12px;border-bottom:1px solid var(--rule);padding:8px 0;margin-bottom:18px;color:var(--ink)}
.dlist{columns:150px;column-gap:18px;font-size:12.5px;line-height:1.35}
.dlist button,.dlist div{display:block;break-inside:avoid;padding:2px 0 4px;cursor:pointer}
.dlist .au{color:var(--muted);font-size:11px;margin-left:5px}

/* link preview card */
.peek{position:fixed;z-index:6;left:0;top:0;width:300px;background:var(--bg);border:1px solid var(--rule);border-radius:8px;overflow:hidden;box-shadow:0 12px 32px rgba(0,0,0,.12);pointer-events:none;opacity:0;visibility:hidden;transform:translateY(4px);transition:opacity .18s,transform .18s,visibility .18s}
[data-theme=dark] .peek{box-shadow:0 12px 32px rgba(0,0,0,.6)}
.peek.on{opacity:1;visibility:visible;transform:none}
.peek img{display:block;width:100%;aspect-ratio:16/10;object-fit:cover;background:var(--rule);border-bottom:1px solid var(--rule)}
.peek .pt{display:flex;flex-direction:column;gap:3px;padding:10px 12px 12px;font-size:15px;line-height:1.35}
.peek .ps{color:var(--muted);font-size:14px}

/* local preview only: highlights text that still needs filling in */
.dev .fill{background:color-mix(in srgb,var(--hl) 35%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--hl) 35%,transparent);border-radius:2px}

/* ---------- small screens: curve becomes a sticky banner ---------- */
@media (max-width:860px),(max-width:1180px) and (max-aspect-ratio:4/5){
  header{position:static;background:none;flex-direction:column;align-items:flex-start;gap:14px;padding:22px 22px 10px}
  .hrow{display:flex;width:100%;justify-content:space-between;align-items:center}
  .theme-m{display:block}
  .theme-d,#coord{display:none}
  nav{gap:8px 20px;font-size:15px;flex-wrap:wrap;white-space:normal}
  .stage{position:sticky;top:0;height:clamp(220px,36vh,360px);z-index:2;background:var(--bg);border-bottom:1px solid var(--rule)}
  #shapes{left:8px;right:8px;bottom:6px;justify-content:center}
  .hello{position:static;padding:22px 22px 0}
  main{width:auto;margin:0;padding:28px 22px 30vh;pointer-events:auto}
  .sec{padding-bottom:88px}
  .sec h2{font-size:36px}
  .row,.entry{grid-template-columns:64px 1fr;gap:12px}
  .term{--gw:36px;--padr:12px;--c1:100cqw;font-size:11.5px}
  .term .l::before{width:calc(var(--gw) - 12px)}
  .term .kv{grid-template-columns:10ch minmax(0,1fr)}
  .term .kv3{grid-template-columns:10ch minmax(0,1fr) auto}
  .drawer{width:100%;border-left:0;border-radius:0}
}
@media (max-height:540px) and (orientation:landscape) and (max-width:1180px){.stage{position:relative}}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
