.page {
  width: min(100%, var(--content-width));
  margin-inline: auto;
}

/* Every block below is spaced in whole --step units, so the page keeps one
   vertical grid from the wordmark to the footer. */
.page > * + * {
  margin-block-start: var(--step);
}

/* ---------- masthead ---------- */

/* Solid block-letter art, 77 columns x 5 rows, set in the accent colour — a
   logo rather than a paragraph. Renders from the dedicated JetBrains Mono
   glyph subset loaded in <head> (see the comment there), not a local system
   font, so the exact glyph and advance width are guaranteed rather than
   whatever happens to be installed. block-size is a whole --step multiple so
   the baseline grid survives. */
/* Neutral page-color, not the accent green — the accent colour does its work
   everywhere else on the page; the header doesn't need it too. No background:
   it sits directly on the page like the rest of the type, just bigger. */
.wordmark {
  display: block;
  block-size: calc(var(--step) * 2);
  color: var(--page-color);
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
  font-size: min(9px, 1.9vw);
  line-height: 1;
  white-space: pre;
  overflow: hidden;
  user-select: none;
  cursor: default;
}

.tagline {
  color: var(--muted-color);
}

/* ---------- section ---------- */

/* The section you are reading gets an accent frame. Two sources feed it: a
   pointer resting on the section, and — see main.js — the section crossing the
   middle of the viewport as you scroll.

   outline, not border: an outline is drawn outside the box and takes no
   layout space, so switching it on cannot shift a single line off the --step
   grid. --step-half of offset puts it midway between the section and the ░
   rule above it, so the frame never collides with the divider. */
.section {
  outline: 1px solid transparent;
  outline-offset: var(--step-half);
  transition: outline-color calc(var(--motion-step) * 2) linear;
}

.section.is-active {
  outline-color: var(--accent-color);
}

@media (hover: hover) {
  .section:hover {
    outline-color: var(--accent-color);
  }

  /* Both sources can be live at once — the pointer on one section while
     another sits at the centre line — and two frames read as a bug. The
     pointer is the more deliberate signal, so while it is over any section
     the scroll-tracked frame stands down. */
  .page:has(.section:hover) .section.is-active:not(:hover) {
    outline-color: transparent;
  }
}

.section__title {
  color: var(--page-color);
  margin-block-end: var(--step);
}

.section__title .prompt {
  color: var(--accent-color);
  user-select: none;
}

/* Hover-revealed heading anchor, opentui.com's own pattern (their
   .prose .anchor rule): hidden until the heading is hovered or the link
   itself is focused, so it doesn't clutter the reading view. Touch devices
   have no hover to reveal it, so it stays visible there. */
.anchor {
  margin-inline-start: 0.75ch;
  color: var(--accent-color);
  text-decoration: none;
  opacity: 0;
}

.section__title:hover .anchor,
.anchor:focus-visible {
  opacity: 1;
}

@media (hover: none) {
  .anchor {
    opacity: 1;
  }
}

.section > p + p {
  margin-block-start: var(--step);
}

/* ---------- divider ---------- */

.divider {
  color: var(--page-rule);
  /* Body text is Iosevka now; ░ isn't in its charset, so this stays pinned to
     the dedicated block-glyph subset loaded for the wordmark. */
  font-family: "JetBrains Mono", ui-monospace, monospace;
  white-space: pre;
  overflow: hidden;
  user-select: none;
}

/* ---------- identity ---------- */

.id {
  display: flex;
  align-items: flex-start;
  gap: var(--step);
}

.facts {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.facts__row {
  display: flex;
  gap: var(--step-half);
}

.facts__key {
  color: var(--muted-color);
  flex: none;
  width: 5.5rem;
}

.facts__value {
  min-width: 0;
}

/* ---------- work ---------- */

.entry + .entry {
  margin-block-start: var(--step);
}

.entry__head {
  display: flex;
  gap: var(--step-half);
  flex-wrap: wrap;
}

.entry__when {
  color: var(--muted-color);
  flex: none;
  width: 5.5rem;
}

/* Without flex-basis and min-width, a content-sized flex item can't shrink to
   wrap in place — flex-wrap just pushes the whole item to the next line
   instead, orphaning .entry__when above it. */
.entry__title {
  flex: 1 1 0;
  min-width: 12rem;
}

.entry__detail {
  color: var(--muted-color);
  font-size: var(--text-small);
  /* Absolute, not a ratio: small text has to keep the same 24px baseline as
     body text or the grid drifts. */
  line-height: var(--step);
  padding-inline-start: calc(5.5rem + var(--step-half));
}

/* ---------- links ---------- */

.links {
  display: flex;
  flex-direction: column;
}

.links a {
  display: flex;
  gap: var(--step-half);
  width: fit-content;
  max-width: 100%;
  text-decoration: none;
}

.links a:hover .links__key,
.links a:focus-visible .links__key,
.links a:hover .links__value,
.links a:focus-visible .links__value {
  color: inherit;
}

/* Wide enough for "instagram" (9 columns) at every breakpoint. */
.links__key {
  color: var(--accent-color);
  flex: none;
  width: 6.5rem;
}

.links__value {
  color: var(--muted-color);
}

/* ---------- footer ---------- */

.footer {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--step);
  color: var(--muted-color);
  font-size: var(--text-small);
  line-height: var(--step);
}

.theme-toggle {
  color: var(--muted-color);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.theme-toggle:hover,
.theme-toggle:focus-visible {
  background: var(--accent-color);
  color: var(--inverted-color);
  text-decoration: none;
}

/* Roomier wordmark once there is width for it. 77 columns at 12px caps out
   around 554px, comfortably inside the 576px (36rem) content-width. */
@media (min-width: 34rem) {
  .wordmark {
    font-size: 12px;
    block-size: calc(var(--step) * 3);
  }
}

/* ---------- mobile ---------- */

@media (max-width: 34rem) {
  :root {
    --page-gutter: 1rem;
  }

  body {
    padding-block: var(--step) var(--step-2);
  }

  /* Side by side, the portrait leaves too little room for a value like
     "Software Engineering Manager", so it moves above the facts. */
  .id {
    flex-direction: column;
    /* Stacked, this gap is vertical, so it has to be a whole step. */
    gap: var(--step);
  }

  .facts__key {
    width: 5rem;
  }

  /* There is not enough width for a label column beside a job title, and
     letting it wrap made some rows inline and others not. Stack every one. */
  .entry__head {
    flex-direction: column;
    gap: 0;
  }

  .entry__when {
    width: auto;
  }

  .entry__detail {
    padding-inline-start: 0;
  }
}
