/* ==========================================================================
   Jacob Rodriguez — Operations Director
   Design brief: corporate executive with a military *feel* — not military
   colours. The discipline comes from structure, not decoration: a strict
   grid, hairline rules, numbered sections, uppercase mono labels, square
   corners, tabular figures. Navy/brass/paper, no gradients, no shadows.
   ========================================================================== */

:root {
  --ink:        #12181f;
  --ink-2:      #1b242f;
  --ink-3:      #26313e;
  --paper:      #f5f3ee;
  --paper-2:    #ece8df;
  --white:      #ffffff;

  --text:       #18212b;
  --muted:      #5c6773;
  --muted-dark: #9aa6b3;

  --rule:       #d9d3c7;
  --rule-dark:  rgba(255, 255, 255, 0.15);

  --accent:     #9c7a37;   /* brass — insignia, not camouflage */
  --accent-lt:  #c9a961;

  --serif: "Source Serif 4", Georgia, "Times New Roman", serif;
  --sans:  Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono:  "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --wrap: 68rem;
  --gut: clamp(1.25rem, 5vw, 4rem);

  color-scheme: light;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--sans);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.6;
  font-feature-settings: "tnum" 1;
  /* NOTE: never set overflow-x here — it makes <body> its own scroll
     container and silently breaks position:sticky on descendants. */
}

h1, h2, h3, h4 { font-family: var(--serif); font-weight: 600; line-height: 1.12; margin: 0; letter-spacing: -0.015em; }
p { margin: 0; }
a { color: inherit; }

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gut); }

.skip {
  position: absolute; left: -999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--white); padding: 0.75rem 1rem;
  font: 500 0.8125rem/1 var(--mono); text-transform: uppercase; letter-spacing: 0.1em;
}
.skip:focus { left: 0; }

:where(a, button, input, textarea, summary):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ── Masthead ───────────────────────────────────────────────────────────── */

.masthead {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 1.5rem;
  padding: 0.875rem var(--gut);
  background: var(--ink);
  color: var(--white);
  border-bottom: 1px solid var(--rule-dark);
}

.wordmark {
  display: flex; align-items: center; gap: 0.625rem;
  font: 600 0.9375rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.18em;
  text-decoration: none;
  white-space: nowrap;
}
/* Two ascending chevrons — rank cadence, not an actual insignia. */
.mark { width: 18px; height: 18px; flex: none; color: var(--accent-lt); }

.mast-nav { display: flex; gap: 1.5rem; margin-left: auto; }
.mast-nav a {
  font: 500 0.75rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted-dark); text-decoration: none;
  padding-block: 0.25rem;
  border-bottom: 1px solid transparent;
  transition: color 0.15s, border-color 0.15s;
}
.mast-nav a:hover { color: var(--white); border-bottom-color: var(--accent); }

.mast-status {
  display: flex; align-items: center; gap: 0.5rem;
  font: 500 0.6875rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--accent-lt);
  white-space: nowrap;
}
.mast-status .dot {
  width: 6px; height: 6px; background: var(--accent-lt);
  border-radius: 50%; flex: none;
}

@media (max-width: 46rem) {
  .mast-nav { display: none; }
  .mast-status { margin-left: auto; }
}
@media (max-width: 24rem) {
  .mast-status { display: none; }
}

/* ── Shared section furniture ───────────────────────────────────────────── */

.band { padding-block: clamp(3.5rem, 9vw, 7rem); }
.band-paper { background: var(--paper-2); }
.band-ink { background: var(--ink); color: var(--white); }
.band-ink .index { color: var(--accent-lt); }
.band-ink .section-title { color: var(--white); }

.index {
  font: 500 0.6875rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.2em;
  color: var(--accent);
  padding-bottom: 0.875rem;
  margin-bottom: clamp(1.5rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--rule);
}
.band-ink .index { border-bottom-color: var(--rule-dark); }

