/* ------------------------------------------------------------------
   jpcoakley.com: "Off-Press" light editorial / Swiss
   paper: #EFEDE5   ink: #16171B   accent (ultramarine): #1C2BE0
   ------------------------------------------------------------------ */

:root {
  --paper: #FFFFFF;                    /* white ground */
  --blue: #16171B;                     /* accent folded into ink: all text/chrome is black */
  --red:  #16171B;                     /* legacy accent slot, folded into ink */
  --ink:  #16171B;                     /* near-black ink */
  --muted: #55564F;                    /* cool grey for secondary text */
  --line: #E2E0DA;                     /* hairline rule */
  --panel: #F4F3EF;                    /* card / frame surfaces */
  --mono: "Chivo Mono", "Courier New", monospace;   /* plain zero; Space Mono and Menlo have a dotted or slashed one */
  --track: 0.3em;                      /* signature wide letterspacing */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);   /* presses and hovers: quick start, soft landing */
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* ---------- header / nav ---------- */

header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--paper);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
  padding: 1.15rem clamp(1.25rem, 5vw, 4rem);
  border-bottom: 1px solid var(--line);
}

.site-name {
  font-weight: 600;
  font-size: 0.9rem;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--blue);
  text-decoration: none;
  white-space: nowrap;
}

nav { position: relative; display: flex; gap: clamp(1rem, 3vw, 2.5rem); }

nav a {
  position: relative;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  padding-bottom: 2px;
  transition: color 180ms ease, transform 260ms var(--ease-spring);
}

nav a:hover { color: var(--blue); transform: translateY(-3px); }
nav a.active { color: var(--blue); }

/* single underline that springs to the hovered link (rests under active) */
.nav-underline {
  position: absolute;
  left: 0;
  bottom: -0.4rem;
  height: 2px;
  width: 0;
  background: var(--blue);
  border-radius: 2px;
  opacity: 0;
  transform: translateX(0);
  pointer-events: none;
  will-change: transform, width;
  transition: transform 460ms var(--ease-spring), width 460ms var(--ease-spring), opacity 220ms ease;
}
@media (prefers-reduced-motion: reduce) {
  nav a, .nav-underline { transition-duration: 0.001ms !important; }
}

/* ---------- shared layout ---------- */

main { padding: 0 clamp(1.25rem, 5vw, 4rem) 3.5rem; }

.kicker {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.75rem;
}

.rule { border: none; border-top: 1px solid var(--line); margin: 4rem 0; }

/* ---------- the donut O (from the Lot Shots mark study) ----------
   ring size ≈ 0.71 cap-height units above cap, stroke 0.175,
   gap 0.040, nudged −0.020 x / −0.015 y for optical centring     */

.donut-o {
  display: inline-block;
  width: 1.06em;
  height: 1.06em;
  border: 0.24em solid var(--red);
  border-radius: 50%;
  vertical-align: baseline;
  margin: 0 0.30em -0.16em 0.02em; /* right margin ≈ tracking + gap 0.040 */
  transform: translate(-0.02em, -0.015em);
}

.donut-o.blue { border-color: var(--blue); }

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

/* ---------- wordmark lockups ---------- */

.wordmark {
  color: var(--blue);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--track);
  line-height: 1.35;
}

.hero {
  min-height: 62vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 6rem 0 4rem;
}

.hero .wordmark { font-size: clamp(2.4rem, 8vw, 6rem); }

.hero-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(2rem, 6vw, 5rem);
  flex-wrap: wrap;
}

.headshot {
  flex: 0 0 auto;
  width: min(300px, 70vw);
  aspect-ratio: 4 / 5;
  margin-bottom: 0;
}

.hero p.tagline {
  margin-top: 2rem;
  max-width: 34rem;
  color: var(--muted);
  font-size: 1.05rem;
}

/* ---------- section cards ---------- */

.section-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.5rem;
  margin-top: 3rem;
}

.card {
  display: block;
  border: 1px solid var(--line);
  background: var(--panel);
  padding: 1.25rem 1.5rem;
  text-decoration: none;
  color: var(--ink);
  transition: border-color 120ms ease, transform 120ms ease;
}

.card:hover { border-color: var(--blue); transform: translateY(-2px); }

.card h2 {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--blue);
  margin-bottom: 0.6rem;
}

.card p { font-size: 0.9rem; color: var(--muted); }

/* ---------- photography / galleries ---------- */

.page-title {
  font-size: clamp(2.6rem, 7vw, 4.6rem);
  margin: 4rem 0 0.5rem;
}

/* Off-Press: page + series titles are tight, title-case, heavy ink
   (overrides the wide uppercase ultramarine of the legacy .wordmark) */
.page-title.wordmark,
.series-head .series-title.wordmark {
  text-transform: none;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-weight: 900;
  line-height: 0.94;
}

.lede { max-width: 38rem; color: var(--muted); margin-top: 1rem; }

.lotshots-mark {
  margin: 5rem auto 3rem;
  text-align: center;
  font-size: clamp(2rem, 6vw, 4rem);
}

.lotshots-mark .line { display: block; }

/* ---------- series bubbles (photography index) ---------- */

.bubblespace {
  position: relative;
  height: clamp(440px, 72vh, 760px);
  margin-top: 2rem;
}

/* pre-JS / no-JS fallback: calm inline layout */
.bubble {
  display: inline-block;
  text-decoration: none;
  text-align: center;
  margin: 1.5rem;
  transition: filter 200ms ease;
}

.bubblespace.ready .bubble {
  position: absolute;
  margin: 0;
  left: 0;
  top: 0;
  will-change: transform;
  cursor: grab;
  touch-action: none;        /* pointer dragging on touch screens */
  user-select: none;
  -webkit-user-select: none;
}

.bubblespace.ready .bubble.grabbed { cursor: grabbing; }
.bubblespace.ready .bubble img { -webkit-user-drag: none; }

.orb {
  display: block;
  margin: 0 auto;
  position: relative;
  width: var(--d, 180px);
  height: var(--d, 180px);
  border-radius: 50%;
  overflow: hidden;
  border: 1px solid rgba(233, 230, 220, 0.35); /* bright rim defines edges on overlap */
  background: radial-gradient(circle at 50% 62%,
    rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.02) 70%);
  box-shadow:
    inset 0 -18px 40px rgba(0, 0, 0, 0.35),
    inset 0 0 24px rgba(143, 176, 217, 0.18),  /* soft blue inner glow */
    0 18px 50px rgba(0, 0, 0, 0.35);
}

.orb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
  display: block;
  opacity: 0.74;                 /* translucent: overlapping bubbles show through */
}

/* moving specular reflection: --gx/--gy driven by mouse or device tilt */
.orb::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(circle at var(--gx, 30%) var(--gy, 24%),
      rgba(255, 255, 255, 0.42), rgba(255, 255, 255, 0.10) 26%,
      transparent 44%),
    radial-gradient(circle at calc(100% - var(--gx, 30%)) calc(100% - var(--gy, 24%)),
      rgba(143, 176, 217, 0.16), transparent 40%);
  pointer-events: none;
}

.bubble:hover .orb {
  box-shadow:
    inset 0 -18px 40px rgba(0, 0, 0, 0.45),
    0 18px 50px rgba(0, 0, 0, 0.35),
    0 0 0 2px var(--blue);
}

.bubble-label {
  display: block;
  margin-top: 0.8rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--blue);
}

.bubble-count {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.6rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
  .bubblespace.ready { height: auto; text-align: center; }
  .bubblespace.ready .bubble { position: static; display: inline-block; margin: 1.5rem; transform: none !important; filter: none !important; }
}

/* ---------- series tiles (photography index) ---------- */

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1.5rem;
  margin-top: 3rem;
}

.tile {
  display: block;
  text-decoration: none;
  border: 1px solid var(--line);
  background: var(--panel);
  transition: border-color 120ms ease, transform 120ms ease;
}

/* .tile is static (no link), so no hover */

.tile img {
  width: 100%;
  aspect-ratio: 16 / 9;          /* shorter, wider tile crop */
  object-fit: cover;
  object-position: center 30%;   /* favor the upper frame (faces) */
  display: block;
  border-bottom: 1px solid var(--line);
}

.tile-name {
  display: block;
  padding: 1.1rem 1.25rem 0.2rem;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--blue);
}

.tile-count {
  display: block;
  padding: 0 1.25rem 1.1rem;
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

.crumb { color: var(--muted); text-decoration: none; letter-spacing: 0.22em; }
.crumb:hover { color: var(--red); }

.series-title {
  text-align: center;
  font-size: clamp(1.4rem, 3.5vw, 2.2rem);
  margin: 1rem 0 0.5rem;
}

.series { margin-top: 4rem; }

.collection-title {
  margin-top: 3.5rem;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--blue);
}

.gallery {
  columns: 240px;          /* masonry-style: photos keep native aspect ratio */
  column-gap: 1.25rem;
  margin-top: 3rem;
}

