:root {
  --color-bg: #fbfaf7;
  --color-ink: #141210;
  --color-ink-muted: #59544a;
  --color-ink-faint: #736d61;
  --color-accent: #a34a2a;
  --color-idx-muted: #9c886f;
  --color-underline: #c9b8a8;
  --color-rule: #ddd6c8;
  --color-rule-faint: #f2efe8;

  --font-sans: -apple-system, system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --font-size-base: 16px;
  --font-size-h1: 3.75rem;
  --font-size-h1-mobile: 2.5rem;
  --font-size-lede: 1.05rem;
  --font-size-subtitle: 0.85rem;
  --font-size-h2: 0.75rem;
  --font-size-role: 1.1rem;
  --font-size-org: 0.92rem;
  --font-size-body: 0.95rem;
  --font-size-idx: 1.2rem;
  --font-size-now: 0.85rem;
  --font-size-tags: 0.8rem;
  --font-size-cat: 0.78rem;
  --font-size-sub-title: 0.95rem;
  --font-size-sub-body: 0.92rem;
  --font-size-sub-tags: 0.78rem;
  --line-height-body: 1.65;

  --shell-width: 800px;
  --measure: 60ch;
  --measure-skill: 34ch;
  --space-row: 2rem;
  --space-section: 2.5rem;
  --col-idx: 130px;
  --col-gap: 1.5rem;

  --spine-gap: 0.9rem;
  --spine-width: 1px;
  --junction-dot: 5px;
}

* {
  box-sizing: border-box;
}

html {
  background: var(--color-bg);
  font-size: var(--font-size-base);
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-sans);
  font-size: var(--font-size-body);
  line-height: var(--line-height-body);
}

a {
  color: var(--color-ink);
  text-decoration-color: var(--color-underline);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

a:hover {
  text-decoration-color: var(--color-accent);
}

a:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.shell {
  max-width: var(--shell-width);
  margin: 0 auto;
  padding: 0 1.5rem;
}

.site-header {
  border-bottom: 1px solid var(--color-rule);
  padding: 3.5rem 0 2.5rem;
}

@media (min-width: 1140px) {
  .site-header .shell {
    transform: translateX(calc(-1 * (var(--col-idx) + var(--col-gap))));
  }
}

.site-header h1 {
  margin: 0;
  font-size: var(--font-size-h1);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
}

.site-header .subtitle {
  margin: 0.6rem 0 0;
  color: var(--color-ink-muted);
  font-size: var(--font-size-subtitle);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.site-header .lede {
  margin: 1.25rem 0 0;
  color: var(--color-ink-muted);
  font-size: var(--font-size-lede);
  line-height: 1.55;
}

.lang-switch {
  margin-top: 1rem;
  margin-left: -0.3rem;
}

.lang-switch a {
  display: inline-block;
  padding: 0.2rem 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-right: 0.45rem;
}

.lang-switch a[aria-current="true"] {
  color: var(--color-accent);
  text-decoration: none;
  font-weight: 700;
}

/* Section labels are the heading of the index column: right-aligned to the
   spine, like the dates below them, so the whole left column hangs off the
   one rail rather than floating on a third edge. */
.section-title {
  width: var(--col-idx);
  padding-right: var(--spine-gap);
  text-align: right;
  font-size: var(--font-size-h2);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 700;
  color: var(--color-accent);
  margin: var(--space-section) 0 1rem;
}

/* The only horizontal rules on the page: dividers between the major
   sections. Full-bleed, matching the masthead rule. */
#education,
#expertise,
#contact {
  border-top: 1px solid var(--color-rule);
}

/* Carry the spine unbroken across a section break (Experience → Education)
   so the whole page reads as one chronological line. The label clears the
   spine, which sits to its right at the same x as the row spine. */
.section-title.on-spine {
  position: relative;
}

.section-title.on-spine::before {
  content: "";
  position: absolute;
  left: var(--col-idx);
  top: calc(-1 * var(--space-section));
  bottom: -1rem;
  border-left: var(--spine-width) solid var(--color-rule);
}

.ledger-row {
  --row-pad-bottom: var(--space-row);
  position: relative;
  display: grid;
  grid-template-columns: var(--col-idx) minmax(0, 1fr);
  column-gap: var(--col-gap);
  padding: var(--space-row) 0 var(--row-pad-bottom);
}

/* The last entry before a section divider needs more clearance from the
   rule than a mid-spine entry, so its closing date isn't crowded. */
.shell > .ledger-row:last-child {
  --row-pad-bottom: 4.5rem;
}

.ledger-row::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: -1px;
  left: var(--col-idx);
  border-left: var(--spine-width) solid var(--color-rule);
}

/* Highlight only the span the current role occupies: an accent segment laid
   over the spine, running between the two dots (NOW → 2026), so the rule
   colour still shows above and below them. */
.ledger-row:has(.idx.current)::after {
  content: "";
  position: absolute;
  left: var(--col-idx);
  top: calc(var(--space-row) / 2);
  bottom: 0;
  border-left: var(--spine-width) solid var(--color-accent);
}

.idx {
  display: flex;
  flex-direction: column-reverse;
  gap: 0.65rem;
  font-size: var(--font-size-idx);
  font-weight: 200;
  font-variant-numeric: tabular-nums;
  color: var(--color-idx-muted);
  line-height: 1;
  letter-spacing: -0.01em;
}

/* Every date is an absolute marker in the left column, right-aligned to the
   spine with a dot node on it. Each entry is bookended: the top marker sits
   in the gap above its content, the bottom marker in the gap below — never
   on a content line. A year shared by two adjacent entries collapses to one
   marker centered on the boundary between them. */