.section-title {
  font-size: clamp(1.75rem, 1.35rem + 1.9vw, 2.75rem);
  max-width: 22ch;
  margin-bottom: clamp(2rem, 5vw, 3rem);
}

.group-label {
  font: 600 0.75rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--muted);
  margin-bottom: 1.5rem;
}

/* Standing note above the record — he is still in the role, so the employer
   is withheld. Reads as a deliberate choice, not an omission. */
.group-note {
  font: 500 0.6875rem/1.6 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted);
  border-left: 2px solid var(--accent);
  padding: 0.5rem 0 0.5rem 0.875rem;
  margin-bottom: 1.75rem;
  max-width: 46ch;
}
/* A group label already carries its own bottom space; don't stack both. */
.group-label + .group-note { margin-top: -0.875rem; }

/* ── Buttons ────────────────────────────────────────────────────────────── */

.btn {
  display: inline-block;
  font: 500 0.75rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  padding: 0.9375rem 1.5rem;
  border: 1px solid transparent;
  border-radius: 0;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s, color 0.15s, border-color 0.15s;
}
.btn-primary { background: var(--accent); color: var(--ink); border-color: var(--accent); }
.btn-primary:hover { background: var(--accent-lt); border-color: var(--accent-lt); }
.btn-ghost { background: transparent; color: inherit; border-color: currentColor; opacity: 0.85; }
.btn-ghost:hover { opacity: 1; background: rgba(255, 255, 255, 0.07); }
.band-paper .btn-ghost:hover, .band .btn-ghost:hover { background: rgba(18, 24, 31, 0.06); }
.btn:disabled { opacity: 0.5; cursor: default; }

/* ── Figures ────────────────────────────────────────────────────────────────
   All imagery on this site is drawn from his own operating numbers — a
   formation of 200 personnel, a tile map of the states he runs. No stock
   photography: it would fight the restraint everything else is built on. */

.figure { margin: 0; }
.figure svg { display: block; width: 100%; height: auto; }

.legend {
  list-style: none; margin: 1.25rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem;
}
.legend li {
  display: flex; align-items: center; gap: 0.5rem;
  font: 500 0.625rem/1.4 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted);
}
.band-ink .legend li, .hero .legend li { color: var(--muted-dark); }
.swatch {
  width: 10px; height: 10px; flex: none;
  border: 1px solid currentColor;
}
.swatch-key { background: var(--accent); border-color: var(--accent); }
.swatch-strong { background: var(--ink); border-color: var(--accent); }
.swatch-muted { background: transparent; border-color: var(--rule); }
.hero .swatch-muted { border-color: var(--rule-dark); }

/* ── Hero ───────────────────────────────────────────────────────────────── */

.hero {
  background: var(--ink);
  color: var(--white);
  padding-top: clamp(3.5rem, 10vw, 7rem);
}

/* Text left, portrait right. The face is the first thing a recruiter should
   meet on an executive page. */
