/* Hallmark · shape: kept, the single centred column · genre: editorial · theme: custom · redesign: restyle
 * idea: "the old column, set exactly: one sans, one easing, nothing extra" · vibe: "quiet, exact, monochrome, one centred column"
 * paper: a grey-black column with a hint of brown oklch(19% 0.005 62) on a warm night sky oklch(10.5% 0.008 62), by request · accent: tan oklch(75% 0.045 66) for subheads, dates, link marks and focus, rust oklch(70% 0.06 42) for hover and the current project, both by request · display: Fira Code 700 on every head and item title, kept from the old site by request · body: IBM Plex Mono 400 and 700, tracked -0.03em, by request (a calmer Courier) · hero: kept, centred by request · nav: kept, a centred bar, the current tab bold · footer: kept, the email and four icons · background: a night sky by request (warm twinkling stars, curved shooting stars, a nebula set in glyphs that re-roll), still under reduced motion · signature: one reddit-style thread for all the work, filling tan as you read down it; the current project's node turns rust
 * axes: dark/mono/warm · posture: restrained · motion: cubic-bezier(.7,0,.2,1) on every entry, by client brief · contrast: pass · fold: pass · v2.0.0 */
/* Hallmark · waive 39b · whole-row entries in the projects list, title and brief in one hit target · a 48px control would split every row of the projects list into two targets */
/* Hallmark · dropped https://space.vance.contact · the owner took it off the project list; the site itself stays live */
/* Hallmark · dropped the sky pause button · the owner asked for it gone; reduced motion still keeps the sky still */
/* Hallmark · dismissed 49 · each row button holds a whole projects entry, title and brief; the title is the label and wraps on a phone like any list item */
/* Hallmark · waive 78 · heads at 1.5rem in an 800px column, kept small by request · the client asked for no large type: the column, the list and the voice are the old page's */
/* Hallmark · waive 59 · sections in one narrow column part by a rule and 48px of air · the client asked for the old compact column; 120px gaps would push the list off the first screen */
/* Hallmark · dropped dotCanvas · the old starfield canvas was rebuilt from the ground up by request, as the .sky canvas script.js draws */
/* Hallmark · reworded "← return home" to "projects" · 63 names the glued arrow; the link still goes home, and both pages share one nav */
/* Hallmark · pre-emit critique: P3 H5 E5 S3 R5 V3 · weakest: S, a plain list could be anyone's; kept that way on purpose, the client asked for the old page, simpler */

/* ── Faces, self-hosted (the CSP allows only same-origin fonts):
   IBM Plex Mono for the text (a calmer Courier, by request), IBM's own Latin1 web subsets;
   Fira Code Bold for every head, the face the old site's heads used, now shipped with it ── */
@font-face{font-family:"IBM Plex Mono"; src:url("fonts/IBMPlexMono-Regular-Latin1.woff2") format("woff2"); font-weight:400; font-style:normal; font-display:swap}
@font-face{font-family:"IBM Plex Mono"; src:url("fonts/IBMPlexMono-Bold-Latin1.woff2") format("woff2"); font-weight:700; font-style:normal; font-display:swap}
@font-face{font-family:"IBM Plex Mono"; src:url("fonts/IBMPlexMono-Italic-Latin1.woff2") format("woff2"); font-weight:400; font-style:italic; font-display:swap}
@font-face{font-family:"IBM Plex Mono"; src:url("fonts/IBMPlexMono-BoldItalic-Latin1.woff2") format("woff2"); font-weight:700; font-style:italic; font-display:swap}
@font-face{font-family:"Fira Code"; src:url("fonts/FiraCode-Bold.woff2") format("woff2"); font-weight:700; font-style:normal; font-display:swap}

