/* ===========================================
   FONTS: Self-hosted (run `node scripts/download-fonts.js` to fetch)
   =========================================== */

/* Atkinson Hyperlegible — body text */
@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/atkinson-regular.woff2') format('woff2');
}
@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/atkinson-italic.woff2') format('woff2');
}
@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/atkinson-bold.woff2') format('woff2');
}
@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/atkinson-bold-italic.woff2') format('woff2');
}

/* Recursive — monospace / code (variable: weight 300–700, slant -15–0deg) */
@font-face {
  font-family: 'Recursive';
  font-style: oblique -15deg 0deg;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/recursive-variable.woff2') format('woff2');
}

/* ===========================================
   BASE: Variables & Reset
   =========================================== */

:root {
  /* Font families */
  --font-body: 'Atkinson Hyperlegible', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: 'Recursive', ui-monospace, SFMono-Regular, monospace;
  
  /* Typography */
  --font-size: 15px;
  --font-size-sm: 0.85rem;
  --font-size-xs: 0.8rem;
  --measure: 70ch;
  --leading: 1.5;
  --leading-tight: 1.3;
  --tracking: 0.02em;
  --tracking-wide: 0.05em;
  --name-outline: 4px;
  --underline-thickness: 1px;
  --underline-thickness-hover: 2px;
  --underline-offset: 3px;
  --radius-sm: 2px;
  --transition-speed: 0.15s;
  
  /* Breakpoints — canonical values live in site.json (layout.breakpoint*).
     CSS cannot use variables in @media queries, so these are hardcoded:
       800px  — sidebar rotation, mobile→desktop layout, background image
      1600px  — high-res background image swap */
  
  /* Spacing */
  --space-xs: 0.2rem;
  --space-sm: 0.4rem;
  --space-md: 0.8rem;
  --space-lg: 1.2rem;
  --space-xl: 2rem;
  
  /* Layout */
  --sidebar-width: 3rem;
  --content-max-width: clamp(40rem, 58vw, 70rem);
  --bg-image-width: 35vw;
  
  /* Border frame */
  --frame-outer: 5px;
  --frame-gap: 2px;
  --frame-inner: 3px;
  --frame: calc(var(--frame-outer) + var(--frame-gap) + var(--frame-inner));
  
  /* ---- Theme colors via light-dark() ----
     color-scheme tells the browser (and light-dark()) which mode is active.
     Adding a new color: just add one light-dark() line here.
     Non-color values (shadows, images) still need overrides below. */
  color-scheme: light dark;

  --bg:              light-dark(#ffffff, #1a1a1a);
  --bg-alt:          light-dark(#f5f5f5, #242424);
  --bg-deep:         light-dark(#fff, #111);
  --bg-deep-t:       light-dark(rgba(255,255,255,0), rgba(17,17,17,0));
  --text:            light-dark(#222, #fff);
  --text-muted:      light-dark(#555, #bbb);
  --text-faint:      light-dark(#888, #888);
  --link:            light-dark(#1e3354, #d4e3f5);
  --link-visited:    light-dark(#352248, #ddd0ee);
  --link-hover:      light-dark(#0f2240, #e6eefc);
  --border:          light-dark(#ddd, #444);
  --border-strong:   light-dark(#999, #666);
  --code-bg:         light-dark(#f5f5f5, #242424);
  --selection:       light-dark(#dbeafe, #1e3a5f);
  --accent-primary:  light-dark(#8b1a1a, #c75050);
  --accent-tertiary: light-dark(#c76060, #e09090);
  --frame-color:     light-dark(#000, #fff);
  --nav-hover-bg:    light-dark(#f8f4f6, #2d2a2c);
  --nav-active-bg:   light-dark(#000, #fff);
  --nav-active-text: light-dark(#ede4f2, #1a1a1a);
  --name-fill:       light-dark(#fff, #1a1a1a);
  --name-shadow:     light-dark(#1a1a1a, #fff);

  /* ---- Non-color values (light defaults) ----
     light-dark() only accepts <color>, so shadows and image URLs
     need @media + force-class overrides for dark mode. */
  --shadow:        0 2px 8px rgba(199, 96, 96, 0.12);
  --shadow-strong: 0 2px 8px rgba(199, 96, 96, 0.25);
  --bg-image-1200: url('/assets/greenland-bg-1200.webp');
  --bg-image-1920: url('/assets/greenland-bg-1920.webp');
}

@media (max-width: 799px) {
  :root {
    --frame-outer: 3px;
    --frame-inner: 2px;
    --frame: calc(var(--frame-outer) + var(--frame-gap) + var(--frame-inner));
  }
}

/* Dark mode non-color overrides (system preference) */
@media (prefers-color-scheme: dark) {
  :root {
    --shadow:        0 2px 8px rgba(224, 144, 144, 0.2);
    --shadow-strong: 0 2px 8px rgba(224, 144, 144, 0.35);
    --bg-image-1200: url('/assets/snowflake-bg-1200.webp');
    --bg-image-1920: url('/assets/snowflake-bg-1920.webp');
  }
}

/* Force dark — color-scheme on :root flips all light-dark() colors */
html.force-dark {
  color-scheme: dark;
  --shadow:        0 2px 8px rgba(224, 144, 144, 0.2);
  --shadow-strong: 0 2px 8px rgba(224, 144, 144, 0.35);
  --bg-image-1200: url('/assets/snowflake-bg-1200.webp');
  --bg-image-1920: url('/assets/snowflake-bg-1920.webp');
}

/* Force light — override system dark back to light */
html.force-light {
  color-scheme: light;
  --shadow:        0 2px 8px rgba(199, 96, 96, 0.12);
  --shadow-strong: 0 2px 8px rgba(199, 96, 96, 0.25);
  --bg-image-1200: url('/assets/greenland-bg-1200.webp');
  --bg-image-1920: url('/assets/greenland-bg-1920.webp');
}

/* Body gradient — single rule, vars resolve per mode */
@media (min-width: 800px) {
  body {
    background: linear-gradient(to right, var(--bg) 0%, var(--bg) calc(100% - clamp(8vw, calc(40rem - 22vw), 35vw)), var(--bg-deep) 100%);
    background-attachment: fixed;
  }
}

*, *::before, *::after {
  box-sizing: border-box;
}

/* ===========================================
   TYPOGRAPHY
   =========================================== */

html {
  font-size: var(--font-size);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--font-body);
  line-height: var(--leading);
  color: var(--text);
  background-color: var(--bg);
  margin: 0;
  padding: 0;
  font-weight: 400;
}

/* Wide screen: background image fading in from right.
   Image URLs and overlay color resolve via palette variables —
   no per-mode overrides needed. */
.bg-image {
  position: fixed;
  top: var(--frame);
  right: var(--frame);
  bottom: 0;
  width: calc(var(--bg-image-width) - var(--frame));
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  animation: fadeInBg 0.2s ease-out 0.15s forwards;
  will-change: transform;
  overflow: hidden;
  transition: top var(--transition-speed) ease, bottom var(--transition-speed) ease;
}

.bg-image::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--bg-image-1200);
  background-size: cover;
  background-position: right top;
  background-repeat: no-repeat;
}

/* Left-side fade overlay — blends image into page bg.
   The transparent stop scales with viewport: at narrow desktop the fade
   covers most of the photo (protecting text), at wide viewports it's
   just a short left-edge blend so the photo is mostly visible. */
.bg-image::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to right,
    var(--bg) 0%,
    transparent clamp(5vw, calc(35rem - 22vw), 30vw));
  z-index: 1;
}

@media (max-width: 799px) {
  .bg-image { display: none; }
}

@media (min-width: 1600px) {
  .bg-image::before {
    background-image: var(--bg-image-1920);
  }
}

/* bg-ready: set by <head> script from sessionStorage, ensures bg-image
   is visible before inline body scripts run — critical for view transition
   snapshots which capture state at first render. */
html.bg-ready .bg-image {
  opacity: 1;
  animation: none;
}

@keyframes fadeInBg {
  to { opacity: 1; }
}

/* Site border - double frame using box-shadows (no miter bevels) */
.site-border {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 900;
  /* Outer frame: left + right + top bars */
  box-shadow:
    inset var(--frame-outer) 0 0 0 var(--frame-color),
    inset calc(-1 * var(--frame-outer)) 0 0 0 var(--frame-color),
    inset 0 var(--frame-outer) 0 0 var(--frame-color);
  transition: box-shadow var(--transition-speed) ease;
}

/* Inner frame uses explicit top/right/bottom/left instead of shorthand inset
   so top and bottom can independently adjust to match border state */
.site-border::after {
  content: "";
  position: absolute;
  left: calc(var(--frame-outer) + var(--frame-gap));
  right: calc(var(--frame-outer) + var(--frame-gap));
  top: calc(var(--frame-outer) + var(--frame-gap));
  bottom: 0; /* default: no bottom border, so extend to edge */
  pointer-events: none;
  box-shadow:
    inset var(--frame-inner) 0 0 0 var(--frame-color),
    inset calc(-1 * var(--frame-inner)) 0 0 0 var(--frame-color),
    inset 0 var(--frame-inner) 0 0 var(--frame-color);
  transition: box-shadow var(--transition-speed) ease, top var(--transition-speed) ease, bottom var(--transition-speed) ease;
}

/* Scrolled: remove top bars, inner top extends to edge */
body.scrolled .site-border {
  box-shadow:
    inset var(--frame-outer) 0 0 0 var(--frame-color),
    inset calc(-1 * var(--frame-outer)) 0 0 0 var(--frame-color);
}
body.scrolled .site-border::after {
  top: 0;
  box-shadow:
    inset var(--frame-inner) 0 0 0 var(--frame-color),
    inset calc(-1 * var(--frame-inner)) 0 0 0 var(--frame-color);
}

/* At bottom: add bottom bars, inner bottom pulls in */
.site-border.at-bottom {
  box-shadow:
    inset var(--frame-outer) 0 0 0 var(--frame-color),
    inset calc(-1 * var(--frame-outer)) 0 0 0 var(--frame-color),
    inset 0 var(--frame-outer) 0 0 var(--frame-color),
    inset 0 calc(-1 * var(--frame-outer)) 0 0 var(--frame-color);
}
.site-border.at-bottom::after {
  bottom: calc(var(--frame-outer) + var(--frame-gap));
  box-shadow:
    inset var(--frame-inner) 0 0 0 var(--frame-color),
    inset calc(-1 * var(--frame-inner)) 0 0 0 var(--frame-color),
    inset 0 var(--frame-inner) 0 0 var(--frame-color),
    inset 0 calc(-1 * var(--frame-inner)) 0 0 var(--frame-color);
}

/* Scrolled AND at bottom: sides + bottom only */
body.scrolled .site-border.at-bottom {
  box-shadow:
    inset var(--frame-outer) 0 0 0 var(--frame-color),
    inset calc(-1 * var(--frame-outer)) 0 0 0 var(--frame-color),
    inset 0 calc(-1 * var(--frame-outer)) 0 0 var(--frame-color);
}
body.scrolled .site-border.at-bottom::after {
  top: 0;
  bottom: calc(var(--frame-outer) + var(--frame-gap));
  box-shadow:
    inset var(--frame-inner) 0 0 0 var(--frame-color),
    inset calc(-1 * var(--frame-inner)) 0 0 0 var(--frame-color),
    inset 0 calc(-1 * var(--frame-inner)) 0 0 var(--frame-color);
}

/* Mobile frame widths set via --frame-outer/--frame-inner in :root override */

/* Frame color is set via --frame-color in dark/light mode variables */

/* ===========================================
   SCROLL STATE - top frame disappears, elements snap to top
   =========================================== */

/* Desktop & mobile: sidebar snaps to viewport top when scrolled */
body.scrolled .sidebar {
  top: 0;
}

/* Background image snaps to top */
body.scrolled .bg-image {
  top: 0;
}

/* At bottom: pull sidebar and bg-image up for bottom border */
@media (min-width: 800px) {
  body.at-bottom .sidebar {
    bottom: var(--frame);
  }
}
body.at-bottom .bg-image {
  bottom: var(--frame);
}

/* Back to top - appears on scroll, button style */
.back-to-top {
  position: fixed;
  top: calc(var(--frame) + 0.4rem);
  right: calc(var(--frame) + 0.4rem);
  font-family: var(--font-body);
  font-size: var(--font-size);
  color: var(--bg);
  background: var(--text);
  border: none;
  text-decoration: none;
  writing-mode: vertical-rl;
  letter-spacing: var(--tracking);
  padding: 0.55rem 0.25rem;
  border-radius: var(--radius-sm);
  z-index: 150;
  opacity: 0;
  transform: translateY(-0.5rem);
  transition: opacity var(--transition-speed) ease, transform var(--transition-speed) ease, top var(--transition-speed) ease;
  pointer-events: none;
  cursor: pointer;
}

.back-to-top:hover { opacity: 0.8; }

/* Arrow needs rotation correction in vertical-rl writing mode */
.btt-arrow {
  display: inline-block;
  transform: rotate(-90deg);
}

.back-to-top.visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

body.scrolled .back-to-top {
  top: 0.4rem;
}

.back-to-top-mobile { display: none; }

/* Mobile: position below sticky nav */
@media (max-width: 799px) {
  .back-to-top {
    top: calc(var(--frame) + 2.5rem);
    right: calc(var(--frame) + 0.4rem);
  }
  body.scrolled .back-to-top {
    top: 2.5rem;
  }
  .back-to-top-desktop { display: none; }
  .back-to-top-mobile { display: inline; }
}

/* Profile picture - floated right in about page, pulled up to heading level */
.about-pic {
  float: right;
  width: 20%;
  height: auto;
  border-radius: 50%;
  object-fit: cover;
  aspect-ratio: 1;
  border: 2px solid var(--accent-tertiary);
  margin: 0 0 var(--space-sm) var(--space-md);
  shape-outside: circle(50%);
}

@media (max-width: 799px) {
  .about-pic {
    width: 30%;
  }
}

/* Name SVG — outlined text with hard 80s drop shadow, themed via CSS */
.name-text {
  fill: var(--name-fill);
  stroke: var(--name-shadow);
  stroke-width: var(--name-outline);
  stroke-linejoin: round;
  paint-order: stroke fill;
}
.name-shadow { fill: var(--name-shadow); }

::selection {
  background: var(--selection);
}

h1, h2, h3, h4, h5, h6 {
  line-height: var(--leading-tight);
  margin: 0 0 var(--space-sm);
  font-weight: 700;
  letter-spacing: var(--tracking);
}

h1 { font-size: 1.5rem; }
h2 { font-size: 1.25rem; margin-top: var(--space-lg); }
h3 { font-size: 1.1rem; margin-top: var(--space-md); }
h4, h5, h6 { font-size: 1rem; font-weight: 700; }

p {
  margin: 0 0 var(--space-md);
  max-width: var(--measure);
}

.small, small { font-size: var(--font-size-sm); }
.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }

/* ===========================================
   PILL — inverted label, reusable on any element
   Usage: <span class="pill">text</span>
          <a href="..." class="pill">link</a>
   =========================================== */

.pill {
  color: var(--bg);
  background: var(--text);
  padding: 0.2em 0.5em;
  border-radius: var(--radius-sm);
  font-size: 0.85em;
  letter-spacing: var(--tracking);
  text-decoration: none;
  white-space: nowrap;
}

a.pill:visited { color: var(--bg); }
a.pill:hover { opacity: 0.8; }

/* Write-me CTA — bold text inside outlined button */
.write-me {
  display: block;
  max-width: var(--measure);
  text-align: center;
  padding: 0.45em 0.7em;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  box-shadow: 1.5px 1.5px 0 var(--name-shadow);
  background: var(--bg);
  color: var(--text);
  text-decoration: none;
  font-weight: 700;
  font-size: var(--font-size);
  letter-spacing: var(--tracking);
  transition: box-shadow var(--transition-speed) ease, border-color var(--transition-speed) ease;
}

.write-me:visited { color: var(--text); }

.write-me:hover {
  border-color: var(--text-muted);
  box-shadow: 5px 5px 0 var(--name-shadow);
}

/* ===========================================
   LINKS
   =========================================== */

a {
  color: var(--link);
  text-decoration: underline;
  text-decoration-thickness: var(--underline-thickness);
  text-underline-offset: var(--underline-offset);
}

a:visited { color: var(--link-visited); }
a:hover { text-decoration-thickness: var(--underline-thickness-hover); }

a.wikilink { text-decoration-style: dotted; }

/* ===========================================
   DIVIDERS — gradient fade from left to right
   =========================================== */

.top-header,
.section-header,
footer.site-footer {
  border-bottom: none;
  border-top: none;
  position: relative;
}

.top-header::after,
.section-header::after,
footer.site-footer::before {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: linear-gradient(
    to right,
    var(--text) 0%,
    color-mix(in srgb, var(--text) 30%, transparent) 60%,
    transparent 100%
  );
}

footer.site-footer::before {
  bottom: auto;
  top: 0;
}

/* ===========================================
   LAYOUT - Rotated sidebar nav on desktop
   =========================================== */

.site-wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  position: relative;
  z-index: 2;
  padding-top: var(--frame);
  padding-bottom: var(--frame);
}

.main-content {
  display: flex;
  flex-direction: column;
  flex: 1;
}

/* Desktop: rotated sidebar */
@media (min-width: 800px) {
  .sidebar {
    position: fixed;
    left: var(--frame);
    top: var(--frame);
    bottom: 0;
    width: var(--sidebar-width);
    background: var(--bg);
    z-index: 10;
    transition: top var(--transition-speed) ease, bottom var(--transition-speed) ease;
  }
  
  .sidebar-inner {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    display: flex;
  }
  
  .mobile-header {
    display: none;
  }
  
  .main-content {
    margin-left: calc(var(--sidebar-width) + var(--frame));
    padding: var(--space-lg) calc(var(--space-xl) * 1.4 + var(--frame)) var(--space-lg) var(--space-lg);
    max-width: var(--content-max-width);
    overflow-x: hidden;
  }
  
  /* Top header with name */
  .top-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: var(--space-sm) var(--space-md);
    padding-bottom: var(--space-md);
    margin-bottom: var(--space-lg);
  }
  
  .top-header .site-title {
    display: block;
  }
  
  .top-links {
    display: flex;
    align-items: baseline;
    gap: var(--space-md);
    font-size: var(--font-size-sm);
  }
  
  .top-links .sep {
    color: var(--text-faint);
  }
  
  .top-links a {
    color: var(--text-muted);
    text-decoration: none;
  }
  
  .top-links a:hover {
    color: var(--text);
    text-decoration: underline;
    text-decoration-thickness: var(--underline-thickness);
    text-underline-offset: var(--underline-offset);
  }
}

/* Mobile: stacked, no rotation */
@media (max-width: 799px) {
  .main-content {
    padding: var(--space-md) calc(var(--space-md) + var(--frame));
  }
  
  .top-header {
    display: none;
  }
}

/* Mobile dark mode: stronger shadow on sticky header */
@media (max-width: 799px) and (prefers-color-scheme: dark) {
  .sidebar {
    box-shadow: var(--shadow-strong);
  }
}

@media (max-width: 799px) {
  html.force-dark .sidebar {
    box-shadow: var(--shadow-strong);
  }
}

main {
  flex: 1;
}

/* ===========================================
   SIDEBAR / HEADER
   =========================================== */

.site-title {
  display: block;
  max-width: 21.5rem;
  text-decoration: none;
  margin-bottom: -0.5rem;
}

.site-title .name-svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: hidden;
}

/* Shared nav link styles (desktop and mobile) */
nav.site-nav a {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  text-decoration: underline;
  text-decoration-thickness: var(--underline-thickness);
  text-underline-offset: var(--underline-offset);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  transition: background-color var(--transition-speed) ease, color var(--transition-speed) ease;
}

nav.site-nav a:hover {
  color: var(--text);
  background: var(--nav-hover-bg);
}

nav.site-nav a[aria-current="page"] {
  background: var(--nav-active-bg);
  color: var(--nav-active-text);
  text-decoration: none;
}

/* Desktop: rotated vertical nav */
@media (min-width: 800px) {
  nav.site-nav {
    display: flex;
    flex-direction: row-reverse;  /* In rotated context, reverses so Writing=top, About=bottom */
    flex: 1;              /* Fill all available space */
    width: 100%;          /* Full width of sidebar-inner */
  }
  
  nav.site-nav a {
    font-size: 1rem;
    /* In rotated context: padding-block = visual left/right */
    padding-block: 0.5rem;
  }
}

/* Mobile: horizontal, matching desktop style */
@media (max-width: 799px) {
  .sidebar {
    position: sticky;
    top: var(--frame);
    z-index: 100;
    background: var(--bg);
    padding: 0;
    margin: 0 var(--frame);
    box-shadow: var(--shadow);
    transition: top var(--transition-speed) ease;
  }
  
  .sidebar-inner {
    display: block;
  }
  
  /* Mobile top row: name + utility links (in document flow) */
  .mobile-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    padding: var(--space-sm) var(--space-md);
    margin: 0 var(--frame);
    border-bottom: 1px solid var(--border);
    max-height: 3rem;
    overflow: hidden;
    transition: max-height 0.18s ease, padding 0.18s ease, opacity 0.18s ease, border-color 0.18s ease;
  }
  
  .mobile-header.scrolled {
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    opacity: 0;
    border-color: transparent;
  }
  
  .mobile-header .site-title {
    max-width: 12.3rem;
    margin: 0;
    margin-bottom: -0.2rem;
  }
  
  .mobile-links {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    font-size: var(--font-size-xs);
  }
  
  .mobile-links .sep {
    color: var(--text-faint);
  }
  
  .mobile-links a {
    color: var(--text-muted);
    text-decoration: none;
  }
  
  .mobile-links a:hover {
    color: var(--text);
    text-decoration: underline;
    text-decoration-thickness: var(--underline-thickness);
    text-underline-offset: var(--underline-offset);
  }
  
  /* Mobile nav row */
  nav.site-nav {
    display: flex;
    flex-wrap: wrap;
  }
  
  nav.site-nav a {
    padding: var(--space-sm) var(--space-md);
    font-size: var(--font-size-sm);
  }
  
  .top-header {
    display: none;
  }
}

/* ===========================================
   FOOTER
   =========================================== */

footer.site-footer {
  margin-top: var(--space-xl);
  padding-top: var(--space-md);
  font-size: var(--font-size-sm);
  color: var(--text-muted);
}

.footer-inner {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

.footer-links {
  display: flex;
  gap: var(--space-md);
}

.footer-links a { color: var(--text-muted); }

/* ===========================================
   SITE CONTROLS (theme + language toggle)
   =========================================== */

.site-controls {
  position: fixed;
  bottom: calc(var(--frame) + 2px);
  right: calc(var(--frame) + var(--space-sm));
  z-index: 100;
  font-size: var(--font-size-sm);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 4px;
  display: flex;
  gap: 3px;
  opacity: 0.88;
  transition: opacity var(--transition-speed) ease, bottom var(--transition-speed) ease;
}

.site-controls:hover { opacity: 1; }

/* Mobile: bump above footer when it's in view */
@media (max-width: 799px) {
  .site-controls.above-footer {
    bottom: calc(var(--frame) + 3rem);
  }
}

.site-controls button {
  background: transparent;
  border: none;
  padding: 4px 8px;
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-family: inherit;
}

.site-controls button:hover { color: var(--text); }
.site-controls button.active {
  color: var(--text);
  background: var(--bg-alt);
}

.site-controls .toggle-sep {
  width: 1px;
  background: var(--border);
  align-self: stretch;
  margin: 2px 2px;
}

#dark-toggle {
  font-size: 0.95rem;
}

#lang-toggle {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: -0.02em;
}

/* ===========================================
   HOMEPAGE
   =========================================== */

.home-intro {
  margin-bottom: var(--space-lg);
}

.home-intro p {
  margin-bottom: var(--space-sm);
}

.home-section {
  margin-bottom: var(--space-lg);
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--space-sm);
  padding-bottom: var(--space-xs);
}

.section-title {
  font-size: var(--font-size-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  color: var(--text-muted);
  margin: 0;
}

.section-link {
  font-size: var(--font-size-xs);
  color: var(--text-faint);
}

/* ===========================================
   POST LISTS
   =========================================== */

.post-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.post-list-item {
  margin-bottom: var(--space-md);
}

.post-list-item h3 {
  font-size: 1rem;
  font-weight: 400;
  margin: 0;
}

.post-list-item h3 a {
  color: var(--text);
  text-decoration: none;
}

.post-list-item h3 a:hover { text-decoration: underline; text-decoration-thickness: var(--underline-thickness); }

.post-meta {
  font-size: var(--font-size-sm);
  color: var(--text-muted);
}

.post-meta time {
  font-variant-numeric: tabular-nums;
}

.post-excerpt {
  color: var(--text-muted);
  font-size: 0.9rem;
  margin-top: var(--space-xs);
}

/* Compact: date and title on same line */
.post-list--compact .post-list-item {
  margin-bottom: var(--space-xs);
  display: flex;
  gap: var(--space-md);
  align-items: baseline;
}

.post-list--compact .post-meta {
  min-width: 5rem;
  flex-shrink: 0;
}

/* ===========================================
   FEATURED LIST (with descriptions)
   =========================================== */

.featured-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.featured-item {
  margin-bottom: var(--space-md);
}

.featured-item h3 {
  font-size: 1rem;
  font-weight: 400;
  margin: 0;
  display: inline;
}

.featured-item h3 a {
  color: var(--text);
  text-decoration: none;
}

.featured-item h3 a:hover { text-decoration: underline; text-decoration-thickness: var(--underline-thickness); }

.featured-item .description {
  color: var(--text-muted);
  font-size: 0.9rem;
}

/* ===========================================
   PHOTOS IN TEXT
   Used via: {% photo "img.jpg", "alt", "full" %}
             {% photo "img.jpg", "alt", "right", "Caption" %}
   =========================================== */

/* Shared figure styles */
.photo-full,
.photo-right {
  margin: var(--space-lg) 0;
  line-height: 0;
  --photo-c1: var(--border);
  --photo-c2: var(--border);
  background: linear-gradient(to top right, var(--photo-c1), var(--photo-c2));
  padding: 2px;
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.photo-full img,
.photo-right img {
  display: block;
  border-radius: calc(var(--radius-sm) - 1px);
}

.photo-full figcaption,
.photo-right figcaption {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  line-height: var(--leading);
  padding: var(--space-sm) 1px 0;
  background: var(--bg);
}
}

/* Full width — spans entire content column */
.photo-full {
  max-width: none;
}

.photo-full img {
  width: 100%;
  height: auto;
}

/* Float right — text wraps around it */
.photo-right {
  float: right;
  max-width: 18rem;
  margin: var(--space-sm) 0 var(--space-md) var(--space-lg);
}

.photo-right img {
  width: 100%;
  height: auto;
}

/* On mobile, float-right collapses to full width */
@media (max-width: 799px) {
  .photo-right {
    float: none;
    max-width: none;
    margin: var(--space-lg) 0;
  }
}

/* Mobile hero — theme-switched images, hidden on desktop */
.mobile-hero {
  display: none;
}

@media (max-width: 799px) {
  .mobile-hero {
    display: block;
    margin-top: var(--space-lg);
  }

  .mobile-hero .photo-full {
    margin: 0;
  }

  /* Light mode: show light, hide dark */
  .mobile-hero-light { display: block; }
  .mobile-hero-dark  { display: none; }
}

/* System dark preference */
@media (max-width: 799px) and (prefers-color-scheme: dark) {
  .mobile-hero-light { display: none; }
  .mobile-hero-dark  { display: block; }
}

/* Manual toggle overrides */
@media (max-width: 799px) {
  html.force-dark .mobile-hero-light  { display: none; }
  html.force-dark .mobile-hero-dark   { display: block; }
  html.force-light .mobile-hero-light { display: block; }
  html.force-light .mobile-hero-dark  { display: none; }
}

/* Clearfix — prevent floated photos from leaking into next section */
.home-section::after,
article::after,
section::after {
  content: "";
  display: table;
  clear: both;
}

/* ===========================================
   PROSE
   =========================================== */

ul, ol {
  padding-left: 1.2rem;
  margin: 0 0 var(--space-md);
}

li {
  margin-bottom: var(--space-xs);
}

blockquote {
  border-left: 2px solid var(--border-strong);
  margin: var(--space-md) 0;
  padding-left: var(--space-md);
  color: var(--text-muted);
}

blockquote p:last-child { margin-bottom: 0; }

hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: var(--space-lg) 0;
}

/* ===========================================
   CODE
   =========================================== */

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--code-bg);
  padding: 0.1em 0.3em;
  border-radius: var(--radius-sm);
}

pre {
  background: var(--code-bg);
  padding: var(--space-md);
  overflow-x: auto;
  border-radius: var(--radius-sm);
  margin: var(--space-md) 0;
  font-size: var(--font-size-sm);
  line-height: 1.4;
}

pre code {
  background: none;
  padding: 0;
}

/* ===========================================
   TABLES
   =========================================== */

table {
  border-collapse: collapse;
  width: 100%;
  margin: var(--space-md) 0;
  font-size: 0.9rem;
}

th, td {
  text-align: left;
  padding: var(--space-xs) var(--space-sm) var(--space-xs) 0;
  border-bottom: 1px solid var(--border);
}

th {
  font-weight: 600;
}

/* ===========================================
   IMAGES
   =========================================== */

img {
  max-width: 100%;
  height: auto;
}

figure {
  margin: var(--space-lg) 0;
}

figcaption {
  font-size: var(--font-size-sm);
  color: var(--text-muted);
  margin-top: var(--space-xs);
}

/* ===========================================
   PHOTOS
   =========================================== */

.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--space-sm);
  margin: var(--space-md) 0;
}

.photo-grid img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
}

.series-header {
  margin-bottom: var(--space-md);
}

.series-meta {
  color: var(--text-muted);
  font-size: 0.9rem;
}

/* ===========================================
   BACKLINKS
   =========================================== */

.backlinks {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--border);
}

.backlinks-title {
  font-size: var(--font-size-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  color: var(--text-muted);
  margin-bottom: var(--space-sm);
}

.backlinks-list {
  list-style: none;
  padding: 0;
}

.backlinks-list li {
  margin-bottom: var(--space-xs);
}

/* ===========================================
   CITATIONS
   =========================================== */

.cite-missing {
  color: var(--accent-primary);
  font-family: var(--font-mono);
  font-size: 0.85em;
}

/* ===========================================
   UTILITIES
   =========================================== */

.visually-hidden {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

/* ===========================================
   RESPONSIVE
   =========================================== */

@media (max-width: 799px) {
  .post-list--compact .post-list-item {
    flex-direction: column;
    gap: 0;
  }
  
  .post-list--compact .post-meta {
    min-width: auto;
  }
}


/* ===========================================
   VIEW TRANSITIONS (MPA cross-document)
   =========================================== */

@view-transition {
  navigation: auto;
}

/* ===========================================
   INTRO ANIMATION (first visit per session)
   =========================================== */

/* While waiting for fonts, hide name SVG and nav underlines to prevent FOUT */
html.waiting-intro .name-svg { visibility: hidden; }

/* Lock page during initial load — prevents scrollbar flash before layout settles.
   Not applied during html.intro because .name-svg has overflow: hidden
   and replay (theme toggle) shouldn't lock scroll position. */
html.waiting-intro {
  overflow: hidden;
}

/* --- Phase 1: Stroke trace --- */

/* The drawing group: contains per-letter <path> elements.
   Two modes are randomly selected per page load:

   trace-stagger — letters sequence left-to-right.
     Each letter traces in 200ms, staggered 80ms apart.
     18 letters → last starts at 1.36s, finishes ~1.56s.

   trace-all — all letter outlines trace simultaneously.
     Single 0.8s animation, no stagger. More meditative.

   Both use pathLength="1" trick: dasharray:1 covers the full path,
   dashoffset:1 hides it, animate to 0 to reveal.

   fill: var(--bg) + paint-order: stroke fill hides the inner half
   of the stroke, matching the visual weight of the final .name-text. */
.name-draw {
  opacity: 0;
}

.name-draw path {
  stroke: var(--name-shadow);
  stroke-width: var(--name-outline);
  stroke-linejoin: round;
  fill: var(--bg);
  paint-order: stroke fill;
}

/* ── trace-stagger mode ── */
html.intro.trace-stagger .name-draw {
  opacity: 1;
  animation: nameFadeOut 0.15s ease 1.55s forwards;
}

html.intro.trace-stagger .name-draw path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: letterTrace 0.2s ease-out forwards;
  animation-delay: calc(var(--i) * 0.08s);
}

html.intro.trace-stagger .name-text {
  opacity: 0;
  animation: nameFadeIn 0.3s ease 1.4s forwards;
}

html.intro.trace-stagger .name-shadow { opacity: 0; }
html.intro.trace-stagger .name-shadow-1 { animation: snapIn 0.01s linear 1.60s forwards; }
html.intro.trace-stagger .name-shadow-2 { animation: snapIn 0.01s linear 1.74s forwards; }
html.intro.trace-stagger .name-shadow-3 { animation: snapIn 0.01s linear 1.88s forwards; }
html.intro.trace-stagger .name-shadow-4 { animation: snapIn 0.01s linear 2.02s forwards; }
html.intro.trace-stagger .name-shadow-5 { animation: snapIn 0.01s linear 2.16s forwards; }

/* ── trace-all mode ── */
html.intro.trace-all .name-draw {
  opacity: 1;
  animation: nameFadeOut 0.15s ease 0.8s forwards;
}

html.intro.trace-all .name-draw path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: letterTrace 0.8s ease-out forwards;
}

html.intro.trace-all .name-text {
  opacity: 0;
  animation: nameFadeIn 0.3s ease 0.65s forwards;
}

html.intro.trace-all .name-shadow { opacity: 0; }
html.intro.trace-all .name-shadow-1 { animation: snapIn 0.01s linear 0.95s forwards; }
html.intro.trace-all .name-shadow-2 { animation: snapIn 0.01s linear 1.09s forwards; }
html.intro.trace-all .name-shadow-3 { animation: snapIn 0.01s linear 1.23s forwards; }
html.intro.trace-all .name-shadow-4 { animation: snapIn 0.01s linear 1.37s forwards; }
html.intro.trace-all .name-shadow-5 { animation: snapIn 0.01s linear 1.51s forwards; }

/* ── Shared keyframes ── */

@keyframes letterTrace {
  to { stroke-dashoffset: 0; }
}

@keyframes nameFadeOut {
  to { opacity: 0; }
}

@keyframes nameFadeIn {
  to { opacity: 1; }
}

@keyframes snapIn {
  to { opacity: 1; }
}

/* --- Nav link underlines --- */
/* Both desktop and mobile: fade in text-decoration-color.
   Timed to coincide with shadow pop-in (the "name pop" moment). */

html.waiting-intro nav.site-nav a:not([aria-current="page"]) {
  text-decoration-color: transparent;
}

html.intro.trace-all nav.site-nav a:not([aria-current="page"]) {
  text-decoration-color: transparent;
  animation: decorReveal 0.3s ease 0.95s forwards;
}

html.intro.trace-stagger nav.site-nav a:not([aria-current="page"]) {
  text-decoration-color: transparent;
  animation: decorReveal 0.3s ease 1.60s forwards;
}

@keyframes decorReveal {
  to { text-decoration-color: currentColor; }
}

/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
  html.intro.trace-stagger .name-draw,
  html.intro.trace-all .name-draw { animation: none; opacity: 0; }
  html.intro.trace-stagger .name-draw path,
  html.intro.trace-all .name-draw path { animation: none; }
  html.intro.trace-stagger .name-text,
  html.intro.trace-all .name-text { animation: none; opacity: 1; }
  html.intro.trace-stagger .name-shadow,
  html.intro.trace-all .name-shadow { opacity: 1; }
  html.intro.trace-stagger .name-shadow-1,
  html.intro.trace-stagger .name-shadow-2,
  html.intro.trace-stagger .name-shadow-3,
  html.intro.trace-stagger .name-shadow-4,
  html.intro.trace-stagger .name-shadow-5,
  html.intro.trace-all .name-shadow-1,
  html.intro.trace-all .name-shadow-2,
  html.intro.trace-all .name-shadow-3,
  html.intro.trace-all .name-shadow-4,
  html.intro.trace-all .name-shadow-5 { animation: none; opacity: 1; }
  html.intro.trace-stagger nav.site-nav a:not([aria-current="page"]),
  html.intro.trace-all nav.site-nav a:not([aria-current="page"]) {
    animation: none; text-decoration-color: currentColor;
  }
}

/* ===========================================
   VIEW TRANSITIONS
   =========================================== */

/* Only name elements that are visually identical between pages.
   Scroll-dependent elements (border, bg-image, sidebar, back-to-top,
   footer) stay in the root — the root snapshot is opaque, so its
   plus-lighter crossfade handles state differences cleanly.
   Transparent elements with VT names cause artifacts because old
   snapshots bleed through transparent areas of new snapshots. */
.site-controls { view-transition-name: site-controls; }
.top-header  { view-transition-name: top-header; }
main          { view-transition-name: main-content; }

/* Shorten the default crossfade for content and root */
::view-transition-group(main-content),
::view-transition-group(root) {
  animation-duration: 0.15s;
}

/* Persistent chrome: hold in place, no animation */
::view-transition-old(site-controls),
::view-transition-new(site-controls),
::view-transition-old(top-header),
::view-transition-new(top-header) {
  animation: none;
}

/* Suppress CSS transitions during view transitions and initial page load —
   prevents border/sidebar from visibly animating into correct positions. */
body.vt-settling .site-border,
body.vt-settling .site-border::after,
body.vt-settling .sidebar,
body.vt-settling .bg-image,
body.vt-settling .back-to-top,
body.vt-settling .mobile-header,
html.no-settle .site-border,
html.no-settle .site-border::after,
html.no-settle .sidebar,
html.no-settle .bg-image,
html.no-settle .back-to-top,
html.no-settle .mobile-header,
html.waiting-intro .site-border,
html.waiting-intro .site-border::after {
  transition: none !important;
}

/* ===========================================
   PRINT
   =========================================== */

@media print {
  .site-controls { display: none; }
  body { font-size: 11pt; color: black; background: white; }
  a { color: black; }
}