.hero-grid {
  display: grid;
  /* Explicit fractions, not minmax: with `1fr minmax(17rem, 28rem)` the
     flexible track absorbed the free space and the portrait never reached its
     max, landing at 355px against a 541px text block.
     Centred rather than bottom-aligned — a near-square portrait can't match
     the text block's height, and splitting the difference reads as breathing
     room instead of a hole under the masthead. */
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
@media (max-width: 56rem) {
  /* The portrait LEADS on a phone. Stacked after the copy it landed at 662px
     — below the call-to-action, mostly under the fold — so the face arrived
     after the ask, which is backwards. Ordered first it introduces him, and
     capping it at 30vh keeps the eyebrow, headline, lede and both buttons on
     the first screen. Desktop keeps text-left / portrait-right, where the
     left-to-right read already puts the headline first. */
  .hero { padding-top: 0; }
  .hero-grid { grid-template-columns: 1fr; align-items: start; }
  .portrait {
    order: -1;
    width: auto;
    margin: 0 calc(var(--gut) * -1) 2.25rem;
    align-self: stretch;
  }
  /* NO definite height, NO object-fit: cover. Capping this at 30vh cropped
     him to a letterboxed strip of face — head only, no shoulders, no suit.
     Rejected on sight, and it is the second time this crop has been tried and
     rejected. The portrait runs at its natural 4:5 aspect so he is shown
     whole. Do NOT "fix" the fold by cropping him again — if the hero ever
     needs to be shorter, cut hero copy or re-crop the source file. */
  .portrait img { width: 100%; height: auto; }
  .hero-actions { padding-bottom: clamp(2.5rem, 7vw, 4rem); }
  /* The two CTAs missed sharing a line by a single pixel at 375px and wrapped,
     which cost 55px of first-screen height and read as an accident. */
  .hero-actions .btn { padding-inline: 1.25rem; }
  /* Gentler than desktop. These percentages were tuned for the old 4:5 crop;
     on the near-square image a 40% bottom fade swallowed the jacket and a 26%
     top fade greyed out the top of his head. The feather should blend the
     edges, not erase the subject. */
  .portrait::after {
    background:
      linear-gradient(to top,    var(--ink) 0%, rgba(18, 24, 31, 0) 22%),
      linear-gradient(to bottom, var(--ink) 0%, rgba(18, 24, 31, 0) 12%),
      linear-gradient(to right,  var(--ink) 0%, rgba(18, 24, 31, 0) 10%),
      linear-gradient(to left,   var(--ink) 0%, rgba(18, 24, 31, 0) 10%);
  }
}

.eyebrow {
  font: 500 0.6875rem/1.5 var(--mono);
  text-transform: uppercase; letter-spacing: 0.2em;
  color: var(--accent-lt);
  margin-bottom: 1.75rem;
}

.hero h1 {
  font-size: clamp(2.5rem, 1.5rem + 4.8vw, 5rem);
  max-width: 15ch;
  margin-bottom: 1.75rem;
  text-wrap: balance;
}

.lede {
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.25rem);
  color: var(--muted-dark);
  max-width: 46ch;
  line-height: 1.55;
}
.lede-sm { color: var(--muted); max-width: 40ch; }

.hero-actions {
  display: flex; flex-wrap: wrap; gap: 0.75rem;
  margin-top: 2.5rem;
  padding-bottom: clamp(3.5rem, 9vw, 6rem);
}

/* Facts strip: the "readiness board" — tabular, ruled, no ornament.
   The band bleeds full width, but its content is inset to line up with the
   .wrap column above it. Without this the first figure sat hard against the
   viewport edge while the headline started 288px in, and the mismatch read
   as an accident. */
.facts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin: 0;
  padding-inline: max(var(--gut), calc((100% - var(--wrap)) / 2 + var(--gut)));
  border-top: 1px solid var(--rule-dark);
  background: var(--ink-2);
}
.fact {
  padding: clamp(1.25rem, 3vw, 2rem) clamp(1rem, 2.5vw, 1.75rem);
  border-right: 1px solid var(--rule-dark);
}
.fact:last-child { border-right: 0; }
/* Flush the outer edges so the first figure sits on the headline's left edge. */
.fact:first-child { padding-left: 0; }
.fact:last-child { padding-right: 0; }
.fact dd {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
  font-weight: 600;
  line-height: 1;
  color: var(--accent-lt);
}
.fact dt {
  font: 500 0.625rem/1.4 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted-dark);
  margin-bottom: 0.625rem;
  min-height: 2.8em;
}

@media (max-width: 46rem) {
  .facts { grid-template-columns: repeat(2, 1fr); }
  .fact:nth-child(2n) { border-right: 0; padding-right: 0; }
  .fact:nth-child(2n+1) { padding-left: 0; }
  .fact:nth-child(-n+2) { border-bottom: 1px solid var(--rule-dark); }
  .fact dt { min-height: 0; }
}

/* ── 01 Profile ─────────────────────────────────────────────────────────── */

