/* JuliaMono: the monospace face used everywhere (falls back to Courier New);
   self-hosted in assets/fonts like every other dependency */
@font-face {
  font-family: "JuliaMono"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("/assets/fonts/JuliaMono-Regular.woff2") format("woff2");
}
@font-face {
  font-family: "JuliaMono"; font-weight: 700; font-style: normal; font-display: swap;
  src: url("/assets/fonts/JuliaMono-Bold.woff2") format("woff2");
}
@font-face {
  font-family: "JuliaMono"; font-weight: 400; font-style: italic; font-display: swap;
  src: url("/assets/fonts/JuliaMono-RegularItalic.woff2") format("woff2");
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; overflow: hidden; background: #000; }
#view { position: fixed; inset: 0; z-index: 0; } /* both renderers live here */
#scene { position: absolute; inset: 0; z-index: 1; display: block; }
.hidden { display: none !important; }
/* the terminal hides via visibility so its layout stays measurable */
#terminal.off { visibility: hidden; }

/* ---- Themes (picked in the Settings window; default is phosphor) ----
   Every color the terminal uses is one of these variables. */
#terminal { /* phosphor & amber */
  --bg0: #060806; --bg1: #131a12; --border: #2a2f28; --bar: #1a1f19;
  --text: #e8e6d8; --dim: #9fb89a; --head: #f0b840; --prompt: #8fc866;
  --link: #6fd0d0; --err: #e07050;
  --wp-sky: #2b6f80; --wp-horizon: #9cc9ad; --wp-hill: #3f7a26; --wp-hill2: #2b5c18;
}
#terminal[data-theme="candy"] {
  --bg0: #0c0916; --bg1: #171226; --border: #322a48; --bar: #1c1630;
  --text: #ece8f0; --dim: #9a8fc0; --head: #ff4fa3; --prompt: #b48fff;
  --link: #4fd8ff; --err: #ff5f56;
  --wp-sky: #241a52; --wp-horizon: #c05a9e; --wp-hill: #4d2b86; --wp-hill2: #33195e;
}
#terminal[data-theme="contrast"] { /* high contrast: pure black, white text, vivid accents */
  --bg0: #000; --bg1: #0a0a0a; --border: #9a9a9a; --bar: #111;
  --text: #fff; --dim: #d8d8d8; --head: #ffd54a; --prompt: #7dff7d;
  --link: #6ee8ff; --err: #ff8060;
  --wp-sky: #101418; --wp-horizon: #23282e; --wp-hill: #171b20; --wp-hill2: #101418;
}
#terminal[data-theme="light"] { /* paper: aged parchment, ink text */
  --bg0: #c6c0aa; --bg1: #ddd7c0; --border: #8f8a76; --bar: #cfc9b3;
  --text: #262418; --dim: #524d3c; --head: #a05a00; --prompt: #3a7a28;
  --link: #085e7c; --err: #b03020;
  --wp-sky: #a8cbe0; --wp-horizon: #dce6c8; --wp-hill: #90b070; --wp-hill2: #7ba05c;
}
/* the CRT dressing is tuned for dark phosphor: the near-black vignette and
   scanlines read as smudge on paper — swap them for a warm sepia version */
#terminal[data-theme="light"] {
  box-shadow: inset 0 0 90px rgba(62, 52, 30, 0.4),
              inset 0 0 12px color-mix(in srgb, var(--prompt) 18%, transparent);
}
#terminal[data-theme="light"]::after {
  background: repeating-linear-gradient(0deg, transparent 0 3px, rgba(62, 52, 30, 0.06) 3px 5px);
}
/* the handful of places that assume a dark theme via hardcoded whites */
#terminal[data-theme="light"] .elevated {
  color: var(--text); background: rgba(0, 0, 0, 0.08); border-color: rgba(0, 0, 0, 0.22);
}
#terminal[data-theme="light"] .pub-legend .lg:hover { background: rgba(0, 0, 0, 0.05); }
#terminal[data-theme="light"] .win-body::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.3); background-clip: padding-box;
}
#terminal[data-theme="light"] .lg-other,
#terminal[data-theme="light"] .pub-other { --c: #8e8a7c; } /* gray reads on light too */
/* ---- The computer's desktop (rendered onto the 3D monitor via CSS3D;
        size is set from JS to match the screen 1:1 in pixels —
        position/transform are set by CSS3DRenderer) ---- */
