/* ==========================================================================
   site.css — THE theme, in one file: reset, layout, every component.

   Implements plan §11.2 item 1 with RESUME §5 — the LIGHT language
   ("cluster C: clean white + one saturated accent"), which supersedes the
   dark one-theme contract:
     1. one white surface system — page, cards and chips are all white; and
        exactly one filled control, the primary CTA, which carries the accent;
     2. a card is separated by ONE hairline (--border); there is no elevation
        token in use (2026-09-30 — see css/tokens.css);
     3. one accent (blue) as text, hairline, tint, the selected chip fill and
        the filled CTA;
     4. sans only, self-hosted, every text element including controls;
     5. bounded decoration — one radial hero glow, clipped to the column;
     6. mobile-first: the 390px column IS the design, wider only adds width;
     7. the seven sections fold behind <details class="fold">: the page reads as
        a site you browse, not a document you scroll. All seven are toggles;
        About and Contact are open on load. (Until 2026-10-01 Projects was an
        eighth section, an open-on-load one — it is off the page for now.)

   Every colour, radius, size and family below comes from var(--token) in
   css/tokens.css. A literal value in this file is a failing check.

   Class contract: plan §10.3 (.wrap, header.masthead, .glow, h1.name,
   p.role, .chips > .chip, a.cta / a.cta.ghost, main#main-content,
   .stats > .stat (.label/.figure/.range), the seven section ids, h2, .card,
   .folio, .row2 (.tile/.k/.v), footer .footer-nav, img.portrait).
   ========================================================================== */

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

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

html { -webkit-text-size-adjust: 100%; }

body,
h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl, dd { margin: 0; }

ul, ol { padding: 0; }

img { display: block; max-width: 100%; }

table { border-collapse: collapse; }

/* --------------------------------------------------------------------------
   Page — the 390 column, one gutter, one white canvas
   -------------------------------------------------------------------------- */

body {
  background-color: var(--bg);
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: var(--step-body-compact);
  font-weight: var(--font-weight-body);
  line-height: var(--leading-body);
  padding: 0 var(--gutter-phone) 72px;   /* D-13: gutter 16-24px at 390 */
  overflow-x: hidden;                    /* the glow can never scroll the page */
  -webkit-font-smoothing: antialiased;
}

/* Controls do not inherit font-family from the UA sheet — say it explicitly,
   so a rendered button carries the same family list as the body text. */
button, input, select, textarea, optgroup { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
code, kbd, samp, pre, tt { font-family: inherit; font-size: inherit; }

a { color: var(--text-1); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Focus: a visible ring on every control, drawn with the outline property
   (never a shadow). Never reset to none.
   Scoped to :focus-visible (2026-10-01): the ring is for KEYBOARD users. The
   bare :focus form also matched a mouse click — and every section fold is a
   <summary>, which focuses on click — so clicking a fold painted a 2px blue
   rectangle on the page. :focus-visible matches Tab (and text fields) only, so
   the ring still shows for the input method that needs it. W-38 tabs, so it
   stays green. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* The skip link: first tabbable thing on the page, off-view until focused. */
.skip-link {
  position: absolute;
  top: 0;
  left: var(--gutter-phone);
  z-index: 10;
  transform: translateY(-200%);
  padding: 12px 18px;
  background-color: var(--surface-2);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--text-1);
  font-size: var(--step-h3);
  font-weight: var(--font-weight-strong);
}
.skip-link:focus { transform: none; }

/* The one column. Holds the masthead AND #main-content (plan §10.3). */
.wrap {
  max-width: var(--wrap-max);
  margin: 0 auto;
}

main { display: block; }

section { margin-bottom: 40px; }
section[id],
[id] { scroll-margin-top: 24px; }

/* --------------------------------------------------------------------------
   Masthead — name, role line, chips, the two CTAs, and the bounded glow
   -------------------------------------------------------------------------- */

header,
.masthead {
  position: relative;
  padding: 44px 0 32px;
}

/* The signature move: one soft accent bloom behind the hero. Absolutely
   positioned inside the header, so its box is bounded by the column and it
   cannot produce a horizontal scroll at 390. It is a radial, never a wash. */
.glow {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(-1 * var(--gutter));
  height: 300px;
  background-image:
    radial-gradient(58% 62% at 50% 18%, var(--accent-soft), transparent 70%),
    radial-gradient(86% 76% at 50% 0%, var(--accent-soft), transparent 78%);
  pointer-events: none;
}

h1,
h1.name,
.name {
  font-size: var(--step-hero);
  font-weight: var(--font-weight-strong);
  line-height: 1.05;
  letter-spacing: -0.03em;
  color: var(--text-1);
}

.role {
  max-width: 46ch;
  margin-top: 14px;
  font-size: var(--step-body-compact);
  line-height: var(--leading-body);
  color: var(--text-2);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 20px 0 22px;
}

.chip {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  background-color: var(--surface-2);      /* white pill chrome on a white page */
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--text-2);
  font-size: var(--step-label);
  font-weight: var(--font-weight-strong);
  letter-spacing: var(--track-label);
}