.statement p {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 1.15rem + 1.6vw, 2.375rem);
  line-height: 1.25;
  max-width: 24ch;
  text-wrap: pretty;
}
.statement p.muted {
  font-family: var(--sans);
  font-size: clamp(1rem, 0.96rem + 0.25vw, 1.125rem);
  line-height: 1.65;
  color: var(--muted-dark);
  max-width: 52ch;
  margin-top: 1.75rem;
}

/* ── 02 Pillars ─────────────────────────────────────────────────────────── */

/* Column counts are explicit, never auto-fit. There are exactly four pillars,
   and auto-fit resolved to THREE columns at common desktop widths — leaving
   one item on a second row beside two empty bordered cells. 1 / 2 / 4 all
   divide four exactly, so a row is never left half-built. */
.pillars {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  border-top: 1px solid var(--rule);
  border-left: 1px solid var(--rule);
}
/* Two columns is the ceiling. Four-across was tried and rejected on review:
   at 1088px of content each pillar got ~240px, which wrapped the body copy to
   six ragged lines and broke the tag chips onto two lines inside their own
   borders. A 2x2 quadrant reads as "four things" just as clearly and gives
   the sentences room to breathe. */
@media (min-width: 34rem) {
  .pillars { grid-template-columns: repeat(2, 1fr); }
}
.pillar {
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.pillar-num {
  display: block;
  font: 500 0.75rem/1 var(--mono);
  letter-spacing: 0.16em;
  color: var(--accent);
  margin-bottom: 1.25rem;
}
.pillar h3 { font-size: 1.1875rem; margin-bottom: 0.75rem; }
.pillar p { color: var(--muted); font-size: 0.9375rem; line-height: 1.6; }

.tags {
  list-style: none; margin: 1.25rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.375rem;
}
.tags li {
  font: 500 0.625rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--muted);
  border: 1px solid var(--rule);
  padding: 0.4375rem 0.5625rem;
}

/* Footprint map — tile grid, not geography. Precision over cartography. */
.footprint {
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding-top: clamp(2rem, 5vw, 3rem);
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 32rem);
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}
@media (max-width: 56rem) {
  .footprint { grid-template-columns: 1fr; }
}
.footprint h3 { font-size: clamp(1.375rem, 1.2rem + 0.8vw, 1.875rem); margin-bottom: 1rem; }
.footprint p { color: var(--muted); max-width: 44ch; }
/* Dot map. Every dot sits at its state's real centroid (equirectangular
   projection, AK/HI inset lower-left), so the cloud reads as the United States
   without any claim to being a survey map. */
.map text {
  font-family: var(--mono); font-size: 11px; font-weight: 600;
  letter-spacing: 0.04em; text-anchor: middle;
}
/* Base dots were var(--rule) on --paper: barely a shade apart, so the country
   never resolved. A muted fill at partial opacity keeps them quiet but legible. */
.m-base circle { fill: var(--muted); opacity: 0.34; }
.m-ops circle  { fill: var(--accent); }
/* NC and SC are ~24 units apart in this projection. At the old r=13 they
   collided and their centred labels sat on top of each other. Smaller dots,
   labels moved outside. */
.m-lic circle  { fill: var(--ink); stroke: var(--accent); stroke-width: 2.5; }
.m-lic-label text { fill: var(--ink); font-size: 11px; font-weight: 600; }

/* Operations and licence states arrive after the quiet ones, in sequence —
   the Carolinas last, because they are the point. */
.js .map .m-ops circle,
.js .map .m-lic circle { transform: scale(0); transform-origin: center; transform-box: fill-box; }
.js .map.in .m-ops circle,
.js .map.in .m-lic circle {
  transform: scale(1);
  transition: transform 0.5s cubic-bezier(0.34, 1.4, 0.64, 1) calc(300ms + var(--i) * 90ms);
}
.js .map.in .m-lic circle { transition-delay: calc(900ms + var(--i) * 140ms); }
.js .map .m-lic-label text { opacity: 0; }
.js .map.in .m-lic-label text { opacity: 1; transition: opacity 0.5s ease 1.2s; }