#terminal {
  display: flex; flex-direction: column;
  background: radial-gradient(ellipse at 30% 15%, var(--bg1), var(--bg0) 75%);
  border: 2px solid var(--border); border-radius: 10px;
  box-shadow: inset 0 0 90px rgba(0, 0, 0, 0.9),
              inset 0 0 12px color-mix(in srgb, var(--prompt) 18%, transparent);
  color: var(--text); font: 16px/1.5 "JuliaMono", "Courier New", monospace;
}
/* CRT power-on, replayed every time you sit down (class set in terminal.js):
   a glowing dot stretches into a horizontal line, then opens up vertically.
   clip-path + filter only — the element's transform belongs to CSS3DRenderer. */
#terminal.booting { animation: crt-on 0.45s ease-out both; }
@keyframes crt-on {
  0%   { clip-path: inset(49.9% 48%);   filter: brightness(18) saturate(0.2); }
  25%  { clip-path: inset(49.75% 0%);   filter: brightness(14) saturate(0.3); }
  45%  { clip-path: inset(49.5% 0%);    filter: brightness(10) saturate(0.5); }
  80%  { clip-path: inset(1.5% 0%);     filter: brightness(1.7); }
  90%  { filter: brightness(1.3); }
  100% { clip-path: inset(0% 0%);       filter: brightness(1); }
}
/* CRT power-off (the reverse: collapse to a line, then a bright dot) */
#terminal.shutdown { animation: crt-off 0.4s ease-in both; }
@keyframes crt-off {
  0%   { clip-path: inset(0% 0%);      filter: brightness(1); }
  35%  { clip-path: inset(1.5% 0%);    filter: brightness(1.5); }
  70%  { clip-path: inset(49.5% 0%);   filter: brightness(9) saturate(0.4); }
  100% { clip-path: inset(49.9% 48%);  filter: brightness(18) saturate(0.2); opacity: 0; }
}
/* subtle scanlines, pure CSS = free */
#terminal::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: 10px;
  background: repeating-linear-gradient(0deg, transparent 0 3px, rgba(0,0,0,0.1) 3px 5px);
}

/* ---- Top bar: name + section buttons ---- */
/* nowrap so an overflowing nav is detectable (terminal.js -> bottom dock) */
#bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; overflow: hidden;
  padding: 6px 12px; border-bottom: 1px solid var(--border);
}
.who { margin-right: auto; }
.who b { display: block; color: var(--text); font-size: 16px; }
.who span { color: var(--dim); font-style: italic; font-size: 16px; }
#desk-nav { display: flex; gap: 5px; flex-wrap: nowrap; }
/* each button gets an --accent from terminal.js; blended into the theme bg */
#desk-nav button, #bar > button {
  --accent: #8a9a88;
  display: flex; align-items: center; gap: 6px;
  background: color-mix(in srgb, var(--accent) 24%, var(--bg0));
  border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--border));
  border-radius: 5px; padding: 4px 11px; white-space: nowrap;
  color: var(--text); font: 16px "JuliaMono", "Courier New", monospace; cursor: pointer;
}
#desk-nav button:hover, #bar > button:hover {
  background: color-mix(in srgb, var(--accent) 40%, var(--bg0));
  border-color: var(--accent);
}
.sb, .lb:empty { display: none; } /* short labels only show in the dock; empty labels keep icon-only buttons tight */
/* the CV button: a filled gold pill that stands out from the outlined nav */
#desk-nav button.cv {
  --accent: #e8c14a;
  background: color-mix(in srgb, var(--accent) 85%, var(--bg0));
  color: #241a00; font-weight: bold; border-color: var(--accent);
  box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 50%, transparent);
}
#desk-nav button.cv:hover { background: var(--accent); }
/* light theme: the pastel accents melt into the parchment — richer fills over
   a lighter base and darker borders so the chips (incl. the gear) stand out */
