/* ============================================================
   matthewsabag.com — "Precision Graphite"
   Neutral graphite canvas, BMW M accent discipline,
   engineering-drawing details. Desktop-first.
   ============================================================ */

/* ---------- Tokens ---------- */
:root {
  /* Surfaces — neutral graphite, no color cast */
  --bg: #141417;
  --bg-raised: #1a1a1e;
  --card: #1d1d22;
  --border: #2a2a30;
  --border-strong: #35353d;

  /* Text */
  --text-hi: #ededef;
  --text-mid: #a0a0a8;
  --text-low: #6e6e76;

  /* BMW M accents — fills vs. text-safe variants */
  --m-red: #e7222e;
  --m-red-hover: #f5303c;
  --m-red-text: #ff4d58;
  --m-blue: #1c69d4;
  --m-blue-text: #5b9fe8;
  --m-lightblue: #58a6e8;
  /* Three solid segments — light blue / dark blue / red. No blending. */
  --stripe: linear-gradient(90deg,
    var(--m-lightblue) 0%, var(--m-lightblue) 33.4%,
    var(--m-blue) 33.4%, var(--m-blue) 66.7%,
    var(--m-red) 66.7%, var(--m-red) 100%);

  /* Chrome */
  --nav-h: 64px;
  --nav-bg: rgba(20, 20, 23, 0.8);
  --shadow-card: 0 12px 32px -12px rgba(0, 0, 0, 0.55);

  /* Type */
  --font-display: "Space Grotesk", "Segoe UI", sans-serif;
  --font-body: "Inter", -apple-system, "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", "Consolas", monospace;

  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 150ms;
  --dur-med: 250ms;
  --dur-reveal: 550ms;
}

/* ---------- Reset / base ---------- */
* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  /* containing block for .corner-page document-corner marks */
  position: relative;
  margin: 0;
  font-family: var(--font-body);
  background-color: var(--bg);
  /* drafting dot-grid spans every page top to bottom */
  background-image: radial-gradient(circle, #1e1e24 1px, transparent 1px);
  background-size: 30px 30px;
  color: var(--text-hi);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

/* When JS paints the interactive dot field, drop the static CSS copy
   so the two grids don't stack. No-JS and touch keep the CSS grid. */
.dot-canvas body {
  background-image: none;
}

#dot-field {
  position: fixed;
  inset: 0;
  /* A canvas is a replaced element: without an explicit layout size it
     lays out at its bitmap size (viewport x devicePixelRatio), which
     scales the whole grid up and pushes it down-right of the cursor. */
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
}

body.modal-open {
  overflow: hidden;
}

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

a {
  color: var(--m-blue-text);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}

a:hover {
  color: var(--m-lightblue);
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--text-hi);
}

:focus-visible {
  outline: 2px solid var(--m-blue);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection {
  background: rgba(28, 105, 212, 0.35);
}

.container {
  max-width: 1160px;
  margin: 0 auto;
  padding: 0 32px;
}

/* ---------- Shared text utilities ---------- */
.eyebrow,
.hero-eyebrow {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-mid);
  margin: 0 0 12px;
}

.stripe-chip {
  display: block;
  width: 48px;
  height: 3px;
  background: var(--stripe);
  border-radius: 2px;
  margin-bottom: 20px;
}

.accent-period {
  color: var(--m-red-text);
}

.period-white {
  color: var(--text-hi);
}

.period-lightblue {
  color: var(--m-lightblue);
}

.period-blue {
  color: var(--m-blue);
}

/* Homepage name lockup — the largest text on the page */
.name-lockup {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.6rem, 5.5vw, 4.2rem);
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--text-hi);
  line-height: 1;
  margin: 0 0 18px;
}

/* ---------- Navigation ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--nav-bg);
  backdrop-filter: saturate(160%) blur(12px);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
}

/* Static M-stripe divider under the nav */
.site-header::after {
  content: "";
  display: block;
  height: 2px;
  background: var(--stripe);
  opacity: 0.25;
}

/* 3-column grid keeps the tabs centered whether or not anything
   sits in the side columns (no wordmark now, hamburger on mobile). */
.nav {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: var(--nav-h);
  padding: 0 32px;
}

.nav-links {
  grid-column: 2;
  justify-self: center;
  display: flex;
  align-items: center;
  gap: 36px;
}

.nav-links a {
  position: relative;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-mid);
  padding: 4px 0;
  transition: color var(--dur-fast) var(--ease-out);
}

.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 2px;
  background: var(--stripe);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-fast) var(--ease-out);
}

.nav-links a:hover,
.nav-links a.active {
  color: var(--text-hi);
}

.nav-links a:hover::after,
.nav-links a.active::after {
  transform: scaleX(1);
}

.nav-right {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
}

.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
}

.nav-toggle span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--text-hi);
  margin: 4px 0;
  transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}