/* Masthead chips are controls in a thumb's reach: tap-sized, and their type
   stays above the legibility floor the band is held to. */
.masthead .chip,
header .chip {
  min-height: var(--tap-min);
  padding: 10px 16px;
  font-size: var(--step-body-compact);
}

/* The selected chip carries the accent as a FILL, with white text. */
.chip.live,
.chip[data-live] {
  background-color: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
}

/* The availability stamp (Max, 2026-09-30; re-cut the same day to look like an
   actual stamp). It is a WATERMARK now, not a fourth chip: it hangs in the
   blank right-hand end of the masthead band, tilted, ruled twice, in the page's
   own ink rather than a second colour.

   Why ink and not a hue: §11.2.1 licenses exactly ONE saturated colour on this
   page, and a red or green stamp would be a foreign saturated hue to D-05 — the
   same rule that keeps the fold label neutral. Ink also happens to be what a
   rubber stamp actually is. The whole treatment is two tokens deep, so it
   follows the scheme for free: --text-1 is near-black on the white page and
   near-white on the dark one.

   It is pinned to the header's top-right slack and taken out of the reading
   order: pointer-events none, aria-hidden in the markup, data-print="omit" so
   paper never grows a stamp. */
.masthead { position: relative; }   /* the box the stamp hangs off (sticky above 1024px) */

.stamp {
  position: absolute;
  top: 14px;
  right: 14px;
  display: inline-block;
  padding: 6px 12px;
  background-color: transparent;
  border: 2px solid var(--text-1);
  outline: 1px solid var(--text-1);   /* the second rule of a real stamp — an OUTLINE, not an
                                         inset shadow: D-02 forbids every shadow on the site,
                                         insets included (2026-09-30 — cards take a hairline) */
  outline-offset: -5px;
  border-radius: 4px;
  color: var(--text-1);
  font-size: var(--step-body-compact);   /* W-75: every masthead text element is >=16px at 390 */
  font-weight: var(--font-weight-strong);
  line-height: 1.2;
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: .5;
  transform: rotate(-6deg);
  pointer-events: none;
}

.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap-min);
  margin: 4px 8px 4px 0;
  padding: 6px 24px;
  background-color: var(--accent);        /* the one accent: the only filled control */
  border: var(--hairline) solid transparent;
  border-radius: var(--radius-pill);
  color: var(--bg);                        /* white text on the blue pill (4.53:1) */
  font-family: var(--font-sans);
  font-size: var(--step-h3);
  font-weight: var(--font-weight-strong);
  line-height: 1.2;
  text-decoration: none;
  text-transform: none;
  letter-spacing: 0;
}
.cta:hover { background-color: var(--accent-strong); text-decoration: none; }

.cta.ghost {
  background-color: var(--bg);             /* white pill, outlined */
  border-color: var(--border-ghost);
  color: var(--text-1);
  font-weight: var(--font-weight-body);
}
.cta.ghost:hover {
  background-color: var(--surface-2);
  border-color: var(--text-3);
}

/* --------------------------------------------------------------------------
   The fold — every section is a <details>, and the summary IS the section head.
   The page reads as a site you browse, not a resume you scroll: About and
   Contact are open on load, the five resume-shaped sections are closed.
   (CHANGED 2026-09-30, Max's call: Projects used to open on load too — eight
   expanded cards made the page long, so it now starts closed like the rest.)

   The header is a CONTROL, so it wears the site's control material — the same
   outlined pill as .chip and a.cta.ghost — with the accent wash across its face
   so it reads as a button you press and not as a form field. Max approved this
   treatment on 2026-09-29. Nothing below is a new literal: the fill, the tint,
   the border colour, the radius and the duration all come from css/tokens.css.
   -------------------------------------------------------------------------- */

