/* =====================================================================
   Jack TSOI Man Chun - portfolio
   Direction: Swiss-industrial "dossier" on cool paper.
   Tokens -> layout -> components -> responsive. No external assets.
   ===================================================================== */

/* ---------- Design tokens ---------- */
:root {
  --paper:      #f1f1ec;
  --paper-2:    #e8e9e3;
  --paper-3:    #dfe0d9;
  --ink:        #141619;
  --ink-2:      #2a2d31;
  --muted:      #5e6366;
  --line:       rgba(20, 22, 25, 0.14);
  --line-2:     rgba(20, 22, 25, 0.30);
  --accent:     #e23e1b;
  --accent-ink: #bd3413;
  --on-ink:     #f1f1ec;

  --ink-lift:   #1c1f24;   /* a hair above ink: dark-card hover, dark mattes */
  --matte:      #e2e3dc;   /* deliberate surface behind contained photos */

  --font-sans: "Segoe UI Variable Display", "Segoe UI", system-ui, -apple-system,
               "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "Cascadia Code", "Cascadia Mono", "SF Mono",
               "JetBrains Mono", Consolas, "Liberation Mono", Menlo, monospace;

  --wrap: 1240px;
  --gutter: clamp(1.25rem, 4vw, 2.75rem);
  --header-h: 66px;

  --section-y: clamp(3.75rem, 5.6vw, 5.75rem);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h) + 16px); }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, p, dl, dd, figure { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
::selection { background: var(--accent); color: #fff; }

.wrap { width: min(100% - (var(--gutter) * 2), var(--wrap)); margin-inline: auto; }

.skip-link {
  position: fixed; top: -60px; left: 12px; z-index: 200;
  background: var(--ink); color: var(--on-ink);
  padding: 10px 16px; font: 600 0.8rem/1 var(--font-mono); letter-spacing: 0.06em;
  text-transform: uppercase; transition: top 0.2s var(--ease);
}
.skip-link:focus { top: 12px; }

/* ---------- Shared bits ---------- */
.brand__mark {
  width: 11px; height: 11px; background: var(--accent);
  display: inline-block; flex: none;
}

.section { padding-block: var(--section-y); }

/* The dossier rule: a full-width hairline with a short accent tick, the title
   set left and its mono meta set right. Repeated across every content section
   so the page reads as one continuous, governed document rather than drifting
   blocks of paper. */
.section-head {
  position: relative;
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding-bottom: 0.85rem; margin-bottom: clamp(1.75rem, 3.6vw, 2.75rem);
  border-bottom: 1px solid var(--line-2);
}
.section-head::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: clamp(30px, 4vw, 46px); height: 2px; background: var(--accent);
}
.section-title {
  font-size: clamp(2rem, 4.6vw, 3.3rem);
  font-weight: 800; letter-spacing: -0.04em; line-height: 0.95;
}
.section-meta {
  font: 600 0.72rem/1 var(--font-mono); letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ---------- Header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: rgba(241, 241, 236, 0.86);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line);
}
.header__bar {
  height: var(--header-h);
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.brand { display: inline-flex; align-items: center; gap: 0.6rem; }
.brand__name { font-weight: 800; letter-spacing: -0.02em; font-size: 1.02rem; }

.nav { display: flex; align-items: center; gap: clamp(1rem, 2.4vw, 2rem); }
.nav__link {
  position: relative; font-size: 0.9rem; font-weight: 500; color: var(--ink-2);
  padding-block: 4px;
}
.nav__link::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: 0; height: 1.5px;
  background: var(--accent); transition: right 0.28s var(--ease);
}
.nav__link:hover::after, .nav__link.is-active::after { right: 0; }
.nav__link.is-active { color: var(--ink); }
.nav__cta {
  font-size: 0.85rem; font-weight: 700; letter-spacing: 0.01em;
  padding: 0.5rem 1.05rem; background: var(--ink); color: var(--on-ink);
  transition: background 0.25s var(--ease), transform 0.15s var(--ease);
}
.nav__cta:hover { background: var(--accent); }
.nav__cta:active { transform: translateY(1px); }