/* ---------- Corner crosshair marks ---------- */
.corner-marks {
  position: absolute;
  inset: 24px;
  pointer-events: none;
}

.corner-marks span {
  position: absolute;
  width: 13px;
  height: 13px;
}

.corner-marks span::before,
.corner-marks span::after {
  content: "";
  position: absolute;
  background: var(--border-strong);
}

.corner-marks span::before {
  left: 6px;
  top: 0;
  width: 1px;
  height: 13px;
}

.corner-marks span::after {
  left: 0;
  top: 6px;
  width: 13px;
  height: 1px;
}

.corner-marks .tl { left: 0; top: 0; }
.corner-marks .tr { right: 0; top: 0; }
.corner-marks .bl { left: 0; bottom: 0; }
.corner-marks .br { right: 0; bottom: 0; }

/* Document-corner variant (subpages): top pair just under the nav,
   bottom pair down by the footer — spans the whole scrolling page. */
.corner-page {
  position: absolute;
  left: 24px;
  right: 24px;
  top: calc(var(--nav-h) + 26px);
  bottom: 20px;
}

/* ---------- Homepage hero (hero-only landing) ---------- */
.hero-home {
  position: relative;
  padding: 0;
  min-height: calc(100dvh - var(--nav-h) - 2px);
  display: flex;
  align-items: center;
  overflow: hidden;
}

.hero-home .container {
  position: relative;
  z-index: 1;
  width: 100%;
  padding-top: 48px;
  padding-bottom: 96px;
  text-align: center;
}

.hero-home h1 {
  font-size: clamp(1.35rem, 2.6vw, 1.9rem);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.3;
  margin: 0 auto 14px;
  max-width: 32ch;
}

.hero-home .hero-sub {
  color: var(--text-mid);
  font-size: 1rem;
  max-width: 52ch;
  margin: 0 auto 36px;
}

.hero-home .button-row {
  justify-content: center;
}

/* ---------- Subpage hero ---------- */
.page-hero {
  position: relative;
  padding: 80px 0 56px;
}

.page-hero h1 {
  font-size: clamp(2rem, 4vw, 3rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin: 0 0 14px;
}

.page-hero .lede {
  color: var(--text-mid);
  font-size: 1.05rem;
  max-width: 58ch;
  margin: 0;
}

/* ---------- Buttons ---------- */
.button-row {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 24px;
  border-radius: 6px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.92rem;
  letter-spacing: 0.01em;
  border: 1px solid transparent;
  transition: transform var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

.btn:hover {
  transform: translateY(-2px);
}

.btn:active {
  transform: translateY(0) scale(0.98);
}

/* Outline buttons — white at rest, M color + glow on hover */
.btn-outline {
  border-color: var(--border-strong);
  color: var(--text-hi);
  background: transparent;
}

.btn-outline.hover-lightblue:hover {
  border-color: var(--m-lightblue);
  color: var(--m-lightblue);
  box-shadow: 0 10px 28px -10px rgba(88, 166, 232, 0.45);
}

.btn-outline.hover-blue:hover {
  border-color: var(--m-blue);
  color: var(--m-blue-text);
  box-shadow: 0 10px 28px -10px rgba(28, 105, 212, 0.5);
}

.btn-outline.hover-red:hover {
  border-color: var(--m-red);
  color: var(--m-red-text);
  box-shadow: 0 10px 28px -10px rgba(231, 34, 46, 0.45);
}

.btn-ghost {
  border-color: var(--border);
  color: var(--text-low);
  cursor: default;
  pointer-events: none;
}

.btn .arrow {
  display: inline-block;
  transition: transform var(--dur-fast) var(--ease-out);
}

.btn:hover .arrow {
  transform: translateX(3px);
}

/* ---------- Sections ---------- */
section {
  padding: 88px 0;
}

.section-tight {
  padding: 64px 0;
}

/* Pulls a section up under the one above it, closing dead space left by
   a short intro column. Used for About's "What I work on". */
.section-pull-up {
  padding-top: 56px;
}

.page-hero.hero-tight-bottom {
  padding-bottom: 20px;
}

.section-header {
  margin-bottom: 44px;
}

.section-header h2 {
  font-size: clamp(1.6rem, 3vw, 2.3rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0 0 10px;
}

.section-header p {
  color: var(--text-mid);
  max-width: 60ch;
  margin: 0;
}

/* ---------- Capability cards (about page) ---------- */
.focus-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
}

.focus-card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 26px 24px 24px;
  overflow: hidden;
  transition: transform var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}

.focus-card::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 2px;
  background: var(--stripe);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-med) var(--ease-out);
}

.focus-card:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-card);
}

.focus-card:hover::before {
  transform: scaleX(1);
}

.card-index {
  position: absolute;
  right: 20px;
  top: 18px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-low);
  letter-spacing: 0.08em;
}