.frame {
  display: block;
  margin-bottom: 1.25rem;
  break-inside: avoid;
  border: 1px solid var(--line);
}

div.frame {
  aspect-ratio: 4 / 5;     /* placeholders only */
  background:
    repeating-linear-gradient(
      -45deg,
      rgba(22, 23, 27, 0.05) 0px, rgba(22, 23, 27, 0.05) 18px,
      rgba(22, 23, 27, 0.02) 18px, rgba(22, 23, 27, 0.02) 36px
    );
  display: flex;
  align-items: center;
  justify-content: center;
}

.frame span {
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--muted);
}

.frame img { width: 100%; height: auto; display: block; }

/* ---------- lightbox ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(20, 21, 25, 0.97);
}

.lightbox.open { display: flex; }

.lb-stage {                 /* the photo with its caption underneath, never over it */
  max-width: min(88vw, 1100px);
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.lb-stage img {
  max-width: 100%;
  max-height: calc(100vh - 10rem);
  max-height: calc(100dvh - 10rem);
  border: 1px solid var(--line);
  background: #fff;
  padding: 8px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
}

.lightbox button {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--blue);
  font-family: inherit;
}

.lb-prev, .lb-next {
  font-size: 3rem;
  line-height: 1;
  padding: 1rem 1.25rem;
  user-select: none;
}

.lb-prev:hover, .lb-next:hover { color: var(--red); }

.lb-close {
  position: absolute;
  top: 1.5rem;
  right: 1.75rem;
  padding: 0.5rem;
}

.lb-donut {
  display: block;
  width: 1.3rem;
  height: 1.3rem;
  border: 0.34rem solid var(--red);
  border-radius: 50%;
  transition: transform 120ms ease;
}

.lb-close:hover .lb-donut { transform: rotate(90deg) scale(1.08); }

@media (max-width: 560px) {
  .lightbox { padding: 4rem 0 6rem; }      /* clear of the close button above and the arrows below */
  .lb-stage img { max-height: calc(100vh - 16rem); max-height: calc(100dvh - 16rem); }
  .lb-prev, .lb-next {
    position: absolute;
    bottom: 1rem;
    z-index: 51;
  }
  .lb-prev { left: 18%; }
  .lb-next { right: 18%; }
  .lb-stage { max-width: 94vw; }
}

/* ---------- projects list ---------- */

.projects {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
  margin-top: 3rem;
}

/* ---------- footer ---------- */

footer {
  border-top: 1px solid var(--line);
  padding: 2rem clamp(1.25rem, 5vw, 4rem);
  display: flex;
  justify-content: space-between;
  gap: 2rem;
  flex-wrap: wrap;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

@media (max-width: 560px) {
  header { flex-direction: column; gap: 1rem; }
}

footer a.contact-link {
  color: var(--blue);
  text-decoration: none;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

footer a.contact-link:hover { color: var(--red); }

/* ---------- home: Off-Press editorial ---------- */
.home-hero { min-height: 0; padding: clamp(2rem, 4vw, 3.5rem) 0 2.5rem; }
.home-hero .hero-row {
  display: grid;
  grid-template-columns: minmax(0, 470px) 1fr;
  align-items: center;
  gap: clamp(2rem, 5vw, 4rem);
}
.hero-text { min-width: 0; }

.home-hero .kicker {
  font-family: var(--mono); font-variant-ligatures: none;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--blue);
  margin-bottom: 0.9rem;
}

.oh-name {
  font-family: "Archivo", sans-serif;
  font-weight: 900;
  font-size: clamp(2.6rem, 8.5vw, 5.4rem);
  line-height: 0.9;
  letter-spacing: -0.035em;
  text-transform: none;
  color: var(--ink);
}
.oh-name em { font-style: normal; color: var(--ink); }

.lead {
  margin-top: 0.9rem;
  font-family: var(--mono); font-variant-ligatures: none;
  font-size: clamp(0.8rem, 1.6vw, 0.95rem);
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--muted);
}

.bio {
  max-width: 60ch;
  margin-top: 1.1rem;
  color: #2b2c26;
  font-size: 1.02rem;
  line-height: 1.55;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--line);
}
.bio a { color: var(--blue); text-decoration: none; border-bottom: 1px solid rgba(22, 23, 27, 0.30); }
.bio a:hover { border-color: var(--blue); }

.home-hero .headshot { width: 100%; max-width: 470px; aspect-ratio: 3 / 2; margin: 0; }
.home-hero .headshot img { object-position: center 46%; }

@media (max-width: 760px) {
  .home-hero .hero-row { grid-template-columns: 1fr; }
  .home-hero .headshot { max-width: 440px; }
}

/* venture index (numbered rows) */
.idxhead {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 1.6rem 0 0.1rem;
}
.idxhead h2 {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink);
}
.idxhead span { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.72rem; color: var(--muted); }

.row {
  display: grid;
  grid-template-columns: auto 116px 1fr auto;
  gap: 0 1.1rem;
  align-items: center;
  padding: 0.55rem 0;
  text-decoration: none;
  color: var(--ink);
  transition: padding 0.25s ease, background 0.2s ease;
}
.row .num { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.72rem; color: var(--muted); }

/* brand logo: transparent marks, uniform cell so mixed logos read as one size */
.rowlogo {
  width: 116px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.rowlogo img { max-width: 100%; max-height: 100%; object-fit: contain; object-position: center; display: block; }

/* name + supporting copy grouped as one left-aligned block */
.rowtext { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.row .nm { font-size: 1.2rem; font-weight: 600; letter-spacing: -0.005em; line-height: 1.15; }
.row .rl { font-size: 0.78rem; color: var(--muted); line-height: 1.25; }
.row .ar { font-family: var(--mono); font-variant-ligatures: none; color: var(--blue); opacity: 0; transition: opacity 0.2s ease; }
.row:hover { padding-left: 0.7rem; background: linear-gradient(90deg, rgba(28, 43, 224, 0.05), transparent 60%); }
.row:hover .nm { color: var(--blue); }
.row:hover .ar { opacity: 1; }
/* Segno has no destination yet: render as a non-link row */
.row.static { cursor: default; }
.row.static:hover { padding-left: 0; background: none; }
.row.static:hover .nm { color: var(--ink); }

@media (max-width: 640px) {
  .row { grid-template-columns: auto 96px 1fr auto; gap: 0 0.9rem; }
  .rowlogo { width: 96px; height: 38px; }
}

/* ---------- photography: sleek collection index ---------- */
.ph-head { margin: 3rem 0 0; }
.ph-head .page-title { margin: 0; }
.ph-head .lede { margin-top: 0.9rem; }

.collections {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 2rem;
  margin-top: 3rem;
}
.collection {
  position: relative;
  display: block;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  text-decoration: none;
  background: #0e2329;
}
.collection img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 32%;
  display: block;
  filter: brightness(0.8);
  transition: transform 700ms cubic-bezier(.2,.7,.2,1), filter 450ms ease;
}
.collection:hover img { transform: scale(1.05); filter: brightness(0.6); }
.collection-cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 2.4rem 1.9rem 1.5rem;
  background: linear-gradient(to top, rgba(9,22,27,0.9), rgba(9,22,27,0.35) 55%, transparent);
  display: flex; flex-direction: column; gap: 0.4rem;
}
.collection-name {
  color: #fff;
  font-size: 1.05rem; font-weight: 600;
  letter-spacing: 0.26em; text-transform: uppercase;
}
.collection-count {
  color: rgba(255,255,255,0.72);
  font-size: 0.64rem; letter-spacing: 0.24em; text-transform: uppercase;
}
.collection::after {
  content: ""; position: absolute; inset: 0;
  border: 1px solid transparent;
  transition: border-color 350ms ease;
  pointer-events: none;
}
.collection:hover::after { border-color: rgba(255,255,255,0.22); }

/* ---------- sleek series (collection) pages ---------- */
.series-head { margin: 3rem 0 2.75rem; max-width: 46rem; }
.series-head .series-title { text-align: left; margin: 0; font-size: clamp(1.8rem, 5vw, 3rem); }
.series-sub { color: var(--muted); margin-top: 1rem; font-size: 1.02rem; line-height: 1.7; }
.series-count {
  margin-top: 1.1rem;
  font-size: 0.64rem; font-weight: 600;
  letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--blue);
}
.gallery a.frame { overflow: hidden; }
.gallery a.frame img { transition: transform 600ms cubic-bezier(.2,.7,.2,1), filter 400ms ease; }
.gallery a.frame:hover img { transform: scale(1.04); filter: brightness(1.06); }
.crumb-top { margin-top: 2.5rem; }

/* ---------- home: headshot photo ---------- */
.headshot { position: relative; }
.headshot img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 42%;
  display: block;
  z-index: 1;
}