.fold { margin: 0; }

.fold > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 58px;                        /* the toggle is a tap target at 390 */
  padding: 14px 18px;
  background-color: var(--surface-2);      /* white pill chrome on a white page */
  background-image: linear-gradient(180deg, var(--accent-wash), transparent 72%);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-pill);
  cursor: pointer;
  list-style: none;
}

/* The UA triangle is replaced by the chevron below; both engines are told. */
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::marker { content: ""; }

/* H2 is the label. It is the only heading the section gets — never a
   heading plus a repeated label. On a control face the label is full-strength
   text, not a muted whisper: it is what the reader aims at. Its size and case
   are pinned by D-06 — 12px, sentence case — and stay exactly that. */
.fold > summary h2 {
  margin: 0;
  color: var(--text-1);
  font-weight: var(--font-weight-strong);
}

/* The chevron: two accent borders, rotated. */
.fold > summary::after {
  content: "";
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  margin-right: 6px;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(45deg);
}

/* Open and hover are the same signal, and only the accent carries it: the border
   colour and the chevron. THE LABEL DOES NOT MOVE. Two measured reasons, both
   found by the run after the first cut of this rule:
     * --accent as label text on the washed face measures 4.29:1 — under W-57's
       >=4.5:1 for a micro-label;
     * --accent-strong as label text is a foreign saturated colour: D-05 allows
       only the accent itself (or a neutral), and this token sits 41/255 off it
       in the blue channel.
   So the label keeps its full-strength neutral ink in every state, and no second
   blue enters the page. */
.fold > summary:hover { border-color: var(--accent); }
.fold[open] > summary { border-color: var(--accent); }
.fold[open] > summary::after { transform: rotate(-135deg); }

/* The drop (Max, 2026-09-29). A <details> reveals its content by toggling
   `content-visibility` on its ::details-content box; that box is what animates,
   and `interpolate-size: allow-keywords` is what lets `block-size: auto` be a
   transition target at all.
   DELIBERATELY NOT TOUCHED: content-visibility. Overriding it — or transitioning
   it — changes what text a reader (and a probe) can extract from a closed fold:
   the first cut of this rule did both and cost W-33 and W-77 on the next run.
   The engine's own instant reveal stays; only the box height moves. */
:root { interpolate-size: allow-keywords; }

.fold::details-content {
  block-size: 0;
  overflow: clip;
  transition: block-size var(--motion) ease-out;
}

.fold[open]::details-content { block-size: auto; }

@media (prefers-reduced-motion: reduce) {
  :root { interpolate-size: initial; }
  .fold::details-content { transition: none; }
}

.fold-body { padding-top: 12px; }

/* The fold owns its bottom edge, not the last card inside it. */
.fold-body > :last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   The entry fold — one nested <details class="fold entry"> per Experience
   position (Max, 2026-09-30: "can each position in experience be its own
   dropdown? default closed"). The section pill above is the pattern; the
   entry's is denser and quieter, because it sits inside the section's own card
   and a second 58px washed pill on one surface would read as a second section
   head:
     * 44px tap target (still a real control at 390) instead of 58;
     * no accent wash. The wash is the section control's own signal; two washes
       stacked on one card is a second visual theme, and this page gets one;
     * the card radius, not the pill radius, so it reads as a row inside the
       position's card and not as another section header;
     * the label is the entry's own <h3>, sized by .card h3 at --step-h3. No
       second, repeated title and no new type step.
   Closed on load — index.html writes no `open` attribute on an entry, and the
   only thing that opens one is a tap. Every value below is a token from
   css/tokens.css; nothing new is introduced. */
.fold.entry { margin: 0; }

.fold.entry > summary {
  flex-wrap: wrap;                         /* the where/when drops to its own line when it must */
  min-height: 44px;
  padding: 10px 16px;
  background-image: none;
  border-radius: var(--radius-card);
}

.fold.entry > summary h3 { margin: 0; }

/* The where/when line, so a CLOSED entry still says which employer and which
   years (Max, 2026-09-30: "looks kind of empty collapsed"). It is a second line
   in the control, not a second heading: --step-meta, body weight, the muted
   third ink, and the row's own 12px gap when it wraps to its own line at phone
   width. The body keeps the full linked employer line; on paper this one is
   hidden (print.css), so the sheet still says it once. */
.fold.entry > summary::after { order: 2; }   /* the chevron stays on the title line */

.fold.entry > summary .meta {
  order: 3;                                /* ...and the where/when takes the line below */
  flex-basis: 100%;
  margin: 0;
  font-size: var(--step-meta);
  font-weight: var(--font-weight-body);
  color: var(--text-3);
}

/* --------------------------------------------------------------------------
   Cards — one surface, ONE hairline, one radius (Max, 2026-09-30). On the
   white page the card and the page are the same colour, so the hairline is the
   whole separation: the ambient shadow this rule used to carry read as a grey
   band under the short Experience rows and a grey halo around every card. On
   dark the card is a fill step, so it never depended on either.
   -------------------------------------------------------------------------- */

.card,
.proj,
.project-card,
.skill-box,
.contact {
  background-color: var(--surface-1);      /* white, like the page */
  border: var(--hairline) solid var(--border);   /* the separation is one hairline */
  border-radius: var(--radius-card);
}

/* The Experience entries: the row inside the wrapper is ALREADY a bordered pill
   (the fold control is .fold.entry > summary), so the wrapper is not a surface —
   a second hairline 20px outside the first reads as a double border. This is the
   state the owner approved in the rendered stance, pixel for pixel. */
#experience .card { border: 0; }

.card,
.proj,
.project-card,
.skill-box { padding: 20px; }

.card { margin-bottom: 12px; }

.card h3,
.proj h3 {
  font-size: var(--step-h3);
  font-weight: var(--font-weight-strong);
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--text-1);
  margin-bottom: 4px;
}