/* project cards: index sits over the thumbnail — shadow keeps it legible */
.project-card .card-index {
  color: var(--text-mid);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
}

.focus-card .icon {
  color: var(--text-mid);
  margin-bottom: 16px;
  transition: color var(--dur-fast) var(--ease-out);
}

.focus-card .icon svg {
  display: block;
  width: 24px;
  height: 24px;
}

.focus-card:hover .icon {
  color: var(--m-blue-text);
}

.focus-card h3 {
  margin: 0 0 8px;
  font-size: 1.05rem;
  font-weight: 500;
}

.focus-card p {
  margin: 0;
  color: var(--text-mid);
  font-size: 0.92rem;
  line-height: 1.6;
  /* Left aligned on purpose. Justifying this narrow a column either
     splits words or opens up gaps between them. */
  hyphens: none;
  text-wrap: pretty;
}

/* ---------- Project cards ---------- */
.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 24px;
}

.project-card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}

.project-card::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 2px;
  z-index: 1;
  background: var(--stripe);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-med) var(--ease-out);
}

.project-card:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-card);
}

.project-card:hover::before {
  transform: scaleX(1);
}

/* CSS-drawn geometric thumbs — angled machined bands */
.project-thumb {
  aspect-ratio: 16 / 10;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background-color: var(--bg-raised);
  background-image:
    linear-gradient(105deg, transparent 58%, rgba(88, 166, 232, 0.14) 58%, rgba(88, 166, 232, 0.14) 66%, transparent 66%),
    linear-gradient(105deg, transparent 70%, rgba(28, 105, 212, 0.18) 70%, rgba(28, 105, 212, 0.18) 80%, transparent 80%),
    linear-gradient(105deg, transparent 84%, rgba(231, 34, 46, 0.16) 84%, rgba(231, 34, 46, 0.16) 96%, transparent 96%),
    radial-gradient(circle, #222228 1px, transparent 1px);
  background-size: 100% 100%, 100% 100%, 100% 100%, 26px 26px;
  background-position: 0 0, 0 0, 0 0, 0 0;
  /* stripe layers must not wrap when they slide; dot grid keeps tiling */
  background-repeat: no-repeat, no-repeat, no-repeat, repeat;
  transition: background-position var(--dur-med) var(--ease-out);
}

/* stripes glide on hover with staggered distances — all in the same
   direction so their gaps only widen and they can never overlap;
   dot-grid layer stays put */
.project-card:hover .project-thumb {
  background-position: 8px 0, 14px 0, 20px 0, 0 0;
}

.project-body {
  padding: 22px 24px 24px;
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 10px;
}

.dwg {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-low);
  margin: 0;
}

.project-body h3 {
  margin: 0;
  font-size: 1.12rem;
  font-weight: 500;
}

.project-body p {
  margin: 0;
  color: var(--text-mid);
  font-size: 0.92rem;
  line-height: 1.6;
  flex: 1;
}

.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 2px;
}

.tag {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  background: var(--bg-raised);
  color: var(--text-mid);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 3px 9px;
}

.project-link {
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--m-blue-text);
}

.project-link .arrow {
  display: inline-block;
  transition: transform var(--dur-fast) var(--ease-out);
}

.project-card:hover .project-link .arrow {
  transform: translateX(4px);
}

/* ---------- About page ---------- */
/* Four equal cells. Row flow places them Education / Work Experience
   on the top row, Activities & Clubs / Skills on the bottom. */
.about-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
  gap: 52px 56px;
}

/* ---------- Timeline rows ----------
   Education, Work Experience, Activities and Skills all read as one timeline
   per column. The rule and the rhombus are defined once here so the four
   columns cannot drift apart.

   The spacing below each row is PADDING, never margin. Padding sits inside the
   border, so consecutive rows' rules touch and the column reads as one
   continuous line. A margin would sit outside it and break the line at every
   row, which is exactly what the Skills column used to do.

   Skills is not simply given .timeline-item because .timeline-item h4 comes
   later in this file and would win on source order, flattening the mono
   uppercase group labels. */
.timeline-item,
.skills-group {
  position: relative;
  border-left: 1px solid var(--border);
  padding-left: 24px;
  padding-bottom: 28px;
}

.timeline-item::before,
.skills-group::before {
  content: "";
  position: absolute;
  width: 8px;
  height: 8px;
  background: var(--m-red);
  transform: rotate(45deg);
  /* Sit the rhombus dead on the rule. The 1px border spans x 0 to 1 of the
     border box, so its centre is 0.5px. An absolutely positioned child is
     offset from the padding box, which starts at 1px, hence the -1px, and
     -4px recentres the 8px square on its own middle. Half a pixel sounds
     like nothing until the display runs at 125% and it lands on a real one. */
  left: calc(0.5px - 1px - 4px);
}

/* Each column's rows carry a different heading size, so the rhombus is nudged
   to the optical centre of the heading it belongs to. */