/* ---------- footer social icons ---------- */
.socials { display: flex; gap: 1.1rem; align-items: center; }
.socials a { color: var(--muted); display: flex; transition: color 120ms ease; }
.socials a:hover { color: var(--blue); }
.socials svg { width: 18px; height: 18px; display: block; fill: currentColor; }

/* ---------- interests: editorial list ---------- */
.ilist { display: flex; flex-direction: column; gap: 1.9rem; margin-top: 1rem; }
.irow { display: block; text-decoration: none; color: var(--ink); }
.irow .inm {
  display: block;
  font-size: clamp(1.8rem, 5vw, 3.1rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  transition: color 0.15s ease;
}
.irow:hover .inm { color: var(--blue); }
.irow .idesc { display: block; color: var(--muted); font-size: 0.95rem; line-height: 1.5; margin-top: 0.55rem; max-width: 48ch; }

/* ---------- photography: header photo + mini bio ---------- */
.ph-hero { margin-top: 2.5rem; }
.ph-hero .hero-img {
  width: 100%; aspect-ratio: 16 / 7; overflow: hidden; background: var(--panel);
  display: flex; align-items: center; justify-content: center;
}
.ph-hero .hero-img img { width: 100%; height: 100%; object-fit: cover; object-position: center 55%; display: block; }
.ph-hero .hero-img .placeholder { color: var(--muted); font-family: var(--mono); font-variant-ligatures: none; font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase; text-align: center; padding: 1rem; }
.ph-hero .hero-copy { max-width: 46rem; margin-top: 1.9rem; }
.ph-hero .hero-copy h1 { text-align: left; margin: 0; }
.ph-bio { color: var(--muted); font-size: 1.05rem; line-height: 1.75; margin: 1.1rem 0 0; }

/* ---------- photography: gallery mosaic ---------- */
.gmosaic { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 200px; gap: 1.1rem; margin-top: 3.5rem; }
.gmosaic .gm { position: relative; overflow: hidden; background: #0e2329; text-decoration: none; }
.gmosaic .gm img { width: 100%; height: 100%; object-fit: cover; filter: brightness(.82); display: block; transition: transform 700ms cubic-bezier(.2,.7,.2,1), filter 450ms ease; }
.gmosaic .gm:hover img { transform: scale(1.05); filter: brightness(.6); }
.gmosaic .gm .cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 1.5rem 1.1rem 1rem; background: linear-gradient(to top, rgba(9,22,27,.85), transparent); }
.gmosaic .gm .n { color: #fff; font-size: .82rem; font-weight: 600; letter-spacing: .2em; text-transform: uppercase; }
.gmosaic .gm .c { color: rgba(255,255,255,.7); font-size: .58rem; letter-spacing: .2em; text-transform: uppercase; display: block; margin-top: .35rem; }
.gmosaic .gm.big { grid-column: span 2; grid-row: span 2; }
.gmosaic .gm.wide { grid-column: span 2; }
@media (max-width: 720px) {
  .gmosaic { grid-template-columns: 1fr 1fr; grid-auto-rows: 150px; }
  .gmosaic .gm.big { grid-column: span 2; grid-row: span 2; }
  .gmosaic .gm.wide { grid-column: auto; }   /* two columns: Overland and Film Portraits share the fourth row */
  .gmosaic .gm.ext { grid-column: span 2; }  /* The 210 Archive: under Live Music, the full width */
}

/* ---------- photography: full-bleed hero with title overlay ---------- */
.ph-hero-full {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  height: min(76vh, 680px);
  min-height: 400px;
  overflow: hidden;
  background: #eef1f3;
}
.ph-hero-full img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 94% 78%; display: block; }   /* JP sits at the right of the frame; phones and tablets crop the sides, so hold the right */
.ph-hero-full .placeholder {
  position: absolute; left: 0; right: 0; bottom: 1.4rem; text-align: center;
  color: #9aa3a8; font-family: var(--mono); font-variant-ligatures: none; font-size: 0.66rem; letter-spacing: 0.2em; text-transform: uppercase;
}
.ph-hero-full .htxt {
  position: absolute; z-index: 2;
  top: clamp(1.4rem, 4vw, 3rem); left: clamp(1.25rem, 5vw, 4rem);
  right: clamp(1.25rem, 5vw, 4rem);
}
.ph-hero-full h1 {
  margin: 0;
  color: var(--ink); text-align: left;
  font-size: clamp(2.6rem, 9vw, 6.5rem); line-height: 0.92; letter-spacing: -0.01em;
}
.ph-hero-full .sub {
  margin: 1.1rem 0 0; max-width: 34rem;
  color: var(--muted); font-size: clamp(0.95rem, 1.6vw, 1.1rem); line-height: 1.6;
}
.gmosaic .gm.tall { grid-row: span 2; }

/* ---------- gallery: normalize odd-aspect previews to the album's ratio ---------- */
.gallery .frame img.crop-l { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.gallery .frame img.crop-p { width: 100%; aspect-ratio: 2 / 3; object-fit: cover; }

/* ---------- 404 ----------
   The Worker serves this file for anything it cannot find
   (not_found_handling = "404-page" in wrangler.toml). */

.nf {
  min-height: 62vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.1rem;
  padding: clamp(3rem, 10vh, 7rem) clamp(1.25rem, 5vw, 4rem);
  text-align: center;
}

.nf-code {
  font-family: var(--mono); font-variant-ligatures: none;
  font-size: 0.72rem;
  letter-spacing: var(--track);
  color: var(--muted);
}

.nf .page-title { margin: 0; }

.nf-lede {
  max-width: 40ch;
  color: var(--muted);
  line-height: 1.7;
}

.nf-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1rem, 3vw, 2.25rem);
  margin-top: 0.6rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
  width: min(46rem, 100%);
}

.nf-links a {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}

.nf-links a:hover { text-decoration: underline; text-underline-offset: 0.35em; }

/* ---------- home: full-viewport hero, name anchored to the baseline (Direction A) ---------- */
.home-full {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  height: 100vh;
  height: 100svh;   /* the screen with the browser bars showing, so the name clears Safari's toolbar */
  min-height: 560px;
  overflow: hidden;
  background: #eef1f3;
}
.home-full img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 25% 30%; }
.home-full .lockup {
  position: absolute; z-index: 2;
  left: clamp(1.25rem, 5vw, 4rem); bottom: clamp(1.5rem, 4vh, 2.75rem);
  display: flex; flex-direction: column; gap: 1.1rem;
}
.home-full .roles { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.68rem; letter-spacing: 0.26em; text-transform: uppercase; color: var(--muted); }
.home-full h1 {
  margin: 0; color: var(--ink); text-align: left;
  font-weight: 800; font-size: clamp(2.7rem, 9.6vw, 8.6rem);
  line-height: 0.9; letter-spacing: -0.01em; white-space: nowrap;
}
@media (max-width: 720px) {
  .home-full img { object-position: 30% 30%; }
  .home-full .roles { font-size: 0.58rem; letter-spacing: 0.22em; }
}

/* ---------- interests/music: album grid ---------- */
.albumgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 2.2rem 1.6rem;
  margin-top: 2.5rem;
}
.albumcell { display: flex; flex-direction: column; gap: 0.15rem; text-decoration: none; color: var(--ink); }
.albumcell img {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
  margin-bottom: 0.65rem;
  transition: transform 260ms var(--ease-spring), filter 200ms ease;
}
.albumcell:hover img { transform: translateY(-4px); filter: brightness(1.05); }
.albumcell .aname { font-size: 0.92rem; font-weight: 600; line-height: 1.35; }
.albumcell .aartist { font-size: 0.82rem; color: var(--muted); }
@media (max-width: 560px) {
  .albumgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.8rem 1rem; }
}

/* ---------- interests/music: frozen title bar with search + filter ---------- */
.music-bar {
  position: sticky; z-index: 30; top: 0; /* nudged under the site header by script */
  background: var(--paper);
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.8rem 2rem; flex-wrap: wrap;
  padding: 1rem 0 0.9rem; margin-top: 1.4rem;
  border-bottom: 1px solid var(--line);
}
.music-bar .series-title {
  margin: 0; font-size: clamp(1.7rem, 4vw, 2.6rem);
  text-transform: none; letter-spacing: -0.03em; color: var(--ink);
  font-weight: 900; line-height: 0.94;
}
.mctrl { display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap; }
.mctrl input, .mctrl select {
  font: inherit; font-size: 0.9rem; color: var(--ink);
  background: #fff; border: 1px solid var(--line); border-radius: 0;
  padding: 0.5rem 0.75rem;
  -webkit-appearance: none; appearance: none;
}
.mctrl select { padding-right: 1.6rem; background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%); background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%; background-size: 5px 5px; background-repeat: no-repeat; max-width: 200px; }
.mctrl input { width: min(280px, 56vw); }
.mctrl input:focus, .mctrl select:focus { outline: 2px solid var(--ink); outline-offset: -1px; }
.mctrl .mcount { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.64rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.albumcell[hidden] { display: none; }

/* ---------- interests/music: albums | artists view toggle ---------- */
.vtoggle { display: flex; gap: 1.4rem; }
.vtoggle button {
  font: inherit; font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.2em; text-transform: uppercase;
  background: none; border: 0; color: var(--muted);
  padding: 0.4rem 0.1rem; cursor: pointer;
  border-bottom: 2px solid transparent;
}
.vtoggle button.active { color: var(--ink); border-bottom-color: var(--ink); }
.artistgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 2rem 1.6rem;
  margin-top: 2.5rem;
}
.artistcell { display: flex; flex-direction: column; align-items: center; gap: 0.7rem; text-decoration: none; color: var(--ink); text-align: center; }
.artistcell img {
  width: 100%; max-width: 170px; height: auto; aspect-ratio: 1 / 1;
  object-fit: cover; border-radius: 50%; display: block; background: var(--panel);
  transition: transform 260ms var(--ease-spring), filter 200ms ease;
}
.artistcell:hover img { transform: translateY(-4px); filter: brightness(1.05); }
.artistcell .aname { font-size: 0.92rem; font-weight: 600; line-height: 1.3; }
.albumgrid[hidden], .artistgrid[hidden] { display: none; }
@media (max-width: 560px) {
  .artistgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.6rem 1rem; }
}