[data-theme="light"] #desk-nav button:not(.cv), [data-theme="light"] #bar > button {
  background: color-mix(in srgb, var(--accent) 42%, #ece7d6);
  border-color: color-mix(in srgb, var(--accent) 55%, #6a6450);
}
[data-theme="light"] #desk-nav button:not(.cv):hover, [data-theme="light"] #bar > button:hover {
  background: color-mix(in srgb, var(--accent) 60%, #ece7d6);
}

/* ---- Collapsed nav: a phone-style dock along the bottom (mobile, or when the
        buttons overflow the bar — terminal.js moves #desk-nav below #desk) ---- */
#terminal.compact #desk-nav {
  gap: 4px; padding: 5px 6px;
  background: var(--bar); border-top: 1px solid var(--border);
}
/* each dock item stacks its icon over the short label; widths follow the
   labels (grow to fill the row, shrink with ellipsis if it ever overflows) */
#terminal.compact #desk-nav button {
  flex: 1 1 auto; min-width: 0; flex-direction: column; gap: 1px; padding: 4px 2px;
}
#terminal.compact #desk-nav .lb { display: none; }
#terminal.compact #desk-nav .sb {
  display: block; max-width: 100%; font-size: 12px;
  overflow: hidden; text-overflow: ellipsis;
}
/* secondary buttons (.no-dock, e.g. News/Terminal) are hidden in the dock */
#terminal.compact #desk-nav .no-dock { display: none; }

/* ---- Narrow (mobile) layout: one fullscreen window ---- */
/* keep the tagline, but never let it break the bar layout: one line, ellipsis */
#terminal.narrow .who { min-width: 0; }
#terminal.narrow .who span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* on a phone a 130px thumbnail beside the text looks cramped: publication
   images span the full width, and the profile photo shrinks (see below) */
#terminal.narrow .pub img { width: 100%; }
/* narrow: the photo shrinks and moves to the card's top right, beside the name */
#terminal.narrow .profile { gap: 10px; }
#terminal.narrow .profile img { order: 1; width: 86px; min-width: 0; }
#terminal.narrow .profile-facts { order: 0; min-width: 120px; }
/* the three social buttons squeeze onto one row */
#terminal.narrow .about .btn { padding: 5px 8px; font-size: 13px; gap: 5px; }
/* the settings gear in the top bar: a square 1:1 button */
#terminal.narrow #bar > button { padding: 8px; }

/* ---- Flat mode: touch devices get the terminal as a fullscreen app (main.js
        sets body.flat and skips the CSS3D monitor entirely) ---- */
body.flat #view { display: none; } /* no 3D canvas / world behind it */
body.flat #terminal {
  position: fixed; top: 0; left: 0; z-index: 1;
  border: none; border-radius: 0; transform: none !important;
}
body.flat #terminal::after { border-radius: 0; } /* scanline overlay, squared off */
/* fullscreen windows keep a slim gutter against the screen edges and nav bar
   (overrides the inline 100%/0 geometry from rect()) */
#terminal.narrow .win {
  left: 7px !important; top: 7px !important;
  width: calc(100% - 14px) !important; height: calc(100% - 14px) !important;
}
#terminal.narrow .win-bar { cursor: default; }

/* ---- Windows ---- */
#desk { position: relative; flex: 1; overflow: hidden; }
/* desktop wallpaper: a very blurred XP-style hill + sky, tinted per theme */
#desk::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(55% 40% at 75% 12%, rgba(255, 255, 255, 0.18), transparent 70%),
    radial-gradient(95% 55% at 74% 106%, var(--wp-hill2), transparent 72%),
    radial-gradient(130% 70% at 20% 112%, var(--wp-hill), transparent 75%),
    linear-gradient(180deg, var(--wp-sky) 0%, var(--wp-horizon) 62%, var(--wp-hill) 100%);
  opacity: 0.85;
}
.win {
  position: absolute; min-width: 200px;
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--bg0) 84%, transparent);
  backdrop-filter: blur(5px);
  /* a tinted, glowing border so each window's edges read clearly */
  border: 1px solid color-mix(in srgb, var(--link) 60%, var(--border)); border-radius: 8px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.65),
              0 0 0 1px color-mix(in srgb, var(--link) 25%, transparent),
              0 0 20px color-mix(in srgb, var(--link) 22%, transparent);
  transform-origin: 50% 50%; /* CRT open/close + drag wobble pivot */
  animation: win-open 0.34s ease-out;
}
/* CRT power-on (echoing the monitor's own boot): a bright horizontal line
   snaps to full width, then unfolds vertically — reversed on close. */