/* Formation: command element above the rule, ranks below. Lives in Profile,
   where the copy is about having held every level of the operation. */
.f-lead circle { fill: var(--accent-lt); }
.f-ranks circle { fill: #45525f; }
.f-rule { stroke: var(--rule-dark); stroke-width: 1; }

.js .formation .f-ranks g { opacity: 0; }
.js .formation.in .f-ranks g {
  opacity: 1;
  transition: opacity 0.45s ease calc(200ms + var(--i) * 70ms);
}
.js .formation .f-lead circle { transform: translateY(10px); opacity: 0; }
.js .formation.in .f-lead circle {
  transform: none; opacity: 1;
  transition:
    transform 0.6s cubic-bezier(0.34, 1.4, 0.64, 1) calc(1000ms + var(--i) * 80ms),
    opacity   0.6s ease calc(1000ms + var(--i) * 80ms);
}
.js .formation .f-rule { opacity: 0; }
.js .formation.in .f-rule { opacity: 1; transition: opacity 0.6s ease 900ms; }

@media (prefers-reduced-motion: reduce) {
  .js .map .m-ops circle, .js .map .m-lic circle,
  .js .formation .f-lead circle { transform: none; opacity: 1; }
  .js .map .m-lic-label text,
  .js .formation .f-ranks g, .js .formation .f-rule { opacity: 1; }
}

/* ── Portrait ──────────────────────────────────────────────────────────────
   A bordered rectangle sitting on the ink reads as a photo stamped onto the
   page. Instead the image is feathered into the background on the two edges
   that face content — bottom and left — so he emerges from the ink rather
   than being pasted over it. A brass rule runs BEHIND the portrait, tying it
   to the column of text rather than framing it like artwork.

   The fade is an overlay, not a mask: it paints the hero's own --ink over the
   image edges, which needs no mask-composite support and cannot leave a halo
   the way a partially-supported mask can. */

.portrait {
  position: relative;
  /* No align-self here — it would override the hero grid's align-items and
     pin the portrait to the bottom, stacking all the slack above it. */
}

.portrait img {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%; height: auto;
  /* Cool the studio grey a touch so it sits with the navy instead of beside it. */
  filter: saturate(0.9) contrast(1.03);
}

/* The feather. All four edges dissolve into the hero's own --ink, strongest
   on the two that face content, so the photograph has no cut edge anywhere
   and reads as part of the surface rather than a rectangle placed on it. */
.portrait::after {
  content: "";
  position: absolute; inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    linear-gradient(to top,    var(--ink) 0%, rgba(18, 24, 31, 0) 34%),
    linear-gradient(to right,  var(--ink) 0%, rgba(18, 24, 31, 0) 24%),
    linear-gradient(to left,   var(--ink) 0%, rgba(18, 24, 31, 0) 16%),
    linear-gradient(to bottom, var(--ink) 0%, rgba(18, 24, 31, 0) 14%);
}

/* Profile: statement left, formation right. */
.profile-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}
@media (max-width: 56rem) {
  .profile-grid { grid-template-columns: 1fr; }
  .profile-grid .formation { max-width: 26rem; }
}

/* ── The climb ──────────────────────────────────────────────────────────────
   His story is ascent, twice: a Marine ladder and then a business ladder. The
   bar length encodes position in that sequence, not headcount — the scope
   figure is stated in words beside it so nothing is implied that isn't true. */