.nav-toggle { display: none; align-items: center; gap: 0.55rem; font-weight: 600; font-size: 0.82rem; letter-spacing: 0.04em; text-transform: uppercase; }
.nav-toggle__glyph { width: 20px; height: 12px; position: relative; }
.nav-toggle__glyph::before, .nav-toggle__glyph::after {
  content: ""; position: absolute; left: 0; right: 0; height: 1.6px; background: var(--ink);
  transition: transform 0.25s var(--ease), opacity 0.25s var(--ease);
}
.nav-toggle__glyph::before { top: 0; }
.nav-toggle__glyph::after { bottom: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__glyph::before { transform: translateY(5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__glyph::after { transform: translateY(-5px) rotate(-45deg); }

.mobile-nav { display: none; border-bottom: 1px solid var(--line-2); background: var(--paper); }
.mobile-nav[hidden] { display: none; }
.mobile-nav .wrap { display: flex; flex-direction: column; padding-block: 0.5rem 1rem; }
.mobile-nav a {
  padding: 0.85rem 0; font-size: 1.15rem; font-weight: 600; letter-spacing: -0.01em;
  border-bottom: 1px solid var(--line); display: flex; justify-content: space-between; align-items: center;
}
.mobile-nav a:last-child { border-bottom: 0; }

/* ---------- Hero ---------- */
.hero { padding-block: clamp(2.5rem, 5vw, 4.75rem) clamp(3rem, 5.6vw, 4.75rem); }
.hero__inner {
  display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.85fr);
  gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
}
.hero__name {
  font-size: clamp(2.6rem, 6.8vw, 5.2rem);
  font-weight: 800; letter-spacing: -0.045em; line-height: 0.97;
  text-wrap: balance;
}
.hero__zh {
  margin-top: 0.7rem; font-size: clamp(1rem, 2vw, 1.3rem);
  letter-spacing: 0.32em; color: var(--muted);
}
.hero__role {
  margin-top: clamp(1.5rem, 3vw, 2.1rem);
  font-size: clamp(1.05rem, 2vw, 1.35rem); font-weight: 700; letter-spacing: -0.01em;
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.85rem;
}
.hero__triad { display: inline-flex; align-items: center; gap: 0.7rem; }
.hero__triad span {
  font: 600 0.72rem/1 var(--font-mono); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink); padding: 0.3rem 0.5rem; border: 1px solid var(--line-2);
}
.hero__triad span:first-child { border-color: var(--accent); color: var(--accent-ink); }
.hero__line {
  margin-top: clamp(1.4rem, 3vw, 2rem); max-width: 48ch;
  color: var(--ink-2); font-size: clamp(1rem, 1.5vw, 1.08rem);
}
.hero__actions { margin-top: clamp(1.8rem, 3.5vw, 2.4rem); display: flex; flex-wrap: wrap; gap: 0.85rem; }

.btn {
  --pad-y: 0.95rem; --pad-x: 1.7rem;
  display: inline-flex; align-items: center; justify-content: center;
  padding: var(--pad-y) var(--pad-x); font-weight: 700; font-size: 0.98rem;
  letter-spacing: -0.005em; white-space: nowrap;
  transition: background 0.25s var(--ease), color 0.25s var(--ease), transform 0.15s var(--ease), border-color 0.25s var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--ink); color: var(--on-ink); }
.btn--primary:hover { background: var(--accent); }
.btn--ghost { border: 1.5px solid var(--ink); color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--on-ink); }

/* photo plate */
.hero__portrait { position: relative; justify-self: end; width: min(100%, 430px); }
.hero__portrait::before {
  content: ""; position: absolute; z-index: 0; width: 42%; padding-top: 42%;
  background: var(--accent); top: -18px; left: -18px;
}
.plate { position: relative; z-index: 1; background: #fff; border: 1px solid var(--line-2); }
/* Portrait plate: source photo is 2:3 (1300x1950), face sits in the upper
   third. A 4/5 plate crops the bottom only, so the head clears the top edge;
   object-position tunes how much building headroom survives above the subject. */
.plate img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 32%; }