@keyframes win-open {
  0%   { transform: scale(0.7, 0.006); opacity: 0; filter: brightness(2.6); }
  45%  { transform: scale(1, 0.006); opacity: 1; filter: brightness(2.2); }
  100% { transform: scale(1, 1); filter: brightness(1); }
}
.win.closing { animation: win-close 0.28s ease-in forwards; pointer-events: none; }
@keyframes win-close {
  0%   { transform: scale(1, 1); opacity: 1; filter: brightness(1); }
  55%  { transform: scale(1, 0.006); opacity: 1; filter: brightness(2.2); }
  100% { transform: scale(0.7, 0.006); opacity: 0; filter: brightness(2.6); }
}
.win-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 10px; background: var(--bar); border-bottom: 1px solid var(--border);
  border-radius: 8px 8px 0 0; cursor: grab; user-select: none;
}
.win-bar:active { cursor: grabbing; }
.win-title { flex: 1; text-align: center; color: var(--text); font-size: 17px; font-weight: bold; }
.win-close {
  background: var(--err); border: none; color: #000; cursor: pointer;
  font: 900 22px/1 monospace; padding: 0 8px; border-radius: 4px;
}
.win-close:hover { background: none; color: var(--err); } /* invert on hover */
.win-body { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 10px 14px; }
/* a padded, translucent-white scrollbar that's easy to spot but unobtrusive
   (the transparent border + padding-box clip leaves breathing room around it) */
.win-body::-webkit-scrollbar { width: 14px; }
.win-body::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.3); border-radius: 7px;
  border: 4px solid transparent; background-clip: padding-box;
}
.win-body::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.5); background-clip: padding-box; }

/* markdown content */
.win-body h1, .win-body h2, .win-body h3 { color: var(--head); margin: 12px 0 6px; }
.win-body h1 { font-size: 1.25em; } .win-body h2 { font-size: 1.1em; }
/* @link -> a clickable title that copies the page's permalink */
.win-body h1.jumplink { width: fit-content; cursor: pointer; }
.win-body h1.jumplink:hover { text-decoration: underline; }
.win-body p, .win-body ul, .win-body ol { margin-bottom: 9px; }
.win-body ul, .win-body ol { padding-left: 20px; }
.win-body a:not(.btn) { color: var(--link); } /* .btn keeps its own black-on-blue text */
.win-body code { background: var(--bar); padding: 1px 5px; border-radius: 3px; }
.win-body hr { border: none; border-top: 1px dashed var(--border); margin: 10px 0; }
.win-body blockquote { border-left: 3px solid var(--border); padding-left: 10px; color: var(--dim); }
.win-body img { max-width: 100%; border-radius: 4px; cursor: zoom-in; } /* click = fullscreen */

/* @cover -> banner image bleeding to the window edges (negates body padding) */
.win-body .cover { width: calc(100% + 28px); margin: -10px -14px 8px; max-width: none; height: 150px; object-fit: cover; border-radius: 0; }

/* @row -> captioned figures side by side */
.figs { display: flex; flex-wrap: wrap; align-items: stretch; gap: 10px; margin: 10px 0; }
/* basis ~half the row so a @row never packs more than two figures side by side;
   each is a faint framed card, echoing the news items and legend */
.figs figure {
  flex: 1 1 calc(50% - 10px); min-width: 150px; text-align: center;
  display: flex; flex-direction: column; padding: 8px;
  background: color-mix(in srgb, var(--bg1) 55%, transparent);
  border: 1px solid var(--border); border-radius: 8px;
}
/* the image area grows to the tallest figure and centers a smaller image, so
   captions of different-sized images still line up along the bottom */
.figs .imw { flex: 1; display: flex; align-items: center; justify-content: center; }
.figs img { width: 100%; }
.figs figcaption { font-size: 16px; font-style: italic; color: var(--text); margin-top: 4px; }

/* fullscreen image viewer (created by lightbox() in terminal.js) */
#lightbox {
  position: absolute; inset: 0; z-index: 1000; cursor: zoom-out;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  background: rgba(0, 0, 0, 0.78);
}
#lightbox img { max-width: 92%; max-height: 82%; }
#lightbox p { color: #fff; background: rgba(0, 0, 0, 0.6); padding: 2px 14px; border-radius: 5px; }