/* ── Tokens: every colour and face on the site lives here ── */
:root{
  /* Warm neutrals, every grey tinted a little toward brown (hue 62); two quiet accents */
  --color-ground:oklch(10.5% 0.008 62); /* the night sky outside the column */
  --color-paper:oklch(19% 0.005 62);    /* the column: a flat grey-black with a hint of the brown, by request */
  --color-paper-2:oklch(16.5% 0.005 62);/* recessed wells */
  --color-paper-3:oklch(22.5% 0.005 62);/* dialogs */
  --color-ink:oklch(92% 0.013 78);      /* titles */
  --color-ink-2:oklch(84% 0.013 78);    /* body text */
  --color-muted:oklch(71% 0.015 72);    /* briefs, meta: 7.8:1 on the column */
  --color-faint:oklch(53% 0.013 68);    /* field edges, icons at rest */
  --color-bright:oklch(96% 0.010 78);
  --color-rule:oklch(29% 0.005 62);
  --color-rule-2:oklch(35% 0.005 62);
  --color-thread:oklch(42% 0.005 62);   /* the thread before you have read down it */
  --color-tan:oklch(75% 0.045 66);      /* the brown: subheads, dates, link marks, focus */
  --color-rust:oklch(70% 0.06 42);      /* the second colour, a redder sibling of the tan: hover, the current project */
  --color-accent:var(--color-tan); --color-accent-ink:var(--color-paper); --color-focus:var(--color-tan);
  --color-scrim:rgba(0,0,0,.55); --color-scrim-deep:rgba(0,0,0,.93);
  --color-draft:#FFB432; --color-draft-wash:rgba(255,180,50,.1); --color-draft-edge:rgba(255,180,50,.3);
  --color-danger:#ff6b6b; --color-danger-strong:#ff4444; --color-danger-wash:rgba(255,80,80,.1); --color-danger-edge:rgba(255,80,80,.2);

  --font-body:"IBM Plex Mono", ui-monospace, "Courier New", monospace;
  --font-display:"Fira Code", ui-monospace, monospace;
  --tracking-body:-.03em; /* set a little tight, by request */
  --font-code:var(--font-body);

  --space-3xs:2px; --space-2xs:4px; --space-xs:8px; --space-sm:12px; --space-md:16px; --space-lg:24px; --space-xl:40px; --space-2xl:64px; --space-3xl:96px;
  --text-xs:.8125rem; --text-sm:.875rem; --text-body:.9375rem; --text-md:1rem; --text-item:.9375rem; --text-brief:.84375rem; --text-lg:1.25rem; --text-xl:1.875rem; --text-name:2.5rem;

  --ease:cubic-bezier(.7,0,.2,1);
  --dur-1:100ms; --dur-2:160ms; --dur-3:240ms; --dur-4:320ms; /* snappy, by request */
  --step:50ms; /* 3 frames at 60fps */
  --clip-open:inset(-8px); /* a wipe's end state: open, with room for focus rings and descenders */

  --column:800px; --gutter:40px; --nav-h:44px;
  --radius:0px; --radius-input:0px;
  --z-raised:10; --z-nav:300; --z-modal:400; --z-lightbox:450; --z-toast:500;

  /* Old names, kept so nothing that still reads them breaks */
  --fg:var(--color-ink-2); --bg:var(--color-ground); --accent:var(--color-ink); --muted:var(--color-muted);
  --heading:var(--color-ink); --text:var(--color-ink-2); --c7:var(--color-muted); --c15:var(--color-ink-2);
  --radius-lg:var(--radius); --radius-md:var(--radius);
}