/* ---------- projects: badge-shaped logos get height, not width ---------- */

/* ---------- magazine series (Lights): an opening spread, then rows ----------
   build_galleries.py MAGAZINE writes the markup. The whole page is one
   .gallery so the lightbox runs through it; this undoes the masonry. */
.gallery.mag { columns: auto; margin-top: 0; }
.gallery.mag .frame { margin-bottom: 0; border: 0; }
.mag-spread {
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin: 0 calc(-1 * clamp(1.25rem, 5vw, 4rem));   /* full bleed past main's gutters */
  min-height: max(560px, min(calc(100vh - 3.8rem), 1000px));
  border-bottom: 1px solid var(--line);
}
.gallery.mag .mag-hero { position: relative; min-height: 100%; }
.gallery.mag .mag-hero img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.mag-page {
  display: flex;
  flex-direction: column;
  padding: clamp(2rem, 4.5vw, 4.5rem);
  border-left: 1px solid var(--ink);
}
.mag-page .kicker { margin-bottom: 2rem; }
.mag-kicker {
  font-size: 0.68rem; font-weight: 600;
  letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--muted);
}
.mag-head {
  margin-top: 1.75rem;
  font-size: clamp(2.6rem, 6.2vw, 6rem);
  font-weight: 900;
  letter-spacing: -0.04em;
  line-height: 0.95;
}
.mag-page .lede { margin-top: 2rem; font-size: 1.06rem; line-height: 1.6; }
.mag-inset {
  margin-top: auto;
  padding-top: 2.5rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}
.mag-inset img, .mag-row img { aspect-ratio: 3 / 2; object-fit: cover; }
.mag-row { display: grid; gap: 1.25rem; margin-top: 1.25rem; }
.mag-spread + .mag-row { margin-top: clamp(1.25rem, 5vw, 4rem); }
.mag-row.n1 .frame { width: min(100%, 60rem); margin-inline: auto; }   /* a leftover single stays under a screen tall */
.mag-row.n2 { grid-template-columns: 1fr 1fr; }
.mag-row.n3 { grid-template-columns: 1fr 1fr 1fr; }
@media (max-width: 820px) {
  .mag-spread { grid-template-columns: 1fr; min-height: 0; }
  .gallery.mag .mag-hero { min-height: 0; aspect-ratio: 4 / 5; }
  .mag-page { border-left: 0; }
  .mag-inset, .mag-row { gap: 0.75rem; }
  .mag-row { margin-top: 0.75rem; }
  .mag-row.n3 { grid-template-columns: 1fr 1fr; }
  .mag-row.n3 .frame:first-child { grid-column: span 2; }
}

/* ---------- dark series pages: Roads (zine) and Lot Shots (typology) ----------
   build_galleries.py ZINE and TYPOLOGY write the markup. Both run full bleed
   on ink, past main's gutters and down to the footer. */