/* dark, uniform, icon-friendly buttons (pub cards, settings, any <a class="btn">
   in the markdown): they sit proud and press down on hover. The About page
   overrides these with per-service brand colors below. */
.btn {
  display: inline-flex; align-items: center; gap: 7px; padding: 6px 13px; cursor: pointer;
  background: color-mix(in srgb, var(--link) 15%, var(--bg0)); color: var(--text);
  font: bold 15px "JuliaMono", "Courier New", monospace;
  border: 1px solid color-mix(in srgb, var(--link) 50%, var(--border)); border-radius: 8px;
  box-shadow: 0 4px 0 rgba(0, 0, 0, 0.5); text-decoration: none;
  transition: transform 0.09s, box-shadow 0.09s, background 0.09s;
}
.btn:hover { transform: translateY(4px); box-shadow: none; background: color-mix(in srgb, var(--link) 30%, var(--bg0)); }
/* publication-card buttons sit on a busy card, so give them a brighter, more
   saturated fill and a bolder edge to make them pop as clear call-to-actions */
.pub .btn {
  background: color-mix(in srgb, var(--link) 32%, var(--bg0));
  border-color: color-mix(in srgb, var(--link) 80%, var(--border));
}
.pub .btn:hover { background: color-mix(in srgb, var(--link) 48%, var(--bg0)); }
.btn svg { width: 1.05em; height: 1.05em; vertical-align: -0.16em; fill: currentColor; }
/* light theme: dark-tuned fills look muddy and the black under-shadow harsh
   on paper — chips lighter than their card, sepia shadow, white on the amber */