.timeline-item::before {
  top: 8px;
}

.skills-group::before {
  top: 5px;
}

.skills-group h4 {
  margin: 0 0 10px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-low);
}

.skills-note {
  margin: 10px 0 0;
  color: var(--text-mid);
  font-size: 0.92rem;
}

.timeline-item h4 {
  margin: 0 0 4px;
  font-size: 1rem;
  font-weight: 500;
}

.timeline-item .meta {
  font-family: var(--font-mono);
  color: var(--text-low);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  margin: 0 0 8px;
}

.timeline-item p:not(.meta) {
  color: var(--text-mid);
  font-size: 0.92rem;
  margin: 0;
}

/* Bulleted detail under a role — the global `ul` reset strips list
   styling, so restore it just here. */
.timeline-list {
  list-style: disc;
  margin: 0;
  padding-left: 18px;
  color: var(--text-mid);
  font-size: 0.92rem;
}

.timeline-list li {
  margin-bottom: 4px;
}

.timeline-list li::marker {
  color: var(--text-low);
}

/* Small label above the coursework list — matches .skills-group h4 */
.timeline-item .coursework-label {
  margin: 14px 0 8px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-low);
}

.timeline-item .tag-row {
  margin: 0;
}

/* 16 courses read as a wall in one column — split them in two */
.course-columns {
  columns: 2;
  column-gap: 28px;
  font-size: 0.85rem;
  color: var(--text-mid);
}

.course-columns li {
  break-inside: avoid;
  padding-left: 14px;
  position: relative;
  line-height: 1.5;
  margin-bottom: 5px;
}

.course-columns li::before {
  content: "·";
  position: absolute;
  left: 2px;
  color: var(--text-low);
}

/* Second section header inside a column needs air above it */
.section-header-stacked {
  margin-top: 20px;
}

/* Bolded phrases in the bio lift out of the muted body text */
.lede strong {
  color: var(--text-hi);
  font-weight: 600;
}

/* ---------- About intro: centred name and bio ---------- */
.about-intro {
  text-align: center;
}

.about-intro .stripe-chip {
  margin-inline: auto;
}

.about-intro .lede {
  margin-inline: auto;
}

/* Photo and résumé, equal halves. The row height is clamped rather than
   left to the portrait's 4:5 ratio — at full half-width that would be
   ~670px tall and reintroduce the dead space this layout removes. */
.about-media {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-top: 36px;
  /* Size the ROW, not the container. A height on the container leaves the
     implicit row auto-sized, so a child's height:100% is circular, falls
     back to auto, and the images render at natural size and overflow. */
  grid-auto-rows: clamp(280px, 30vw, 400px);
}

/* Grid items default to min-height:auto, which stops the resume card's
   flex:1 thumbnail from shrinking below its intrinsic height. */
.about-media > * {
  min-height: 0;
}

.about-portrait {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Square source in a landscape box. Bias the crop upward so it takes
     from the jacket rather than the top of his head. */
  object-position: center 25%;
  border: 1px solid var(--border);
  border-radius: 10px;
}

/* ---------- Résumé card ----------
   A .doc-card showing the real first page. It fills the media row, so
   the thumbnail takes the leftover height and the label sits below. */
.resume-card {
  height: 100%;
}

.resume-card .doc-card-thumb {
  flex: 1;
  min-height: 0;
  aspect-ratio: auto;
  object-fit: contain;
  object-position: center;
}

/* ---------- Résumé lightbox ---------- */
.doc-lightbox {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 28px;
  background: rgba(10, 10, 12, 0.82);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-med) var(--ease-out), visibility var(--dur-med);
}

.doc-lightbox.is-open {
  opacity: 1;
  visibility: visible;
}

.doc-panel {
  display: flex;
  flex-direction: column;
  width: min(920px, 92vw);
  height: min(88dvh, 1100px);
  background: var(--bg-raised);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  overflow: hidden;
  transform: scale(0.97);
  transition: transform var(--dur-med) var(--ease-out);
}

.doc-lightbox.is-open .doc-panel {
  transform: scale(1);
}

.doc-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 16px 14px 20px;
  border-bottom: 1px solid var(--border);
}

.doc-panel-head p {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-mid);
}

.doc-close {
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-mid);
  font-size: 0.9rem;
  line-height: 1;
  padding: 8px 11px;
  transition: color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.doc-close:hover {
  color: var(--text-hi);
  border-color: var(--border-strong);
}

.doc-frame {
  flex: 1;
  width: 100%;
  border: 0;
  background: #2a2a30;
}

.doc-panel-foot {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
}

.doc-newtab {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-mid);
}

.doc-newtab:hover {
  color: var(--m-blue-text);
}

/* ---------- Inline document links (project write-ups) ---------- */
.doc-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 18px 0 0 !important;
}