.climb {
  list-style: none; margin: 0 0 clamp(3rem, 7vw, 5rem); padding: 0;
  counter-reset: rung;
}
.climb-step {
  display: grid;
  /* Every column is a FIXED width. Each row is its own grid, so an `auto`
     scope column would size to its own text ("7 Marines" vs "200+ personnel")
     and give every row a different track width — the bars would then encode
     nothing and the staircase would read crooked. Fixed columns keep all
     eight tracks identical, so bar length is comparable down the list. */
  grid-template-columns: 3.75rem 13rem minmax(0, 1fr) 9rem;
  align-items: center;
  gap: 0 clamp(0.75rem, 2vw, 1.5rem);
  padding-block: 0.6875rem;
  border-top: 1px solid var(--rule);
}
.climb-step:last-child { border-bottom: 1px solid var(--rule); }

.climb-year {
  font: 500 0.75rem/1 var(--mono);
  letter-spacing: 0.06em;
  color: var(--muted);
}
.climb-title { font-size: 0.9375rem; font-weight: 500; }
.climb-scope {
  font: 500 0.6875rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--muted);
  white-space: nowrap;
  text-align: right;
}

.climb-track { display: block; height: 10px; }
.climb-bar {
  display: block; height: 100%;
  width: calc(var(--rung) / 8 * 100%);
  background: var(--accent);
  transform-origin: left center;
}
.climb-bar.climb-usmc { background: #b3aa98; }

.climb-top .climb-title { font-weight: 600; }
.climb-top .climb-bar { background: var(--ink); }
.climb-top .climb-year, .climb-top .climb-scope { color: var(--accent); }

/* The one place the ladder restarts: Marine Corps out, business in. */
.climb-turn { border-top: 1px solid var(--accent); }

.js .climb-bar { transform: scaleX(0); }
.js .climb-step.in .climb-bar {
  transform: none;
  transition: transform 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) calc(var(--i) * 90ms);
}
@media (prefers-reduced-motion: reduce) {
  .js .climb-bar { transform: none; }
}

@media (max-width: 46rem) {
  .climb-step {
    grid-template-columns: 3.25rem minmax(0, 1fr) auto;
    row-gap: 0.5rem;
  }
  .climb-title { grid-column: 2; }
  .climb-scope { grid-column: 3; }
  .climb-track { grid-column: 1 / -1; }
}

.section-lede {
  color: var(--muted);
  max-width: 52ch;
  margin: -1rem 0 clamp(2rem, 5vw, 3rem);
  font-size: clamp(1rem, 0.96rem + 0.25vw, 1.0625rem);
}

/* ── 03 Record ──────────────────────────────────────────────────────────── */

.timeline { list-style: none; margin: 0 0 clamp(2.5rem, 6vw, 4rem); padding: 0; }

.entry {
  display: grid;
  grid-template-columns: 9rem 1fr;
  gap: 0 clamp(1.5rem, 4vw, 3rem);
  padding-block: clamp(1.5rem, 3vw, 2rem);
  border-top: 1px solid var(--rule);
}
.timeline .entry:last-child { border-bottom: 1px solid var(--rule); }

.dates {
  font: 500 0.75rem/1.5 var(--mono);
  letter-spacing: 0.08em;
  color: var(--muted);
  padding-top: 0.375rem;
  white-space: nowrap;
}
.dates span { color: var(--accent); }

.entry-body h4 { font-size: clamp(1.1875rem, 1.1rem + 0.4vw, 1.4375rem); }
.org {
  font: 500 0.6875rem/1.5 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted);
  margin-top: 0.4375rem;
}
.one-line { margin-top: 0.875rem; color: var(--text); max-width: 54ch; }

details { margin-top: 0.875rem; }
summary {
  font: 500 0.6875rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--accent);
  cursor: pointer;
  list-style: none;
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding-block: 0.375rem;
}
summary::-webkit-details-marker { display: none; }
summary::after {
  content: "+";
  font-family: var(--mono);
  font-size: 0.875rem;
  line-height: 1;
}
details[open] summary::after { content: "–"; }
summary:hover { color: var(--ink); }

details ul {
  margin: 0.625rem 0 0; padding: 0;
  list-style: none;
  max-width: 58ch;
}
details li {
  position: relative;
  padding-left: 1.125rem;
  margin-top: 0.5rem;
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.6;
}
details li::before {
  content: "";
  position: absolute; left: 0; top: 0.6875em;
  width: 6px; height: 1px;
  background: var(--accent);
}