[data-theme="light"] .btn {
  background: color-mix(in srgb, var(--link) 12%, #efead9);
  box-shadow: 0 4px 0 rgba(62, 52, 30, 0.4);
}
[data-theme="light"] .pub .btn { background: color-mix(in srgb, var(--link) 24%, #efead9); }
[data-theme="light"] .btn:hover { box-shadow: none; background: color-mix(in srgb, var(--link) 36%, #efead9); }
[data-theme="light"] .btn.active {
  color: #fff; background: var(--head);
  box-shadow: 0 0 0 2px var(--head), 0 4px 0 rgba(62, 52, 30, 0.4);
}
/* current selection (Settings): amber fill so it stands apart from the base */
.btn.active {
  border-color: var(--head); color: var(--bg0);
  background: var(--head); box-shadow: 0 0 0 2px var(--head), 0 4px 0 rgba(0, 0, 0, 0.5);
}
/* social buttons on the About page keep bright brand colors + white text */
.about .btn[href*="github"], .about .btn[href*="linkedin"],
.about .btn[href*="youtube"] { color: #fff; }
.about .btn[href*="github"] { background: #2b3137; }
.about .btn[href*="linkedin"] { background: #0a5c9e; }
.about .btn[href*="youtube"] { background: #c4302b; }
.btn-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; margin-top: 8px; }
/* a project page's action buttons (a top-level .btn-row in the markdown) fill
   the width as an even grid of equal cards, wrapping to one column when narrow */
.md > .btn-row {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 9px; margin: 14px 0;
}
.md > .btn-row .btn { justify-content: flex-start; padding: 8px 14px; }

/* copy/tooltip notice at the bottom of the desk (see toast() in terminal.js) */
.toast {
  position: absolute; bottom: 18px; left: 50%; z-index: 1200; pointer-events: none;
  padding: 6px 16px; border-radius: 6px;
  background: var(--bar); color: var(--text); font: 16px "JuliaMono", "Courier New", monospace;
  border: 1px solid var(--link); box-shadow: 0 4px 18px rgba(0, 0, 0, 0.6);
  animation: toast 1.4s ease forwards;
}
@keyframes toast {
  0% { opacity: 0; transform: translate(-50%, 10px); }
  12%, 72% { opacity: 1; transform: translate(-50%, 0); }
  100% { opacity: 0; transform: translate(-50%, 0); }
}
/* .at: pinned just above the cursor (left/top set inline in toast()) */
.toast.at { bottom: auto; transform: translate(-50%, -145%); animation: toast-at 1.4s ease forwards; }
@keyframes toast-at { 0% { opacity: 0; } 12%, 72% { opacity: 1; } 100% { opacity: 0; } }
/* @settings groups + author marks */
.settings b { display: block; color: var(--head); margin: 12px 0 5px; }
.settings > b:first-child { margin-top: 2px; }
.mark { cursor: pointer; color: var(--head); padding: 0 2px; }
.mark svg { width: 1em; height: 1em; vertical-align: -0.15em; }
.mark:hover { filter: brightness(1.3); }

/* @year -> a section divider: white text on a whiter plate, with extra room
   above so each section reads as its own block */
.elevated {
  margin: 22px 0 10px; padding: 5px; text-align: center; font-weight: bold;
  color: #fff; background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 6px;
}

/* @pub -> a publication card (thumbnail | title, authors, venue, buttons).
   Raised with a tinted, glowing edge like the windows, so each card is its
   own distinct object. */
.pub {
  display: flex; flex-wrap: wrap; gap: 12px; padding: 12px; margin: 16px 0;
  background: color-mix(in srgb, var(--bg0) 84%, transparent);
  border: 1px solid color-mix(in srgb, var(--link) 60%, var(--border)); border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5),
              0 0 0 1px color-mix(in srgb, var(--link) 22%, transparent);
}
/* legend mapping the category colors: centered chips, compact enough that the
   five of them fit on a single row */
.pub-legend {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 8px;
  margin: 10px 0 14px; padding: 7px 8px; font-size: 15px; color: var(--text);
  background: color-mix(in srgb, var(--bg1) 55%, transparent);
  border: 1px solid var(--border); border-radius: 8px;
}
/* each chip toggles a category filter; active chips are boxed in their color */
.pub-legend .lg {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none;
  padding: 2px 7px; border-radius: 6px; border: 1px solid transparent;
}
.pub-legend .lg:hover { background: rgba(255, 255, 255, 0.06); }
.pub-legend .lg.active { border-color: var(--c); background: color-mix(in srgb, var(--c) 22%, transparent); }
.pub-legend .lg::before { content: ""; width: 14px; height: 14px; border-radius: 4px; background: var(--c); }
/* smaller chips on mobile so the five fit within two rows */
#terminal.narrow .pub-legend { gap: 3px 5px; padding: 5px 6px; font-size: 13px; }
#terminal.narrow .pub-legend .lg { gap: 4px; padding: 2px 5px; }
#terminal.narrow .pub-legend .lg::before { width: 11px; height: 11px; }
/* category colors (colorblind-safe Okabe-Ito palette): --c drives both a
   legend chip and the matching cards' left accent bar */
.lg-thesis, .pub-thesis { --c: #cc79a7; }         /* reddish purple */
.lg-poster, .pub-poster { --c: #009e73; }         /* bluish green */
.lg-conference, .pub-conference { --c: #56b4e9; } /* sky blue */
.lg-journal, .pub-journal { --c: #e69f00; }       /* orange */
.lg-other, .pub-other { --c: #c8d0d0; }           /* neutral gray */
.pub { border-left: 4px solid var(--c); }
/* JCR quartile: a small badge flowing inline right after the venue text */
.pub-jcr {
  display: inline-block; margin-left: 4px;
  font-style: normal; padding: 1px 8px; border-radius: 5px; font-size: 13px; font-weight: bold;
  color: var(--head); background: color-mix(in srgb, var(--head) 18%, var(--bg0));
  border: 1px solid color-mix(in srgb, var(--head) 45%, var(--border));
}
.pub img { width: 34%; min-width: 130px; align-self: flex-start; border-radius: 4px; }
.pub-info { flex: 1; min-width: 190px; }
.pub-info > b { color: var(--text); }
.pub-authors { font-size: 16px; margin: 4px 0 2px; }
/* author links: near-white, just underlined so they read as links without shouting */
.pub-authors a { color: var(--text); text-decoration: underline; text-decoration-color: var(--dim); text-underline-offset: 2px; }
.pub-authors a:hover { text-decoration-color: var(--link); }
.pub-venue { font-size: 16px; font-style: italic; color: var(--dim); }
/* awards get a gold pill so they clearly stand out from the venue line */
.pub-mention {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 6px;
  padding: 3px 11px; border-radius: 6px; font-size: 15px; font-weight: bold;
  color: #2a1e00; background: linear-gradient(180deg, #ffd766, #e8a838);
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}
.pub-mention .award { width: 1.15em; height: 1.15em; flex: none; }

/* @grid -> project tiles: cover image, title, description, tinted with the
   project's own color (--tint, an "r,g,b" set on the tile from the JSON) */
.grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); /* three tiles per row */
  gap: 10px; margin: 8px 0 14px;
}
/* on a phone-sized window three tiles get too cramped: drop to two */
#terminal.narrow .grid { grid-template-columns: 1fr; }
/* raised tiles (border + shadow) so they stand out over a window behind them */
.proj {
  display: flex; flex-direction: column; overflow: hidden; text-decoration: none;
  border: 1px solid color-mix(in srgb, rgb(var(--tint)) 55%, var(--border)); border-radius: 8px;
  background: color-mix(in srgb, rgb(var(--tint)) 22%, var(--bg1));
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  transition: transform 0.1s, box-shadow 0.1s, border-color 0.1s;
}
.proj:hover { border-color: var(--link); transform: translateY(-2px); box-shadow: 0 8px 22px rgba(0, 0, 0, 0.6); }
.proj img { width: 100%; aspect-ratio: 16 / 7; object-fit: cover; border-radius: 0; }
.proj b { color: var(--text); padding: 6px 10px 0; }
.proj span { color: color-mix(in srgb, var(--text) 82%, var(--dim)); font-size: 16px; line-height: 1.35; padding: 2px 10px 9px; }

/* the "about me" profile card (photo | neofetch-style facts) */
.profile { display: flex; flex-wrap: wrap; gap: 14px; margin: 4px 0 12px; }
.profile img { width: 34%; min-width: 130px; align-self: flex-start; border-radius: 6px; cursor: auto; }
.profile-facts { flex: 1; min-width: 190px; font-size: 16px; }
.profile-facts b { color: var(--prompt); }
.profile-facts hr { margin: 2px 0 6px; }
.profile-facts i { color: var(--head); font-style: normal; }

/* the News page: each item a card with an accent edge + highlighted date */
.news ul { list-style: none; padding-left: 0; margin: 0; }
.news li {
  margin: 0 0 9px; padding: 8px 12px; line-height: 1.4;
  background: color-mix(in srgb, var(--bg1) 60%, transparent);
  border: 1px solid var(--border); border-left: 3px solid var(--head);
  border-radius: 0 6px 6px 0;
}
.news li strong { color: var(--head); }

/* the shell window */
.shell { display: flex; flex-direction: column; }
.shell .log { flex: 0 1 auto; white-space: pre-wrap; word-break: break-word; }
.shell .log .in::before { content: "❯ "; color: var(--prompt); }
/* each echoed command sits on its own prompt-tinted bar, so the log reads
   as one section per command (negative margin keeps the text aligned) */
.shell .log .in {
  margin: 16px -8px 0; padding: 3px 8px; border-radius: 5px;
  background: color-mix(in srgb, var(--prompt) 22%, transparent);
}
.shell .log .in:first-child { margin-top: 0; }
.shell .log .err { color: var(--err); }
.shell .log .md { white-space: normal; margin: 20px 0 16px; padding-left: 2px; }
.shell .line { display: flex; }
.shell .line span { color: var(--prompt); white-space: pre; }
/* min-width:0 lets the input shrink below its intrinsic size — without it the
   prompt line overflows narrow windows and focusing scrolls the body sideways */
.shell input {
  flex: 1; min-width: 0; background: none; border: none; outline: none;
  color: inherit; font: inherit; caret-color: var(--text);
}

/* ---- Reduced motion: keep every animation's end state but make it instant
        (durations near-zero, not `none`, so animationend still fires — the
        shutdown sequence waits for it). The drag wobble is skipped in JS. ---- */
@media (prefers-reduced-motion: reduce) {
  #terminal.booting, #terminal.shutdown, .win, .win.closing, .toast { animation-duration: 0.01s; }
  .btn, .proj { transition: none; }
}

/* ---- Hints ---- */
#hint {
  position: fixed; bottom: 12vh; left: 50%; transform: translateX(-50%);
  padding: 8px 18px; border-radius: 6px; z-index: 2;
  background: rgba(0, 0, 0, 0.55); color: #fff;
  font: 16px "JuliaMono", "Courier New", monospace; pointer-events: none;
}