.doc-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 9px 16px;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--text-hi);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 6px;
  transition: border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.doc-link:hover {
  color: var(--m-blue-text);
  border-color: var(--border-strong);
  transform: translateY(-2px);
}

.doc-size {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-low);
}

/* Off-site material worth actually opening. The plain .doc-link sits quietly
   next to body copy, which is right for a file and wrong for a folder of
   photos and video nobody would guess is there. This reads as a button. */
.doc-link-feature {
  padding: 14px 20px;
  font-size: 0.98rem;
  gap: 14px;
  border-color: var(--m-blue);
  background: linear-gradient(180deg, rgba(28, 105, 212, 0.14), rgba(28, 105, 212, 0.05));
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset;
}

.doc-link-feature .doc-link-icon {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--m-lightblue);
  transition: transform var(--dur-fast) var(--ease-out);
}

.doc-link-feature .doc-size {
  color: var(--m-lightblue);
}

.doc-link-feature:hover {
  color: var(--text-hi);
  border-color: var(--m-lightblue);
  background: linear-gradient(180deg, rgba(28, 105, 212, 0.26), rgba(28, 105, 212, 0.1));
}

.doc-link-feature:hover .doc-link-icon {
  transform: translate(2px, -2px);
}

/* Placeholder copy awaiting real content — deliberately obvious so it
   can never be mistaken for finished writing. */
.fill-note {
  color: var(--text-low) !important;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  line-height: 1.6;
  border-left: 2px solid var(--border-strong);
  padding-left: 14px;
}

/* Explains how a document is put together, sitting under its card. */
.doc-note {
  margin: 12px 0 0 !important;
  font-size: 0.86rem !important;
  color: var(--text-low) !important;
}

.doc-subhead {
  margin: 26px 0 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-low);
}

/* ---------- Document preview cards ----------
   Each shows the real first page of its PDF, rendered at author time by
   tools/make-pdf-thumbs.mjs. Clicking opens the shared [data-doc] lightbox. */
.doc-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 18px;
  margin: 20px 0 0;
}

.doc-card {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  color: var(--text-hi);
  transition: transform var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}

.doc-card:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-card);
  color: var(--text-hi);
}

.doc-card-thumb {
  width: 100%;
  aspect-ratio: 210 / 200;
  object-fit: cover;
  object-position: top center;
  background: #fff;
  border-bottom: 1px solid var(--border);
}

/* .doc-card is an <a>, so its children are spans — force block flow. */
.doc-card-body {
  display: block;
  padding: 14px 16px 16px;
}

.doc-card-title {
  display: block;
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.35;
}

.doc-card-meta {
  display: block;
  margin: 6px 0 0;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-low);
}

.doc-card:hover .doc-card-meta {
  color: var(--m-blue-text);
}

/* Tighter variant for the one-page MIR inspection sheets */
.doc-grid {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 14px;
}

.doc-grid .doc-card-thumb {
  aspect-ratio: 4 / 3;
}

.doc-grid .doc-card-body {
  padding: 10px 12px 12px;
}

.doc-grid .doc-card-title {
  font-size: 0.82rem;
}

/* ---------- CAD viewer ---------- */
.cad-viewers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
  margin-top: 20px;
}

.cad-viewer {
  margin-top: 20px;
}

.cad-viewers .cad-viewer {
  margin-top: 0;
}

/* One model per row. Side by side, two viewers land at about 340px each, which
   is too small to actually inspect an assembly in. Full column width more than
   doubles the area without touching .cad-stage. */
.cad-viewers-stacked {
  grid-template-columns: 1fr;
  gap: 34px;
}

.cad-item .cad-viewer {
  margin-top: 12px;
}

/* Outranks `.detail-grid p` on specificity, so no !important needed here. */
.cad-item .cad-item-note {
  margin: 6px 0 0;
  font-size: 0.9rem;
  color: var(--text-mid);
}

.cad-stage {
  position: relative;
  aspect-ratio: 16 / 11;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-raised);
  background-image: radial-gradient(circle, #232329 1px, transparent 1px);
  background-size: 22px 22px;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

.cad-stage canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
}

.cad-stage canvas:active {
  cursor: grabbing;
}

.cad-status {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: var(--text-low);
}

.cad-status.is-error {
  color: var(--m-red-text);
}

.cad-caption {
  margin: 10px 0 0 !important;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-low);
  text-align: center;
}

.cad-viewer.is-placeholder .cad-stage {
  border-style: dashed;
}

.cad-placeholder {
  text-align: center;
  padding: 20px;
  color: var(--text-low);
}

.cad-placeholder svg {
  width: 46px;
  height: 46px;
  margin: 0 auto 14px;
  display: block;
  color: var(--border-strong);
}

.cad-placeholder-title {
  margin: 0 !important;
  font-family: var(--font-display);
  font-size: 0.95rem;
  color: var(--text-mid);
}

.cad-placeholder-note {
  margin: 5px 0 0 !important;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-low);
}