.card h3:last-child { margin-bottom: 0; }

.card a { color: var(--accent-ink); text-decoration: none; }
.card a:hover { text-decoration: underline; }

/* A filled CTA inside a card keeps its white label. `.card a` (0,1,1) outranks the
   .cta rule (0,1,0), so the pill's label was painted the same blue as the pill it
   sits on. Measured live on /mirror/ 2026-10-13 before this rule: color
   rgb(27,111,245) on background rgb(27,111,245) — an invisible button. The home
   page never showed it because its only CTA sits in .masthead-actions, not a card. */
.card a.cta,
.card a.cta:hover { color: var(--bg); text-decoration: none; }

/* The card's footer row: the link and the chip sit on one line, wrapping. */
.card .row,
.proj .row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
}

/* Body copy inside a card is the readable path: never below the floor. */
.card p,
.card li {
  color: var(--text-2);
  font-size: var(--step-body-compact);
  line-height: var(--leading-body);
}

/* Meta lines (employer · dates · place) recede by colour, never by size —
   the measured floor for resume prose is a hard one (W-31). */
.card .meta,
.card .entry-meta,
.meta,
.entry-meta { color: var(--text-3); }

/* --------------------------------------------------------------------------
   Resume prose — the floor: >=17px at 1280, >=16px at 390, ratio >=1.5,
   measured line boxes inside the cap. :where() keeps this at zero
   specificity so every component rule below still wins its own element.
   -------------------------------------------------------------------------- */

:where(#about, #experience, #projects, #skills, #education, #credentials, #contact) :where(p, li) {
  font-size: var(--step-body-compact);
  line-height: var(--leading-body);
  max-width: 70ch;
  color: var(--text-2);
}

ul,
ol { list-style: none; }

/* Every list item is positioned, so the dot below can never resolve against
   the page box and scatter across the canvas. */
li {
  position: relative;
  padding-left: 16px;
  margin-bottom: 6px;
}

li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background-color: var(--marker);
}

.two-column-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px 24px;
}

.skills-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.skill-box {
  padding: 14px 18px;
  color: var(--text-2);
  font-size: var(--step-meta);
  line-height: 1.45;
}

/* --------------------------------------------------------------------------
   Projects — a folio, a title, a line of what it is, a link and a chip
   -------------------------------------------------------------------------- */

#projects .card,
#projects .proj,
#projects .project-card { margin-bottom: 12px; }

.folio,
.card .folio,
.project-figure { margin-bottom: 8px; }

/* --------------------------------------------------------------------------
   Contact — one panel, ruled rows, each led by an icon tile
   -------------------------------------------------------------------------- */

#contact .card { padding: 4px 20px; }

.row2 {
  display: flex;
  flex-direction: column;                  /* label above value at 390 */
  align-items: flex-start;
  gap: 6px;
  padding: 14px 0;
  border-bottom: var(--hairline) solid var(--rule-row);
}