/* ── Base ── */
*,*::before,*::after{box-sizing:border-box}
html,body{overflow-x:clip}
html{scrollbar-color:var(--color-faint) var(--color-ground); scroll-padding-top:calc(var(--nav-h) + var(--space-xl)); -webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--color-ground); color:var(--color-ink-2);
  font-family:var(--font-body); font-size:var(--text-md); line-height:1.55; letter-spacing:var(--tracking-body);
  font-synthesis:none; -webkit-font-smoothing:antialiased; caret-color:var(--color-ink);
}
::selection{background:var(--color-ink); color:var(--color-paper)}
:focus-visible{outline:2px solid var(--color-focus); outline-offset:3px}
a{color:inherit; text-decoration-thickness:1px; text-underline-offset:.2em}
h1,h2,h3{margin:0; font-family:var(--font-display); font-weight:700; color:var(--color-ink); letter-spacing:-.02em; line-height:1.15; overflow-wrap:break-word; min-width:0; text-wrap:balance}
p{margin:0; text-wrap:pretty}
img,video{max-width:100%; height:auto; display:block}
svg{display:block; flex-shrink:0}
[hidden]{display:none !important}
button,input,select,textarea{font:inherit; color:inherit}
button{cursor:pointer}
.muted,.subtle{color:var(--color-muted)}
.visually-hidden{position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap}

/* ── The column: one darker strip down the middle ── */
.content-wrap{
  position:relative; z-index:1; max-width:var(--column); min-height:100svh; margin:0 auto;
  background:var(--color-paper); /* flat; the sky lives in the margins */
}
/* The sky: one canvas behind everything (script.js) */
.sky{position:fixed; inset:0; z-index:0; pointer-events:none}
.section{padding:0 var(--gutter)}
.container{max-width:none; margin:0; padding:0}

/* ── Navbar: a small bar, centred; the current tab is bold ── */
.navbar{
  position:fixed; top:var(--space-md); left:50%; z-index:var(--z-nav);
  transform:translateX(-50%);
  display:flex; align-items:center; height:var(--nav-h); padding:0 var(--space-md);
  background:var(--color-paper); border:1px solid var(--color-rule-2);
  transition:border-color var(--dur-2) var(--ease);
}
.navbar.scrolled{border-color:var(--color-faint)}
.nav-links{list-style:none; display:flex; align-items:center; gap:var(--space-xs); margin:0; padding:0}
.nav-link{
  display:inline-flex; flex-direction:column; align-items:center; justify-content:center;
  min-height:40px; padding:0 var(--space-sm);
  font-size:var(--text-sm); line-height:1; color:var(--color-muted); text-decoration:none; white-space:nowrap;
  transition:color var(--dur-1) var(--ease);
}
/* Reserve the bold width so the active tab never shifts its neighbour */
.nav-link::after{content:attr(data-text); font-weight:700; height:0; visibility:hidden; overflow:hidden; pointer-events:none}
.nav-link:hover{color:var(--color-rust)}
.nav-link.active,.nav-link[aria-current="page"]{color:var(--color-ink); font-weight:700}

