/* ===== Design tokens ===== */
:root {
  --ink: #14181f;        /* primary text */
  --muted: #5b6470;      /* secondary text */
  --line: #e2e5ea;       /* hairlines */
  --paper: #fbfbf9;      /* light page background */
  --sky: #05070c;        /* research page background — near-black, faint cool cast */
  --sky-text: #cbd5e3;   /* text on dark */
  --accent: #5c7cfa;     /* highlight signal (hover/active) — periwinkle */
  --accent-dim: #3b5bd9;
  --serif: Georgia, "Times New Roman", serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
}

/* ===== Dark theme =====
   Applied when <html> carries data-theme="dark" (set by assets/theme.js,
   either from the saved preference or the OS setting). Only the colour
   tokens change — every rule below reads them, so nothing else needs
   a dark variant. The research page is dark in both themes by design. */
:root[data-theme="dark"] {
  --ink: #e8e8e8;
  --muted: #8a8a8a;
  --line: #242424;         /* lifted off pure black so hairlines stay visible */
  --paper: #000000;
  --accent: #91a7ff;       /* lifted periwinkle: the light value is too dark on black */
  --accent-dim: #b5c4ff;   /* lightened: the dim variant must read on dark */
}

/* Smooth the switch, but never fight a reduced-motion preference. */
body { transition: background-color .2s ease, color .2s ease; }

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--serif);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line); }
a:hover { border-color: var(--accent); color: var(--accent-dim); }

/* ===== Landing page ===== */
.home {
  max-width: 960px;
  margin: 0 auto;
  padding: 8vh 28px 8vh;
}
.home-head {
  display: flex;
  gap: 40px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.portrait {
  width: 190px;
  height: 190px;
  object-fit: cover;
  border-radius: 3px;
  background: var(--line);
  flex-shrink: 0;
}
.portrait-col { flex: 0 0 190px; }
.intro { flex: 1; min-width: 260px; }
h1 { font-size: 2rem; margin: 0 0 2px; letter-spacing: -0.01em; }
.role {
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 18px;
}
.bio { margin: 0 0 22px; }
.pages { display: flex; flex-wrap: wrap; gap: 18px; }
/* Profile links: stacked under the portrait, in its column. */
.links {
  display: flex;
  flex-direction: column;
  gap: 7px;
  align-items: flex-start;
  font-family: var(--mono);
  font-size: 0.8rem;
  margin-top: 14px;
}
.links a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border-bottom: none;      /* the icon+text row shouldn't carry a rule */
}
.links a:hover { color: var(--accent); }
.links a:hover span { border-bottom: 1px solid var(--accent); }
/* Each icon's viewBox is cropped to its own measured ink bounds, so the
   artwork is centred in this square slot regardless of the glyph's
   aspect ratio (preserveAspectRatio defaults to xMidYMid). currentColor
   in the paths means the icon follows the link colour. */
.icon {
  width: 14px;
  height: 14px;
  flex: 0 0 14px;
  align-self: center;
  overflow: visible;
  /* Optical nudge: centring on the flex line sits low against the text's
     x-height, so lift each icon to sit level with the label. */
  position: relative;
  top: -1px;
}
.pages a { border-bottom: none; font-style: italic; color: var(--muted); }
.pages a:hover { color: var(--accent-dim); }

/* ===== Shared top bar ===== */
.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 28px;
  max-width: 960px;
  margin: 0 auto;
  font-family: var(--mono);
  font-size: 0.82rem;
}
.topbar a { border-bottom: none; }
.topbar-links a { margin-left: 20px; color: var(--muted); }
.topbar-links a[aria-current="page"] { color: var(--ink); }
/* Hover: match the name link and theme toggle. Listed after the
   [aria-current] rule so the current page highlights too. */
.topbar a:hover,
.topbar-links a:hover,
.topbar-links a[aria-current="page"]:hover { color: var(--accent); }