/* ---------- About ---------- */
.about__grid {
  display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem); align-items: start;
}
.about__lead { font-size: clamp(1.12rem, 1.9vw, 1.42rem); line-height: 1.55; letter-spacing: -0.01em; }
.facts { border-top: 1px solid var(--line-2); }
.facts__row {
  display: flex; justify-content: space-between; gap: 1.25rem;
  padding: 0.95rem 0; border-bottom: 1px solid var(--line);
}
.facts dt { font: 600 0.72rem/1.4 var(--font-mono); letter-spacing: 0.13em; text-transform: uppercase; color: var(--muted); }
.facts dd { font-weight: 600; font-size: 0.95rem; text-align: right; }

/* ---------- Projects (hairline grid) ---------- */
.projects-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px; background: var(--line-2);
  border: 1px solid var(--line-2);
}
.card {
  position: relative;
  background: var(--paper); padding: clamp(1.4rem, 3vw, 2.4rem);
  display: flex; flex-direction: column; gap: 0.9rem;
  transition: background 0.3s var(--ease);
}
/* A short accent rule wipes in along the card's top edge on hover / keyboard
   focus - a precise "this is live" cue, not a decorative lift. */
.card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
  transition: transform 0.4s var(--ease);
}
.card:hover { background: var(--paper-2); }
.card:hover::before, .card:focus-within::before { transform: scaleX(1); }
.card--featured { grid-column: 1 / -1; background: var(--ink); color: var(--on-ink); }
.card--featured:hover { background: var(--ink-lift); }
.card__top { display: flex; flex-direction: column; gap: 0.55rem; }
.card__title { font-size: clamp(1.2rem, 2vw, 1.5rem); font-weight: 700; letter-spacing: -0.025em; line-height: 1.15; }
.card__meta {
  font: 600 0.7rem/1 var(--font-mono); letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--muted); display: inline-flex; align-items: center; gap: 0.5rem;
  font-variant-numeric: tabular-nums;
}
.card__meta::before {
  content: ""; width: 16px; height: 1.5px; background: var(--accent);
  transform-origin: left; transition: transform 0.3s var(--ease);
}
.card:hover .card__meta::before, .card:focus-within .card__meta::before { transform: scaleX(1.5); }
.card--featured .card__meta { color: rgba(241, 241, 236, 0.66); }
.card__desc { font-size: 0.96rem; line-height: 1.62; color: var(--ink-2); }
.card--featured .card__desc { color: rgba(241, 241, 236, 0.82); font-size: 1rem; max-width: 82ch; }
.card--featured .card__title { font-size: clamp(1.5rem, 2.8vw, 2.1rem); max-width: 26ch; }
.card:focus-within { background: var(--paper-2); }
.card--featured:focus-within { background: var(--ink-lift); }

.tags { display: flex; flex-wrap: wrap; gap: 0.4rem; padding-top: 0.2rem; margin-top: auto; }
.tags li {
  font: 600 0.68rem/1 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase;
  padding: 0.4rem 0.6rem; border: 1px solid var(--line-2); color: var(--ink-2);
  transition: border-color 0.25s var(--ease), color 0.25s var(--ease);
}
.card:hover .tags li { border-color: var(--line-2); color: var(--ink); }
.card--featured .tags li { border-color: rgba(241, 241, 236, 0.32); color: rgba(241, 241, 236, 0.9); }

/* Project links: prominent, unmissable vermilion buttons sitting right under
   the description (above the photos) - never buried at the card foot. Solid
   accent fill with paper text, a leading kind glyph and a mono uppercase
   label. A 44px min height on mobile keeps the tap target comfortable. */
.card__links { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.15rem; }
.link-chip {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font: 700 0.76rem/1 var(--font-mono); letter-spacing: 0.09em; text-transform: uppercase;
  padding: 9px 14px; color: var(--on-ink);
  background: var(--accent); border: 1px solid var(--accent);
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.15s var(--ease);
}
.link-chip__glyph { font-size: 0.9em; line-height: 1; letter-spacing: 0; }
.link-chip:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
.link-chip:active { transform: translateY(1px); }
.card--featured .link-chip { color: var(--on-ink); background: var(--accent); border-color: var(--accent); }
.card--featured .link-chip:hover { background: var(--accent-ink); border-color: var(--accent-ink); }