/* ---------- Video embeds ---------- */
.video-embed {
  margin-top: 20px;
}

.video-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

/* A phone video shot vertically. Left in the 16:9 frame it would either be
   cropped to a sliver or letterboxed into two black slabs, and at full column
   width a 9:16 frame is over a thousand pixels tall, so it is capped and
   centred instead. */
.video-embed-portrait .video-frame {
  aspect-ratio: 9 / 16;
  max-width: 330px;
  margin: 0 auto;
}

.video-embed-portrait + .video-caption {
  max-width: 330px;
  margin-left: auto !important;
  margin-right: auto !important;
}

.video-frame iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

.video-play {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
}

.video-poster {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity var(--dur-med) var(--ease-out);
}

.video-play:hover .video-poster {
  opacity: 0.75;
}

.video-play-icon {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.video-play-icon svg {
  width: 68px;
  height: 48px;
}

/* Dimmed until hover, then YouTube red */
.video-play-bg {
  fill: #1d1d22;
  fill-opacity: 0.82;
  transition: fill var(--dur-fast) var(--ease-out), fill-opacity var(--dur-fast) var(--ease-out);
}

.video-play:hover .video-play-bg {
  fill: var(--m-red);
  fill-opacity: 1;
}

/* ---------- Project photos ----------
   Plain links to the full-size file rather than a lightbox. A photo is
   already legible at this width, and opening it in a tab needs no JS. */
.photo-figure {
  display: block;
  margin: 22px 0 0;
}

.photo-figure img,
.photo-row img {
  display: block;
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-raised);
  transition: border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.photo-figure:hover img,
.photo-row a:hover img {
  border-color: var(--border-strong);
  transform: translateY(-2px);
}

.photo-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-top: 16px;
}

/* Two portrait shots side by side. At three across a phone photo is too small
   to read, and one across is taller than the viewport. */
.photo-row-2 {
  grid-template-columns: repeat(2, 1fr);
}

/* All three sources are 3:4 already, so nothing is actually cropped. The
   ratio is pinned so a future replacement at another size still lines up. */
.photo-row img {
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

.photo-caption {
  margin: 10px 0 0 !important;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-low);
  text-align: center;
}

.photo-row .photo-caption {
  text-align: left;
  margin-top: 8px !important;
  letter-spacing: 0.06em;
}

.video-caption {
  margin: 10px 0 0 !important;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-low);
  text-align: center;
}

/* ---------- Back to top ----------
   Only shown once the reader reaches the end of the page. */
.back-to-top {
  position: fixed;
  right: 28px;
  bottom: 28px;
  z-index: 200;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 500;
  line-height: 1;
  color: var(--text-mid);
  background: var(--card);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  box-shadow: var(--shadow-card);
  opacity: 0;
  visibility: hidden;
  translate: 0 10px;
  transition: opacity var(--dur-med) var(--ease-out),
    translate var(--dur-med) var(--ease-out),
    visibility var(--dur-med),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.back-to-top.is-visible {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
}

.back-to-top:hover {
  color: var(--text-hi);
  border-color: var(--m-blue);
}

/* ---------- Projects lede ----------
   Held to a single line on desktop; wraps normally on narrow screens
   so it can't overflow the page. */
.lede-oneline {
  max-width: none;
}

@media (min-width: 900px) {
  .lede-oneline {
    white-space: nowrap;
  }
}

/* ---------- Project detail pages ---------- */
.back-link {
  display: inline-block;
  margin: 0 0 28px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-mid);
}

.back-link:hover {
  color: var(--m-blue-text);
}

.detail-head {
  margin-bottom: 28px;
}

.detail-head h1 {
  font-size: clamp(1.8rem, 3.5vw, 2.6rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
}

.project-hero {
  position: relative;
  height: clamp(160px, 24vw, 260px);
  border: 1px solid var(--border);
  border-radius: 12px;
  margin-bottom: 44px;
  overflow: hidden;
  background-color: var(--bg-raised);
  background-image:
    linear-gradient(105deg, transparent 55%, rgba(88, 166, 232, 0.12) 55%, rgba(88, 166, 232, 0.12) 62%, transparent 62%),
    linear-gradient(105deg, transparent 67%, rgba(28, 105, 212, 0.16) 67%, rgba(28, 105, 212, 0.16) 78%, transparent 78%),
    linear-gradient(105deg, transparent 83%, rgba(231, 34, 46, 0.15) 83%, rgba(231, 34, 46, 0.15) 94%, transparent 94%),
    radial-gradient(circle, #222228 1px, transparent 1px);
  background-size: 100% 100%, 100% 100%, 100% 100%, 26px 26px;
}

.detail-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 56px;
  padding-bottom: 32px;
}

.detail-grid h2 {
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 36px 0 12px;
}

.detail-grid h2:first-child {
  margin-top: 0;
}

.detail-grid p {
  color: var(--text-mid);
  margin: 0 0 16px;
}

/* Spec sidebar — engineering-drawing title block */
.detail-sidebar {
  background: var(--card);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  padding: 0;
  margin: 0;
  align-self: start;
  position: sticky;
  top: calc(var(--nav-h) + 26px);
  overflow: hidden;
}

.detail-sidebar dt {
  font-family: var(--font-mono);
  font-weight: 500;
  color: var(--text-low);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  padding: 14px 20px 0;
  border-top: 1px solid var(--border);
}

.detail-sidebar dt:first-child {
  border-top: none;
}

.detail-sidebar dd {
  margin: 4px 0 0;
  padding: 0 20px 14px;
  font-weight: 500;
  font-size: 0.95rem;
}

/* Prev / next project nav */
.proj-nav {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  border-top: 1px solid var(--border);
  padding: 28px 0 8px;
  margin-top: 24px;
}

.proj-nav a {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-width: 46%;
}

.proj-nav .dir {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-low);
}

