/* ---------------------------------------------------------------
   Departure Mono
   --------------------------------------------------------------- */
@font-face {
  font-family: "Departure Mono";
  src: url("fonts/DepartureMono-Regular.woff2") format("woff2"),
       url("fonts/DepartureMono-Regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------
   Tokens — OKLCH. Neutrals are pure grey (C=0); the one accent hue
   sits at ~80% of its max sRGB chroma for that lightness so nothing
   clips. Every text token clears APCA Lc 60 against --bg.
   --------------------------------------------------------------- */
:root {
  --bg:              oklch(0.145 0 0);       /* #0a0a0a           */
  --fg:              oklch(0.949 0 0);       /* #eeeeee  Lc 96.6  */
  --fg-body:         oklch(0.869 0 0);       /* #d4d4d4  Lc 80.2  */
  --fg-muted:        oklch(0.769 0 0);       /* #b4b4b4  Lc 61.5  */
  --accent:          oklch(0.8 0.09 249);    /*          Lc 67.5  */
  --accent-hover:    oklch(0.88 0.049 249);  /*          Lc 82.6  */
  --rule:            oklch(1 0 0 / 0.08);
  --rule-strong:     oklch(1 0 0 / 0.18);
  --surface-active:  oklch(1 0 0 / 0.05);

  /* Type ramp */
  --text:       clamp(13px, 3.2vw, 16px);
  --text-name:  clamp(15px, 3.8vw, 19px);
  --emoji-size: min(8vw, 72px);
  --emoji-lh:   1.374;
  --emoji-gap:  min(4vw, 36px);

  /* Also the clearance under the last line when the page scrolls past the
     fixed corner link, so the floor cannot drop below that link's height. */
  --pad-y: clamp(48px, 6vh, 64px);
  --column: min(90vw, 560px);
  --edge-x: clamp(24px, 4vw, 40px);
  --edge-y: clamp(20px, 3.5vh, 32px);

  --ease: cubic-bezier(0.2, 0, 0, 1);
}

/* ---------------------------------------------------------------
   Base
   --------------------------------------------------------------- */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  background: var(--bg);
  color-scheme: dark;
}

body {
  background: var(--bg);
  color: var(--fg-body);
  font-family: "Departure Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--text);
  line-height: 1.5;
  letter-spacing: -0.04em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100svh;
  display: flex;
  justify-content: center;
  /* `safe` keeps the top of the column reachable when the content is
     taller than the viewport — plain `center` overflows in both
     directions and puts the first lines above the scroll origin. */
  align-items: center;
  align-items: safe center;
  transition: opacity 420ms ease-out;
}

/* transition.js sets .js on <html> before first paint, so the page
   starts hidden and fades in. Without JS the rule never applies and
   the content is visible immediately. */
.js body { opacity: 0; }

::selection {
  background: var(--accent);
  color: var(--bg);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---------------------------------------------------------------
   Column
   --------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--column);
  /* Symmetric, so the block centres optically rather than sitting low. */
  padding: var(--pad-y) var(--edge-x);
}

.emoji {
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
  font-size: var(--emoji-size);
  line-height: var(--emoji-lh);
  margin-bottom: var(--emoji-gap);
  user-select: none;
}

.name {
  color: var(--fg);
  display: inline-block;
  /* One step up from body text — enough to lead the card without a
     second weight, since the face only ships at 400. */
  font-size: var(--text-name);
  font-weight: 400;
  line-height: 1.5;
}

a.name {
  color: var(--fg-muted);
  text-decoration: none;
  transition: color 200ms var(--ease);
}

a.name:hover { color: var(--fg); }

/* ---------------------------------------------------------------
   Bio
   --------------------------------------------------------------- */
.bio {
  margin-top: clamp(18px, 3.6vh, 30px);
}

.bio p {
  color: var(--fg-body);
  text-wrap: pretty;
}