.row2:last-child,
.row2:last-of-type { border-bottom: 0; }

.tile {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  background-color: var(--accent-soft);    /* the accent as a tint */
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-tile);
}

.tile img {
  width: 20px;
  height: 20px;
}

.row2 .k { flex: 0 0 auto; }

.row2 .v {
  min-width: 0;
  color: var(--text-1);
  font-size: var(--step-h3);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.row2 .v a { color: var(--accent-ink); }

/* --------------------------------------------------------------------------
   Portrait — a real photograph, framed like any other tile
   -------------------------------------------------------------------------- */

.portrait {
  width: 160px;
  height: 160px;
  margin: 0 0 20px;
  border-radius: var(--radius-tile);
  border: var(--hairline) solid var(--border);
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   Micro-labels — the one 12px sentence-case role, in every carrier.
   The size stays 12px in the light set; only the case and the tracking moved.
   -------------------------------------------------------------------------- */

h2,
.stat .label,
.folio,
.card .folio,
.project-figure,
.row2 .k,
.badge,
.entry-tag,
.tag {
  font-size: var(--step-label);
  font-weight: var(--font-weight-strong);
  line-height: 1.4;
  text-transform: none;
  letter-spacing: var(--track-label);      /* normal in the light set (D-06) */
  color: var(--text-3);
}

h2 { margin: 0 0 14px; }

.badge,
.entry-tag,
.tag {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  margin-left: 8px;
  background-color: var(--surface-2);
  border: var(--hairline) solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--accent-ink);
  vertical-align: middle;
}

/* --------------------------------------------------------------------------
   Footer — the closing block and its section index
   -------------------------------------------------------------------------- */

footer {
  margin-top: 44px;
  padding-top: 22px;
  border-top: var(--hairline) solid var(--rule-footer);
  color: var(--text-3);
  font-size: var(--step-meta);
  line-height: 1.5;
}

.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  margin-bottom: 16px;
}

.footer-nav a {
  color: var(--text-2);
  font-size: var(--step-meta);
}
.footer-nav a:hover { color: var(--text-1); }

/* --------------------------------------------------------------------------
   Wider than a phone: the column keeps its width, the rhythm opens up
   -------------------------------------------------------------------------- */

@media (min-width: 640px) {
  body { padding: 0 var(--gutter) 96px; }

  .card,
  .proj,
  .project-card { padding: 22px 24px; }

  .skills-grid { grid-template-columns: repeat(2, 1fr); }
  .two-column-list { grid-template-columns: repeat(2, 1fr); }

  .row2 {
    flex-direction: row;
    align-items: center;
    gap: 14px;
  }
  .row2 .k { min-width: 96px; }
  .row2 .v { font-size: var(--step-body-compact); }

  /* THE PROJECT TILES (Max, 2026-09-30). Eight stacked cards made the section
     long; the project cards lay out two-up from 640px instead, which halves the
     section's height without touching a card's internals — every tile keeps its
     folio, title, one line of what it is, and the link + chip footer row D-09
     asserts. The tiles stretch to a shared row height so the grid reads as a
     grid rather than eight floating boxes, and each footer row is pushed to the
     bottom of its tile so the links line up across a row. */
  #projects .fold-body {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
  }
  #projects .card,
  #projects .proj,
  #projects .project-card {
    display: flex;
    flex-direction: column;
    margin-bottom: 0;
  }
  #projects .proj .row { margin-top: auto; }

  /* The portrait sits BESIDE the About copy from 640px up (Max, 2026-09-30): it
     floats into the text, so the photograph and the opening paragraph share the
     top of the section. Below 640px it stays the stacked block it was and the
     phone column is untouched. No DOM change — the float is the whole trick. */
  #about .portrait {
    float: left;
    margin: 4px 22px 10px 0;
  }
  #about .fold-body::after {
    content: "";
    display: block;
    clear: both;
  }
}

/* --------------------------------------------------------------------------
   THE TWO-ZONE DESKTOP (Max, 2026-09-29 — plan §11.8).

   Below 1024px nothing here applies: the 390 column is still the design.
   From 1024 up, the width that used to be margin becomes a second zone — the
   masthead becomes a sticky rail and the content keeps the shipped column. No
   markup, no class, no DOM change: the rail is the existing header, moved, so
   no probe needed re-pointing. Because it sticks, the name, the resume CTA and
   the availability chips stay in view while the sections fold open and shut —
   which is the part of the page a visitor actually acts on.

   The content column is still capped at --wrap-max, so the prose measure W-31
   measures is the shipped one. Values are tokens: --rail-w and --rail-gap.
   -------------------------------------------------------------------------- */