/* ── Hero: the name, one line, a rule ── */
.hero-section{padding-top:calc(var(--space-md) + var(--nav-h) + var(--space-xl)); text-align:center}
.title.about{font-size:var(--text-name); line-height:1.1}
.mask{display:inline-block; overflow:clip; vertical-align:top; padding:0 .06em .2em; margin:0 -.06em -.2em}
.mask .w{display:inline-block}
.lead{margin-top:var(--space-2xs); font-size:var(--text-body); color:var(--color-tan)}
.hero-contact{margin-top:var(--space-sm); font-size:var(--text-sm)}
/* Contact: a small outlined control that takes you to the footer */
.contact-btn{
  display:inline-flex; align-items:center; gap:var(--space-xs); min-height:36px; padding:0 var(--space-sm) 0 var(--space-md);
  border:1px solid var(--color-rule-2); border-radius:var(--radius);
  color:var(--color-ink); text-decoration:none; font-weight:700;
  transition:color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.contact-btn svg{color:var(--color-tan); transition:transform var(--dur-2) var(--ease), color var(--dur-1) var(--ease)}
.contact-btn:hover{color:var(--color-rust); border-color:var(--color-rust)}
.contact-btn:hover svg{color:var(--color-rust); transform:translateY(2px)}
.contact-btn:active{transform:translateY(1px)}
.hero-divider{height:1px; margin-top:var(--space-lg); background:var(--color-rule-2); color:var(--color-ink); transform-origin:50% 50%}

/* ── Projects ── */
.projects-section{padding-top:var(--space-lg); padding-bottom:var(--space-xl)}
.projects-title{font-size:var(--text-xl); letter-spacing:-.025em; margin-bottom:var(--space-md)}
.subsection-title{
  margin:0 0 var(--space-sm);
  font-size:var(--text-lg); font-weight:700; color:var(--color-tan); text-transform:lowercase;
}
.project-list{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--space-sm)}
.project-item{position:relative}
.project-item-anchor{
  position:relative; display:block; width:100%;
  padding:var(--space-2xs) 0;
  border:0; border-radius:var(--radius); background:none; color:inherit; text-align:left; text-decoration:none;
  cursor:pointer;
}
.project-item-anchor:focus-visible{outline:2px solid var(--color-focus); outline-offset:2px}
.project-item-title{
  display:inline-block; font-family:var(--font-display); font-size:var(--text-item); font-weight:700; line-height:1.25; letter-spacing:-.01em; color:var(--color-ink);
  transition:transform var(--dur-2) var(--ease), color var(--dur-1) var(--ease);
}
/* Hover: the title snaps a few pixels right, nothing else moves */
.project-item-anchor:hover .project-item-title,.project-item-anchor:focus-visible .project-item-title{transform:translateX(6px); color:var(--color-rust)}
.project-item-brief{display:block; margin-top:0; font-size:var(--text-brief); line-height:1.5; color:var(--color-muted); max-width:62ch}
.row-mark{display:inline-block; margin-left:var(--space-3xs); vertical-align:0; color:var(--color-tan)}

/* ── Thread: projects hang off the heading on curved elbows, reddit style, and
   competitions / teams branches off the same trunk with its own replies.
   script.js measures each trunk once (load, resize) and on scroll only moves a
   tan fill down it; items you have passed light up. ── */
.tree{--x:7px; --indent:30px; --gap:var(--space-sm); --elbow:13px; position:relative}
.project-list{position:relative; padding-left:var(--indent)}
.tree-branch{position:relative; padding-left:var(--indent); padding-top:var(--space-lg)}
.trunk{position:absolute; left:var(--x); width:1px; background:var(--color-thread); pointer-events:none}
.project-list > .trunk{left:var(--x)}
.trunk-fill{position:absolute; inset:0; background:var(--color-tan); transform:scaleY(var(--f, 0)); transform-origin:50% 0}
/* Without script the trunk is a plain line down each list */
html:not(.js) .project-list{border-left:1px solid var(--color-thread); margin-left:var(--x)}
/* Elbow: a short curve from the trunk into the title, then a square node */
.project-item::before,.subsection-title::before{
  content:''; position:absolute; pointer-events:none;
  left:calc(var(--x) - var(--indent)); top:calc(var(--elbow) - 8px);
  width:calc(var(--indent) - var(--x) - 9px); height:8px;
  border-left:1px solid var(--color-thread); border-bottom:1px solid var(--color-thread); border-bottom-left-radius:8px;
}
.project-item::after,.subsection-title::after{
  content:''; position:absolute; pointer-events:none;
  left:-9px; top:calc(var(--elbow) - 2px); width:5px; height:5px; background:var(--color-thread);
}
.subsection-title{position:relative; --elbow:12px}
.project-item.is-passed::before,.subsection-title.is-passed::before{border-color:var(--color-tan)}
.project-item.is-passed::after,.subsection-title.is-passed::after{background:var(--color-tan)}
.project-item.is-current::after{background:var(--color-rust)}
/* Colour steps ease only after the first paint, so landing on the page is still */
.thread-live .project-item::before,.thread-live .subsection-title::before{transition:border-color var(--dur-2) var(--ease)}
.thread-live .project-item::after,.thread-live .subsection-title::after{transition:background-color var(--dur-2) var(--ease)}