/* Theme toggle button (sits in the topbar) */
.theme-toggle {
  margin-left: 20px;
  padding: 3px 9px;
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--muted);
  background: none;
  border: 1px solid var(--line);
  border-radius: 3px;
  cursor: pointer;
  line-height: 1.4;
}
.theme-toggle:hover { color: var(--accent); border-color: var(--accent); }
.research-body .theme-toggle { color: var(--sky-text); border-color: #33506f; }
.research-body .theme-toggle:hover { color: var(--accent); border-color: var(--accent); }

/* ===== Research page ===== */
.research-body { background: var(--sky); color: var(--sky-text); }
.research-body .topbar a { color: var(--sky-text); }
.research-body .topbar-links a[aria-current="page"] { color: #fff; }
.research-body .topbar a:hover,
.research-body .topbar-links a[aria-current="page"]:hover { color: var(--accent); }
.research {
  max-width: 960px;
  margin: 0 auto;
  padding: 10px 28px 10vh;
}
.scene-wrap { text-align: center; }
.scene-hint {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: #7c8aa0;
  letter-spacing: 0.03em;
  margin: 0 0 12px;
}
.scene { width: 100%; height: auto; max-height: 62vh; overflow: visible; }

/* Scene elements */
.orbit { fill: none; stroke: #38506e; stroke-width: 1.2; stroke-dasharray: 4 5; }
.station { fill: #5d7a9e; }
.sat rect { fill: #aebfd4; stroke: #dce6f2; stroke-width: 0.8; }
.sat line { stroke: #6f86a4; stroke-width: 1.4; }
.tca-line { stroke: #8ea3bf; stroke-width: 1; stroke-dasharray: 2 3; }
.scene-label {
  font-family: var(--mono);
  font-size: 11px;
  fill: #6f86a4;
  text-anchor: middle;
}

/* Interactive hotspots */
.hot { cursor: pointer; transition: opacity .15s; }
.hit { fill: transparent; }
.hot:hover .sat rect,
.hot.active .sat rect { fill: var(--accent); stroke: #ccd8ff; }
.hot:hover .station,
.hot.active .station { fill: var(--accent); }
.hot:hover .scene-label,
.hot.active .scene-label { fill: var(--accent); }
.hot:focus { outline: none; }
.hot:focus-visible .scene-label { fill: var(--accent); text-decoration: underline; }

/* ===== Paper list ===== */
.papers { margin-top: 36px; }
.papers-head { display: flex; align-items: baseline; gap: 16px; border-bottom: 1px solid #24344c; padding-bottom: 8px; }
.papers h2 { font-size: 1.1rem; margin: 0; color: #fff; }
.clear-filter {
  font-family: var(--mono);
  font-size: 0.75rem;
  background: none;
  border: 1px solid #33506f;
  color: var(--sky-text);
  padding: 3px 10px;
  border-radius: 3px;
  cursor: pointer;
}
.clear-filter:hover { border-color: var(--accent); color: var(--accent); }
.paper-list { list-style: none; padding: 0; margin: 18px 0 0; }
.paper-list li {
  padding: 14px 0;
  border-bottom: 1px solid #1a2740;
  transition: opacity .2s;
}
.paper-list li.dim { opacity: 0.28; }
.paper-title { display: block; color: #eef2f8; }
.paper-meta { display: block; font-size: 0.85rem; color: #7c8aa0; margin: 2px 0 4px; }
.paper-link { font-family: var(--mono); font-size: 0.78rem; color: var(--accent); border: none; }

/* ===== Projects page ===== */
.projects { max-width: 720px; margin: 0 auto; padding: 4vh 28px 10vh; }
.projects h2 { font-size: 1.4rem; }
.project-list { list-style: none; padding: 0; }
.project-list li { padding: 20px 0; border-top: 1px solid var(--line); }
.project-list h3 { margin: 0 0 6px; }
.project-list p { margin: 0; color: var(--muted); }

/* ===== News page ===== */
.news-page { max-width: 960px; margin: 0 auto; padding: 4vh 28px 10vh; }
.news-page h2 { font-size: 1.4rem; margin: 0 0 4px; }
.page-intro { color: var(--muted); margin: 0 0 28px; }

/* Sidebar year filter + list */
.news-layout { display: flex; gap: 44px; align-items: flex-start; }
.year-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 0 0 88px;
  position: sticky;
  top: 24px;           /* keeps the years in view while the list scrolls */
}
.year-btn {
  font-family: var(--mono);
  font-size: 0.8rem;
  text-align: left;
  padding: 4px 8px;
  background: none;
  border: none;
  border-left: 2px solid transparent;
  color: var(--muted);
  cursor: pointer;
}
.year-btn:hover { color: var(--accent); }
.year-btn.is-active {
  color: var(--ink);
  border-left-color: var(--accent);
}

.news-list { list-style: none; padding: 0; margin: 0; flex: 1; min-width: 0; }
.news-list li { border-top: 1px solid var(--line); }
.news-list li:first-child { border-top: none; }

/* Whole row is one link: square thumb left, text right */
.news-item {
  display: flex;
  gap: 18px;
  align-items: center;
  padding: 16px 0;
  border-bottom: none;
  text-decoration: none;
}
.news-thumb {
  width: 132px;
  height: 88px;           /* 3:2 — gently landscape, closer to the source crops */
  flex: 0 0 132px;
  object-fit: cover;      /* crops to fill, never squashes */
  border-radius: 3px;
  background: var(--line);
  display: block;
}
.news-text { min-width: 0; }
.news-title { display: block; color: var(--ink); }
.news-item:hover .news-title { color: var(--accent-dim); }
.news-meta {
  display: block;
  font-family: var(--mono);
  font-size: 0.76rem;
  color: var(--muted);
  margin-top: 5px;
}

/* ===== Motion / accessibility ===== */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ===== Mobile ===== */
@media (max-width: 600px) {
  .home { padding-top: 4vh; }
  .home-head { gap: 24px; }
  .portrait { width: 130px; height: 130px; }
  .portrait-col { flex-basis: 130px; }
  .links { font-size: 0.76rem; gap: 6px; }

  /* News: year filter becomes a horizontal strip above the list */
  .news-layout { flex-direction: column; gap: 18px; }
  .year-nav {
    flex-direction: row;
    flex-wrap: wrap;
    flex-basis: auto;
    position: static;
    gap: 4px;
  }
  .year-btn {
    border-left: none;
    border-bottom: 2px solid transparent;
  }
  .year-btn.is-active { border-left-color: transparent; border-bottom-color: var(--accent); }
  .news-thumb { width: 102px; height: 68px; flex-basis: 102px; }
}