/* Link-only cards (no photos): the link(s) ARE the card's media area. Instead
   of a solid accent slab, each is a structured panel - paper field, hairline
   frame, a 3px accent tab pinned to the top edge, a small accent glyph tile,
   the mono label and the destination host beneath it. Three in a column read
   as a considered set, never a wall of orange. Hover inverts the panel to ink
   so it stays unmistakably clickable. */
.card__media {
  flex: 1 1 auto;
  display: flex; flex-direction: column; justify-content: center;
  gap: 0.6rem;
  min-height: clamp(150px, 16vw, 184px);
  margin-top: 0.35rem;
}
.link-panel {
  position: relative;
  flex: 0 1 auto;
  width: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.7rem; text-align: center;
  padding: 1.4rem 1.4rem 1.25rem;
  min-height: clamp(128px, 13vw, 158px);
  background: var(--paper);
  border: 1px solid var(--line-2);
  color: var(--ink);
  transition: background 0.25s var(--ease), border-color 0.25s var(--ease),
              color 0.25s var(--ease), transform 0.15s var(--ease);
}
.link-panel::before {
  content: ""; position: absolute; top: -1px; left: -1px; right: -1px; height: 3px;
  background: var(--accent);
}
.link-panel__glyph {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  background: var(--accent); color: var(--on-ink);
  font: 700 0.95rem/1 var(--font-mono);
  transition: background 0.25s var(--ease), color 0.25s var(--ease);
}
.link-panel__label {
  font: 700 1.02rem/1 var(--font-mono); letter-spacing: 0.14em; text-transform: uppercase;
}
.link-panel__url {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font: 500 0.68rem/1 var(--font-mono); letter-spacing: 0.03em; color: var(--muted);
  transition: color 0.25s var(--ease);
}
.link-panel:hover {
  background: var(--ink); border-color: var(--ink); color: var(--on-ink);
}
.link-panel:hover .link-panel__glyph { background: var(--on-ink); color: var(--ink); }
.link-panel:hover .link-panel__url { color: rgba(241, 241, 236, 0.66); }
.link-panel:active { transform: translateY(1px); }
.link-panel:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---------- Skills (hairline grid) ---------- */
.skills-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px; background: var(--line-2); border: 1px solid var(--line-2);
}
.skill { background: var(--paper); padding: clamp(1.4rem, 2.6vw, 2rem); transition: background 0.3s var(--ease); }
.skill:hover { background: var(--paper-2); }
.skill__title {
  display: flex; align-items: center; gap: 0.55rem;
  font-size: 0.98rem; font-weight: 700; letter-spacing: -0.01em;
  padding-bottom: 0.9rem; margin-bottom: 1rem; border-bottom: 1px solid var(--line);
}
.skill__mark { width: 9px; height: 9px; background: var(--accent); flex: none; transition: transform 0.3s var(--ease); }
.skill:hover .skill__mark { transform: scale(1.4); }
.skill__list li {
  position: relative; padding-left: 1.1rem; padding-block: 0.36rem;
  font-size: 0.92rem; color: var(--ink-2);
}
.skill__list li::before { content: ""; position: absolute; left: 0; top: 0.85em; width: 6px; height: 1px; background: var(--muted); }

/* ---------- Education ---------- */
.edu { border-top: 1px solid var(--line-2); }
.edu__item {
  display: grid; grid-template-columns: clamp(84px, 11vw, 140px) minmax(0, 1fr);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  padding: clamp(1.6rem, 3.2vw, 2.5rem) 0; border-bottom: 1px solid var(--line);
}
.edu__years {
  font: 700 0.82rem/1.3 var(--font-mono); letter-spacing: 0.08em;
  color: var(--accent-ink); font-variant-numeric: tabular-nums; padding-top: 0.4rem;
}
.edu__school { font-size: clamp(1.35rem, 2.6vw, 1.95rem); font-weight: 800; letter-spacing: -0.03em; line-height: 1.05; }
.edu__degree { margin-top: 0.5rem; font-size: clamp(1rem, 1.6vw, 1.12rem); color: var(--ink-2); }
.edu__meta {
  margin-top: 1.1rem; display: flex; flex-wrap: wrap; gap: 0.55rem 1.1rem;
  font: 600 0.7rem/1 var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted); font-variant-numeric: tabular-nums;
}
.edu__meta li { position: relative; padding-left: 1.05rem; }
.edu__meta li::before {
  content: ""; position: absolute; left: 0; top: 50%; width: 6px; height: 1px;
  background: var(--line-2); transform: translateY(-50%);
}