.j-year,
.idx-top,
.idx-bottom {
  position: absolute;
  left: 0;
  width: var(--col-idx);
  padding-right: var(--spine-gap);
  text-align: right;
}

.idx-top {
  top: calc(var(--space-row) / 2);
  transform: translateY(-50%);
}

.idx-bottom {
  bottom: calc(var(--row-pad-bottom) / 2);
  transform: translateY(50%);
}

.j-year {
  top: 0;
  transform: translateY(-50%);
}

.j-year::after,
.idx-top::after,
.idx-bottom::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 0;
  width: var(--junction-dot);
  height: var(--junction-dot);
  border-radius: 50%;
  background: var(--color-idx-muted);
  transform: translate(calc(50% + var(--spine-width) / 2), -50%);
}

/* The current role's endpoints are accented on the spine — the NOW dot and
   the shared boundary dot below it (carried by the next entry's j-year) —
   while the labels stay muted like every other date. */
.idx.current .idx-top::after,
.ledger-row:has(.idx.current) + .ledger-row .j-year::after {
  background: var(--color-accent);
}

/* The neighbouring entry's duplicate of a shared year is redundant on the
   spine; it only reappears inline on mobile to show each role's full range. */
.j-dup {
  display: none;
}

.idx .now {
  font-size: var(--font-size-now);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.content {
  min-width: 0;
}

.role {
  font-weight: 700;
  font-size: var(--font-size-role);
  margin: 0 0 0.15rem;
}

.org {
  color: var(--color-ink-muted);
  font-size: var(--font-size-org);
  margin-bottom: 0.85rem;
}

.content p {
  font-size: var(--font-size-body);
  line-height: var(--line-height-body);
  margin: 0.65rem 0;
  max-width: var(--measure);
}

.spec-list p {
  margin: 0.3rem 0;
}

.tags {
  font-family: var(--font-mono);
  font-size: var(--font-size-tags);
  color: var(--color-ink-faint);
  margin-top: 0.7rem;
}

.sub-list {
  margin-top: 0.9rem;
  padding-top: 0.9rem;
}

.sub-item {
  padding: 0.7rem 0;
}

.sub-title {
  font-weight: 700;
  font-size: var(--font-size-sub-title);
}

.sub-item p {
  font-size: var(--font-size-sub-body);
  line-height: 1.55;
  margin: 0.3rem 0;
  max-width: 58ch;
}

.sub-tags {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--font-size-sub-tags);
  color: var(--color-ink-faint);
  margin-top: 0.3rem;
}

/* Skills and Contact aren't chronological, so no dates hang here — but the
   spine is the ledger's margin rule, not the timeline, so it carries on
   unbroken as the same 1px line. Their content sits in the same content
   column as every dated entry. */
.ledger-area {
  position: relative;
}

.ledger-area::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--col-idx);
  border-left: var(--spine-width) solid var(--color-rule);
}

.skills-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 3rem 3.5rem;
  padding: 2.25rem 0;
  margin-left: calc(var(--col-idx) + var(--col-gap));
}

/* One relaxed line per skill — bold key, muted value — rather than a
   cramped two-column table, so the four groups read as open, not dense. */
.cat h3 {
  margin: 0 0 0.9rem;
  font-size: var(--font-size-cat);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  color: var(--color-ink-faint);
}

.cat p {
  margin: 0.6rem 0;
  line-height: 1.5;
  max-width: var(--measure-skill);
  color: var(--color-ink-muted);
  font-size: var(--font-size-body);
}

.cat p .k {
  color: var(--color-ink);
  font-weight: 600;
  margin-right: 0.4rem;
}

.contact-block {
  padding: 1.75rem 0;
  margin-left: calc(var(--col-idx) + var(--col-gap));
}

.contact-block p {
  margin: 0.4rem 0;
}

/* A full-bleed rule closes the ledger: the spine terminates into it, and the
   page is bookended by the masthead rule above and this one below. */
.site-footer {
  border-top: 1px solid var(--color-rule);
  padding: 2rem 0 3rem;
  color: var(--color-ink-faint);
  font-size: 0.85rem;
  text-align: center;
}

.site-footer p {
  margin: 0;
  opacity: 0.4;
}

@media (max-width: 640px) {
  .site-header h1 {
    font-size: var(--font-size-h1-mobile);
  }

  .ledger-row {
    grid-template-columns: 1fr;
    row-gap: 0.75rem;
  }

  .ledger-row::before,
  .ledger-row:has(.idx.current)::after {
    display: none;
  }

  .idx {
    padding-right: 0;
    flex-direction: row;
    justify-content: flex-start;
    align-items: baseline;
    text-align: left;
    gap: 0.5rem;
  }

  /* On mobile there's no spine; every date folds back into its role's
     inline range, so restore the duplicate and de-anchor the markers. */
  .j-dup {
    display: inline;
  }

  .j-year,
  .idx-top,
  .idx-bottom {
    position: static;
    width: auto;
    padding-right: 0;
    text-align: left;
    transform: none;
  }

  .idx span::after {
    display: none;
  }

  .section-title.on-spine::before {
    display: none;
  }

  .idx span + span::before {
    content: "– ";
  }

  /* No spine on mobile, so nothing to hang the margin off — content goes
     full width and the carried-on rule drops out. The section label, with
     no rail to align to, returns to a plain full-width heading. */
  .ledger-area::before {
    display: none;
  }

  .section-title {
    width: auto;
    padding-right: 0;
    text-align: left;
  }

  .skills-grid {
    grid-template-columns: 1fr;
    margin-left: 0;
  }

  .contact-block {
    margin-left: 0;
  }

  .cat p {
    max-width: none;
  }
}

@media print {
  .lang-switch,
  .site-footer {
    display: none;
  }

  .ledger-row {
    break-inside: avoid;
  }
}