.project-item-head{display:block}

/* ── Footer ── */
.site-footer{
  display:flex; flex-direction:column; align-items:center; gap:var(--space-xs);
  margin:0 var(--gutter); padding:var(--space-lg) 0 var(--space-lg);
  border-top:1px solid var(--color-rule); text-align:center;
}
.footer-card{position:relative; display:flex; flex-direction:column; align-items:center; gap:var(--space-xs); padding:var(--space-sm) var(--space-lg)}
/* After the contact button scrolls here, a square frame snaps in around the details, holds, then fades */
.footer-card::after{content:''; position:absolute; inset:0; border:1px solid var(--color-tan); opacity:0; pointer-events:none}
.footer-card.is-flagged::after{animation:flag 1.5s var(--ease) both}
@keyframes flag{0%{opacity:0; transform:scale(1.08)} 12%{opacity:1; transform:scale(1)} 70%{opacity:1; transform:scale(1)} 100%{opacity:0; transform:scale(1)}}
.footer-contact{font-size:var(--text-sm); color:var(--color-muted)}
.footer-contact .email{color:var(--color-ink); font-weight:700; text-decoration:underline; text-decoration-color:var(--color-tan); transition:text-decoration-color var(--dur-1) var(--ease)}
.footer-contact .email:hover{color:var(--color-rust); text-decoration-color:var(--color-rust)}
.footer-icons{display:flex; align-items:center; gap:var(--space-2xs)}
.footer-icon{
  display:inline-flex; align-items:center; justify-content:center; width:44px; height:44px;
  color:var(--color-faint); transition:color var(--dur-1) var(--ease);
}
.footer-icon:hover{color:var(--color-rust)}

