/* dyrland.ai — homepage.
   Blue-black ink on overcast Bergen paper. The only colour that is not ink is
   the red pencil, and it is reserved for marks that look drawn by hand. The CV
   pages still use style.css. */

:root{
  --paper:#edefea;
  --paper-deep:#e2e6df;
  --sheet:#f7f8f4;
  --ink:#1b2c37;
  --graphite:#5d6a70;
  --pencil:#c4cbc6;
  --red:#b0392b;

  --serif:"Source Serif 4",Georgia,"Times New Roman",serif;
  --hand:"Kalam","Bradley Hand","Segoe Print",cursive;

  --wrap:min(1180px,100% - 3rem);
  --gap:clamp(5rem,12vw,10rem);
  --ease:cubic-bezier(.22,.8,.24,1);
  --spring:cubic-bezier(.3,1.35,.45,1);
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%; scroll-behavior:smooth; scroll-padding-top:5rem; color-scheme:light}
body{
  margin:0; background:var(--paper); color:var(--ink);
  font:400 1.1rem/1.62 var(--serif); font-optical-sizing:auto;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  font-feature-settings:"onum" 1,"kern" 1;
}
/* Paper grain. Fixed so it doesn't scroll with the content like a texture. */
body::before{
  content:""; position:fixed; inset:0; pointer-events:none; z-index:100;
  opacity:.42;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .36 0 0 0 0 .38 0 0 0 0 .36 0 0 0 .09 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
html.locked{overflow:hidden; scroll-behavior:auto}
@media (min-width:861px){ html{scrollbar-gutter:stable} }

h1,h2,h3{font-weight:400; margin:0; text-wrap:balance}
p{margin:0; text-wrap:pretty}
a{color:inherit; text-decoration-thickness:1px; text-underline-offset:.2em; text-decoration-color:var(--pencil)}
a:hover{text-decoration-color:var(--ink)}
img{max-width:100%; height:auto; display:block}
button{font:inherit; color:inherit; background:none; border:0; padding:0; cursor:pointer}
:focus-visible{outline:2px solid var(--red); outline-offset:4px; border-radius:3px}
.wrap{width:var(--wrap); margin-inline:auto}
.visually-hidden{position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap}

/* ---- hand-drawn marks ------------------------------------------------------
   Every .ink path is drawn by site.js as it scrolls into view. The filter
   roughens the edge so a clean bezier reads as pencil on paper. */
.ink{fill:none; stroke:var(--red); stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round; filter:url(#pencil)}
.ink--ink{stroke:var(--ink)}
.ink--thin{stroke-width:1.5}
.note{font-family:var(--hand); font-weight:300; color:var(--red); font-size:1.15rem; line-height:1.25}

/* ---- bar ------------------------------------------------------------------ */
.bar{
  position:sticky; top:0; z-index:20;
  background:color-mix(in srgb,var(--paper) 86%,transparent);
  -webkit-backdrop-filter:blur(10px) saturate(1.1); backdrop-filter:blur(10px) saturate(1.1);
  border-bottom:1px solid transparent; transition:border-color .4s;
}
.bar.scrolled{border-bottom-color:var(--pencil)}
.bar{transition:border-color .4s, background-color .4s, color .4s}
.bar.dark{background:color-mix(in srgb,var(--ink) 88%,transparent); color:var(--paper); border-bottom-color:transparent}
.bar.dark nav a{color:#aebbc0}
.bar.dark nav a:hover,.bar.dark .lang [aria-current]{color:var(--paper)}
.bar.dark .lang{border-left-color:#43565f}
.bar .wrap{display:flex; align-items:center; justify-content:space-between; gap:1rem; padding-block:1rem}
.bar__name{font-size:1.08rem; text-decoration:none; font-weight:500; letter-spacing:-.005em}
.bar nav{display:flex; align-items:center; gap:clamp(.9rem,2.4vw,2rem); font-size:.98rem}
.bar nav a{text-decoration:none; color:var(--graphite); transition:color .2s}
.bar nav a:hover{color:var(--ink)}
.lang{display:inline-flex; gap:.45rem; padding-left:clamp(.2rem,1vw,.8rem); border-left:1px solid var(--pencil); font-size:.9rem}
.lang [aria-current]{color:var(--ink)}
@media (max-width:640px){ .bar nav .opt{display:none} }

/* ---- hero ----------------------------------------------------------------- */
.hero{padding:clamp(3.5rem,9vw,7.5rem) 0 var(--gap)}
.hero .wrap{display:grid; grid-template-columns:minmax(0,1.15fr) minmax(0,1fr); gap:3rem; align-items:center}
.hero h1{
  font-size:clamp(2.3rem,4.6vw,3.9rem); line-height:1.06; letter-spacing:-.028em;
  font-weight:360; font-variation-settings:"opsz" 60;
}
.hero__lede{margin-top:2rem; max-width:34rem; font-size:clamp(1.12rem,1.6vw,1.3rem); color:var(--graphite); line-height:1.55}
.hero__lede a{color:var(--ink)}
.hero__meta{margin-top:2.4rem; display:flex; flex-wrap:wrap; gap:.6rem 1.6rem; font-size:1rem}
.hero__meta a{text-decoration:none; color:var(--ink); position:relative}
.hero__meta a::after{content:""; position:absolute; left:0; right:0; bottom:-.15rem; height:1px; background:var(--pencil); transform-origin:left; transition:background .3s}
.hero__meta a:hover::after{background:var(--ink)}

/* The pile: app icons tossed on the desk. Each tile is a button that opens
   the app. Positions come from inline custom properties. */
.pile{position:relative; aspect-ratio:1/1; width:100%; max-width:520px; justify-self:end}
.pile__tile{
  position:absolute; left:var(--x); top:var(--y); width:var(--s,26%);
  transform:translate3d(0,var(--py,0px),0) rotate(var(--r));
  transition:transform .6s var(--spring), filter .4s;
  will-change:transform;
}
.pile__tile img{
  width:100%; border-radius:22.5%;
  box-shadow:0 1px 1px rgba(27,44,55,.08),0 10px 24px -8px rgba(27,44,55,.28),0 30px 50px -30px rgba(27,44,55,.35);
}
.pile__tile:hover,.pile__tile:focus-visible{transform:translate3d(0,calc(var(--py,0px) - 8px),0) rotate(0deg) scale(1.06); z-index:5}
.pile__note{position:absolute; left:-2%; bottom:-4%; width:58%; pointer-events:none}
.pile__note .note{position:absolute; left:0; bottom:0; transform:rotate(-4deg)}
.pile__note svg{position:absolute; left:38%; bottom:1.6rem; width:52%; overflow:visible}

@media (max-width:860px){
  .hero .wrap{grid-template-columns:1fr}
  /* On phones the pile becomes a still, slightly tilted grid: no overlap, no drift. */
  .pile{aspect-ratio:auto; max-width:26rem; justify-self:start; margin-top:.5rem; display:grid; grid-template-columns:repeat(3,1fr); gap:1.3rem 1.4rem; padding-bottom:2.6rem; max-width:20rem}
  .pile__tile{position:relative; left:auto; top:auto; width:100%; transform:rotate(calc(var(--r) * .45))}
  .pile__tile:hover,.pile__tile:focus-visible{transform:rotate(0deg) scale(1.05)}
  .pile__tile img{box-shadow:0 1px 2px rgba(27,44,55,.1),0 8px 16px -8px rgba(27,44,55,.3)}
  .pile__note{left:0; bottom:0; width:100%}
  .pile__note svg{display:none}
}

/* ---- section heads -------------------------------------------------------- */
.chapter{padding-bottom:var(--gap)}
.chapter__head{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.2fr); gap:1rem 4rem; align-items:end; margin-bottom:clamp(2.5rem,5vw,4rem)}
.chapter__head h2{font-size:clamp(2.2rem,4.6vw,3.8rem); line-height:1.02; letter-spacing:-.022em; font-weight:360; font-variation-settings:"opsz" 60; position:relative; justify-self:start}
.chapter__head h2 svg{position:absolute; left:-2%; bottom:-.42em; width:104%; height:.5em; overflow:visible}
.chapter__head p{color:var(--graphite); max-width:36rem}
@media (max-width:760px){ .chapter__head{grid-template-columns:1fr} }

/* ---- the index of apps ----------------------------------------------------
   A list, not a grid: names set large, one line each. On devices with a
   mouse, hovering a row floats that app's first screenshot beside the cursor. */
.shelf{border-top:1px solid var(--pencil)}
.app{
  width:100%; display:grid; align-items:center; text-align:left;
  grid-template-columns:4rem minmax(0,15rem) minmax(0,1fr) minmax(0,13rem);
  gap:0 clamp(1.2rem,3vw,2.6rem); padding:1.35rem 0;
  border-bottom:1px solid var(--pencil); position:relative;
}
.app__icon{position:relative; width:4rem; aspect-ratio:1}
.app__icon img,.app__icon .blank{width:100%; border-radius:22.5%; box-shadow:0 1px 2px rgba(27,44,55,.12),0 8px 18px -10px rgba(27,44,55,.35); transition:transform .5s var(--spring)}
.app:hover .app__icon img,.app:hover .app__icon .blank{transform:rotate(-5deg) scale(1.05)}
.app__icon svg{position:absolute; inset:-24%; width:148%; height:148%; overflow:visible; pointer-events:none}
.app__icon svg path{stroke-dasharray:1; stroke-dashoffset:1; transition:stroke-dashoffset .6s var(--ease)}
.app:hover .app__icon svg path,.app:focus-visible .app__icon svg path{stroke-dashoffset:0}
.app__name{
  font-size:clamp(1.7rem,3vw,2.5rem); line-height:1; letter-spacing:-.02em; font-weight:380;
  font-variation-settings:"opsz" 60; transition:transform .5s var(--ease); display:block;
}
.app:hover .app__name{transform:translateX(.35rem)}
.app__line{color:var(--graphite); font-size:1.08rem; line-height:1.4}
.app__state{font-style:italic; font-size:.95rem; color:var(--graphite); justify-self:end; text-align:right}
.app__state::before{content:""; display:inline-block; width:.45rem; height:.45rem; border-radius:50%; background:#3e7a55; margin-right:.55rem; vertical-align:.1em}
.app[data-state="bench"] .app__state::before{background:transparent; box-shadow:inset 0 0 0 1.3px var(--red)}
.app[data-state="client"] .app__state::before{background:var(--ink)}
.app__text{display:contents}
@media (max-width:860px){
  .app{grid-template-columns:3.4rem 1fr; gap:.2rem 1.1rem; align-items:start}
  .app__icon{width:3.4rem; grid-row:span 3}
  .app__line,.app__state{grid-column:2; justify-self:start; text-align:left}
  .app__name{margin-top:.2rem}
}

.peek{
  position:fixed; left:0; top:0; z-index:15; width:190px; pointer-events:none;
  opacity:0; transform:translate3d(var(--px,0),var(--py,0),0) rotate(var(--pr,0deg)) scale(.85);
  transition:opacity .3s var(--ease), transform .12s linear;
}
.peek.on{opacity:1; transform:translate3d(var(--px,0),var(--py,0),0) rotate(var(--pr,0deg)) scale(1)}
.peek img{width:100%; border-radius:1rem; box-shadow:0 2px 4px rgba(27,44,55,.1),0 30px 50px -20px rgba(27,44,55,.5)}
@media (hover:none),(max-width:860px){ .peek{display:none} }

/* Placeholder icon for apps without artwork: a pencilled outline. */
.blank{display:grid; place-items:center; aspect-ratio:1; background:var(--sheet); font-size:2rem; font-weight:400; color:var(--ink); border:1.5px dashed var(--graphite)}

.bench{margin-top:clamp(3.5rem,7vw,5.5rem)}
.bench__head{display:flex; flex-wrap:wrap; align-items:baseline; gap:.5rem 1.5rem; margin-bottom:1.6rem}
.bench__head h3{font-size:clamp(1.6rem,2.8vw,2.2rem); font-weight:380; letter-spacing:-.015em}
.bench__head p{color:var(--graphite); max-width:34rem}

/* Items are revealed once, in order, when the shelf first scrolls in. */
.js .reveal{opacity:0; transform:translateY(14px)}
.js .reveal.in{opacity:1; transform:none; transition:opacity .8s var(--ease),transform .8s var(--ease); transition-delay:calc(var(--i,0) * 55ms)}

/* ---- data and AI ------------------------------------------------------------
   Roles are <details>: the summary is one line, the body opens smoothly where
   the browser can animate to height:auto and simply appears elsewhere. */
:root{interpolate-size:allow-keywords}
.pipeline{width:100%; height:auto; overflow:visible; margin:0 0 clamp(2.5rem,5vw,4rem)}
.pipeline text{font-family:var(--hand); font-weight:300; font-size:21px; fill:var(--graphite); text-anchor:middle}
.pipeline text.end{text-anchor:end}
.pipeline .fadein,.flow .fadein{opacity:0; transition:opacity .7s var(--ease)}
.pipeline .fadein.on,.flow .fadein.on{opacity:1}
@media (max-width:640px){ .pipeline text{font-size:30px} }

.roles{border-top:1px solid var(--pencil)}
.role{border-bottom:1px solid var(--pencil)}
.role summary{
  list-style:none; cursor:pointer; display:grid; align-items:baseline;
  grid-template-columns:minmax(0,13rem) minmax(0,1fr) minmax(0,12rem) 1.4rem;
  gap:0 clamp(1rem,3vw,2.5rem); padding:1.5rem 0;
}
.role summary::-webkit-details-marker{display:none}
.role__when{color:var(--graphite); font-size:.98rem}
.role__org{font-size:clamp(1.6rem,2.8vw,2.3rem); line-height:1.05; letter-spacing:-.02em; font-weight:380; font-variation-settings:"opsz" 60; transition:transform .5s var(--ease)}
.role summary:hover .role__org{transform:translateX(.35rem)}
.role__title{font-style:italic; color:var(--graphite); justify-self:end; text-align:right}
.role__plus{width:1.1rem; height:1.1rem; align-self:center; stroke:var(--ink); stroke-width:1.6; fill:none; stroke-linecap:round; transition:transform .45s var(--spring)}
.role[open] .role__plus{transform:rotate(45deg)}
.role::details-content{block-size:0; overflow:clip; transition:block-size .55s var(--ease), content-visibility .55s allow-discrete}
.role[open]::details-content{block-size:auto}
.role__body{display:grid; grid-template-columns:minmax(0,13rem) minmax(0,1fr); gap:0 clamp(1rem,3vw,2.5rem); padding:0 0 2rem}
.role__body > *{grid-column:2; max-width:40rem}
.role__body p{color:#3b4b54}
.role__stack{margin-top:1.2rem; font-size:.95rem; color:var(--graphite)!important}
.ticks{list-style:none; margin:1.2rem 0 0; padding:0; display:grid; gap:.6rem}
.ticks li{display:grid; grid-template-columns:1.3rem 1fr; gap:.7rem}
.ticks svg{width:1.1rem; height:1.1rem; margin-top:.35rem; overflow:visible}
.ticks .ink{stroke-dasharray:1; stroke-dashoffset:1; transition:stroke-dashoffset .5s var(--ease); transition-delay:calc(.15s + var(--i,0) * 90ms)}
.role[open] .ticks .ink,.timeline .ticks .ink,.study .ticks .ink{stroke-dashoffset:0}
@media (max-width:760px){
  .role summary{grid-template-columns:1fr 1.4rem; gap:.3rem 1rem}
  .role__when,.role__title{grid-column:1; justify-self:start; text-align:left}
  .role__org{grid-column:1; grid-row:2}
  .role__title{grid-row:3}
  .role__plus{grid-column:2; grid-row:1 / span 3}
  .role__body{grid-template-columns:1fr}
  .role__body > *{grid-column:1}
}

.tools__head{margin-top:clamp(3.5rem,7vw,5rem); font-size:clamp(1.5rem,2.6vw,2rem); font-weight:380; letter-spacing:-.015em; margin-bottom:1.6rem}
.tools{margin:0; display:grid; grid-template-columns:repeat(auto-fit,minmax(15rem,1fr)); gap:1.8rem 3rem}
.tools dt{font-style:italic; color:var(--graphite); margin-bottom:.3rem}
.tools dd{margin:0; font-size:1.05rem; line-height:1.55}

/* ---- research: text beside a live figure ------------------------------- */
.study{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.1fr); gap:clamp(2rem,5vw,5rem); align-items:start; padding:clamp(2.5rem,5vw,4rem) 0; border-top:1px solid var(--pencil)}
.study:last-child{border-bottom:1px solid var(--pencil)}
.study__paper{display:grid; grid-template-columns:9.5rem minmax(0,1fr); gap:0 1.8rem; align-items:start}
.study__page{grid-row:span 3}
.study__summary,.study__links{grid-column:2}
/* The real first page, lying on the desk like a printout. */
.study__page{display:block; transform:rotate(-2.5deg); transition:transform .5s var(--spring)}
.study__page img{width:100%; background:#fff; padding:.35rem; box-shadow:0 1px 2px rgba(27,44,55,.12),0 18px 30px -16px rgba(27,44,55,.45)}
.study__page:hover{transform:rotate(0deg) translateY(-4px) scale(1.03)}
.study:nth-child(odd of .study) .study__page{transform:rotate(2deg)}
.study__kind{font-size:.92rem; color:var(--red); font-style:italic; margin:0 0 .5rem}
.study h3{font-size:clamp(1.3rem,2.1vw,1.65rem); line-height:1.2; font-weight:420; letter-spacing:-.012em}
.study__authors{margin-top:.7rem; color:var(--graphite); font-size:.98rem}
.study__summary{margin-top:1.1rem; color:#3b4b54; padding-left:1rem; border-left:2px solid var(--pencil)}
.study__links{margin-top:1.2rem; display:flex; flex-wrap:wrap; gap:.4rem 1.3rem; font-size:.98rem}
.study__links a{color:var(--ink)}
@media (max-width:900px){ .study{grid-template-columns:1fr} }
@media (max-width:520px){
  .study__paper{grid-template-columns:6.5rem minmax(0,1fr); gap:0 1.1rem}
  .study__page{grid-row:auto}
  .study__summary,.study__links{grid-column:1 / -1}
}

.fig{margin:0; background:var(--sheet); border-radius:1.2rem; padding:clamp(1.2rem,2.5vw,2rem); box-shadow:0 1px 2px rgba(27,44,55,.06),0 20px 40px -30px rgba(27,44,55,.45); position:sticky; top:5.5rem}
.fig svg{width:100%; height:auto; display:block; overflow:visible}
.fig figcaption{margin-top:1rem; font-size:.95rem; color:var(--graphite); line-height:1.5}
.fig__controls{display:grid; gap:1rem; margin-top:1.2rem}
.fig__controls label{display:grid; gap:.35rem; font-size:.98rem}
.fig__controls output{font-variant-numeric:tabular-nums; color:var(--ink); white-space:nowrap}
.fig__row{display:flex; justify-content:space-between; gap:1rem}
.fig input[type=range]{width:100%; accent-color:var(--ink)}
.fig__toggle{display:inline-flex; border:1px solid var(--pencil); border-radius:999px; padding:.2rem; gap:.2rem; flex-wrap:wrap}
.fig__toggle button{padding:.35rem .9rem; border-radius:999px; font-size:.92rem; color:var(--graphite); transition:background .25s,color .25s}
.fig__toggle button[aria-pressed=true]{background:var(--ink); color:var(--sheet)}
.fig .axis{stroke:var(--graphite); stroke-width:1; fill:none}
.fig .grid{stroke:var(--pencil); stroke-width:1; fill:none; stroke-dasharray:2 4}
.fig text{font-family:var(--serif); font-size:13px; fill:var(--graphite)}
.fig .hand{font-family:var(--hand); font-weight:300; font-size:16px; fill:var(--red)}
.fig .lbl{fill:var(--ink); font-size:14px}
.fig .ref{font-size:12.5px; fill:var(--red)}
.fig .muted{fill:var(--graphite); font-style:italic}
.fig .tiny{font-size:11.5px}
.fig .hand{font-size:17px}
.fig__panel[hidden]{display:none}
.fig__toggle{margin-bottom:1.3rem}
.fig__sub{font-size:.95rem; font-style:italic; color:var(--graphite); margin:0 0 .6rem}
.fig__table{width:100%; border-collapse:collapse; margin-bottom:1.6rem; font-variant-numeric:tabular-nums}
.fig__table th,.fig__table td{text-align:right; padding:.4rem .6rem; border-bottom:1px solid var(--pencil); font-weight:400}
.fig__table th:first-child,.fig__table td:first-child{text-align:left; padding-left:0}
.fig__table th{color:var(--graphite); font-size:.92rem}
.fig__table td{color:var(--graphite)}
.fig__table td.win{color:var(--ink); font-weight:560}
.fig__bars{margin-bottom:.4rem}
@media (max-width:640px){
  .fig{padding:1.1rem; border-radius:1rem}
  .fig text{font-size:19px}
  .fig .hand{font-size:22px}
  .fig .ref{font-size:17px}
  .fig__toggle{display:flex; width:100%}
  .fig__toggle button{flex:1; white-space:nowrap; font-size:.88rem; padding:.35rem .5rem}
  .fig__result b{font-size:1.6rem}
}
.fig__readout{font-family:var(--hand); font-weight:300; color:var(--red); font-size:1.2rem; margin:.4rem 0 0; min-height:1.6em}
.fig__result{display:grid; grid-template-columns:1fr 1fr; gap:1rem; margin-top:1rem}
.fig__result div{display:grid; gap:.15rem}
.fig__result span{font-size:.92rem; color:var(--graphite)}
.fig__result b{font-size:2rem; font-weight:380; letter-spacing:-.02em; font-variant-numeric:tabular-nums; font-variation-settings:"opsz" 48}
.fig__result div:last-child b{color:var(--red)}
.swatch{display:inline-block; width:.9rem; height:.45rem; border-radius:2px; background:var(--ink); margin-right:.45rem; vertical-align:.12em}
.swatch--std{background:var(--graphite); opacity:.55}
.fig__result small{font-size:.88rem; color:var(--graphite)}

/* ---- CV ------------------------------------------------------------------- */
.cv__intro{padding:clamp(3rem,8vw,6.5rem) 0 var(--gap)}
.cv__intro .wrap{display:grid; grid-template-columns:minmax(0,1fr) auto; gap:3rem; align-items:start}
.cv__intro h1{font-size:clamp(2.8rem,7vw,5.6rem); line-height:1; letter-spacing:-.03em; font-weight:360; font-variation-settings:"opsz" 60}
.cv__role{margin-top:.8rem; font-style:italic; font-size:1.3rem; color:var(--graphite)}
.cv__lede{margin-top:1.4rem; max-width:40rem; font-size:1.15rem}
.cv__intro .portrait{margin-top:1rem}
.print{color:var(--graphite); text-decoration:underline; text-decoration-color:var(--pencil); text-underline-offset:.2em}
.print:hover{color:var(--ink)}
@media (max-width:760px){ .cv__intro .wrap{grid-template-columns:1fr} .cv__intro .portrait{order:-1; width:9rem; margin-left:.4rem} }

.timeline{position:relative}
.timeline__line{position:absolute; left:calc(13rem + 1.25rem); top:.6rem; bottom:0; width:10px; height:calc(100% - .6rem); overflow:visible}
.timeline ol{list-style:none; margin:0; padding:0}
.timeline > ol > li{display:grid; grid-template-columns:13rem minmax(0,1fr); gap:0 3.5rem; padding-bottom:clamp(2.5rem,5vw,3.5rem); position:relative}
.timeline > ol > li::before{content:""; position:absolute; left:calc(13rem + 1.25rem + 1px); top:.55rem; width:9px; height:9px; border-radius:50%; background:var(--paper); box-shadow:inset 0 0 0 1.5px var(--ink)}
.timeline > ol > li:first-child::before{background:var(--red); box-shadow:none}
.timeline__when{color:var(--graphite); padding-top:.2rem; text-align:right}
.timeline h3{font-size:clamp(1.5rem,2.6vw,2.1rem); line-height:1.1; font-weight:380; letter-spacing:-.018em; font-variation-settings:"opsz" 60}
.timeline__title{font-style:italic; color:var(--graphite); margin-top:.3rem}
.timeline > ol > li > div > p:not(.timeline__title):not(.role__stack){margin-top:.9rem; max-width:40rem; color:#3b4b54}
@media (max-width:760px){
  .timeline__line{left:.2rem}
  .timeline > ol > li{grid-template-columns:1fr; padding-left:1.8rem}
  .timeline > ol > li::before{left:.25rem}
  .timeline__when{text-align:left; margin-bottom:.3rem}
}

.edu{display:grid; grid-template-columns:repeat(auto-fit,minmax(20rem,1fr)); gap:2.5rem 4rem}
.edu h3{font-size:1.35rem; font-weight:420; line-height:1.25}
.edu__where{font-style:italic; color:var(--graphite); margin-top:.3rem}
.edu p:not(.edu__where){margin-top:.6rem; color:#3b4b54}

.mini-apps{list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:1.6rem 2rem}
.mini-apps a{display:grid; justify-items:center; gap:.5rem; text-decoration:none; color:var(--graphite); font-size:.95rem}
.mini-apps img{width:3.6rem; border-radius:22.5%; box-shadow:0 1px 2px rgba(27,44,55,.12),0 8px 18px -10px rgba(27,44,55,.35); transition:transform .45s var(--spring)}
.mini-apps a:hover img{transform:rotate(-5deg) scale(1.06)}
.mini-apps a:hover{color:var(--ink)}

@media print{
  @page{margin:16mm 14mm}
  body{font-size:10.5pt; background:#fff}
  body::before,.bar,.print,#cv-apps,.foot,.pipeline{display:none}
  .chapter,.cv__intro{padding:0 0 8mm}
  .chapter__head{margin-bottom:4mm}
  .chapter__head h2 svg,.timeline__line{display:none}
  .js .reveal{opacity:1; transform:none}
  .timeline > ol > li{break-inside:avoid; padding-bottom:5mm}
  .portrait{box-shadow:none; transform:none; width:32mm}
  a{text-decoration:none}
}

/* ---- Entro ---------------------------------------------------------------- */
.entro{background:var(--ink); color:var(--paper); padding:var(--gap) 0; position:relative; overflow:hidden}
.entro .chapter__head p{color:#aebbc0}
.entro .wrap{position:relative}
.entro__grid{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.15fr); gap:clamp(2.5rem,6vw,6rem); align-items:start}
.entro__text p + p{margin-top:1.1rem}
.entro__text p{color:#d3dbdc; max-width:34rem}
.entro__text a{color:var(--paper); text-decoration-color:#6f8189}
.entro__facts{margin:2.4rem 0 0; padding:0; list-style:none; display:grid; gap:1.1rem}
.entro__facts li{display:grid; grid-template-columns:1.4rem 1fr; gap:.8rem; color:#d3dbdc}
.entro__facts svg{width:1.3rem; height:1.3rem; margin-top:.3rem; overflow:visible}
.entro .ink{stroke:#e0735f}
.entro .ink--ink{stroke:#dfe5e3}
.flow{width:100%; height:auto; overflow:visible}
.flow text{font-family:var(--hand); font-weight:300; fill:#dfe5e3; font-size:19px}
.flow .label-strong{font-family:var(--serif); font-size:21px; font-weight:400}
.flow .label-red{fill:#e0735f}
@media (max-width:860px){ .entro__grid{grid-template-columns:1fr} }

/* ---- research ------------------------------------------------------------- */
.research{padding-top:var(--gap)}
.papers{display:grid; gap:0}
.paper{
  display:grid; grid-template-columns:5rem minmax(0,1fr); gap:1.5rem; padding:1.8rem 0;
  border-top:1px solid var(--pencil); text-decoration:none;
}
.paper:last-child{border-bottom:1px solid var(--pencil)}
.paper__year{color:var(--graphite); font-variant-numeric:oldstyle-nums; font-size:1.05rem; padding-top:.3rem}
.paper h3{font-size:clamp(1.3rem,2.2vw,1.65rem); line-height:1.25; font-style:italic; font-weight:380; letter-spacing:-.01em; max-width:44rem; transition:color .3s}
.paper__by{display:block; margin-top:.6rem; color:var(--graphite); font-size:.98rem}
.paper:hover h3{color:var(--red)}
@media (max-width:600px){ .paper{grid-template-columns:1fr; gap:.4rem} }

/* ---- contact -------------------------------------------------------------- */
.contact{padding:var(--gap) 0}
.contact .wrap{display:grid; grid-template-columns:minmax(0,1fr) auto; gap:3rem; align-items:center}
.portrait{width:clamp(11rem,18vw,15rem); transform:rotate(3deg); background:#fbfbf8; padding:.7rem .7rem 2.6rem; box-shadow:0 1px 2px rgba(27,44,55,.1),0 22px 40px -22px rgba(27,44,55,.5); position:relative; margin-right:2rem}
.portrait img{width:100%; aspect-ratio:1; object-fit:cover; filter:grayscale(.15) contrast(1.02)}
.portrait figcaption{position:absolute; left:.9rem; bottom:.55rem; font-family:var(--hand); font-weight:300; font-size:1.05rem; color:var(--graphite)}
@media (max-width:760px){ .contact .wrap{grid-template-columns:1fr} .portrait{margin:0 0 0 .5rem; width:11rem} }
.contact__mail{
  display:inline-block; position:relative; margin-top:1.5rem; text-decoration:none;
  font-size:clamp(2.1rem,6.4vw,5rem); line-height:1.05; letter-spacing:-.03em; font-weight:340; font-variation-settings:"opsz" 60;
}
.contact__mail svg{position:absolute; left:-8%; top:-30%; width:116%; height:165%; overflow:visible; pointer-events:none}
.contact__links{margin-top:2.6rem; display:flex; flex-wrap:wrap; gap:.6rem 2rem; font-size:1.05rem}
.contact__links a{text-decoration:none; color:var(--graphite)}
.contact__links a:hover{color:var(--ink)}
.contact h2{font-size:clamp(1.4rem,2.4vw,1.8rem); font-weight:380; color:var(--graphite)}

.foot{border-top:1px solid var(--pencil); padding:2.2rem 0 3rem; font-size:.9rem; color:var(--graphite)}
.foot .wrap{display:flex; flex-wrap:wrap; justify-content:space-between; gap:.8rem 2rem}

/* ---- the app sheet ---------------------------------------------------------
   One <dialog> per app, rendered in the page so the text is indexable. */
.sheet{
  width:min(1040px,100vw - 2rem); max-width:none; max-height:min(92vh,58rem);
  margin:auto; padding:0; border:0; border-radius:1.4rem; overflow:hidden;
  background:var(--sheet); color:var(--ink);
  box-shadow:0 2px 4px rgba(27,44,55,.06),0 40px 90px -30px rgba(27,44,55,.55);
}
.sheet::backdrop{background:rgba(226,230,223,.55); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px)}
.sheet[open]{animation:sheet-in .55s var(--ease)}
.sheet[open]::backdrop{animation:fade-in .4s var(--ease)}
.sheet.closing{animation:sheet-out .28s var(--ease) forwards}
.sheet.closing::backdrop{animation:fade-in .28s var(--ease) reverse forwards}
@keyframes sheet-in{from{opacity:0; transform:translateY(28px) scale(.985)}to{opacity:1; transform:none}}
.sheet[open][data-step]{animation:step-in .32s var(--ease)}
.sheet[open][data-step]::backdrop{animation:none}
.sheet[data-step="prev"]{--from:-28px}
@keyframes step-in{from{opacity:.7; transform:translateX(var(--from,28px))}to{opacity:1; transform:none}}
@keyframes sheet-out{to{opacity:0; transform:translateY(16px) scale(.99)}}
@keyframes fade-in{from{opacity:0}to{opacity:1}}

.sheet h2:focus{outline:none}
.sheet__body{display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,1fr); max-height:inherit; overflow:auto; overscroll-behavior:contain}
.sheet__text{padding:clamp(1.8rem,4vw,3.2rem)}
.sheet__top{display:flex; align-items:center; gap:1.1rem}
.sheet__top img,.sheet__top .blank{width:4.6rem; border-radius:22.5%; box-shadow:0 1px 2px rgba(27,44,55,.12),0 10px 22px -12px rgba(27,44,55,.4)}
.sheet__top .blank{width:4.6rem}
.sheet h2{font-size:clamp(2rem,3.6vw,2.8rem); line-height:1; letter-spacing:-.02em; font-weight:400; font-variation-settings:"opsz" 60}
.sheet__state{display:block; margin-top:.4rem; font-style:italic; color:var(--graphite); font-size:.98rem}
.sheet__tag{margin-top:1.8rem; font-size:clamp(1.25rem,2vw,1.45rem); line-height:1.35; font-variation-settings:"opsz" 30}
.sheet__desc{margin-top:1.1rem; color:#3b4b54}
.sheet__desc p + p{margin-top:.9rem}
.sheet__feats{list-style:none; margin:1.8rem 0 0; padding:0; display:grid; gap:.75rem}
.sheet__feats li{display:grid; grid-template-columns:1.3rem 1fr; gap:.7rem; font-size:1.02rem; line-height:1.5}
.sheet__feats svg{width:1.1rem; height:1.1rem; margin-top:.35rem; overflow:visible}
.sheet__feats .ink{stroke-dasharray:1; stroke-dashoffset:1}
.sheet[open] .sheet__feats .ink{animation:draw .5s var(--ease) forwards; animation-delay:calc(.3s + var(--i,0) * 110ms)}
@keyframes draw{to{stroke-dashoffset:0}}
.sheet__stack{margin-top:1.8rem; font-size:.95rem; color:var(--graphite)}
.sheet__stack b{font-weight:500; color:var(--ink)}
.sheet__cta{margin-top:2rem; display:flex; flex-wrap:wrap; align-items:center; gap:1rem 1.4rem}

.store{
  display:inline-flex; align-items:center; gap:.7rem; padding:.7rem 1.3rem .7rem 1.05rem;
  background:var(--ink); color:var(--sheet); border-radius:.8rem; text-decoration:none;
  font-size:1.02rem; line-height:1.1; transition:transform .35s var(--spring), background .3s;
}
.store svg{width:1.3rem; height:1.3rem; fill:currentColor}
.store small{display:block; font-size:.72rem; opacity:.75; letter-spacing:.01em}
.store:hover{transform:translateY(-2px); background:#0f1d26}
.sheet__cta .plain{color:var(--graphite); font-size:.98rem}
.sheet__soon{font-family:var(--hand); color:var(--red); font-size:1.2rem; font-weight:300}

.sheet__shots{
  position:relative; background:var(--paper-deep);
  display:flex; align-items:center; justify-content:center; padding:2.5rem 1.5rem; min-height:26rem;
  position:sticky; top:0; height:min(92vh,58rem);
}
.shots{position:relative; width:100%; height:100%; min-height:30rem}
.shots img{
  position:absolute; top:50%; left:50%; width:37%; border-radius:1.1rem;
  box-shadow:0 2px 4px rgba(27,44,55,.1),0 24px 40px -18px rgba(27,44,55,.5);
  transform:translate(-50%,-50%) translateX(var(--tx)) rotate(var(--rot));
  transition:transform .7s var(--spring);
}
.shots img:nth-child(1){--tx:-60%; --rot:-7deg; z-index:1}
.shots img:nth-child(2){--tx:0%; --rot:0deg; z-index:3}
.shots img:nth-child(3){--tx:60%; --rot:7deg; z-index:2}
.sheet__shots:hover .shots img:nth-child(1){--tx:-88%; --rot:-4deg}
.sheet__shots:hover .shots img:nth-child(3){--tx:88%; --rot:4deg}
.sheet__sketch{max-width:20rem; text-align:center}
.sheet__sketch svg{width:100%; overflow:visible}
.sheet__sketch .note{display:block; margin-top:1rem}

.sheet__nav{
  position:absolute; top:1rem; right:1rem; z-index:4; display:flex; gap:.4rem;
}
.sheet__nav button{
  width:2.5rem; height:2.5rem; border-radius:50%; display:grid; place-items:center;
  background:color-mix(in srgb,var(--sheet) 88%,transparent); -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  box-shadow:0 0 0 1px rgba(27,44,55,.1); transition:background .2s, transform .3s var(--spring);
}
.sheet__nav button:hover{background:#fff; transform:scale(1.06)}
.sheet__nav svg{width:1rem; height:1rem; stroke:var(--ink); stroke-width:1.8; fill:none; stroke-linecap:round; stroke-linejoin:round}

@media (max-width:820px){
  .sheet{width:100vw; max-height:94vh; margin:auto auto 0; border-radius:1.4rem 1.4rem 0 0}
  .sheet::backdrop{-webkit-backdrop-filter:none; backdrop-filter:none; background:rgba(27,44,55,.28)}
  .sheet__nav button{-webkit-backdrop-filter:none; backdrop-filter:none; background:var(--sheet)}
  /* Rise the last stretch rather than from below the screen: WebKit scrolls the
     page to reveal a focused element that starts off-screen. */
  @keyframes sheet-in{from{opacity:0; transform:translateY(64px)}to{opacity:1; transform:none}}
  @keyframes sheet-out{to{opacity:0; transform:translateY(64px)}}
  .sheet__body{grid-template-columns:1fr}
  .sheet__shots{order:-1; min-height:0; height:auto; position:static; padding:4rem 0 1.5rem}
  .shots{display:flex; align-items:flex-start; gap:1rem; overflow-x:auto; height:auto; min-height:0; padding:0 1.5rem 1rem; scroll-snap-type:x mandatory}
  .shots img{position:static; width:auto; height:auto; flex:0 0 46%; min-width:0; transform:none!important; scroll-snap-align:center}
}

/* ---- view transition from shelf icon to sheet icon ----------------------- */
::view-transition-group(app-icon){animation-duration:.5s; animation-timing-function:var(--ease)}
/* Only the icon morphs; the page itself must not crossfade under the sheet. */
::view-transition-old(root),::view-transition-new(root){animation:none}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important; transition-duration:.01ms!important}
  .js .reveal{opacity:1; transform:none}
  .sheet__feats .ink{stroke-dashoffset:0}
}