/* ---------- Contact ---------- */
.section--contact { background: var(--paper-2); border-top: 1px solid var(--line-2); }
.contact__grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: end; }
.contact__head { position: relative; border-top: 1px solid var(--line-2); padding-top: 1.25rem; }
.contact__head::after {
  content: ""; position: absolute; left: 0; top: -1px;
  width: clamp(30px, 4vw, 46px); height: 2px; background: var(--accent);
}
.contact__note { margin-top: 1.1rem; max-width: 40ch; color: var(--ink-2); }
.contact__body { justify-self: end; display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
.contact__email {
  display: inline-block; font-size: clamp(1.2rem, 3.1vw, 2.05rem); font-weight: 700; letter-spacing: -0.02em;
  overflow-wrap: anywhere; border-bottom: 2px solid var(--accent); padding-bottom: 0.15rem;
  font-variant-numeric: tabular-nums; transition: color 0.25s var(--ease);
}
.contact__email:hover { color: var(--accent-ink); }
.contact__channels {
  margin-top: 1.3rem; padding-top: 1.05rem; border-top: 1px solid var(--line);
  width: min(100%, 32rem); display: flex; flex-direction: column; align-items: flex-end; gap: 0.7rem;
}
.contact__loc { display: inline-flex; align-items: center; gap: 0.5rem; font: 600 0.75rem/1 var(--font-mono); letter-spacing: 0.13em; text-transform: uppercase; color: var(--muted); }
.contact__mark { width: 8px; height: 8px; background: var(--ink); flex: none; }
.contact__link { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line-2); transition: color 0.2s var(--ease), border-color 0.2s var(--ease); }
.contact__link:hover { color: var(--accent-ink); border-color: var(--accent); }

/* ---------- Footer ---------- */
.site-footer { background: var(--ink); color: var(--on-ink); padding-block: clamp(2.5rem, 5vw, 3.5rem); }
.footer__bar { display: flex; flex-wrap: wrap; gap: 1.25rem; justify-content: space-between; align-items: center; }
.footer__brand { display: inline-flex; align-items: center; gap: 0.6rem; font-weight: 700; letter-spacing: -0.01em; }
.footer__zh { color: rgba(241, 241, 236, 0.55); letter-spacing: 0.2em; margin-left: 0.35rem; font-weight: 500; }
.footer__nav { display: flex; flex-wrap: wrap; gap: 1.1rem; }
.footer__nav a { font-size: 0.86rem; color: rgba(241, 241, 236, 0.72); transition: color 0.2s var(--ease); }
.footer__nav a:hover { color: var(--accent); }
.footer__base {
  margin-top: 2.2rem; padding-top: 1.3rem; border-top: 1px solid rgba(241, 241, 236, 0.16);
  display: flex; flex-wrap: wrap; gap: 0.6rem 1.5rem; justify-content: space-between;
  font: 600 0.7rem/1.5 var(--font-mono); letter-spacing: 0.09em; text-transform: uppercase; color: rgba(241, 241, 236, 0.5);
}

/* ---------- Reveal ----------
   Hidden initial state is gated behind .js (added by an inline head script),
   so with JavaScript disabled everything is fully visible by default. */
.reveal { transition: opacity 0.65s var(--ease), transform 0.65s var(--ease); transition-delay: calc(var(--d, 0) * 1ms); }
.js .reveal { opacity: 0; transform: translateY(22px); }
.js .reveal.is-in { opacity: 1; transform: none; }