@media (min-width: 1024px) {
  body { font-size: var(--step-body); }

  .wrap {
    max-width: calc(var(--wrap-max) + var(--rail-w) + var(--rail-gap));
    display: grid;
    grid-template-columns: var(--rail-w) minmax(0, 1fr);
    column-gap: var(--rail-gap);
    align-items: start;            /* the rail is content-height, so it can stick */
  }

  main {
    max-width: var(--wrap-max);
    min-width: 0;
  }

  /* One top edge for both zones (Max, 2026-09-29). The rail is sticky at the
     same offset the wrap pads by, so at rest the card's top edge and the top of
     the content column sit on the same line — before this the sticky offset
     dropped the rail 32px below a content column that started flush at the top
     of the window. */
  .wrap { padding-top: 40px; }

  /* THE RAIL IS A CARD (Max's call, 2026-09-29 — plan §11.9). The rail wears
     the site's own card material — white surface, --radius-card, and the same
     one --border hairline every card wears (2026-09-30) — so the 20px radius
     here obligates exactly what D-03 obligates of every card. --accent-wash across the face is the same tint the fold
     headers already carry, and it retires the radial bloom at this width only:
     below 1024px the hero is still a band and the glow still paints. */
  header,
  .masthead {
    position: sticky;
    top: 40px;
    padding: 26px 24px 22px;
    background-color: var(--surface-1);
    background-image: linear-gradient(180deg, var(--accent-wash), transparent 62%);
    border: var(--hairline) solid var(--border);
    border-radius: var(--radius-card);
    overflow: hidden;              /* the wash can never paint outside the card */
  }

  .glow { display: none; }

  /* Max, 2026-10-01: the name was clipped at EVERY rail width, not just one —
     "Hemmerich" needs 4.86em, and the card's inner box is rail - 50px, so the
     band's 62px step could never fit it (42px of overflow at the 280px rail,
     13px at 340px; the card's overflow:hidden cut the rest). At this width the
     hero is sized against the rail it sits in: /5.05 leaves ~4% slack and keeps
     the widest word inside the card at every rail width, while still clearing
     the >=52px D-06 obliges at 1280 (55.6px there). Below 1024px the band is
     unchanged — the name has 189px of slack at 390. */
  h1,
  h1.name,
  .name {
    font-size: min(var(--step-hero), calc((var(--rail-w) - 50px) / 5.05));
  }

  /* The rail sets the measure for the role line, not the 46ch prose cap; its
     size is unchanged. */
  .role {
    max-width: none;
    font-size: var(--step-h3);
  }

  /* The three facts become a ruled list in the rail, not three more pills on a
     card face — pill chrome there reads as three more buttons, and the contact
     panel already owns this material (--rule-row hairlines). Below 1024px they
     are the shipped pills, untouched. */
  .chips { display: block; margin: 18px 0 22px; }

  .masthead .chip,
  header .chip {
    display: flex;
    width: 100%;
    min-height: 0;
    padding: 9px 2px;
    background-color: transparent;
    border: 0;
    border-bottom: var(--hairline) solid var(--rule-row);
    border-radius: 0;
    color: var(--text-2);
    font-size: var(--step-body-compact);
    font-weight: var(--font-weight-body);
  }

  .chips > .chip:last-child { border-bottom: 0; }

  /* The two actions are the rail's footer: stacked, full width, the filled pill
     first. */
  .masthead-actions { display: grid; gap: 10px; margin-top: 4px; }

  .masthead-actions .cta { width: 100%; margin: 0; }

  /* The closing block belongs to the page, not to either zone. */
  footer { grid-column: 1 / -1; }

  .card p,
  .card li { font-size: var(--step-body); }

  :where(#about, #experience, #projects, #skills, #education, #credentials, #contact) :where(p, li) {
    font-size: var(--step-body);
  }
}

/* The hero bloom at night (2026-09-30, with the dark scheme): the same radial
   wash, turned down so it reads as a glow rather than a lamp. Values only —
   the gradient itself is unchanged, and the >=1024 rail still omits it. */
@media (prefers-color-scheme: dark) {
  .glow { opacity: .45; }
}