.proj-nav .name {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.98rem;
  color: var(--text-hi);
  transition: color var(--dur-fast) var(--ease-out);
}

.proj-nav a:hover .name {
  color: var(--m-blue-text);
}

.proj-nav .next {
  margin-left: auto;
  text-align: right;
}

/* ---------- Contact page ---------- */
.contact-grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}

/* Three matching panels — 01 LinkedIn / 02 message / 03 direct.
   Red sits in the middle on purpose, so the two blues are never adjacent and
   still read as different colours. */
.contact-option {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 32px;
}

.contact-option h2 {
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 12px;
}

/* Short rule under each heading in that card's own colour, so the palette
   reads as part of the layout rather than only sitting on the icon tile. */
.contact-option h2::after {
  content: "";
  display: block;
  width: 32px;
  height: 2px;
  margin-top: 12px;
  border-radius: 2px;
  background: var(--card-accent, var(--border-strong));
}

.contact-option:has(.icon-blue) {
  --card-accent: var(--m-blue);
}

.contact-option:has(.icon-red) {
  --card-accent: var(--m-red);
}

.contact-option:has(.icon-lightblue) {
  --card-accent: var(--m-lightblue);
}

.contact-option > p:not(.eyebrow) {
  color: var(--text-mid);
  margin: 0 0 26px;
}

.contact-option form {
  width: 100%;
}

.contact-icon {
  width: 64px;
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  margin-bottom: 22px;
}

.contact-icon svg {
  width: 30px;
  height: 30px;
  display: block;
}

.contact-icon.icon-blue {
  background: rgba(28, 105, 212, 0.16);
  border-color: var(--m-blue);
  color: var(--m-lightblue);
  box-shadow: 0 8px 26px -10px rgba(28, 105, 212, 0.5);
}

.contact-icon.icon-red {
  background: rgba(231, 34, 46, 0.14);
  border-color: var(--m-red);
  color: var(--m-red-text);
  box-shadow: 0 8px 26px -10px rgba(231, 34, 46, 0.45);
}

.contact-icon.icon-lightblue {
  background: rgba(88, 166, 232, 0.16);
  border-color: var(--m-lightblue);
  color: var(--m-lightblue);
  box-shadow: 0 8px 26px -10px rgba(88, 166, 232, 0.5);
}

/* The three cards carry very different amounts of content, and the form is
   roughly twice the height of the other two. Rather than let the short cards
   trail off, every card pins its payload to the floor. All three then read the
   same way: heading and blurb at the top, the thing you act on at the bottom,
   and deliberate space between. */
.contact-option > .btn,
.contact-option > .contact-lines {
  margin-top: auto;
}

/* ---------- Direct contact rows ----------
   Laid out like the drafting title block in .detail-sidebar, so the page
   stays of a piece with the project pages. */
.contact-lines {
  width: 100%;
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--border);
}

.contact-lines li {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 0;
  border-bottom: 1px solid var(--border);
}

.contact-line-label {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-low);
}

.contact-line-value {
  font-size: 0.98rem;
  color: var(--text-hi);
  /* Long addresses must not push the card wider than its grid track. */
  overflow-wrap: anywhere;
  transition: color var(--dur-fast) var(--ease-out);
}

/* Card three is the red one, so its links hover red. --m-red-text rather than
   --m-red, which is the lighter tone the site uses for red text on dark. */
.contact-line-value:hover {
  color: var(--m-red-text);
}

.contact-noscript {
  margin: 14px 0 0;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-low);
}

.connect-panel h2 {
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 12px;
}

.connect-panel p {
  color: var(--text-mid);
  margin: 0 0 26px;
}