.timeline-usmc .dates span { color: var(--muted); }

/* Service photo, inside the record where it reads as evidence. The two-column
   split is applied by script.js (.has-photo) only when the image really loads
   — otherwise an empty grid track would leave a hole. */
.usmc-body { display: grid; gap: clamp(1.25rem, 3vw, 2rem); }
@media (min-width: 52rem) {
  .usmc-body.has-photo { grid-template-columns: 1fr minmax(0, 14rem); }
}

.entry-figure { margin: 0; }
.entry-figure img {
  display: block;
  width: 100%; height: auto;
  border: 1px solid var(--rule);
  /* Documentary treatment: a full-colour desert photo fights the
     navy/brass/paper palette. Delete this line to show it as shot. */
  filter: grayscale(1) contrast(1.05) sepia(0.15);
}
.entry-figure figcaption {
  margin-top: 0.625rem;
  font: 500 0.625rem/1.5 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted);
}

.print-note { margin-top: -1rem; }

@media (max-width: 40rem) {
  .entry { grid-template-columns: 1fr; gap: 0.5rem; }
  .dates { padding-top: 0; }
}

/* ── 04 Next ────────────────────────────────────────────────────────────── */

.pills {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.625rem;
}
.pills li {
  font: 500 0.75rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.1em;
  padding: 0.8125rem 1rem;
  border: 1px solid var(--rule-dark);
  color: var(--white);
}
.next-note {
  margin-top: 2rem;
  font: 500 0.6875rem/1.6 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted-dark);
}

/* ── 05 Qualifications ──────────────────────────────────────────────────── */

.quals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: clamp(2rem, 5vw, 4rem);
}
.qual-list { list-style: none; margin: 0; padding: 0; }
.qual-list li {
  display: grid;
  grid-template-columns: 3.5rem 1fr;
  gap: 0.75rem;
  padding-block: 0.8125rem;
  border-top: 1px solid var(--rule);
  font-size: 0.9375rem;
}
.qual-list li:last-child { border-bottom: 1px solid var(--rule); }
.yr {
  font: 500 0.75rem/1.6 var(--mono);
  color: var(--accent);
  letter-spacing: 0.06em;
}

/* ── Contact ────────────────────────────────────────────────────────────── */

.band-contact { background: var(--ink-2); color: var(--white); }
.band-contact .index { color: var(--accent-lt); border-bottom-color: var(--rule-dark); }
.band-contact .section-title { color: var(--white); margin-bottom: 1.25rem; }
.band-contact .lede-sm { color: var(--muted-dark); }

.contact-grid {
  display: grid;
  grid-template-columns: 1fr minmax(20rem, 26rem);
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: start;
}
@media (max-width: 52rem) {
  .contact-grid { grid-template-columns: 1fr; }
}

.contact-details { margin: 2.5rem 0 0; }
.contact-details > div {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 0.75rem;
  padding-block: 0.875rem;
  border-top: 1px solid var(--rule-dark);
}
.contact-details dt {
  font: 500 0.625rem/1.9 var(--mono);
  text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--muted-dark);
}
.contact-details dd { margin: 0; font-size: 0.9375rem; }
.contact-details a { color: var(--accent-lt); text-decoration: none; border-bottom: 1px solid currentColor; }
.contact-details a:hover { color: var(--white); }

.card {
  background: var(--paper);
  color: var(--text);
  padding: clamp(1.5rem, 4vw, 2.25rem);
  border-top: 3px solid var(--accent);
}

.field { margin-bottom: 1.125rem; }
.field label {
  display: block;
  font: 500 0.625rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--muted);
  margin-bottom: 0.5rem;
}
.field input, .field textarea {
  width: 100%;
  font: 400 0.9375rem/1.5 var(--sans);
  color: var(--text);
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: 0;
  padding: 0.75rem 0.875rem;
  transition: border-color 0.15s;
}
.field textarea { resize: vertical; min-height: 7rem; }
.field input:focus, .field textarea:focus { border-color: var(--accent); }
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: #a33b2f; }

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