.zine, .typo {
  --gut: clamp(1.25rem, 5vw, 4rem);
  margin: 0 calc(-1 * var(--gut)) -3.5rem;
  padding: 0 var(--gut) clamp(3rem, 6vw, 5rem);
  background: var(--ink);
  color: #FFFFFF;
}
.zine .crumb, .typo .crumb { color: #B9B8B0; }
.zine .crumb:hover, .typo .crumb:hover { color: #FFFFFF; }
.zine .frame, .typo .frame { border: 0; margin-bottom: 0; }

/* Roads: the cover runs edge to edge, the title straddles its bottom edge */
.gallery.zine { columns: auto; margin-top: 0; }
.gallery.zine .zine-cover {
  display: block;
  margin: 0 calc(-1 * var(--gut));
  height: min(78vh, 58vw, 900px);
  min-height: 320px;
}
.gallery.zine .zine-cover img { width: 100%; height: 100%; object-fit: cover; }
.gallery.zine a.zine-cover:hover img { transform: none; filter: none; }
.zine-head { position: relative; margin-top: -0.4em; font-size: min(18.5vw, 17rem); }
.zine-title {
  font-size: 1em;
  font-weight: 900;
  font-stretch: 125%;
  letter-spacing: -0.04em;
  line-height: 0.8;
  text-transform: uppercase;
  color: #FFFFFF;
  text-shadow: 0 0 0.3em rgba(0, 0, 0, 0.25);
}
.zine-meta {
  margin-top: 1.5rem;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.28em; text-transform: uppercase;
}
.zine .kicker { margin: clamp(2.5rem, 6vw, 4.5rem) 0 1.25rem; }
.zine-grid { columns: 360px; column-gap: 1.25rem; }
.zine-grid .frame { margin-bottom: 1.25rem; }

/* Lot Shots: title bar, then every portrait in one even grid */
.typo { padding-top: 2.5rem; }   /* padding, not the crumb's margin, or it collapses out of the band */
.typo .kicker { margin: 0 0 1.5rem; }
.typo-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
  flex-wrap: wrap;
}
.typo-title {
  font-size: clamp(4.5rem, 15vw, 13rem);
  font-weight: 900;
  font-stretch: 62%;
  line-height: 0.8;
  text-transform: uppercase;
  color: #FFFFFF;
}
.typo-meta {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  text-align: right;
  font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.26em; text-transform: uppercase;
  color: #B9B8B0;
}
.typo-meta span:first-child { color: #FFFFFF; }
.typo-sub { margin-top: 1.5rem; max-width: 38rem; color: #B9B8B0; font-size: 1.02rem; }
.gallery.typo-grid {
  columns: auto;
  margin-top: clamp(2rem, 4vw, 3rem);
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 10px;
}
.typo-grid img { aspect-ratio: 2 / 3; object-fit: cover; }
@media (max-width: 1000px) { .gallery.typo-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
@media (max-width: 640px) {
  .gallery.typo-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
  .typo-meta { flex-direction: row; flex-wrap: wrap; gap: 0.5rem 1rem; text-align: left; }
}

/* ==================================================================
   2026-09-22 redesign: one unit for every project and love,
   the home page as one scroll, and scroll-driven motion.
   ================================================================== */

/* the header over the home photo: clear at first, solid once the photo scrolls away (see motion) */
body.home header { height: 64px; margin-bottom: -64px; padding-top: 0; padding-bottom: 0; align-items: center; background: transparent; border-bottom: 0; }
body.home main { padding-bottom: 0; }
header .prog { position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--ink); transform: scaleX(0); transform-origin: 0 50%; pointer-events: none; }
@media (max-width: 560px) {
  header { flex-direction: row; align-items: center; gap: 1rem; }
  .site-name { letter-spacing: 0.2em; }
}


/* the unit */
.cards { display: grid; gap: 3rem 1.5rem; }
.cards.c4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cards.c3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.unit { display: flex; flex-direction: column; gap: 1rem; min-width: 0; color: var(--ink); text-decoration: none; }
.unit .plate { position: relative; aspect-ratio: 4 / 3; background: var(--panel); overflow: hidden; container-type: inline-size; }
.unit .pz { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; transition: scale 0.6s cubic-bezier(0.2, 0.7, 0.2, 1); }
.unit .logo { display: block; width: auto; height: auto; max-width: var(--mw, 60%); max-height: var(--mh, 40%); }
.unit .photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.unit .covers { width: 78%; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.unit .covers img { display: block; width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover; }
.unit .cap { display: flex; flex-direction: column; gap: 0.45rem; }
.unit .meta { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 0.4rem 0.75rem; min-height: 1rem; font-family: var(--mono); font-variant-ligatures: none; font-size: 0.69rem; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.unit .st { display: flex; align-items: center; gap: 0.45rem; color: var(--ink); }
.unit .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ink); flex: none; }
.unit .dot.hollow { background: transparent; border: 1.5px solid var(--ink); }
.unit .nm { font-size: 1.375rem; line-height: 1.15; font-weight: 800; letter-spacing: -0.01em; }
.unit .ln { font-size: 0.94rem; line-height: 1.45; font-weight: 500; color: var(--muted); }
.cards.c3 .unit .nm { font-size: 1.5rem; }
.cards.c3 .unit .ln { font-size: 1rem; }
a.unit:hover .pz { scale: 1.045; }
a.unit:hover .nm { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 5px; }
a.unit:focus-visible { outline: 2px solid var(--ink); outline-offset: 6px; }
/* pressing a card sinks its picture a touch. On .plate, not .unit: the unit's
   transform carries the slow fade-up. The press replaces the browser's grey tap
   flash, and iOS only shows :active because site.js listens for touchstart. */
.unit { -webkit-tap-highlight-color: transparent; }
.unit .plate { transition: transform 160ms var(--ease-out); }
a.unit:active .plate { transform: scale(0.98); }
@media (prefers-reduced-motion: reduce) {
  .unit .plate { transition: opacity 160ms var(--ease-out); }
  a.unit:active .plate { transform: none; opacity: 0.9; }
}

/* section heads */
.shead { display: flex; flex-direction: column; gap: 1.1rem; margin-bottom: 2.5rem; }
.shead .drawrule, .glabel .drawrule { height: 1.5px; background: var(--ink); transform-origin: 0 50%; }
.shead-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.shead h2 { margin: 0; font-size: clamp(1.9rem, 3.1vw, 2.75rem); line-height: 1; font-weight: 900; letter-spacing: -0.02em; }
.more, .hint { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.69rem; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink); text-decoration: none; white-space: nowrap; }
.more:hover { text-decoration: underline; text-underline-offset: 4px; }
.hint { display: none; color: var(--muted); }

/* home sections */
.home-full + .hsec { padding-top: 7.5rem; }   /* whichever section sits first under the photo */
.hsec { padding-bottom: 9rem; }
.sayhi {
  width: 100vw; margin-left: calc(50% - 50vw);
  background: var(--ink); color: #fff;
  padding: 7rem clamp(1.25rem, 5vw, 4rem) 4rem;
  display: flex; flex-direction: column; gap: 3rem;
}
.sayhi .lbl { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.69rem; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; color: #B9BBC1; }
.sayhi .mail { align-self: flex-start; position: relative; color: #fff; text-decoration: none; font-size: clamp(2.6rem, 8.9vw, 8rem); line-height: 0.9; font-weight: 900; letter-spacing: -0.035em; }
/* pointing at the address draws a rule under it, like the section heads */
.sayhi .mail::after { content: ""; position: absolute; left: 0; right: 0; bottom: -0.15em; height: 0.035em; background: currentColor; transform: scaleX(0); transform-origin: 0 50%; transition: transform 220ms var(--ease-out); pointer-events: none; }
.sayhi .mail:focus-visible::after { transform: none; }
@media (hover: hover) and (pointer: fine) { .sayhi .mail:hover::after { transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .sayhi .mail::after { transform: none; opacity: 0; transition: opacity 150ms ease; }
  .sayhi .mail:focus-visible::after { opacity: 1; }
  @media (hover: hover) and (pointer: fine) { .sayhi .mail:hover::after { opacity: 1; } }
}
.sayhi .foot { display: flex; justify-content: space-between; align-items: center; gap: 1rem; }
.sayhi .socials a { color: #fff; }
.sayhi .socials a:hover { color: #B9BBC1; }

/* projects page */
.phead { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 26rem); gap: 2.5rem; align-items: end; padding: 6rem 0 4.5rem; }
.phead h1 { margin: 0; font-size: clamp(4rem, 10.4vw, 9.4rem); line-height: 0.84; font-weight: 900; letter-spacing: -0.045em; transform-origin: 0 100%; }
.phead .side { display: flex; flex-direction: column; gap: 1rem; padding-bottom: 0.5rem; }
.phead .count { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.69rem; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; }
.phead p { font-size: 1.3rem; line-height: 1.45; font-weight: 500; color: var(--muted); }
.pgroup { padding-bottom: 6rem; }
.glabel { position: sticky; top: 61px; z-index: 5; background: var(--paper); display: flex; flex-direction: column; gap: 1rem; padding-bottom: 0.9rem; margin-bottom: 2.25rem; }
.glabel .grow { display: flex; justify-content: space-between; font-family: var(--mono); font-variant-ligatures: none; font-size: 0.69rem; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; }
.glabel .grow span + span { color: var(--muted); }

@media (max-width: 1100px) {
  .cards.c4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1000px) {
  .phead { grid-template-columns: 1fr; gap: 1.25rem; padding: 4rem 0 3.5rem; }
}
@media (max-width: 760px) {
  .phead { grid-template-columns: 1fr; gap: 1.25rem; padding: 3.5rem 0 3rem; }
  .phead p { font-size: 1.05rem; }
  .pgroup { padding-bottom: 4rem; }
}
@media (max-width: 640px) {
  .home-full + .hsec { padding-top: 4rem; }
  .hsec { padding-bottom: 4.5rem; }
  .shead { margin-bottom: 1.75rem; }
  .shead h2 { font-size: 1.875rem; }
  .hint { display: inline; }
  /* home: cards swipe sideways and snap, the next one peeking in */
  .cards.swipe { display: flex; gap: 1rem; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-left: 1.25rem; margin: 0 -1.25rem; padding: 0 1.25rem 0.4rem; scrollbar-width: none; }
  .cards.swipe::-webkit-scrollbar { display: none; }
  .cards.swipe > .unit { flex: 0 0 272px; scroll-snap-align: start; }
  .cards.swipe .unit .nm, .cards.c3.swipe .unit .nm { font-size: 1.125rem; }
  .cards.swipe .unit .ln, .cards.c3.swipe .unit .ln { font-size: 0.875rem; }
  /* Things I Love stacks, one card to a row, so nothing hides off to the side */
  .cards.c3:not(.swipe) { grid-template-columns: 1fr; gap: 2.75rem; }
  .cards.c4:not(.swipe) { gap: 2rem 1rem; }
  .cards.c4:not(.swipe) .unit .nm { font-size: 1.05rem; }
  .cards.c4:not(.swipe) .unit .ln { font-size: 0.82rem; }
  .cards.c4:not(.swipe) .unit .meta { font-size: 0.6rem; letter-spacing: 0.1em; }
  .sayhi { padding: 4rem 1.25rem 2.5rem; gap: 1.75rem; }
}

/* ---------- motion: scroll-driven, CSS only ----------
   Resting styles are the finished page, so browsers without scroll timelines
   and visitors who ask for reduced motion simply see everything in place. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    body.home header { animation: hdr linear both; animation-timeline: scroll(root); animation-range: 60vh 88vh; }
    header .prog { animation: prog linear both; animation-timeline: scroll(root); }
    .home-full img { animation: drift linear both; animation-timeline: scroll(root); animation-range: 0 100vh; }
    .home-full .lockup { animation: away linear both; animation-timeline: scroll(root); animation-range: 0 55vh; }
    .phead h1 { animation: shrink linear both; animation-timeline: scroll(root); animation-range: 0 320px; }
    .shead .drawrule, .glabel .drawrule { animation: draw linear both; animation-timeline: view(); animation-range: entry 0% entry 100%; }
    .sayhi .mail { animation: lift linear both; animation-timeline: view(); animation-range: entry 0% entry 100%; }   /* it sits at the page bottom, so the lift must finish on entry */
  }
}
/* the header name arrives as the big name leaves, so the first screen says it once.
   Opacity only, so reduced-motion visitors get it too; keyboard focus shows it at once. */
@supports (animation-timeline: scroll()) {
  body.home .site-name { animation: arrive linear both; animation-timeline: scroll(root); animation-range: 30vh 55vh; }
  body.home .site-name:focus-visible { animation: none; }
}
@keyframes arrive { from { opacity: 0; } }
@keyframes hdr { from { background-color: rgba(255, 255, 255, 0); box-shadow: 0 1px 0 rgba(226, 224, 218, 0); } to { background-color: rgba(255, 255, 255, 0.95); box-shadow: 0 1px 0 var(--line); } }
@keyframes prog { to { transform: scaleX(1); } }
@keyframes drift { to { transform: translateY(22%) scale(1.08); } }
@keyframes away { to { transform: translateY(-90px); opacity: 0; } }
@keyframes shrink { to { transform: translateY(-40px) scale(0.82); opacity: 0.15; } }
@keyframes draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes lift { from { opacity: 0; transform: translateY(90px); } to { opacity: 1; transform: none; } }

/* ---------- where a photograph was taken ----------
   The place is JP's line from photo-locations.json, the year is EXIF;
   build_galleries.py stamps both under the frame and onto data-caption,
   which the lightbox reads. */
.frame .cap {
  display: block;
  margin-top: 0.6rem;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}
.zine .frame .cap { color: #B9B8B0; }
.zine-grid .frame { margin-bottom: 2rem; }
.lb-caption {
  margin-top: 1rem;
  max-width: 40rem;
  line-height: 1.6;
  text-align: center;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #D9D7D0;      /* the overlay is near-black: ink would vanish */
}
.lb-caption:empty { display: none; }

/* ---------- after ammunitiongroup.com (2026-09-25) ----------
   Cards fade up once as they arrive (site.js adds .in). With a mouse, each card
   is just its picture; pointing at it fades the picture away to show the words
   behind. Touch screens keep the caption under the picture. */
.js .unit { opacity: 0; transform: translateY(28px); transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1); }
.js .unit.in { opacity: 1; transform: none; }
.js .unit.d2 { transition-delay: 0.08s; }
.js .unit.d3 { transition-delay: 0.16s; }
.js .unit.d4 { transition-delay: 0.24s; }
@media (prefers-reduced-motion: reduce) { .js .unit { opacity: 1; transform: none; transition: none; } }
/* Music: covers and artists fade up the same way (site.js adds .in and a short ripple delay) */
.js .albumcell, .js .artistcell { opacity: 0; transform: translateY(20px); transition: opacity 0.55s ease, transform 0.55s cubic-bezier(0.2, 0.7, 0.2, 1); }
.js .albumcell.in, .js .artistcell.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .js .albumcell, .js .artistcell { opacity: 1; transform: none; transition: none; } }

.unit .back { display: none; }
@media (hover: hover) and (pointer: fine) {
  .unit .plate { border: 1px solid var(--line); }
  .unit .pz { z-index: 1; background: var(--panel); transition: opacity 0.3s ease-in-out, scale 0.6s cubic-bezier(0.2, 0.7, 0.2, 1); }
  .unit:hover .pz, .unit:focus-visible .pz { opacity: 0; }
  .unit .back { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: space-between; gap: 0.75rem; padding: 1.1rem 1.25rem 1.2rem; background: #fff; }
  .unit .back .bnm { display: block; margin-top: 0.7rem; font-size: 1.6rem; line-height: 1.08; font-weight: 800; letter-spacing: -0.015em; }
  .unit .back .bln { font-size: 0.92rem; line-height: 1.4; font-weight: 500; color: var(--muted); }
  .unit .back .go { display: inline-block; margin-top: 0.75rem; font-family: var(--mono); font-variant-ligatures: none; font-size: 0.66rem; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; border-bottom: 1.5px solid var(--ink); padding-bottom: 2px; }
  .cards.c3 .unit .back .bnm { font-size: 2rem; }
  .cards.c3 .unit .back .bln { font-size: 1rem; }
  .unit .cap { display: none; }
  .cards { gap: 1.5rem; }
  /* the words fit the tile: smaller tiles clamp the line, the smallest drop it */
  .unit .plate { container-type: size; }
  @container (max-height: 240px) {
    .unit .back .bnm { font-size: 1.35rem; }
    .unit .back .bln { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  }
  @container (max-height: 185px) {
    .unit .back .bln { display: none; }
    .unit .back .go { margin-top: 0; }
  }
  a.unit:hover .nm { text-decoration: none; }
}

/* Things I Love: the name first, then the picture. Each card's .ptitle covers
   its picture as the card arrives; once the card is well in view site.js adds
   .lit, the name holds a moment, then fades to the photo. Without JS the photos
   show straight away. Opacity only, so reduced-motion visitors get it too. */
.ptitle { display: none; }
.js .ptitle {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: flex-end;
  padding: 1.1rem 1.25rem 1.05rem;
  background: var(--panel); color: var(--ink);
  font-size: clamp(1.9rem, 3.2vw, 2.9rem); font-size: 11cqi;
  line-height: 1; font-weight: 900; letter-spacing: -0.03em;
  pointer-events: none;
}
.js .unit.lit .ptitle { opacity: 0; transition: opacity 0.7s ease 1.1s; }
.js .unit.d2.lit .ptitle { transition-delay: 1.25s; }
.js .unit.d3.lit .ptitle { transition-delay: 1.4s; }

/* Things I Love: the section head freezes under the site header while the
   cards scroll by, and each card opens with its name under a rule that freezes
   just below it, like the Projects group labels. The section head has a set
   height (--love-head: its rule, gap and h2, plus room below) so the card
   headings know where to stop. On phones the cards stack, so their headings
   take turns and carry the status too, and the caption keeps only the line.
   Wider, the three sit in a row and their headings freeze together; the status
   joins them once a column has room for it (--love-st). */
#love { --love-head: calc(1.5px + 1.1rem + clamp(1.9rem, 3.1vw, 2.75rem) + 1rem); }
#love .shead { position: sticky; top: 64px; z-index: 4; height: var(--love-head); margin-bottom: 1.5rem; background: var(--paper); }
.unit .uhead {
  position: sticky; top: calc(64px + var(--love-head, 0px)); z-index: 3;
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  margin-bottom: -0.25rem; padding: 0.8rem 0 0.7rem;
  border-top: 1.5px solid var(--ink); background: var(--paper);
}
.uhead h3 { margin: 0; font-size: 1.5rem; line-height: 1.1; font-weight: 800; letter-spacing: -0.015em; white-space: nowrap; }
.unit .uhead .st { display: none; font-family: var(--mono); font-variant-ligatures: none; font-size: 0.69rem; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; white-space: nowrap; }
.uhead ~ .cap .nm { display: none; }
@media (min-width: 1080px) { .unit .uhead .st { display: flex; } }   /* "Photography" and its status need about 290px */
@media (max-width: 640px) {
  #love { --love-head: 4rem; }
  #love .shead { margin-bottom: 0.75rem; }
  .unit .uhead .st { display: flex; }
  .uhead ~ .cap .meta { display: none; }
}

/* ---------- journey series (Overland): cover with the route, then stops ----------
   build_galleries.py JOURNEY writes the markup; one .gallery so the lightbox
   runs start to finish. Photos sit in justified rows: each frame's flex
   grow is its width:height ratio, so a row shares one height and nothing
   is cropped. */
.gallery.journey { columns: auto; margin-top: 0; }
.journey .frame { border: 0; margin-bottom: 0; }
.journey-open {
  --gut: clamp(1.25rem, 5vw, 4rem);
  position: relative;
  margin: 0 calc(-1 * var(--gut));
  height: min(88vh, 62vw, 980px);
  min-height: 460px;
  overflow: hidden;
  background: var(--ink);
}
.journey-cover { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.journey-open::after {     /* a light overall shade; the dark scrim follows the text (.journey-head::before) */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(18, 19, 22, 0.35) 0%, rgba(18, 19, 22, 0) 45%);
}
.journey-head {
  position: absolute; z-index: 1;
  left: var(--gut); right: var(--gut); bottom: clamp(1.5rem, 4vw, 3.25rem);
  color: #FFFFFF;
}
.journey-head::before {    /* sized to the text block at every width, so the crumb and route never sit on bare photo */
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  left: calc(-1 * var(--gut)); right: calc(-1 * var(--gut));
  top: -3rem; bottom: calc(-1 * clamp(1.5rem, 4vw, 3.25rem));
  background: linear-gradient(to bottom, rgba(18, 19, 22, 0) 0, rgba(18, 19, 22, 0.75) 3rem, rgba(18, 19, 22, 0.9) 100%);
}
.journey-head .kicker { margin-bottom: 1.25rem; }
.journey-head .crumb { color: #D9D7D0; }
.journey-head .crumb:hover { color: #FFFFFF; }
.journey-title {
  font-size: clamp(3.6rem, 13vw, 11rem);
  font-weight: 900;
  letter-spacing: -0.045em;
  line-height: 0.86;
  color: #FFFFFF;
}
.journey-sub { margin-top: 1.1rem; max-width: 40rem; font-size: clamp(1rem, 1.6vw, 1.2rem); line-height: 1.5; color: #E9E7E1; }
.journey-route {
  list-style: none; padding: 0; margin-top: 1.4rem;
  display: flex; flex-wrap: wrap; gap: 0.5rem 0;
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
}
.journey-route li + li::before { content: "\2192"; padding: 0 0.7rem; color: #B9B8B0; }
.journey-route a { color: #FFFFFF; text-decoration: none; border-bottom: 1px solid rgba(255, 255, 255, 0.35); padding: 0.35rem 0; }
.journey-route a:hover { border-bottom-color: #FFFFFF; }
.journey-count { margin-top: 1rem; font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.24em; text-transform: uppercase; color: #B9B8B0; }
.stop {
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  padding: clamp(3rem, 7vw, 5.5rem) 0 0;
  scroll-margin-top: 4rem;
}
.stop + .stop { border-top: 1px solid var(--line); margin-top: clamp(3rem, 7vw, 5.5rem); }
.stop-head { position: sticky; top: 5.5rem; align-self: start; }
.stop-n { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.26em; color: var(--muted); }
.stop-name { margin-top: 0.6rem; font-size: clamp(1.6rem, 2.6vw, 2.3rem); font-weight: 800; letter-spacing: -0.025em; line-height: 1.05; }
.stop-when { margin-top: 0.8rem; font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--muted); }
.stop-photos { display: flex; flex-direction: column; gap: 0.9rem; }
.jrow { display: flex; gap: 0.9rem; align-items: flex-start; }
.jrow .frame { min-width: 0; }
.jrow .frame img { width: 100%; height: auto; }
@media (max-width: 900px) {
  .stop { grid-template-columns: 1fr; gap: 1.25rem; }
  .stop-head { position: static; }
}
@media (max-width: 600px) {
  .jrow { flex-wrap: wrap; gap: 0.6rem; }
  .jrow .frame { flex: 1 1 100% !important; }
  .jrow[style] { max-width: none !important; }   /* the short last row's inline cap only makes sense side by side */
  .stop-photos { gap: 0.6rem; }
}

/* ---------- contact-print series (Film Portraits): a strip per roll ----------
   build_galleries.py CONTACT writes the markup. Frames keep the 35mm 3:2
   box; verticals sit upright inside it. .keeper frames get the grease
   pencil ring JP's five-star frames earn. */
.contact {
  --gut: clamp(1.25rem, 5vw, 4rem);
  margin: 0 calc(-1 * var(--gut)) -3.5rem;
  padding: 2.5rem var(--gut) clamp(3rem, 6vw, 5rem);
  background: #F2F0EA;
}
.contact-crumb { margin-bottom: 1.75rem; }
.contact-head { max-width: 50rem; }
.contact-title { font-size: clamp(2.8rem, 8vw, 6.5rem); font-weight: 900; letter-spacing: -0.04em; line-height: 0.92; }
.contact-sub { margin-top: 1.1rem; font-size: 1.05rem; line-height: 1.6; color: var(--muted); }
.contact-legend { margin-top: 1.1rem; display: flex; align-items: center; gap: 0.75rem; font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.contact-ring { flex: none; width: 2.1rem; height: 1.3rem; border: 3px solid #C4301F; border-radius: 50%; transform: rotate(-6deg); }
.gallery.contact-years { columns: auto; margin-top: clamp(0.5rem, 2vw, 1.5rem); }   /* a section per year */
.contact .stop { padding-top: clamp(2rem, 4.5vw, 3.25rem); }
.contact .stop + .stop { margin-top: clamp(2rem, 4.5vw, 3.25rem); }
.contact .stop-name { font-size: clamp(2rem, 3.6vw, 3rem); letter-spacing: -0.03em; }
.contact-rolls {                 /* cut strips laid side by side on the light table */
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 1.75rem 1.25rem;
}
.strip {
  position: relative;
  flex: 0 1 auto;
  max-width: 100%;
  background: #111112;
  padding: 1.6rem clamp(0.75rem, 1.6vw, 1.25rem);
}
.strip::before, .strip::after {         /* sprocket holes along both edges */
  content: ""; position: absolute; left: 0.9rem; right: 0.9rem; height: 0.55rem;
  background: repeating-linear-gradient(90deg, #F2F0EA 0 0.85rem, transparent 0.85rem 1.9rem);
  opacity: 0.9;
}
.strip::before { top: 0.45rem; }
.strip::after { bottom: 0.45rem; }
.strip-edge {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: #E8A33D; margin: 0.35rem 0 0.8rem;
}
.strip-frames { display: flex; flex-wrap: wrap; gap: 0.9rem 0.75rem; }
.strip-frames .frame { width: clamp(200px, 19vw, 262px); }
.contact .frame { border: 0; margin: 0; position: relative; display: block; text-decoration: none; }
.contact .gallery a.frame { overflow: visible; }   /* the keeper ring draws outside the frame */
.strip-img { display: block; aspect-ratio: 3 / 2; background: #050506; overflow: hidden; }
.strip-img img { width: 100%; height: 100%; object-fit: contain; }
.contact .gallery a.frame:hover img { transform: none; filter: brightness(1.12); }
.contact .frame .strip-n {       /* beats .frame span, which would grey it out */
  display: block; min-height: 1.6em; margin-top: 0.4rem;
  font-family: var(--mono); font-size: 0.66rem; font-weight: 400; letter-spacing: 0.12em; text-transform: none; color: #E8A33D;
}
.contact .frame.keeper::after {
  content: ""; position: absolute; left: -0.55rem; right: -0.55rem; top: -0.7rem; bottom: 0.9rem;
  border: 4px solid #D8412C; border-radius: 50%; transform: rotate(-3deg); pointer-events: none;
}
.contact .frame.keeper:nth-child(2n)::after { transform: rotate(2.5deg); }
@media (max-width: 600px) {
  .strip { flex: 1 1 100%; }
  .strip-frames { gap: 0.7rem 0.5rem; }
  .strip-frames .frame { width: calc(50% - 0.25rem); }
  .contact .frame.keeper::after { left: -0.35rem; right: -0.35rem; border-width: 3px; }
}

/* ---------- tour series (Live Music): a gig poster ----------
   build_galleries.py TOUR writes the markup (tour_body). It reuses the
   journey cover and the stop grid with justified rows; the page is stage
   black, the tour dates list the shows, and each show's heading is a paper
   ticket stub. */
.gallery.tour {
  --gut: clamp(1.25rem, 5vw, 4rem);
  columns: auto;
  margin: 0 calc(-1 * var(--gut)) -3.5rem;
  padding: 0 var(--gut) clamp(3rem, 6vw, 5rem);
  background: #0E0E10;
  color: #F2F0EA;
}
.tour .frame { border: 0; margin-bottom: 0; }
.tour-title { text-transform: uppercase; font-stretch: 75%; letter-spacing: -0.02em; }
.tour-dates-band { padding: clamp(2.5rem, 6vw, 4.5rem) 0 0.5rem; }
.tour-dates-title { font-family: var(--mono); font-size: 0.72rem; font-weight: 500; letter-spacing: 0.3em; text-transform: uppercase; color: #E8A33D; }
.tour-dates { list-style: none; padding: 0; margin-top: 1.25rem; columns: 2 24rem; column-gap: 3rem; }
.tour-dates li { break-inside: avoid; border-top: 1px solid rgba(242, 240, 234, 0.14); }
.tour-dates a {
  display: grid; grid-template-columns: 6.4rem minmax(0, 1fr); column-gap: 1rem; row-gap: 0.15rem;
  padding: 0.75rem 0; color: #F2F0EA; text-decoration: none;
}
.td-date { grid-row: 1 / span 2; font-family: var(--mono); font-size: 0.8rem; letter-spacing: 0.06em; color: #E8A33D; padding-top: 0.1rem; }
.td-act { grid-column: 2; grid-row: 1; font-weight: 800; font-size: 1rem; text-transform: uppercase; letter-spacing: 0.02em; }
.td-where { grid-column: 2; grid-row: 2; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase; color: #B9B8B0; }
.tour-dates a:hover .td-act, .tour-dates a:focus-visible .td-act { color: #E8A33D; }
.tour .stop + .stop { border-top-color: rgba(242, 240, 234, 0.12); }
.ticket {
  background: #EFE3C2;
  color: #16171B;
  padding: 1.1rem 1.3rem 1.05rem;
  border-radius: 6px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.4);
}
.ticket-act {
  font-size: clamp(1.4rem, 2vw, 1.8rem); font-weight: 900; font-stretch: 75%;
  text-transform: uppercase; letter-spacing: -0.01em; line-height: 0.95; color: #16171B;
  overflow-wrap: break-word; hyphens: auto;     /* a name longer than the stub breaks instead of spilling out */
}
.ticket-tour { margin-top: 0.45rem; font-size: 1.05rem; font-weight: 800; font-stretch: 80%; text-transform: uppercase; letter-spacing: 0.01em; line-height: 1.1; }
.ticket-where { margin-top: 0.65rem; font-size: 0.92rem; line-height: 1.35; }
.ticket-date {                            /* torn off along the dashed line */
  position: relative;
  margin-top: 0.9rem; padding-top: 0.8rem; border-top: 2px dashed rgba(22, 23, 27, 0.3);
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase;
}
.ticket-date::before, .ticket-date::after {   /* the punched notches at the tear line */
  content: ""; position: absolute; top: calc(-0.55rem - 1px); width: 1.1rem; height: 1.1rem;
  border-radius: 50%; background: #0E0E10;
}
.ticket-date::before { left: -1.85rem; }       /* the stub's 1.3rem padding plus half a notch */
.ticket-date::after { right: -1.85rem; }
@media (min-width: 901px) {
  .tour .stop { grid-template-columns: 16rem minmax(0, 1fr); }   /* room for ESTRADASPHERE */
}
@media (max-width: 900px) {
  .ticket { max-width: 24rem; }
}

/* the mosaic's seventh tile runs the full width of the grid, two rows tall */
.gmosaic .gm.full { grid-column: 1 / -1; grid-row: span 2; }

/* ---------- card series (Lights, Roads): one photo per section ----------
   build_galleries.py CARDS writes the markup (card_body) inside the Live
   Music page's dark .tour wrapper. Beside each photo, a card that stays put
   while the photo scrolls: Lights reads out its shutter speed, aperture and
   ISO; Roads is a road sign with the place. */
.expo-head { font-size: clamp(1.4rem, 2.6vw, 2rem); font-weight: 800; font-stretch: 80%; letter-spacing: -0.01em; color: #F2F0EA; }
.cards .stop-photos .frame { display: block; }
.cards .stop-photos .frame img { width: 100%; height: auto; }
.cards.work .stop-photos .frame img { width: auto; max-width: 100%; max-height: calc(100vh - 8rem); }   /* Work mixes small phone photos (the chalk one is 388 px wide), shown at their own size and never stretched, with tall ones kept within the screen */
.meter-read {
  margin: 0; padding: 1rem 1.2rem 1.1rem;
  display: grid; gap: 0.8rem;
  background: #17171B; border: 1px solid rgba(242, 240, 234, 0.14); border-radius: 6px;
}
.meter-read div { display: grid; gap: 0.1rem; }
.meter-read dt { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.6rem; letter-spacing: 0.24em; text-transform: uppercase; color: #9C9A93; }
.meter-read dd { margin: 0; font-family: var(--mono); font-variant-ligatures: none; font-size: 1.3rem; line-height: 1.2; color: #E8A33D; }
.meter-read div:first-child dd { font-size: 1.9rem; }
@media (max-width: 900px) {
  .meter-read { grid-template-columns: repeat(3, auto); justify-content: start; gap: 0.4rem 1.6rem; max-width: 24rem; padding: 0.8rem 1rem; }
  .meter-read div:first-child dd { font-size: 1.3rem; }
}

/* ---------- a photo's own page, and sharing it ----------
   build_galleries.py writes photography/<series>/<photo>.html (one per
   photo, so a shared link previews that photo); gallery.js wires the
   Share buttons (the phone's share sheet, else copy the link). */
.lightbox .lb-share, .pv-share {
  margin-top: 0.85rem; padding: 0.45rem 1rem; border-radius: 999px;
  border: 1px solid rgba(242, 240, 234, 0.3); background: none; cursor: pointer;
  font-family: var(--mono); font-variant-ligatures: none; font-size: 0.64rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: #D9D7D0;
}
.lightbox .lb-share:hover, .pv-share:hover { border-color: #E8A33D; color: #E8A33D; }
.lightbox .lb-share:focus-visible, .pv-share:focus-visible { outline: 2px solid #F2F0EA; outline-offset: 3px; }
.photo-view {
  --gut: clamp(1.25rem, 5vw, 4rem);
  margin: 0 calc(-1 * var(--gut)) -3.5rem;
  padding: 1.5rem var(--gut) 3rem;
  min-height: calc(100vh - 9rem); min-height: calc(100dvh - 9rem);   /* dark to the footer, even for a small photo */
  background: #141519; color: #F2F0EA;
}
.photo-view .crumb { color: #B9B8B0; }
.pv-figure { margin: 1.25rem auto 0; display: flex; flex-direction: column; align-items: center; }
.pv-figure img {
  display: block; width: auto; height: auto; max-width: 100%;
  max-height: calc(100vh - 15rem); max-height: calc(100dvh - 15rem);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
}
.pv-cap { margin-top: 1rem; max-width: 40rem; text-align: center; line-height: 1.6; font-family: var(--mono); font-variant-ligatures: none; font-size: 0.68rem; letter-spacing: 0.18em; text-transform: uppercase; color: #D9D7D0; }
.pv-nav { margin-top: 1.25rem; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 0.75rem 1.75rem; font-family: var(--mono); font-variant-ligatures: none; font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase; }
.pv-nav a { color: #F2F0EA; text-decoration: none; }
.pv-nav a:hover, .pv-nav a:focus-visible { color: #E8A33D; }
.pv-nav .pv-share { margin-top: 0; }

/* Work: a punch-clock time card, cream stock with red rules, the date in
   stamp ink. The notch at the top is the clock's slot, cut in the stage colour. */
.punch {
  position: relative;
  padding: 1.1rem 1.15rem 1.1rem;
  background: #EFE6CC; color: #231F1A; border-radius: 3px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
}
.punch::before {
  content: ""; position: absolute; top: 0; left: 50%;
  width: 2.2rem; height: 0.7rem; margin-left: -1.1rem;
  background: #0E0E10; border-radius: 0 0 1.1rem 1.1rem;
}
.punch-top {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: 0.35rem 0 0.5rem; border-bottom: 2px solid #B0362B;
  font-family: var(--mono); font-variant-ligatures: none; font-size: 0.58rem; font-weight: 500; letter-spacing: 0.26em; text-transform: uppercase; color: #B0362B;
}
.punch-at { margin-top: 0.75rem; font-size: 1.45rem; font-weight: 800; font-stretch: 85%; line-height: 1.1; letter-spacing: -0.005em; text-wrap: balance; }
.punch-job { margin-top: 0.2rem; font-size: 0.95rem; font-weight: 500; color: #4A443C; }
.punch-rows { margin: 0.85rem 0 0; }
.punch-rows div {
  display: grid; grid-template-columns: 3.6rem minmax(0, 1fr); align-items: baseline; gap: 0.6rem;
  padding: 0.45rem 0; border-top: 1px solid rgba(176, 54, 43, 0.35);
}
.punch-rows dt { font-family: var(--mono); font-variant-ligatures: none; font-size: 0.56rem; letter-spacing: 0.22em; text-transform: uppercase; color: #B0362B; }
.punch-rows dd { margin: 0; font-size: 0.92rem; font-weight: 600; line-height: 1.3; }
.punch-rows div:last-child dd {
  justify-self: start; transform: rotate(-1.5deg); transform-origin: left center;
  font-family: var(--mono); font-variant-ligatures: none; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: #4A3C8C;
}
@media (max-width: 900px) {
  .punch { max-width: 24rem; }
  .punch-at { font-size: 1.2rem; }
}

/* Roads: the place on a green guide sign, white letters inside a white rule */
.sign-read {
  margin: 0; padding: 1rem 1.2rem 1.05rem;
  display: grid; gap: 0.2rem;
  background: #0B5A38; color: #FFFFFF; border-radius: 10px;
  box-shadow: inset 0 0 0 4px #0B5A38, inset 0 0 0 6px #F2F0EA, 0 12px 30px rgba(0, 0, 0, 0.4);
}
.sign-main { font-size: 1.45rem; font-weight: 700; font-stretch: 90%; line-height: 1.12; letter-spacing: 0.005em; text-wrap: balance; }
.sign-sub { font-size: 0.95rem; font-weight: 600; letter-spacing: 0.02em; color: #E4EFE8; }
@media (max-width: 900px) {
  .sign-read { max-width: 24rem; padding: 0.85rem 1.05rem 0.9rem; }
  .sign-main { font-size: 1.2rem; }
}

/* Lot Shots: the typology grid on black, its title and shoot pinned beside it */
.gallery.typo-sections { columns: auto; margin-top: 0; }
.typo .stop { padding-top: 0.5rem; }
.typo .stop + .stop { border-top-color: rgba(255, 255, 255, 0.12); margin-top: clamp(2.5rem, 5vw, 4rem); padding-top: clamp(2.5rem, 5vw, 4rem); }
.typo-label .typo-title { font-size: clamp(3.5rem, 6.5vw, 6.5rem); line-height: 0.82; overflow-wrap: break-word; }
.typo-label .typo-sub { margin-top: 1.1rem; font-size: 0.98rem; line-height: 1.5; }
.typo-label .typo-meta { margin-top: 1.1rem; text-align: left; }
.typo-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; }
@media (min-width: 901px) { .typo .stop { grid-template-columns: 17rem minmax(0, 1fr); } }
@media (max-width: 1200px) { .typo-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 640px) { .typo-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; } }

/* a series with no layout of its own (Portraits): title pinned, photos in rows */
.gallery.plain { columns: auto; margin-top: 0.5rem; }
.plain .stop { padding-top: 1rem; }
.plain .frame { border: 0; margin-bottom: 0; }
.plain .series-head { margin: 0; }
.plain .series-head .series-title { font-size: clamp(2rem, 3.6vw, 3rem); }
/* Ice Hockey: JP's line under the pinned title, "website" linking to the team site */
.plain .series-head .series-sub { margin-top: 0.75rem; max-width: 17rem; font-size: 0.98rem; line-height: 1.55; }
.plain .series-sub a { color: var(--ink); text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
.plain .series-sub a:hover, .plain .series-sub a:focus-visible { color: var(--muted); }