/* ---------- Responsive ---------- */
@media (max-width: 1024px) {
  .hero__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); gap: 2.5rem; }
  .skills-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  .nav { display: none; }
  .nav-toggle { display: inline-flex; }
  .mobile-nav { display: block; }

  .hero__inner { grid-template-columns: minmax(0, 1fr); gap: 2.75rem; }
  .hero__portrait { justify-self: start; width: min(78%, 340px); order: 2; }
  .hero__copy { order: 1; }

  .about__grid { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .education .edu__item { grid-template-columns: 1fr; gap: 0.5rem; }
  .contact__grid { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .contact__body { justify-self: start; text-align: left; }
}

@media (max-width: 620px) {
  body { font-size: 16px; }
  .projects-grid, .skills-grid { grid-template-columns: minmax(0, 1fr); }
  .card--featured { grid-column: auto; }
  .link-chip { min-height: 44px; padding-inline: 16px; }
  .card__media { min-height: 128px; }
  .link-panel { min-height: 104px; padding: 1.2rem 1rem; }
  .link-panel__glyph { width: 36px; height: 36px; }
  .hero__portrait { width: min(86%, 300px); }
  .hero__actions .btn { flex: 1 1 auto; }
  .facts__row { flex-direction: column; gap: 0.3rem; }
  .facts dd { text-align: left; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
  .reveal, .js .reveal { opacity: 1; transform: none; transition: none; }
}

/* =====================================================================
   Project photo galleries + lightbox
   Injected by main.js only when photos exist for a card, so with JS
   disabled (or a missing/empty gallery.json) the cards look as before.
   ===================================================================== */
.gallery {
  margin-top: 0.4rem;
  display: flex; flex-direction: column; gap: 0.75rem;
  animation: galleryIn 0.45s var(--ease) both;
}
@keyframes galleryIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.gallery__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.gallery__count {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font: 600 0.7rem/1 var(--font-mono); letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--muted);
}
.gallery__count::before { content: ""; width: 14px; height: 1.5px; background: var(--accent); }
.gallery__all {
  font: 600 0.7rem/1 var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink); border-bottom: 1px solid var(--line-2); padding-bottom: 2px;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.gallery__all:hover { color: var(--accent-ink); border-color: var(--accent); }

.gallery__thumbs {
  display: grid;
  grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
  gap: 1px; background: var(--line-2); border: 1px solid var(--line-2);
  --thumb-cap: min(58vh, 520px);
}
/* Every project image shows COMPLETE - never cropped. Each thumb is a fixed
   box (uniform aspect ratio per strip, set by JS as --thumb-ar) and the image
   is letterboxed inside with object-fit: contain. The box carries a real matte
   surface (--matte), so any band reads as an intentional mounting board rather
   than empty void. --thumb-cap is the height ceiling; boxes stay uniform per
   row so the rhythm stays tidy even with mixed portrait / ultrawide sources. */
.gallery__thumb {
  position: relative; display: block; width: 100%; padding: 0;
  overflow: hidden; background: var(--matte);
  aspect-ratio: var(--thumb-ar, 4 / 3);
  max-height: var(--thumb-cap);
  cursor: zoom-in;
}
.gallery__thumb img {
  width: 100%; height: 100%; object-fit: contain; display: block;
  transition: transform 0.5s var(--ease);
}
.gallery__thumb:hover img, .gallery__thumb:focus-visible img { transform: scale(1.012); }
.gallery__thumb:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* A strip holding a single photo: the container drops its frame so no full
   width void appears, and the thumb is framed like a mounted plate. Its width
   is derived from the true photo ratio (--thumb-ar) against the height cap, so
   the image exactly fills its plate - no internal banding - and centres in the
   card instead of stretching edge to edge. */
.gallery__thumbs--single {
  background: none; border: 0; gap: 0;
  --thumb-cap: min(68vh, 600px);
}
.gallery__thumbs--single .gallery__thumb {
  width: min(100%, calc(var(--thumb-cap) * var(--thumb-ar, 4 / 3)));
  max-height: none;
  margin-inline: auto;
  border: 1px solid var(--line-2);
}

/* Tiny images (logos): contained on a paper plaque, inset so they read as a
   mark rather than a stretched photo. */
.gallery__thumb--contain img { padding: clamp(1rem, 5%, 2.25rem); }

/* dark featured card adaptation */
.card--featured .gallery__count { color: rgba(241, 241, 236, 0.6); }
.card--featured .gallery__all { color: var(--on-ink); border-color: rgba(241, 241, 236, 0.35); }
.card--featured .gallery__all:hover { color: var(--accent); border-color: var(--accent); }
.card--featured .gallery__thumbs { background: rgba(241, 241, 236, 0.22); border-color: rgba(241, 241, 236, 0.22); }
.card--featured .gallery__thumb { background: rgba(241, 241, 236, 0.06); }
/* The featured hero photo: a larger plate on a lifted ink matte with a faint
   light hairline, so the frame reads as a deliberate mount on the dark card. */
.card--featured .gallery__thumbs--single { background: none; border: 0; --thumb-cap: min(72vh, 640px); }
.card--featured .gallery__thumbs--single .gallery__thumb { background: rgba(241, 241, 236, 0.05); border-color: rgba(241, 241, 236, 0.20); }

/* ---------- Lightbox ---------- */
.lightbox { position: fixed; inset: 0; z-index: 300; background: rgba(20, 22, 25, 0.92); }
.lightbox[hidden] { display: none; }
.lightbox__inner {
  position: absolute; inset: 0; display: grid; place-items: center;
  padding: clamp(3.5rem, 8vw, 4.5rem) clamp(3.5rem, 8vw, 5rem);
  overflow: auto;
}
.lightbox__stage { display: flex; flex-direction: column; align-items: center; gap: 0.9rem; max-width: 100%; }
.lightbox__img {
  max-width: min(88vw, 1400px); max-height: 78vh; width: auto; height: auto;
  object-fit: contain; background: rgba(241, 241, 236, 0.06);
}
/* Small images (logos): sit contained on a paper plate, capped to roughly
   their natural size so a 200x200 mark is never upscaled or blurred. */
.lightbox__img--contain {
  background: var(--paper-2);
  padding: clamp(0.85rem, 4vw, 2.5rem);
  max-width: min(88vw, 560px);
}
.lightbox__cap {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.5rem 0.9rem;
  max-width: min(88vw, 900px); text-align: center;
  font: 600 0.72rem/1.4 var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(241, 241, 236, 0.6);
}
.lightbox__counter { color: var(--on-ink); }
.lightbox__name { letter-spacing: 0.03em; text-transform: none; overflow-wrap: anywhere; }

.lightbox__close, .lightbox__nav {
  position: absolute; z-index: 2; display: grid; place-items: center;
  background: rgba(241, 241, 236, 0.06); border: 1px solid rgba(241, 241, 236, 0.24);
  color: var(--on-ink); line-height: 1;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease);
}
.lightbox__close:hover, .lightbox__nav:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
.lightbox__close:focus-visible, .lightbox__nav:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lightbox__close { top: clamp(0.75rem, 2.5vw, 1.6rem); right: clamp(0.75rem, 2.5vw, 1.6rem); width: 46px; height: 46px; font-size: 1.5rem; }
.lightbox__nav { top: 50%; transform: translateY(-50%); width: clamp(44px, 5vw, 58px); height: clamp(44px, 5vw, 58px); font-size: 1.9rem; }
.lightbox__nav--prev { left: clamp(0.5rem, 2.5vw, 2rem); }
.lightbox__nav--next { right: clamp(0.5rem, 2.5vw, 2rem); }
.lightbox__nav[hidden] { display: none; }

body.lightbox-open { overflow: hidden; }

@media (max-width: 620px) {
  .lightbox__inner { padding: 3.75rem 0.5rem 1rem; }
  .lightbox__img { max-width: calc(100vw - 7.5rem); max-height: 70vh; }
  .lightbox__img--contain { padding: 0.85rem; }
  .lightbox__nav { width: 42px; height: 46px; font-size: 1.5rem; }
  .lightbox__close { width: 42px; height: 42px; }
}

@media (prefers-reduced-motion: reduce) {
  .gallery { animation: none; }
  .gallery__thumb img { transition: none; }
}