#submit-btn { width: 100%; }

.form-status {
  margin-top: 0.875rem;
  font: 500 0.75rem/1.5 var(--mono);
  text-transform: uppercase; letter-spacing: 0.08em;
  min-height: 1.5rem;
}
.form-status.ok { color: #2f6b46; }
.form-status.err { color: #a33b2f; }

/* ── Footer ─────────────────────────────────────────────────────────────── */

.foot { background: var(--ink); color: var(--muted-dark); padding-block: 2rem; }
.foot-inner {
  display: flex; flex-wrap: wrap; gap: 0.75rem;
  font: 500 0.6875rem/1.6 var(--mono);
  text-transform: uppercase; letter-spacing: 0.12em;
}
.foot-sep { color: var(--accent); }

/* ── Scroll choreography ────────────────────────────────────────────────────
   Everything below is progressive enhancement: without JS the `.js` class is
   never set, nothing is hidden, and the page is a complete static document.
   Motion is a single vocabulary — rise 18px and fade, 0.7s, one easing curve —
   so the page feels composed rather than decorated. `--i` staggers members of
   a group; nothing else varies. */

.js .reveal {
  opacity: 0;
  transform: translateY(18px);
}
.js .reveal.in {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.7s cubic-bezier(0.22, 0.61, 0.36, 1) calc(var(--i, 0) * 55ms),
    transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1) calc(var(--i, 0) * 55ms);
}

/* Reading-progress hairline. Brass on ink, top of the viewport. */
.progress {
  position: fixed; inset: 0 0 auto 0; z-index: 60;
  height: 2px; background: transparent;
  pointer-events: none;
}
.progress span {
  display: block; height: 100%; width: 0%;
  background: var(--accent);
  transform-origin: left center;
}

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; }
  .js .reveal.in { transition: none; }
  .progress { display: none; }
}

/* ── Print: the page becomes the résumé ─────────────────────────────────── */

@media print {
  @page { margin: 15mm; }
  body { background: #fff; color: #000; font-size: 10.5pt; }
  .masthead, .mast-nav, .mast-status, .hero-actions, .skip, .progress,
  .print-note, #contact-form, .foot, .pills, .next-note,
  /* US résumés don't carry a photo, and the data figures don't survive
     monochrome at print size — drop all of it, keep the words. */
  .portrait, .formation, .map, .legend { display: none !important; }
  .hero-grid, .footprint, .profile-grid { display: block !important; }
  .climb-step { break-inside: avoid; border-color: #ccc !important; }
  .climb-track { display: none !important; }
  .climb-step { grid-template-columns: 3.5rem 1fr auto !important; }
  .band, .band-ink, .band-paper, .band-contact, .hero, .card { background: #fff !important; color: #000 !important; padding-block: 0.6rem !important; }
  .wrap { max-width: none; padding-inline: 0; }
  .hero h1 { font-size: 20pt; max-width: none; }
  .eyebrow, .index, .lede, .muted, .org, .dates, .yr, .group-label { color: #333 !important; }
  .facts { grid-template-columns: repeat(4, 1fr); border-color: #ccc; }
  .fact { border-color: #ccc; }
  .fact dd { color: #000 !important; font-size: 16pt; }
  .section-title { font-size: 14pt; margin-bottom: 0.75rem; }
  .statement p { font-size: 12pt; max-width: none; }
  .pillar, .entry, .qual-list li, .pillars { break-inside: avoid; border-color: #ccc !important; }
  details, details ul { display: block !important; }
  summary { display: none !important; }
  .band { break-inside: avoid; }
  a { text-decoration: none; }
  .reveal { opacity: 1 !important; transform: none !important; }
}