.hp-field {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

form.contact-form {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.contact-form label {
  font-size: 0.85rem;
  font-weight: 500;
  margin-bottom: 7px;
  display: block;
  color: var(--text-hi);
}

.contact-form input,
.contact-form textarea {
  width: 100%;
  padding: 12px 14px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg-raised);
  color: var(--text-hi);
  font-family: var(--font-body);
  font-size: 0.95rem;
  transition: border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}

.contact-form input:focus,
.contact-form textarea:focus {
  outline: none;
  border-color: var(--m-blue);
  box-shadow: 0 0 0 3px rgba(28, 105, 212, 0.22);
}

/* Shorter than it was as a two-column page. In a third-width card the extra
   height only widened the gap to the two cards beside it, and the field is
   still resizable. */
.contact-form textarea {
  resize: vertical;
  min-height: 120px;
}

.contact-form button {
  cursor: pointer;
  width: fit-content;
}

.contact-form button:disabled {
  opacity: 0.5;
  cursor: default;
  transform: none;
}

#contact-status {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--text-mid);
}

/* While empty it still costs a flex gap, which would drop the submit button
   below where the other two cards end theirs. */
#contact-status:empty {
  display: none;
}

/* ---------- Minimal subpage footer ---------- */
.site-footer {
  position: relative;
  padding: 26px 0;
  margin-top: 48px;
}

.site-footer::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--stripe);
  opacity: 0.35;
}

.footer-inner {
  display: flex;
  justify-content: center;
  align-items: center;
}

.copyright {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-low);
  margin: 0;
}

/* ---------- Scroll reveal ----------
   Standalone `translate` property so entrance never competes
   with the `transform` transitions used by hover states. */
.reveal {
  opacity: 0;
  translate: 0 14px;
  transition: opacity var(--dur-reveal) var(--ease-out), translate var(--dur-reveal) var(--ease-out);
  transition-delay: var(--delay, 0s);
}

.reveal.is-visible {
  opacity: 1;
  translate: 0 0;
}

/* ---------- Homepage entrance sequence ----------
   Hidden only when JS is confirmed present (html.js),
   released by body.loaded. */
.js .enter {
  opacity: 0;
  translate: 0 18px;
  transition: opacity 0.7s var(--ease-out), translate 0.7s var(--ease-out);
  transition-delay: var(--enter-delay, 0s);
}

.js .loaded .enter {
  opacity: 1;
  translate: 0 0;
}

/* ---------- Cursor ----------
   Native system cursor everywhere; interactive elements get pointer. */
button,
.btn {
  cursor: pointer;
}

/* Three contact cards collapse earlier than the other grids. Below about a
   thousand pixels a third of the container leaves the message form too narrow
   to type in comfortably. */
@media (max-width: 1000px) {
  .contact-grid {
    grid-template-columns: 1fr;
    gap: 28px;
  }

  .contact-option {
    padding: 32px 36px;
  }
}

/* ---------- Responsive: grids ---------- */
@media (max-width: 800px) {
  .about-grid,
  .detail-grid,
  .contact-grid {
    grid-template-columns: 1fr;
    gap: 44px;
  }

  .about-media {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
  }

  .about-portrait {
    aspect-ratio: 4 / 5;
  }

  .resume-card {
    height: auto;
  }

  .resume-card .doc-card-thumb {
    aspect-ratio: 210 / 272;
  }

  .back-to-top {
    right: 16px;
    bottom: 16px;
  }

  .course-columns {
    columns: 1;
  }

  /* Three portraits at a third of a phone screen are unreadable. */
  .photo-row {
    grid-template-columns: 1fr 1fr;
  }

  .detail-sidebar {
    position: static;
  }

  .corner-marks {
    display: none;
  }

  section {
    padding: 64px 0;
  }

  .container {
    padding: 0 24px;
  }

  .nav {
    padding: 0 24px;
  }
}

/* ---------- Responsive: mobile nav ---------- */
@media (max-width: 720px) {
  .nav-toggle {
    display: block;
  }

  .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--bg-raised);
    border-bottom: 1px solid var(--border);
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: 8px 24px;
    display: none;
  }

  .nav-links.open {
    display: flex;
  }

  .nav-links a {
    padding: 16px 0;
    width: 100%;
    border-bottom: 1px solid var(--border);
  }

  .nav-links a::after {
    display: none;
  }

  .nav-links a:last-child {
    border-bottom: none;
  }
}

/* ---------- Touch devices ---------- */
@media (hover: none), (pointer: coarse) {
  .btn:active,
  .project-card:active,
  .focus-card:active {
    transform: scale(0.98);
  }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .js .enter {
    opacity: 1;
    translate: 0 0;
    transition: none;
  }

  .reveal {
    transition-duration: 0.01s;
    translate: 0 0;
  }

  .btn,
  .focus-card,
  .project-card,
  .project-link .arrow,
  .focus-card .icon,
  .nav-links a::after,
  .project-thumb,
  .doc-card,
  .doc-lightbox,
  .doc-panel,
  .back-to-top {
    transition: none !important;
  }

  .doc-panel {
    transform: none !important;
  }
}
