/* ==========================================================================
   Joseph Pettinato — personal site
   Direction: "A3b Dual Beacon" — near-black blue ground, scarlet primary
   accent, ice-blue secondary accent. Bricolage Grotesque (display) /
   Manrope (body) / JetBrains Mono (labels, data, nav).
   This is a deliberately fixed dark identity (no light mode), matching the
   reference site's approach. See README.md for how to extend sections.
   ========================================================================== */

:root{
  /* palette */
  --bg:            #0b1220;
  --bg-raise:      #0e1729;
  --surface:       #101b30;
  --surface-2:     #16223b;
  --border:        #223049;
  --border-soft:   #1a2740;
  --text:          #eef2f5;
  --text-muted:    #93a3b8;
  --text-faint:    #5c6b81;
  --accent:        #e0473d;      /* scarlet — primary */
  --accent-strong: #ff5b50;
  --accent-2:      #5ec8d8;      /* ice-blue — secondary */
  --accent-2-soft: rgba(94, 200, 216, 0.12);
  --accent-soft:   rgba(224, 71, 61, 0.14);

  /* type */
  --font-display: 'Bricolage Grotesque', 'Segoe UI', system-ui, sans-serif;
  --font-body:    'Manrope', 'Segoe UI', system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* layout */
  --max: 1180px;
  --gutter: clamp(20px, 5vw, 56px);
  --radius: 12px;
  --radius-sm: 8px;
}

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

html{
  scroll-behavior: smooth;
  scroll-padding-top: 84px;
}
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }
}