.bio p + p {
  margin-top: clamp(12px, 2.4vh, 22px);
}

.bio a,
.note-body a {
  color: var(--accent);
  text-decoration: none;
  text-underline-offset: 3px;
  transition: color 200ms var(--ease);
}

.bio a:hover,
.note-body a:hover {
  color: var(--accent-hover);
  text-decoration: underline;
}

/* ---------------------------------------------------------------
   Notes
   --------------------------------------------------------------- */
.notes {
  margin-top: clamp(18px, 3.6vh, 30px);
  border-top: 1px solid var(--rule);
}

.note {
  border-bottom: 1px solid var(--rule);
}

.note-summary {
  display: flex;
  align-items: baseline;
  gap: 12px;
  /* Padding, not height, so the row clears 44px for touch while the
     text stays optically snug against the rules. */
  padding: 14px 0;
  cursor: pointer;
  color: var(--fg-muted);
  list-style: none;
  transition: color 200ms var(--ease);
}

.note-summary::-webkit-details-marker { display: none; }
.note-summary::marker { content: ""; }

.note-summary:hover,
.note[open] > .note-summary {
  color: var(--fg);
}

.chevron {
  flex: none;
  width: 1em;
  height: 1em;
  /* Optical nudge: the glyph baseline sits above the chevron's
     visual centre, so drop it to line up with the title. */
  transform: translateY(0.14em);
  rotate: 0deg;
  transition: rotate 220ms var(--ease);
}

.note[open] > .note-summary .chevron { rotate: 180deg; }

.note-title {
  /* Basis 0, not auto: flex decides line breaks from the hypothetical size,
     so an auto-sized long title would jump to its own line under the chevron
     once the row is allowed to wrap. Starting at 0 keeps it beside the
     chevron and lets it grow, wrapping as text rather than as a flex line. */
  flex: 1 1 0;
  min-width: 0;
  text-wrap: pretty;
}

.note-date {
  flex: none;
  font-variant-numeric: tabular-nums;
  color: var(--fg-muted);
}

/* Animated reveal: 0fr -> 1fr is an interruptible transition, so a
   fast second click retargets instead of restarting. notes.js adds
   .reveal only when it can drive it; the plain <details> works
   without it. */
.note-reveal {
  display: grid;
  grid-template-rows: 1fr;
}

.note-reveal > * { min-height: 0; }

.js .note-reveal {
  grid-template-rows: 0fr;
  transition: grid-template-rows 140ms var(--ease);
}

.js .note[open] > .note-reveal {
  grid-template-rows: 1fr;
  transition-duration: 200ms;
}

.note-body {
  overflow: hidden;
  color: var(--fg-body);
}

.js .note-body {
  opacity: 0;
  translate: 0 -4px;
  transition: opacity 140ms ease-out, translate 140ms ease-out;
}

.js .note[open] > .note-reveal > .note-body {
  opacity: 1;
  translate: 0 0;
  transition-duration: 200ms;
}

.note-body > :first-child { padding-top: 2px; }
.note-body > :last-child  { padding-bottom: 18px; }

.note-body p + p,
.note-body p + ul,
.note-body p + ol,
.note-body ul + p,
.note-body ol + p {
  margin-top: clamp(12px, 2.4vh, 22px);
}

.note-body ul,
.note-body ol { padding-left: 1.4em; }

.note-body li + li { margin-top: 6px; }

.note-body code {
  font-family: inherit;
  color: var(--fg);
  background: var(--rule);
  padding: 0.1em 0.35em;
  border-radius: 3px;
}

.note-body pre {
  background: var(--rule);
  padding: 12px 14px;
  border-radius: 6px;
  overflow-x: auto;
  margin-top: clamp(12px, 2.4vh, 22px);
}

.note-body pre code {
  background: none;
  padding: 0;
}