/* ── Dialogs: hard-edged panels, opened by a wipe ── */
.modal-overlay{
  position:fixed; inset:0; z-index:var(--z-modal);
  display:none; align-items:center; justify-content:center; padding:var(--space-md);
  background:var(--color-scrim);
}
.modal-overlay.active{display:flex; animation:scrim-in var(--dur-2) var(--ease) both}
.modal-overlay.is-closing{animation:scrim-out var(--dur-2) var(--ease) both}
.modal,.project-modal{
  position:relative; width:100%;
  background:var(--color-paper-3); border:1px solid var(--color-rule-2); border-radius:var(--radius);
}
.modal{max-width:400px; padding:var(--space-xl) var(--space-lg) var(--space-lg)}
.modal-overlay.active .modal,.modal-overlay.active .project-modal{animation:wipe-down var(--dur-3) var(--ease) both}
.modal-overlay.is-closing .project-modal{animation:wipe-up var(--dur-2) var(--ease) both}
.modal-close{
  position:absolute; top:var(--space-xs); right:var(--space-xs); z-index:var(--z-raised);
  display:inline-flex; align-items:center; justify-content:center; width:40px; height:40px;
  border:1px solid transparent; border-radius:var(--radius); background:var(--color-paper-3); color:var(--color-muted);
  transition:color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.modal-close:hover{color:var(--color-ink); border-color:var(--color-rule-2)}
.modal-close:active{transform:translateY(1px)}
.modal-title{margin:0 0 var(--space-xs); font-size:var(--text-lg); letter-spacing:-.02em}
.modal-desc{margin:0 0 var(--space-lg); font-size:var(--text-body); color:var(--color-muted)}
.modal-input{
  display:block; width:100%; min-height:44px; padding:var(--space-sm) var(--space-md);
  border:1px solid var(--color-faint); border-radius:var(--radius-input);
  background:var(--color-paper); color:var(--color-ink-2);
  font-size:var(--text-md); outline:2px solid transparent; outline-offset:-3px;
}
.modal-input::placeholder{color:var(--color-muted)}
.modal-input:focus-visible{outline-color:var(--color-focus)}
.modal-submit{
  display:inline-flex; align-items:center; justify-content:center; width:100%; min-height:44px;
  margin-top:var(--space-md); padding:0 var(--space-lg);
  border:1px solid var(--color-accent); border-radius:var(--radius);
  background:var(--color-accent); color:var(--color-accent-ink);
  font-weight:700; font-size:var(--text-sm);
  transition:background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.modal-submit:hover{background:var(--color-rust); border-color:var(--color-rust)}
.modal-submit:active{transform:translateY(1px)}
.modal-submit:disabled{opacity:.55; cursor:not-allowed; transform:none}
.modal-submit--outline{background:transparent; color:var(--color-ink); border-color:var(--color-rule-2)}
.modal-submit--outline:hover{background:var(--color-paper-2); border-color:var(--color-faint)}
.blog-confirm-actions{display:flex; gap:var(--space-xs); margin-top:var(--space-md)}
.blog-confirm-actions .modal-submit{flex:1; margin-top:0}
.success-checkmark{
  display:flex; align-items:center; justify-content:center; width:40px; height:40px; margin:0 0 var(--space-md);
  border:1px solid var(--color-ink); color:var(--color-ink);
}
.success-text{margin:0; color:var(--color-ink-2)}

/* Project detail: one centred panel, scrolls inside */
.project-modal{max-width:560px; max-height:85svh; overflow-y:auto; overscroll-behavior:contain; padding:var(--space-lg)}
.project-modal .modal-close{position:sticky; top:0; float:right; margin:calc(-1 * var(--space-sm)) calc(-1 * var(--space-sm)) 0 var(--space-sm)}
.project-modal::-webkit-scrollbar{width:4px}
.project-modal::-webkit-scrollbar-thumb{background:var(--color-rule-2)}
.project-modal-img{clear:both; width:100%; max-height:40svh; margin:0 0 var(--space-md); object-fit:contain; background:var(--color-paper-2); border-radius:var(--radius)}
.project-modal img{cursor:zoom-in}
.project-modal-title{margin:0 0 var(--space-2xs); font-size:var(--text-xl); letter-spacing:-.025em}
.project-modal-date{margin:0 0 var(--space-md); font-size:var(--text-xs); color:var(--color-tan)}
.project-modal-link{
  display:inline-flex; align-items:center; min-height:36px; margin-bottom:var(--space-md);
  padding:0 var(--space-sm); border:1px solid var(--color-rule-2);
  color:var(--color-ink); text-decoration:none; font-size:var(--text-sm);
  transition:border-color var(--dur-1) var(--ease);
}
.project-modal-link:hover{border-color:var(--color-rust); color:var(--color-rust)}
.project-modal-desc-body{font-size:var(--text-body); color:var(--color-ink-2); line-height:1.65}
.pm-sec + .pm-sec{margin-top:var(--space-md)}
.project-modal-section-label{display:block; margin:0 0 var(--space-3xs); font-family:var(--font-display); font-size:var(--text-md); font-weight:700; letter-spacing:-.01em; color:var(--color-ink); line-height:1.3}
.project-modal-desc-body p{margin:0}
.project-modal-desc-body img{width:100%; margin-top:var(--space-sm); background:var(--color-paper-2)}
.project-modal-desc-body a{color:var(--color-ink); text-decoration:underline; text-decoration-color:var(--color-tan)}
.project-modal-desc-body a:hover{color:var(--color-rust); text-decoration-color:var(--color-rust)}
.project-modal-desc-body b{color:var(--color-ink); font-weight:700}

/* Lightbox: the image opens like a shutter from its centre line */
.lightbox-overlay{
  position:fixed; inset:0; z-index:var(--z-lightbox);
  display:none; align-items:center; justify-content:center;
  padding:var(--space-xl); background:var(--color-scrim-deep);
}
.lightbox-overlay.active{display:flex; animation:scrim-in var(--dur-2) var(--ease) both}
.lightbox-overlay img{max-width:100%; max-height:100%; object-fit:contain}
.lightbox-overlay.active img{animation:shutter var(--dur-3) var(--ease) both}
.lightbox-close{
  position:fixed; top:var(--space-sm); right:var(--space-sm); z-index:var(--z-raised);
  display:inline-flex; align-items:center; justify-content:center; width:44px; height:44px;
  border:1px solid var(--color-rule-2); border-radius:var(--radius); background:var(--color-paper-3); color:var(--color-ink);
  transition:border-color var(--dur-1) var(--ease);
}
.lightbox-close:hover{border-color:var(--color-ink)}

/* Toast: a strip wiped up from the bottom */
.toast-banner{
  position:fixed; left:50%; bottom:var(--space-lg); z-index:var(--z-toast);
  transform:translateX(-50%); max-width:calc(100% - 2 * var(--space-md));
  padding:var(--space-sm) var(--space-md);
  border:1px solid var(--color-rule-2); border-radius:var(--radius);
  background:var(--color-paper-3); color:var(--color-ink-2); font-size:var(--text-sm); text-align:center;
  clip-path:inset(100% 0 0 0); pointer-events:none;
  transition:clip-path var(--dur-3) var(--ease);
}
.toast-banner.visible{clip-path:inset(0); pointer-events:auto}
.toast-banner .toast-topic{color:var(--color-ink); font-weight:700}

/* ── Shared pieces the blog reuses ── */
.title{font-size:var(--text-xl); color:var(--color-ink)}
.card{background:none; border:0; border-radius:var(--radius)}
.pill{
  display:inline-flex; align-items:center; padding:0 var(--space-xs); min-height:22px;
  border:1px solid var(--color-rule-2); border-radius:var(--radius);
  font-size:var(--text-xs); line-height:1.2; color:var(--color-muted);
}
.fade-in,.fade-in-up{opacity:1}

/* Broken-image fallback */
.img-unavailable{
  position:relative; min-height:2.5rem;
  background:var(--color-paper-2); border:1px dashed var(--color-rule-2); border-radius:var(--radius);
  color:transparent;
}
.img-unavailable::after{
  content:'image unavailable'; position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  font-size:var(--text-sm); color:var(--color-muted);
}

/* ── Motion: nothing animates on page load (by request); only what the visitor does moves ── */
@keyframes scrim-in{from{opacity:0}to{opacity:1}}
@keyframes scrim-out{from{opacity:1}to{opacity:0}}
@keyframes wipe-down{from{clip-path:inset(0 0 100% 0)}to{clip-path:inset(0)}}
@keyframes wipe-up{from{clip-path:inset(0)}to{clip-path:inset(0 0 100% 0)}}
@keyframes shutter{from{clip-path:inset(50% 0 50% 0)}to{clip-path:inset(0)}}

/* ── Phone ── */
@media (max-width:40rem){
  :root{--gutter:20px; --text-name:2rem; --text-xl:1.625rem}
  /* phones have no margins, so the column lets the sky through faintly */
  .content-wrap{background:color-mix(in oklch, var(--color-paper) 92%, transparent)}
  .tree{--indent:24px; --x:5px}
  .project-item::after,.subsection-title::after{left:-8px}
  .navbar{top:var(--space-sm)}
  .hero-section{padding-top:calc(var(--space-sm) + var(--nav-h) + var(--space-lg))}
  .project-modal{max-height:90svh; padding:var(--space-md)}
  .modal-close{width:44px; height:44px}
}

/* ── Reduced motion: everything at its end state, nothing moves ── */
@media (prefers-reduced-motion:reduce){
  *:not(.keep-motion),*:not(.keep-motion)::before,*:not(.keep-motion)::after{
    animation-duration:.01ms !important; animation-delay:0s !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; transition-delay:0s !important; scroll-behavior:auto !important;
  }
}