body{
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

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

a{ color: inherit; text-decoration: none; }

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

h1, h2, h3, h4{
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0;
  text-wrap: balance;
}

p{ margin: 0; }

.container{
  max-width: var(--max);
  margin: 0 auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}

.eyebrow{
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin: 0 0 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.eyebrow::before{
  content: "";
  width: 18px;
  height: 1px;
  background: var(--accent-2);
  display: inline-block;
}

.section-index{
  font-family: var(--font-mono);
  color: var(--text-faint);
  font-size: 0.8rem;
}

/* focus visibility */
a:focus-visible, button:focus-visible{
  outline: 2px solid var(--accent-2);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn{
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 13px 22px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.15s ease, background 0.15s ease, border-color 0.15s ease;
  white-space: nowrap;
}
/* Reset UA button chrome for <button class="btn">, e.g. the resume
   buttons — anchors don't need this, they have no default styling.
   :where() keeps this at zero specificity so .btn-solid/.btn-outline
   still win regardless of source order. */
:where(button.btn){
  background: none;
  font: inherit;
  appearance: none;
  -webkit-appearance: none;
}
.btn:hover{ transform: translateY(-1px); }
@media (prefers-reduced-motion: reduce){ .btn:hover{ transform: none; } }

.btn-solid{
  background: var(--accent);
  color: #fff;
}
.btn-solid:hover{ background: var(--accent-strong); }

.btn-outline{
  border-color: var(--accent-2);
  color: var(--accent-2);
}
.btn-outline:hover{ background: var(--accent-2-soft); }

/* ==========================================================================
   Boot loader — full-page overlay held until the page has actually
   finished loading (fonts + images), not just DOM-ready.
   Logic in js/main.js; <noscript> fallback in index.html.
   ========================================================================== */

body.is-booting{ overflow: hidden; }

.boot-overlay{
  position: fixed;
  inset: 0;
  z-index: 999;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  transition: opacity 0.7s ease;
}
.boot-overlay.is-hidden{
  opacity: 0;
  pointer-events: none;
}
.boot-mark{
  display: flex;
  align-items: center;
  gap: 9px;
}
.boot-mark svg{ width: 28px; height: 28px; }
.boot-mark span{
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.boot-pct{
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: clamp(2.4rem, 6vw, 3.4rem);
  color: var(--text);
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: flex-start;
  gap: 2px;
}
.boot-pct .sign{
  font-size: 1.1rem;
  color: var(--accent-2);
  margin-top: 8px;
}
.boot-bar{
  width: 220px;
  height: 2px;
  border-radius: 999px;
  background: var(--border-soft);
  overflow: hidden;
}
.boot-bar span{
  display: block;
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  border-radius: 999px;
  transition: width 0.15s linear;
}
.boot-status{
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  height: 1em;
  margin: 0;
}
@media (prefers-reduced-motion: reduce){
  .boot-overlay{ transition: none; }
}

/* ==========================================================================
   Toast — small transient notice. Currently only used by the resume
   buttons (see js/main.js), written generically so it's reusable for
   anything else later.
   ========================================================================== */

.toast{
  position: fixed;
  left: 50%;
  bottom: 28px;
  z-index: 998;
  transform: translateX(-50%) translateY(10px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent-2);
  border-radius: var(--radius-sm);
  padding: 14px 20px;
  max-width: calc(100vw - 40px);
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--text);
  box-shadow: 0 16px 32px rgba(0,0,0,0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.toast.is-visible{
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
@media (prefers-reduced-motion: reduce){
  .toast{ transition: opacity 0.15s linear; transform: translateX(-50%); }
}

/* ==========================================================================
   Header / Nav
   ========================================================================== */

.site-header{
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  background: rgba(11, 18, 32, 0.82);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  border-bottom: 1px solid var(--border-soft);
}

.site-header .container{
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 68px;
}

.logo{
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.02em;
  display: flex;
  align-items: center;
  gap: 10px;
}
.logo .mark{
  width: 32px; height: 32px;
  flex-shrink: 0;
}

.nav-links{
  display: flex;
  gap: 28px;
  list-style: none;
  margin: 0; padding: 0;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.nav-links a{
  color: var(--text-muted);
  position: relative;
  padding: 6px 0;
}
.nav-links a:hover{ color: var(--text); }
.nav-links a::after{
  content:"";
  position:absolute; left:0; right:100%; bottom:0;
  height: 1px; background: var(--accent);
  transition: right 0.2s ease;
}
.nav-links a:hover::after{ right: 0; }

.nav-toggle{
  display: none;
  background: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  width: 40px; height: 40px;
  color: var(--text);
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
}

@media (max-width: 860px){
  .nav-links{
    position: fixed;
    top: 68px; left: 0; right: 0;
    flex-direction: column;
    background: var(--bg-raise);
    border-bottom: 1px solid var(--border-soft);
    padding: 20px var(--gutter) 28px;
    gap: 18px;
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.18s ease, transform 0.18s ease;
  }
  .nav-links.is-open{
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }
  .nav-toggle{ display: flex; }
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero{
  padding: 168px 0 96px;
  position: relative;
  overflow: hidden;
}

.hero::before{
  content:"";
  position:absolute;
  top: -220px; right: -160px;
  width: 620px; height: 620px;
  background: radial-gradient(circle, rgba(94,200,216,0.14) 0%, rgba(94,200,216,0) 70%);
  pointer-events: none;
}
.hero::after{
  content:"";
  position:absolute;
  bottom: -260px; left: -180px;
  width: 560px; height: 560px;
  background: radial-gradient(circle, rgba(224,71,61,0.10) 0%, rgba(224,71,61,0) 70%);
  pointer-events: none;
}

.hero-inner{
  position: relative;
  max-width: 640px;
}

.hero-photo{
  width: 240px;
  margin: 8px auto 0;
}
.hero-photo img{
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  display: block;
}

.hero-social{
  display: flex;
  justify-content: center;
  gap: 14px;
  margin-top: 30px;
}
.social-icon{
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.social-icon:hover{
  color: var(--accent-2);
  border-color: var(--accent-2);
  background: var(--accent-2-soft);
}
.social-icon svg{ width: 18px; height: 18px; }
.social-icon.li-mark{
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.82rem;
}

.hero-location{
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-muted);
  margin: 0 0 22px;
  letter-spacing: 0.04em;
}
.hero-location b{ color: var(--text); font-weight: 600; }

.hero h1{
  font-size: clamp(2.6rem, 7vw, 5rem);
  line-height: 0.98;
  margin-bottom: 26px;
}

.hero p.tagline{
  font-size: clamp(1.05rem, 2vw, 1.25rem);
  color: var(--text-muted);
  max-width: 56ch;
  margin-bottom: 38px;
}

.hero .btns{
  display: flex;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
}
/* Match "View Resume" to "View Portfolio" (the wider of the two, ~161px)
   so the pair reads as one balanced unit instead of two different-sized
   pills — .btn is already inline-flex/align-items:center, so centering
   the now-wider content just needs justify-content added. */
.hero .btns .btn{
  min-width: 162px;
  justify-content: center;
}

.scroll-cue{
  margin-top: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.scroll-cue .line{
  width: 40px; height: 1px;
  background: var(--text-faint);
}

/* ==========================================================================
   Marquee / ticker
   ========================================================================== */

.marquee{
  border-top: 1px solid var(--border-soft);
  border-bottom: 1px solid var(--border-soft);
  overflow: hidden;
  background: var(--bg-raise);
  padding: 18px 0;
}
.marquee-track{
  display: flex;
  gap: 40px;
  width: max-content;
  animation: scroll-left 38s linear infinite;
}
@keyframes scroll-left{
  from{ transform: translateX(0); }
  to{ transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce){
  .marquee-track{ animation: none; overflow-x: auto; }
}
.marquee-track span{
  font-family: var(--font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 40px;
}
.marquee-track span b{
  color: var(--accent-2);
  font-weight: 600;
}
.marquee-track span::after{
  content: "◆";
  color: var(--accent);
  font-size: 0.6rem;
}

/* ==========================================================================
   Stats
   ========================================================================== */

.stats{
  padding: 64px 0;
  border-bottom: 1px solid var(--border-soft);
}
.stats-grid{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
}
@media (max-width: 760px){
  .stats-grid{ grid-template-columns: repeat(2, 1fr); }
}
.stat{
  border-left: 2px solid var(--accent);
  padding-left: 16px;
}
.stat .num{
  font-family: var(--font-mono);
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  display: block;
}
.stat .label{
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-top: 4px;
  display: block;
}

/* ==========================================================================
   Section shell
   ========================================================================== */

.section{
  padding: 96px 0;
  border-bottom: 1px solid var(--border-soft);
}
.section:last-of-type{ border-bottom: none; }

.section-head{
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  margin-bottom: 48px;
  flex-wrap: wrap;
}
.section-head h2{
  font-size: clamp(1.7rem, 3.2vw, 2.3rem);
}
.section-head .section-sub{
  color: var(--text-muted);
  max-width: 46ch;
  font-size: 0.98rem;
}

/* ==========================================================================
   Education
   ========================================================================== */

.edu-grid{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 28px;
}
@media (max-width: 760px){
  .edu-grid{ grid-template-columns: 1fr; }
}
.edu-card{
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 30px;
}
.edu-card .tag{
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin-bottom: 14px;
  display: block;
}
.edu-card h3{
  font-size: 1.3rem;
  margin-bottom: 6px;
}
.edu-card .meta{
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-faint);
  margin-bottom: 18px;
  display: block;
}
.edu-card ul{
  margin: 0;
  padding-left: 18px;
  color: var(--text-muted);
  font-size: 0.94rem;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.edu-card ul li::marker{ color: var(--accent); }

/* ==========================================================================
   Flight training
   ========================================================================== */

.flight-panel{
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(24px, 4vw, 44px);
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 40px;
}
@media (max-width: 860px){
  .flight-panel{ grid-template-columns: 1fr; }
}
.flight-cert{
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 22px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--border-soft);
}
.flight-cert .badge{
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-strong);
  border: 1px solid rgba(224,71,61,0.35);
  white-space: nowrap;
}
.flight-cert h3{ font-size: 1.4rem; }
.flight-cert p{ color: var(--text-muted); font-size: 0.9rem; margin-top: 4px; }

.aircraft-list{
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
}
.aircraft-chip{
  font-family: var(--font-mono);
  font-size: 0.76rem;
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-muted);
}

.flight-note{
  color: var(--text-muted);
  font-size: 0.94rem;
  line-height: 1.7;
}
.flight-note b{ color: var(--text); font-weight: 600; }

.flight-side{
  display: flex;
  flex-direction: column;
  gap: 18px;
  justify-content: center;
}
.flight-metric{
  border-left: 2px solid var(--accent-2);
  padding-left: 16px;
}
.flight-metric .num{
  font-family: var(--font-mono);
  font-size: 1.9rem;
  font-weight: 700;
  color: var(--accent-2);
  font-variant-numeric: tabular-nums;
  display: block;
}
.flight-metric .label{
  color: var(--text-muted);
  font-size: 0.82rem;
}

/* ==========================================================================
   Timeline (Leadership)
   ========================================================================== */

.timeline{
  position: relative;
  padding-left: 32px;
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 36px;
}
.timeline-item{
  position: relative;
}
.timeline-item::before{
  content: "";
  position: absolute;
  /* Line (.timeline's border-left) sits at the timeline's left edge;
     .timeline-item is offset from that edge by the timeline's own
     border (1px) + padding (32px) = 33px. -33px lines this pseudo's
     `left` up with the line itself, then translateX(-50%) centers the
     dot ON that line regardless of the dot's own width — more robust
     than hand-computing left = -33px - width/2, which drifts if the
     dot size (or timeline padding) ever changes and is prone to the
     sub-pixel rounding that caused the off-center look. */
  left: -32.5px;
  transform: translateX(-50%);
  top: 4px;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--accent);
}
.timeline-item .when{
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.05em;
  color: var(--accent-2);
  display: block;
  margin-bottom: 6px;
}
.timeline-item h3{
  font-size: 1.15rem;
  margin-bottom: 2px;
}
.timeline-item .org{
  font-family: var(--font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-faint);
  display: block;
  margin-bottom: 10px;
}
.timeline-item p{
  color: var(--text-muted);
  font-size: 0.94rem;
  max-width: 62ch;
}
/* Dim via color, not opacity — opacity on the item would also fade
   its own ::before dot, which needs to stay fully opaque to mask the
   timeline's connecting line behind it (that's what makes the line
   look like it "stops" at each dot instead of running through it). */
.timeline-item.is-upcoming .when{ color: var(--text-faint); }
.timeline-item.is-upcoming h3{ color: var(--text-muted); }
.timeline-item .status{
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 9px;
  margin-left: 8px;
}

/* ==========================================================================
   Awards
   ========================================================================== */

.awards-grid{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
@media (max-width: 700px){
  .awards-grid{ grid-template-columns: 1fr; }
}
.award-row{
  padding: 20px;
  padding-left: 19px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius-sm);
}
.award-row h3{ font-size: 1rem; margin-bottom: 3px; }
.award-row p{ color: var(--text-muted); font-size: 0.86rem; }

/* ==========================================================================
   Media & Press
   ========================================================================== */

.media-grid{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 22px;
}
@media (max-width: 760px){
  .media-grid{ grid-template-columns: 1fr; }
}
.media-card{
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 28px;
}
.media-card .tag{
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  display: block;
  margin-bottom: 12px;
}
.media-card h3{ font-size: 1.15rem; margin-bottom: 10px; }
.media-card p{ color: var(--text-muted); font-size: 0.92rem; }

/* ==========================================================================
   Experience
   ========================================================================== */

.exp-list{
  display: flex;
  flex-direction: column;
  gap: 0;
}
.exp-item{
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 28px;
  padding: 28px 0;
  border-top: 1px solid var(--border-soft);
}
.exp-item:first-child{ border-top: none; padding-top: 0; }
@media (max-width: 700px){
  .exp-item{ grid-template-columns: 1fr; gap: 8px; }
}
.exp-item .when{
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--text-faint);
  letter-spacing: 0.03em;
}
.exp-item h3{ font-size: 1.1rem; margin-bottom: 3px; }
.exp-item .org{
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--accent-2);
  display: block;
  margin-bottom: 10px;
}
.exp-item ul{
  margin: 0;
  padding-left: 18px;
  color: var(--text-muted);
  font-size: 0.92rem;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.exp-item ul li::marker{ color: var(--accent); }

/* ==========================================================================
   Skills
   Card treatment (border + left accent-bar) intentionally echoes
   .edu-card and .award-row so this section reads as part of the same
   system rather than a bolt-on component — separate classes since
   those two have their own fields (tag/meta), but same visual idea.
   ========================================================================== */

.skills-groups{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}
.skill-group{
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 20px;
}
.skill-group h3{
  font-size: 0.98rem;
  margin: 0 0 12px;
}
.skill-list{
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.skill-item{
  font-size: 0.88rem;
  color: var(--text-muted);
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.skill-item::before{
  content: "·";
  color: var(--accent-2);
  font-weight: 700;
}

/* .skill-chip/.skill-chips: a different, pill-style pattern used only
   by the Thrust Vectored Rocket project card's tool list (Portfolio
   section below) — not used by Skills above, don't confuse the two. */
.skill-chips{
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.skill-chip{
  font-family: var(--font-mono);
  font-size: 0.82rem;
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-muted);
  background: var(--surface);
}

/* ==========================================================================
   Portfolio
   ========================================================================== */

.portfolio-grid{
  display: grid;
  /* minmax(…, 1fr), not a fixed px max: with a fixed max, the browser
     counts how many tracks fit using THAT max (not the min) once it's
     a definite length, and any width left over after that isn't
     redistributed — the grid just leaves it as dead space. That's
     what was quietly shrinking .has-photo/.is-full-width cards below
     the container's true width, since grid-column: 1/-1 only spans
     the tracks the grid actually defined. 1fr always fills the
     container exactly, so a full-width card always reaches the real
     edges — verify with the browser's resolved gridTemplateColumns
     (getComputedStyle), not just eyeballing it, if this changes again. */
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 24px;
}
.project-card{
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.project-card .tag{
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-2);
}
.project-card h3{ font-size: 1.4rem; }
.project-card p{ color: var(--text-muted); font-size: 0.95rem; }
.project-status{
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--accent-2-soft);
  color: var(--accent-2);
  border: 1px solid rgba(94,200,216,0.35);
}

/* Stage stepper — an alternative to .project-status for a project with
   known named stages rather than just "in progress" (currently the
   Rocket card). Echoes the Leadership timeline's dot-and-line
   language rather than inventing a new device. */
.stage-stepper{
  display: flex;
  align-items: flex-start;
  width: 100%;
  max-width: 480px;
}
.stage-step{
  /* Equal-width columns, not sized to each label — the connecting
     line (.stage-connector) is positioned at left:50%/width:100% of
     its OWN step, which only lands exactly on the next dot's center
     if every step is the same width. (A previous version sized steps
     to their labels instead, which fixed a label-collision bug but
     broke this — the line stopped short of the dot instead of
     reaching it, since a differently-sized step shifts the dot away
     from the step's edge by a different amount each time.) 480px
     total gives "Fabrication" (the longest label) enough room in its
     120px share not to collide with its neighbors either way.
     Adjust the stepper's max-width above, not this, if a future
     label is long enough to need more room. */
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.stage-dot{
  z-index: 1;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid var(--border);
  background: var(--bg);
  flex-shrink: 0;
}
.stage-step.is-done .stage-dot{
  border-color: var(--accent);
  background: var(--accent);
}
.stage-step.is-current .stage-dot{
  border-color: var(--accent-2);
  background: var(--bg);
  box-shadow: 0 0 0 3px var(--accent-2-soft);
}
.stage-label{
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  white-space: nowrap;
}
.stage-step.is-done .stage-label{ color: var(--text-muted); }
.stage-step.is-current .stage-label{ color: var(--accent-2); }
.stage-connector{
  z-index: 0;
  position: absolute;
  top: 5px; /* vertically centers it on the 12px dot above */
  left: 50%;
  width: 100%;
  height: 2px;
  background: var(--border);
}
.stage-step:last-child .stage-connector{ display: none; }
.stage-step.is-done .stage-connector{ background: var(--accent); }
.project-card .progress-label{
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-muted);
  display: flex;
  justify-content: space-between;
}
.progress-bar{
  height: 6px;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}
.progress-bar span{
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  border-radius: 999px;
}
.project-card .remaining{
  font-size: 0.86rem;
  color: var(--text-muted);
}
.project-card .remaining b{ color: var(--text); font-weight: 600; }

/* Photo variant — split layout: image column left, content right.
   Spans the full grid row (not the 300–460px card width) since it
   needs the room for the photo. Add another .filmstrip <img> pair or
   a second .has-photo card the same way if more builds get this
   treatment later. */
.project-card.has-photo,
.project-card.is-full-width{
  grid-column: 1 / -1;
  max-width: none;
}
/* Full width with left-aligned content left a big empty gap on the
   right (nothing there to balance it, unlike .has-photo's image
   column) — centering everything spreads the leftover space evenly
   on both sides instead. Same idea as the Contact section. */
.project-card.is-full-width{
  align-items: center;
  text-align: center;
}
.project-card.is-full-width p{ max-width: 65ch; margin: 0 auto; }
.project-card.is-full-width .stage-stepper{ margin: 0 auto; }
.project-card.is-full-width .skill-chips{ justify-content: center; }
.project-card.has-photo{
  flex-direction: row;
  padding: 0;
}
.project-card.has-photo .photo-col{
  width: 38%;
  flex-shrink: 0;
  border-right: 1px solid var(--border);
}
.project-card.has-photo .photo-col img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Shifted right so the aircraft's nose/front stays fully in frame;
     crops into the wing/tail on the left instead. Adjust this if the
     card's proportions change enough to reframe awkwardly. */
  object-position: 78% center;
  display: block;
}
.project-card.has-photo .content-col{
  flex: 1;
  min-width: 0;
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.project-card .filmstrip{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.project-card .filmstrip img{
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--border);
  display: block;
}
@media (max-width: 680px){
  .project-card.has-photo{ flex-direction: column; }
  .project-card.has-photo .photo-col{
    width: 100%;
    aspect-ratio: 4 / 3;
    border-right: none;
    border-bottom: 1px solid var(--border);
  }
}

.project-card.is-placeholder{
  border-style: dashed;
  align-items: flex-start;
  justify-content: center;
  color: var(--text-faint);
  min-height: 220px;
}
.project-card.is-placeholder .plus{
  font-family: var(--font-mono);
  font-size: 1.6rem;
  color: var(--text-faint);
}
.project-card.is-placeholder h3{ color: var(--text-muted); font-size: 1.05rem; }
.project-card.is-placeholder p{ font-size: 0.88rem; }

/* ==========================================================================
   Contact / Footer
   ========================================================================== */

.contact{
  padding: 96px 0 64px;
  text-align: center;
}
.contact h2{
  font-size: clamp(2rem, 5vw, 3rem);
  max-width: 18ch;
  margin: 0 auto 20px;
}
.contact p.sub{
  color: var(--text-muted);
  max-width: 52ch;
  margin: 0 auto 36px;
}
.contact .btns{
  display: flex;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 48px;
}
.contact-links{
  display: flex;
  justify-content: center;
  gap: 28px;
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: 0.82rem;
}
.contact-links a{
  color: var(--text-muted);
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
}
.contact-links a:hover{
  color: var(--accent-2);
  border-color: var(--accent-2);
}

.site-footer{
  border-top: 1px solid var(--border-soft);
  padding: 28px 0 40px;
}
.site-footer .container{
  /* 1fr / auto / 1fr, not flex space-between: with 3 different-width
     items, space-between only equalizes the *gaps*, not the middle
     item's actual position — it visibly drifted off true-center.
     Two equal flanking columns guarantee the middle one sits at the
     real horizontal center regardless of how long any of the three
     strings are. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-faint);
  letter-spacing: 0.02em;
}
.site-footer .container span:first-child{ justify-self: start; }
.site-footer .container span:nth-child(2){ justify-self: center; }
.site-footer .container span:last-child{ justify-self: end; }
@media (max-width: 640px){
  .site-footer .container{
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
  }
  /* Without this, the first/last items keep their desktop
     justify-self: start/end and hug the edges instead of stacking
     centered like the middle item. */
  .site-footer .container span:first-child,
  .site-footer .container span:nth-child(2),
  .site-footer .container span:last-child{
    justify-self: center;
  }
}

/* ==========================================================================
   Scroll reveal (progressive enhancement — see js/main.js)
   ========================================================================== */

.reveal{
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.is-visible{
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce){
  .reveal{ opacity: 1; transform: none; transition: none; }
}

/* --- admin-portal: not-yet-final block style --- */
/* Generalizes the Leadership timeline's existing .is-upcoming treatment
   (dim via color, not opacity — see the comment above .timeline-item's
   rule) into a reusable per-block "not-yet-final" toggle. Added by the
   admin portal; safe to hand-edit like anything else in this file. */
.is-draft{ opacity: 0.6; }
.is-draft h3{ color: var(--text-muted); }