.note-body blockquote {
  border-left: 1px solid var(--rule);
  padding-left: 14px;
  color: var(--fg-muted);
  margin-top: clamp(12px, 2.4vh, 22px);
}

.notes-empty {
  margin-top: clamp(18px, 3.6vh, 30px);
  color: var(--fg-muted);
}

/* On a narrow screen the date and a long title fight over the same
   line and squeeze the title to a few characters per row. Drop the
   date underneath instead, aligned to the title's left edge. */
@media (max-width: 420px) {
  .note-summary { flex-wrap: wrap; }

  .note-date {
    flex-basis: 100%;
    margin-left: calc(1em + 12px);
    margin-top: 4px;
  }
}

/* ---------------------------------------------------------------
   Fixed corner link
   --------------------------------------------------------------- */
.corner {
  position: fixed;
  left: var(--edge-x);
  bottom: var(--edge-y);
  z-index: 2;
}

/* A hairline frame, so the link reads as a control rather than as a
   stray line of body text sitting in the corner. */
.corner a {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 7px 12px;
  color: var(--fg-muted);
  text-decoration: none;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: transparent;
  transition: color 200ms var(--ease),
              border-color 200ms var(--ease),
              scale 120ms var(--ease);
}

/* The frame is shorter than a comfortable touch target at the small end
   of the type ramp. Grow the hit area without growing the box. */
.corner a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  height: 44px;
}

/* Hover and current-page use different channels — border for hover,
   fill for current — so on the notes page, where the link is already
   current, hovering it still reads as a response. */
.corner a:hover {
  color: var(--fg);
  border-color: var(--rule-strong);
}

.corner a:active { scale: 0.96; }

.corner a[aria-current="page"] {
  color: var(--fg);
  background: var(--surface-active);
}

/* The global :focus-visible rule sets border-radius: 2px, which would
   pinch this box's corners on keyboard focus. Hold the box radius; the
   outline offsets outward from it. */
.corner a:focus-visible { border-radius: 4px; }

/* Keeps the link legible when long note bodies scroll underneath.
   Invisible on the home page, which does not scroll. */
.corner::before {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(var(--edge-y) * 2 + 44px);
  background: linear-gradient(to top, var(--bg) 45%, transparent);
  pointer-events: none;
  z-index: -1;
}

/* ---------------------------------------------------------------
   Sideways phone — the vertical centring has no room to work.
   --------------------------------------------------------------- */
.rotate-notice { display: none; }

@media (orientation: landscape) and (max-height: 500px) {
  .container,
  .corner { display: none; }

  .rotate-notice {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg);
  }

  .rotate-notice .emoji {
    margin-bottom: 0;
    font-size: 56px;
    line-height: 1;
  }
}

/* ---------------------------------------------------------------
   Reduced motion — everything still works, nothing moves.
   --------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .js body { opacity: 1; }

  body,
  .chevron,
  .js .note-reveal,
  .js .note-body,
  a,
  .note-summary {
    transition: none !important;
  }

  .js .note-reveal { grid-template-rows: 1fr; }
  .js .note:not([open]) > .note-reveal { grid-template-rows: 0fr; }
  .js .note-body { opacity: 1; translate: none; }

  .corner a:active { scale: none; }
}

/* ---------------------------------------------------------------
   Narrow screens — centre the text, not just the column.

   The column is centred at every width, but under ~640px it is the
   screen: `min(90vw, 560px)` leaves a gutter too thin to read as
   centring, so the block goes flush-left and ragged-right and the
   card stops looking centred the way it does on a wide viewport.
   Centre the text itself instead. The notes list stays left-aligned —
   a chevron/title/date row is a table, not a caption — and the corner
   link stays pinned bottom-left.
   --------------------------------------------------------------- */
@media (max-width: 640px) {
  .container { text-align: center; }

  /* Short centred lines read better balanced than ragged. */
  .bio p { text-wrap: balance; }

  .notes,
  .note-body { text-align: left; }
}
