/* Johnny Shoots. Layout, grid, and spacing from tylerstableford.com; skin is "Night Game" (2026-10-05). See DESIGN.md. */
/* Self-hosted fonts (SIL Open Font License 1.1, see assets/fonts/LICENSE.txt). No third-party requests. */
@font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; font-display: swap; src: url("../assets/fonts/roboto-400.woff2") format("woff2"); }
@font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; font-display: swap; src: url("../assets/fonts/roboto-500.woff2") format("woff2"); }
@font-face { font-family: "Barlow Condensed"; font-style: normal; font-weight: 500; font-display: swap; src: url("../assets/fonts/barlow-condensed-500.woff2") format("woff2"); }
@font-face { font-family: "Barlow Condensed"; font-style: normal; font-weight: 600; font-display: swap; src: url("../assets/fonts/barlow-condensed-600.woff2") format("woff2"); }

:root {
  /* Night Game: warm charcoal ground, film grain, bone type, one accent (brass, from the stadium lights in his night frames). */
  --ground: #161412;      /* page background, never pure black */
  --surface: #1f1c19;     /* inputs, placeholders, image loading */
  --panel: #0f0e0c;       /* video slots and hero backing */
  --line: rgba(239,232,220,.12);
  --bone: #efe8dc;        /* headings, nav, lead, labels */
  --text: #cfc7ba;        /* body copy */
  --muted: #a59c8e;       /* crumbs, notes, copyright */
  --brass: #d9b47c;       /* the one accent */
  --brass-hi: #ecd1a4;    /* hover, focus ring, links in long text */
  --error: #f0a08a;
  --field-line: #7b7264;  /* input outline, 3:1 on the ground */
  --on-brass: #161412;
  --wrap: 1140px;
  --edge: 24px;
  --gap: 19px;
  --section: 120px;
  --font: "Roboto", system-ui, sans-serif;
  --font-display: "Barlow Condensed", "Roboto", sans-serif;
  /* Film grain: static SVG noise, textures the ground only (photos and the BRMM bar stay clean). */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .95 0 0 0 0 .9 0 0 0 0 .82 0 0 0 .08 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 96px; background: var(--ground); overflow-x: clip; }
body {
  margin: 0; color: var(--text); font: 400 16px/1.7 var(--font); overflow-x: clip;
  background-color: var(--ground);
  /* grain plus a faint warm spill from the top, like light towers over the field */
  background-image: var(--grain), radial-gradient(120% 50% at 50% 0, rgba(217,180,124,.08), transparent 65%);
  background-repeat: repeat, no-repeat;
}
::selection { background: var(--brass); color: var(--on-brass); }
img { max-width: 100%; height: auto; display: block; }
picture { display: contents; }
a { color: inherit; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--brass-hi); outline-offset: 3px;
}
ul { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, p { margin: 0; }

.wrap { width: min(var(--wrap), 100% - var(--edge) * 2); margin-inline: auto; }
.narrow { max-width: 640px; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip { position: absolute; left: 12px; top: -60px; background: var(--brass); color: var(--on-brass); font-weight: 500; padding: 10px 16px; z-index: 50; }
.skip:focus { top: 12px; }

/* Header: 117px, logo left, nav right */
.site-header { position: sticky; top: 0; z-index: 20; background: var(--grain), var(--ground); border-bottom: 1px solid transparent; transition: border-color .25s ease; }
.site-header.scrolled { border-bottom-color: var(--line); }
.header-row { display: flex; align-items: center; justify-content: space-between; height: 117px; transition: height .25s ease; }
.scrolled .header-row { height: 80px; }
.logo { font: 500 26px/1.1 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; }
.logo a { display: inline-block; padding: 6px 0; text-decoration: none; white-space: nowrap; }
.logo-name { color: var(--bone); font-weight: 600; }
.site-nav ul { display: flex; gap: 30px; }
.site-nav a { display: block; padding: 12px 0; font: 500 17px/1.2 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--bone); text-decoration: none; border-bottom: 2px solid transparent; }
.site-nav a:hover { border-bottom-color: var(--muted); }
.site-nav a[aria-current] { border-bottom-color: var(--brass); }
.nav-toggle { display: none; }

/* Home hero (v3, Paxton 2026-10-06): the reel is the whole first screen and the tagline sits on the video itself.
   The header floats over it, clear at the top, and turns solid once the page scrolls (site.js adds .scrolled).
   Readability comes from soft gradients on the footage and a text shadow, not a box behind the words. */
.home .site-header { position: fixed; left: 0; right: 0; background: transparent; }
.home .site-header::before { content: ""; position: absolute; inset: 0 0 -60px; z-index: -1; pointer-events: none;
  background: linear-gradient(rgba(12,11,10,.62), rgba(12,11,10,0)); transition: opacity .25s ease; }
.home .site-header.scrolled { background: var(--grain), var(--ground); }
.home .site-header.scrolled::before { opacity: 0; }
.hero { position: relative; height: 100vh; height: 100svh; min-height: 560px; overflow: hidden; background: var(--panel); }
.hero::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(12,11,10,0) 30%, rgba(12,11,10,.48) 52%, rgba(12,11,10,.72) 70%, rgba(12,11,10,.9) 90%, var(--ground)); }
.hero-media { width: 100%; height: 100%; object-fit: cover; object-position: center; }   /* matches the video, so the fade-in never shifts the picture */
/* The reel sits over the still and fades in only once it plays */
.hero-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; pointer-events: none; transition: opacity .6s ease; }
.hero-video.is-playing { opacity: 1; }
.hero-copy { position: absolute; z-index: 2; left: 0; right: 0; bottom: clamp(48px, 9vh, 104px); text-align: center; max-width: 900px;
  text-shadow: 0 2px 18px rgba(0,0,0,.65), 0 1px 3px rgba(0,0,0,.6); }

/* Hero text (Paxton, 2026-10-06): "Johnny Shoots" is the H1, "Media by Johnny Bell" smaller under it. Nothing else:
   the "Photographer" line and the brass tick came off (Paxton, 2026-10-06). */
.home-h1 { font: 600 clamp(48px, 6.6vw, 96px)/.95 var(--font-display); letter-spacing: 3px; text-transform: uppercase; color: var(--bone); margin-bottom: 14px; }
.hero-by { font: 500 clamp(24px, 2.6vw, 38px)/1.1 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--bone); margin-bottom: 0; }
.hero-by .by { white-space: nowrap; }
.hero-copy .by { color: var(--brass-hi); }   /* lighter brass on the moving footage: holds 3:1 on every frame (build/contrast_over_reel.js) */

/* Video: the reel with controls, and Johnny's vertical social cuts as click-to-play tiles */
.reel-player { margin: 0; }
.reel-player video, .social-tile video { display: block; width: 100%; height: auto; background: var(--panel); box-shadow: 0 0 0 1px var(--line), 0 24px 60px -24px rgba(0,0,0,.9); }
.reel-player figcaption { margin-top: 12px; font-size: 15px; color: var(--muted); text-align: center; }
.social-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 40px var(--gap); }
.social-tile { width: min(320px, 100%); }
.social-tile figure { margin: 0; }
.social-tile video { aspect-ratio: 9 / 16; object-fit: contain; }   /* one frame for both cuts (The Freeze is 3:4, Union Peak 9:16), nothing cropped */
.social-note { display: block; margin-top: 6px; font-size: 15px; color: var(--text); text-align: center; }
.clip-frame { position: relative; }   /* holds the brass play button (901 and up) over the poster */
.vid-aside { display: none; }         /* home Video: lead and Instagram link beside the clips, 1200 and up */
.hero + .section { padding-top: 72px; }

/* Sections and titles: condensed bone caps over a short brass rule */
.section { padding-top: var(--section); }
.page-top { padding-top: 72px; }
.section-title { font: 600 40px/1 var(--font-display); letter-spacing: 4px; text-transform: uppercase; color: var(--bone); text-align: center;
  padding-bottom: 20px; margin-bottom: 60px; position: relative; }
.section-title::after { content: ""; position: absolute; left: 50%; bottom: 0; width: 44px; height: 2px; background: var(--brass); transform: translateX(-50%); }
.intro { text-align: center; max-width: 620px; margin: -28px auto 48px; color: var(--text); }
.crumb { text-align: center; margin-bottom: 14px; font: 500 16px/1.7 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; }
.crumb a { color: var(--brass); text-decoration: none; }
.crumb a:hover { color: var(--brass-hi); text-decoration: underline; }
.more { text-align: center; margin-top: 44px; }
.more a:not(.btn), .text-link { display: inline-block; white-space: nowrap; padding: 4px 0; font: 500 17px/1.7 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--bone);
  text-decoration: underline; text-decoration-color: var(--brass); text-decoration-thickness: 2px; text-underline-offset: 7px; }
.more a:not(.btn):hover, .text-link:hover { color: var(--brass-hi); }
.sec-head > .head-link { display: none; }   /* home section heads: the link shows at 1200 and up only */

/* Photo backdrop behind an inner page header. One of Johnny's own frames per page (bd-* class set in build_site.py),
   blurred and dimmed under a dark scrim, fading to the plain ground before the grid starts. */
.has-bd { position: relative; isolation: isolate; }
.has-bd::before, .has-bd::after { content: ""; position: absolute; z-index: -1; top: 0; left: calc(50% - 50vw); width: 100vw;
  height: calc(72px + var(--bd-extra, 300px)); pointer-events: none; }
.has-bd::before {
  background: var(--bd) var(--bd-pos, center 50%) / cover no-repeat;
  filter: blur(2px) saturate(.8) sepia(.15) brightness(.72);
  clip-path: inset(0);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 60px, #000 50%, transparent 100%); mask-image: linear-gradient(to bottom, transparent 0, #000 60px, #000 50%, transparent 100%); }
.has-bd::after {
  background:
    radial-gradient(ellipse 50% 42% at 50% 44%, rgba(18,16,14,.6), rgba(18,16,14,0) 100%),
    linear-gradient(to bottom, rgba(22,20,18,.5) 0%, rgba(22,20,18,.38) 40%, rgba(22,20,18,.7) 75%, rgba(22,20,18,0) 100%); }
.has-bd > .section-title, .has-bd > .crumb a, .has-bd > .intro { text-shadow: 0 1px 14px rgba(0,0,0,.6); }
.has-bd > .intro { color: var(--bone); }
.has-bd > .crumb a { color: var(--brass-hi); }
.bd-hunting { --bd: url("../assets/img/hunter-walking-with-geese-1200.webp"); --bd-pos: center 40%; }
.bd-brands { --bd: url("../assets/img/shirts-hung-on-a-plane-wing-1200.webp"); --bd-pos: center 55%; }
.bd-travel { --bd: url("../assets/img/coastline-cliffs-1200.webp"); }
.bd-about { --bd: url("../assets/img/combine-pulls-wakeboarder-1200.webp"); --bd-pos: center 45%; }
.bd-contact { --bd: url("../assets/img/field-crew-on-atvs-1200.webp"); --bd-pos: center 40%; }

/* 3-column 16:9 grid with centered captions. Tiles are prints on a dark wall: dimmed a little at rest, full light on hover. */
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px var(--gap); }
.grid-center { display: flex; flex-wrap: wrap; justify-content: center; }
.grid-center > .tile { width: calc((100% - var(--gap) * 2) / 3); }   /* the five galleries: three over two, centered */
.tile-link { display: block; text-decoration: none; }
.tile-img, .slot { display: block; position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--panel);
  box-shadow: 0 0 0 1px var(--line), 0 18px 40px -18px rgba(0,0,0,.8); transition: box-shadow .4s ease; }
.tile-img img, .slot-bg img { width: 100%; height: 100%; object-fit: cover; object-position: var(--focus, center); transition: transform .5s ease, filter .4s ease; }
.tile-img img { filter: brightness(.9) saturate(.95); }
.tile-link:hover .tile-img img { transform: scale(1.04); }
.tile-link:hover .tile-img img, .tile-link:focus-visible .tile-img img { filter: none; }
.tile-link:hover .tile-img, .tile-link:focus-visible .tile-img { box-shadow: 0 0 0 1px rgba(217,180,124,.45), 0 24px 60px -16px rgba(217,180,124,.22); }
.tile-cap { margin-top: 16px; font: 500 19px/1.1 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; text-align: center; color: var(--bone); }
.tile-link:hover .tile-cap { color: var(--brass-hi); text-decoration: underline; text-decoration-color: var(--brass); text-underline-offset: 5px; }

/* Video slots: his photo, toned down, behind a brass play mark and a note. A soft dark pool keeps the note readable. */
.slot { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--panel-text, var(--bone)); }
.slot-bg { position: absolute; inset: 0; }
.slot-bg img { filter: grayscale(.55) sepia(.2) brightness(.58); }
.slot::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 46% 52% at 50% 50%, rgba(15,14,12,.62), rgba(15,14,12,0) 100%); }
.slot .play { position: relative; z-index: 1; width: 48px; height: 48px; color: var(--brass); }
.slot-note { position: relative; z-index: 1; padding: 6px 10px; background: rgba(15,14,12,.76); font: 500 16px/1 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--bone); }
.reel-slot { aspect-ratio: 16 / 9; margin-bottom: 56px; }
.reel-slot .play { width: 72px; height: 72px; }

/* About band */
.about-band { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.about-img img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; box-shadow: 0 0 0 1px var(--line), 0 24px 60px -24px rgba(0,0,0,.9); }
.about-copy p + p { margin-top: 18px; }
/* About photos of Johnny: the field shot, with the headshot tucked lower right */
.about-pair { display: grid; grid-template-columns: 3fr 2fr; gap: 16px; align-items: end; }
.about-pair img { width: 100%; height: auto; aspect-ratio: auto; object-fit: cover; box-shadow: 0 0 0 1px var(--line), 0 24px 60px -24px rgba(0,0,0,.9); }
.about-pair source { display: none; }   /* picture is display: contents site-wide, so keep its sources out of the grid */
.about-pair picture:last-child img { aspect-ratio: 4 / 5; }
.clients { margin-top: 14px; color: var(--text); }
.inline-link { color: var(--bone); text-decoration: underline; text-decoration-color: var(--brass); text-underline-offset: 3px; }
.inline-link:hover { color: var(--brass-hi); }
.lead { font: 600 32px/1.08 var(--font-display); letter-spacing: 1.5px; text-transform: uppercase; color: var(--bone); }
.placeholder-panel { aspect-ratio: 3 / 2; background: var(--surface); border: 1px dashed rgba(217,180,124,.5); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  color: var(--muted); font: 500 17px/1.4 var(--font-display); letter-spacing: 2px; text-transform: uppercase; text-align: center; padding: 20px; }
.placeholder-panel svg { width: 56px; height: 56px; color: var(--brass); }
/* Johnny's bio in his own words (About): a quiet pull quote on the brass edge, signed */
.bio { margin: 18px 0 22px; border-left: 2px solid var(--brass); padding-left: 18px; font-size: 17px; line-height: 1.75; color: var(--bone); }
.bio footer { margin-top: 8px; font: 500 15px/1.2 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--brass-hi); }
.placeholder-text { border-left: 2px solid var(--brass); padding-left: 14px; color: var(--muted); font-style: italic; }

/* Home About (Paxton, 2026-10-07): Johnny's photo of Old Main in Fayetteville next to "Based in Fayetteville", on every
   screen. Phones and tablets: the photo above the copy card, 480px at most (the file is 1040 wide). At 1200 and up it
   becomes a split (see the 1200 block). This replaced the dimmed hunter-and-lab backdrop and the coast photo. */
.about-shot { max-width: 480px; margin: 0 auto 28px; }
.about-shot img { display: block; width: 100%; height: auto; box-shadow: 0 0 0 1px var(--line), 0 24px 60px -24px rgba(0,0,0,.9); }
.photo-band { position: relative; isolation: isolate; padding-bottom: var(--section); margin-top: var(--section); }
.about-band.solo { grid-template-columns: minmax(0, 560px); justify-content: start; }
.photo-band .about-copy { background: linear-gradient(to right, rgba(22,20,18,.92), rgba(22,20,18,.8)); padding: 36px 38px; border-left: 2px solid var(--brass); }
.photo-band .section-title { text-shadow: 0 1px 14px rgba(0,0,0,.6); }

/* Home "Selected Work" (catalog.HOME_FEATURE): 1200 and up only. Hidden below, so its lazy images never load there. */
.feature { display: none; }
/* Gallery chapters (Photos hub, and the next gallery at the end of each gallery) and the Brands set labels:
   hidden below 1200 (labels below 901), so phones and tablets get nothing new and fetch no strip images. */
.hub-strips, .next-chapter { display: none; }
.ch-kicker { display: block; }
.set-title { display: none; }

/* Buttons: brass fill, dark type */
.btn { display: inline-block; background: var(--brass); color: var(--on-brass); border: 1px solid var(--brass); padding: 14px 28px; font: 600 17px/1 var(--font-display);
  letter-spacing: 2.5px; text-transform: uppercase; text-decoration: none; cursor: pointer; transition: background-color .2s ease, color .2s ease, border-color .2s ease; margin-right: 18px; }
.btn:hover { background: transparent; color: var(--brass-hi); border-color: var(--brass-hi); }

/* Gallery: justified rows in catalog order, never cropped. Each item grows by its aspect ratio (--r, set per item
   by build_site.py), so every photo in a row has the same height. */
.gallery { display: flex; flex-direction: column; gap: var(--gap); }
.g-row { display: flex; gap: var(--gap); }
.g-cell { flex: var(--r) 1 0; min-width: 0; }
.g-cell img { width: 100%; height: auto; }
.g-item { display: block; overflow: hidden; background: var(--surface); box-shadow: 0 0 0 1px var(--line); cursor: zoom-in; }
.g-item img { width: 100%; transition: filter .2s ease; }
.g-item:hover img { filter: brightness(1.06); }
.g-item:focus-visible { outline-offset: 4px; }
.gallery-note { margin-top: 24px; text-align: center; font-size: 14px; color: var(--muted); }   /* Sports: the not-affiliated line */

.lightbox { position: fixed; inset: 0; z-index: 60; background: rgba(14,13,11,.97); display: flex; align-items: center; justify-content: center; }
.lightbox[hidden] { display: none; }
.lightbox figure { margin: 0; max-width: calc(100vw - 160px); }
.lightbox img { max-height: calc(100vh - 110px); width: auto; margin: 0 auto; }
.lightbox figcaption { color: var(--text); text-align: center; font-size: 14px; margin-top: 12px; }
.lightbox button { position: absolute; background: none; border: 0; color: var(--bone); cursor: pointer; font-size: 44px; line-height: 1; width: 56px; height: 56px; }
.lightbox button:hover { color: var(--brass-hi); }
.lightbox button:focus-visible { outline: 2px solid var(--brass-hi); outline-offset: -4px; }
.lb-close { top: 14px; right: 14px; }
.lb-prev { left: 16px; top: calc(50% - 28px); }
.lb-next { right: 16px; top: calc(50% - 28px); }

/* Contact */
.contact-direct { text-align: center; line-height: 2.6; margin-bottom: 20px; }
.contact-direct .btn { margin-right: 0; }
#instagram { margin: 0 auto 48px; max-width: 420px; }
.contact-form { display: grid; gap: 20px; }
.field label { display: block; font: 500 16px/1.4 var(--font-display); letter-spacing: 2px; text-transform: uppercase; color: var(--bone); margin-bottom: 6px; }
.field input, .field select, .field textarea { width: 100%; font: 400 16px/1.4 var(--font); color: var(--bone); background: var(--surface); border: 1px solid var(--field-line); padding: 12px 14px; border-radius: 0; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--muted); }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible { border-color: var(--brass); outline-offset: 2px; }
.contact-form .btn { justify-self: start; }
.form-status { color: var(--bone); }
.form-status:empty { display: none; }
.field-error { margin-top: 6px; font-size: 14px; color: var(--error); }
.field [aria-invalid="true"] { border-color: var(--error); border-width: 2px; padding: 11px 13px; }
.field [aria-invalid="true"]:focus-visible { border-color: var(--error); }
.form-note { font-size: 14px; color: var(--muted); }
.form-note a { color: var(--brass-hi); }

/* Text pages: accessibility, privacy */
.prose h2 { font: 600 24px/1.2 var(--font-display); letter-spacing: 2px; text-transform: uppercase; color: var(--bone); margin: 40px 0 12px; }
.prose p + p { margin-top: 14px; }
.prose a { color: var(--brass-hi); }
.prose strong { color: var(--bone); }
.prose .list { list-style: disc; padding-left: 22px; }
.prose .list li::marker { color: var(--brass); }
.prose .list li + li { margin-top: 8px; }
.prose .list + p, .prose p + .list { margin-top: 14px; }
.muted-note { margin-top: 32px !important; font-size: 14px; color: var(--muted); }
.link-list { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 28px; }

/* Footer: centered round icons, page links, copyright, then the BRMM signature bar */
.site-footer { margin-top: 140px; padding: 64px var(--edge) 56px; text-align: center; border-top: 1px solid var(--line); }
.social { display: flex; justify-content: center; gap: 10px; margin-bottom: 22px; }
.social a { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; background: transparent; color: var(--brass); box-shadow: inset 0 0 0 1px var(--brass); }
.social a:hover { background: var(--brass); color: var(--on-brass); }
.social svg { width: 18px; height: 18px; }
.footer-nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 22px; margin-bottom: 16px; }
.footer-nav a { font: 500 16px/1.7 var(--font-display); letter-spacing: 2px; text-transform: uppercase; color: var(--text); text-decoration: none; padding: 4px 0; }
.footer-nav a:hover { color: var(--brass-hi); text-decoration: underline; text-decoration-color: var(--brass); }
.copy { font-size: 14px; color: var(--muted); }

/* 900 and down: hamburger */
@media (max-width: 900px) {
  :root { --section: 88px; }
  html { scroll-padding-top: 84px; }
  .header-row, .scrolled .header-row { height: 72px; }
  .logo { font-size: 22px; }
  .nav-toggle { display: grid; place-items: center; width: 44px; height: 44px; background: none; border: 0; cursor: pointer; color: var(--bone); }
  .bars, .bars::before, .bars::after { display: block; width: 24px; height: 2px; background: currentColor; position: relative; transition: transform .2s ease; }
  .bars::before, .bars::after { content: ""; position: absolute; left: 0; }
  .bars::before { top: -7px; } .bars::after { top: 7px; }
  .nav-open .bars { background: transparent; }
  .nav-open .bars::before { transform: translateY(7px) rotate(45deg); }
  .nav-open .bars::after { transform: translateY(-7px) rotate(-45deg); }
  .site-nav { position: absolute; left: 0; right: 0; top: 72px; background: var(--grain), var(--ground); border-top: 1px solid var(--line); box-shadow: 0 16px 30px rgba(0,0,0,.5); display: none; }
  .nav-open .site-nav { display: block; }
  .site-nav ul { flex-direction: column; gap: 0; padding: 8px var(--edge) 16px; }
  .site-nav a { padding: 14px 0; font-size: 19px; }
  .grid { grid-template-columns: 1fr 1fr; }
  .grid-center > .tile { width: calc((100% - var(--gap)) / 2); }
  .about-band { grid-template-columns: 1fr; gap: 32px; }
  .about-band.solo { grid-template-columns: 1fr; }
}

/* 600 and down */
@media (max-width: 600px) {
  :root { --edge: 16px; --section: 72px; }
  .logo { font-size: 19px; letter-spacing: 1.5px; }
    .hero { min-height: 520px; }
  .grid { grid-template-columns: 1fr; gap: 32px; }
  .grid-center > .tile { width: 100%; }
  .g-row { flex-direction: column; }
  .home-h1 { font-size: 50px; letter-spacing: 2px; }
    .hero-copy { bottom: 36px; }
  .hero + .section { padding-top: 56px; }
  .section-title { font-size: 34px; letter-spacing: 3px; margin-bottom: 44px; }
  .intro { margin-top: -16px; }
  .lead { font-size: 28px; }
  .photo-band .about-copy { padding: 24px 20px; }
  .has-bd { --bd-extra: 260px; }
  .bd-hunting { --bd: url("../assets/img/hunter-walking-with-geese-800.webp"); }
  .bd-brands { --bd: url("../assets/img/shirts-hung-on-a-plane-wing-800.webp"); }
  .bd-travel { --bd: url("../assets/img/coastline-cliffs-800.webp"); }
  .bd-about { --bd: url("../assets/img/combine-pulls-wakeboarder-800.webp"); }
  .bd-contact { --bd: url("../assets/img/field-crew-on-atvs-800.webp"); }
  .has-bd::after { background:
    radial-gradient(ellipse 80% 42% at 50% 44%, rgba(18,16,14,.66), rgba(18,16,14,0) 100%),
    linear-gradient(to bottom, rgba(22,20,18,.56) 0%, rgba(22,20,18,.44) 40%, rgba(22,20,18,.72) 75%, rgba(22,20,18,0) 100%); }
  .lightbox figure { max-width: 100vw; }
  .lb-prev, .lb-next { top: auto; bottom: 16px; }
  .btn { margin-right: 12px; }
}

@media (max-width: 400px) {
  .logo { font-size: 17px; letter-spacing: 1px; }
}

/* 901 and up: polish and video. Phones and tablets are left exactly as they are. */
@media (min-width: 901px) {
  /* The hero's last 72px fade to transparent, so it melts into the grained body instead of stopping on flat ground.
     The floor on .hero-copy keeps "Media by Johnny Bell" clear of that fade on short screens. */
  .hero { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 72px), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - 72px), transparent); }
  .hero-copy { bottom: max(clamp(48px, 9vh, 104px), 88px); }
  /* Body and header carry the same warm spill, both fixed to the viewport, so there is no step under the header */
  body { background-attachment: scroll, fixed; }
  body:not(.home) .site-header, .home .site-header.scrolled { background: var(--grain), radial-gradient(120% 50% at 50% 0, rgba(217,180,124,.08), transparent 65%) fixed, var(--ground); }
  .site-nav a { transition: border-color .2s ease, color .2s ease; }
  .site-nav a:hover { border-bottom-color: rgba(217,180,124,.55); }
  .site-nav a[aria-current]:hover { border-bottom-color: var(--brass); }
  .section-title, .lead, .tile-cap { text-wrap: balance; }
  .intro, .about-copy p, .clients, .prose p, .prose li, .form-note { text-wrap: pretty; }

  /* Social clips at their own shape and full height, no bars (--ar set per clip in build_site.py) */
  .social-grid { gap: 40px 32px; }
  .social-tile { width: auto; }
  .social-tile video { width: auto; height: min(720px, 70vh, 60vw); aspect-ratio: var(--ar); object-fit: contain; }
  /* The Union Peak poster has a near-black 1 to 2px rim on its left and top edges. Show the frame from 2px in
     (the clip itself has no rim). Where object-view-box is not supported the poster shows as before. */
  .social-tile video[poster*="union-peak"] { object-view-box: inset(2px 0 0 2px); aspect-ratio: 600 / 1070; }

  /* Brass play mark over the poster instead of the browser's control bar. js/site.js shows it and swaps in the
     native controls on first play; without script it stays hidden and the controls stay. */
  .clip-play { position: absolute; inset: 0; display: grid; place-items: center; padding: 0; border: 0; cursor: pointer; color: var(--brass);
    background: radial-gradient(ellipse 40% 30% at 50% 50%, rgba(15,14,12,.45), rgba(15,14,12,0)); }
  .clip-play[hidden] { display: none; }
  .clip-play .play { width: 72px; height: 72px; transition: transform .3s ease, color .2s ease; }
  /* Its own dark disc, reaching 6px past the ring, so the brass holds 3:1 on a light poster (Union Peak's blue shirt) */
  .clip-play .play { border-radius: 50%; background: rgba(15,14,12,.7); box-shadow: 0 0 0 6px rgba(15,14,12,.7); }
  .reel-player .clip-play .play { width: 96px; height: 96px; }
  .clip-play:hover .play, .clip-play:focus-visible .play { color: var(--brass-hi); transform: scale(1.06); }
  .clip-play:focus-visible { outline: 2px solid var(--brass-hi); outline-offset: -6px; }

  /* Brands: a label over each shoot (catalog "sets") carries the brand's link and what it makes, so the separate
     credit line under the intro hides here and each brand is named once in the labels. Phones keep the credit line. */
  .set-title { display: block; font: 500 19px/1.1 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--brass-hi); text-align: left; }
  .set-title:not(:first-child) { margin-top: 36px; }
  .set-title a { display: inline-block; padding: 4px 0; color: inherit; text-decoration: underline; text-decoration-color: var(--brass); text-decoration-thickness: 2px; text-underline-offset: 6px; }
  .set-title a:hover { color: var(--bone); }
  .set-what { margin-left: 14px; font-size: 16px; letter-spacing: 2px; color: var(--muted); }
  .page-top > .clients { display: none; }

  /* Lightbox: solid backdrop, the place counter shown top left (the same live node, so nothing is announced twice),
     and each photo fades in once loaded (js/site.js sets .is-loading) instead of painting top to bottom */
  .lightbox { background: #0e0d0b; }
  .lightbox .lb-count { position: absolute; top: 28px; left: 32px; width: auto; height: auto; clip: auto; overflow: visible; white-space: nowrap;
    font: 500 16px/1 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--muted); }
  .lightbox img { max-height: calc(100vh - 160px); transition: opacity .25s ease; }   /* keeps the centered photo about 62px down, clear of the counter */
  .lightbox.is-loading img { opacity: 0; }
  .lightbox figcaption { font: 500 16px/1.4 var(--font-display); letter-spacing: 2px; text-transform: uppercase; color: var(--bone); margin-top: 14px; }

  /* Page-header backdrops: Hunting on the reel poster (landscape, dogs first), and a longer soft top edge so no
     backdrop starts on a hard line under the header. The Lab and the decoys are in the top 40% of the poster, so the
     band sits high on it (center 12%); lower than that it shows only stubble. */
  .bd-hunting { --bd: url("../assets/video/johnny-hero-poster.webp"); --bd-pos: center 12%; }
  .has-bd::before { -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 140px, #000 50%, transparent 100%); mask-image: linear-gradient(to bottom, transparent 0, #000 140px, #000 50%, transparent 100%); }
  .has-bd::after { -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 140px); mask-image: linear-gradient(to bottom, transparent 0, #000 140px); }   /* the scrim fades in too */

  /* Contact: title and intro across the top, then the email button, address and Instagram in a left column
     (held in view while the form scrolls) and the form on the right, so nothing sits on a form label. */
  .contact-page { max-width: none; }
  .contact-cols { display: grid; grid-template-columns: 4fr 7fr; gap: 72px; align-items: start; }
  .contact-side { position: sticky; top: 120px; }
  .contact-side .contact-direct { text-align: left; margin-bottom: 8px; }
  .contact-side .contact-direct .btn { margin-bottom: 14px; }   /* room between the button and the address line */
  .contact-ig { margin: 0; }

  /* 404 is shorter than a tall screen: main fills the gap so the footer and signature bar sit on the bottom edge */
  body:has(.not-found) { min-height: 100vh; display: flex; flex-direction: column; }
  body:has(.not-found) > main { flex: 1 0 auto; }
  /* The five links need about 690px, more than the 640 text measure, so the section takes the full wrap and they sit on one line */
  .not-found.narrow { max-width: none; }
}
/* The twelve footer links need a 1121px screen for one line (1136 leaves room for font metrics). Below that, two even lines of six, not one orphan. */
@media (min-width: 901px) and (max-width: 1135px) {
  .footer-nav { max-width: 600px; margin-inline: auto; }
}
@media (min-width: 901px) and (hover: hover) {
  /* Gallery hover matches the home tiles: a brass edge and a faint glow */
  .g-item { transition: box-shadow .3s ease; }
  .g-item:hover, .g-item:focus-visible { box-shadow: 0 0 0 1px rgba(217,180,124,.45), 0 18px 44px -18px rgba(217,180,124,.22); }
}
@media (min-width: 1201px) {
  /* Sharper backdrop files where the band is widest */
  .bd-brands { --bd: url("../assets/img/shirts-hung-on-a-plane-wing-1600.webp"); }
  .bd-travel { --bd: url("../assets/img/coastline-cliffs-1600.webp"); }
  .bd-about { --bd: url("../assets/img/combine-pulls-wakeboarder-1600.webp"); }
  .bd-contact { --bd: url("../assets/img/field-crew-on-atvs-1600.webp"); }
}

/* 1200 and up: the wide frame. Photos and video get up to 1600px (--wide); text keeps its narrow measure.
   --wide uses vw, not %, on purpose: a % inside a custom property resolves against whatever element uses it,
   which would break the breakouts inside the 1140 .wrap. A breakout inside a .wrap grows it by (--wide - --wrap) /2
   a side, so it matches the header to the pixel: a classic scrollbar can squeeze the .wrap under 1140 between 1200
   and about 1205px, where --wide is still 1140 and a plain width: var(--wide) would overhang the header. */
@media (min-width: 1200px) {
  :root { --wide: clamp(1140px, 100vw - 160px, 1600px); }
  .site-header .header-row.wrap { width: min(var(--wide), 100% - 48px); }
  .wrap.home-wide { width: min(var(--wide), 100% - 48px); }

  /* Home section heads: title left on a hairline, brass tick at its left end, link on the right */
  .sec-head { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; position: relative; padding-bottom: 16px; margin-bottom: 40px; border-bottom: 1px solid var(--line); }
  .sec-head::after { content: ""; position: absolute; left: 0; bottom: -1px; width: 44px; height: 2px; background: var(--brass); }
  .sec-head > .section-title { text-align: left; margin: 0; padding: 0; }
  .sec-head > .section-title::after { display: none; }
  .sec-head > .head-link { display: inline-block; }
  .has-head-link > .more { display: none; }

  /* Home Video as a spread: the two clips left, the lead and Instagram link right, centered on the clips under a
     hairline with the brass tick, like the section heads */
  .home-video { display: flex; flex-wrap: wrap; align-items: center; column-gap: 64px; }
  .home-video > .sec-head { flex: 0 0 100%; }
  .home-video .social-grid { flex: none; flex-wrap: nowrap; justify-content: flex-start; }
  /* Keep 300px for the aside beside the pair: the two clips together are 1.3125 times their height wide, plus the
     32px gap and the 64px column gap. Without this cap the aside drops under the clips on 1280x1080 screens. */
  .home-video .social-tile video { height: min(720px, 70vh, (var(--wide) - 396px) / 1.3125); }
  .vid-aside { display: block; flex: 1; max-width: 420px; margin-bottom: 64px; position: relative; padding-top: 28px; border-top: 1px solid var(--line); }   /* margin: the clip captions' height, so it centers on the clips */
  .vid-aside::before { content: ""; position: absolute; left: 0; top: -1px; width: 44px; height: 2px; background: var(--brass); }
  .vid-aside .lead + p { margin-top: 20px; }
  .reel-player { width: calc(100% + var(--wide) - var(--wrap)); margin-inline: calc((var(--wrap) - var(--wide)) / 2); }

  /* Selected Work: justified rows, never cropped (each cell grows by its ratio --r), plus one full-bleed band.
     The gallery tag shows on hover or focus, and always on the band. */
  .feature { display: block; }
  .f-row { display: flex; gap: var(--gap); }
  .f-row + .f-row, .f-row + .f-bleed, .f-bleed + .f-row { margin-top: var(--gap); }
  .f-cell { flex: var(--r) 1 0; min-width: 0; position: relative; display: block; overflow: hidden; box-shadow: 0 0 0 1px var(--line); transition: box-shadow .3s ease; }
  .f-cell img { width: 100%; height: auto; }
  .f-cell:hover, .f-cell:focus-visible { box-shadow: 0 0 0 1px rgba(217,180,124,.45), 0 24px 60px -16px rgba(217,180,124,.22); }
  /* The band link is the frame's width, so its tag sits on the frame edge; the photo spreads past it to the screen
     edges. The largest combine file is 1843px, so up to 1920 it scales at most 1.04x, too little to see. Wider
     screens would show it soft, so there the photo stops at the frame and lines up with the rows. */
  .f-bleed { display: block; position: relative; height: clamp(480px, 64vh, 720px); --bleed: 100vw; }
  .f-bleed img { position: absolute; top: 0; left: calc(50% - var(--bleed) / 2); width: var(--bleed); max-width: none; height: 100%; object-fit: cover; object-position: 50% 38%; }   /* keeps the combine roof and the wakeboarder */
  .f-bleed:focus-visible { outline: none; }
  /* Focus ring on the photo, 12px inside its edge, with a dark keyline on both sides so it reads on sky and on stubble */
  .f-bleed:focus-visible::after { content: ""; position: absolute; z-index: 1; top: 12px; bottom: 12px; left: calc(50% - var(--bleed) / 2 + 12px);
    width: calc(var(--bleed) - 24px); border: 2px solid var(--brass-hi); box-shadow: 0 0 0 2px rgba(15,14,12,.85), inset 0 0 0 2px rgba(15,14,12,.85); pointer-events: none; }
  .f-tag { position: absolute; left: 16px; bottom: 14px; padding: 7px 10px; background: rgba(15,14,12,.78); font: 500 16px/1 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--bone);
    opacity: 0; transform: translateY(4px); transition: opacity .25s ease, transform .25s ease; }
  .f-cell:hover .f-tag, .f-cell:focus-visible .f-tag, .f-bleed .f-tag { opacity: 1; transform: none; }
  .f-bleed .f-tag { left: 0; bottom: 24px; }

  /* Home gallery covers: one row of five tall prints. Rest dim and hover lift stay as they are. */
  .home-galleries .grid-center { flex-wrap: nowrap; }
  .home-galleries .grid-center > .tile { width: calc((100% - var(--gap) * 4) / 5); }
  .home-galleries .tile-img { aspect-ratio: 4 / 5; }
  .home-galleries .tile-img img { object-position: var(--focus-tall, var(--focus, center)); }
  .home-galleries .tile-cap { text-align: left; }
  .home-galleries .tile-cap { font-size: clamp(16px, 1.25vw, 19px); letter-spacing: clamp(1.5px, .16vw, 2.5px); }   /* five covers: room between captions at 1200 to 1500 */

  /* Home About: Old Main beside the copy, as one centered pair */
  .photo-band { padding-bottom: 0; margin-top: 0; }   /* the band's extra top space only made room for the backdrop fade */
  .photo-band .about-band.solo { grid-template-columns: minmax(0, 540px) minmax(0, 520px); gap: 80px; align-items: center; justify-content: center; }   /* one centered pair, 1140 across */
  .about-shot { max-width: none; margin: 0; }
  .photo-band .about-copy { background: none; padding: 8px 0 8px 38px; }

  /* About page: the photos of Johnny at print size on the wide frame, the copy beside them from the top (not centered) */
  .about-page .about-band { width: calc(100% + var(--wide) - var(--wrap)); margin-inline: calc((var(--wrap) - var(--wide)) / 2); grid-template-columns: 7fr 5fr; gap: 64px; align-items: start; }
  .about-page .about-pair { align-items: start; }   /* the headshot lines up with the coast photo and the copy along one top edge */
  .about-page .about-copy { max-width: 560px; padding-top: 8px; }

  /* Gallery walls and the next chapter break out to the wide frame. The section stays the 1140 .wrap, so the crumb,
     h1, intro and the .has-bd backdrop do not move; the rows (worked out at 1140) just scale up, never re-flow. */
  .page-top > .gallery, .page-top > .next-chapter { width: calc(100% + var(--wide) - var(--wrap)); margin-inline: calc((var(--wrap) - var(--wide)) / 2); }

  /* Photos hub as five chapters: a head row (title, first line of the lead, count) over an uncropped strip.
     The title link's ::after covers the whole chapter, so a click anywhere opens the gallery and Tab stops once. */
  .wrap.hub { width: min(var(--wide), 100% - 48px); }
  .hub .hub-tiles { display: none; }
  .hub-strips { display: block; }
  .chapter { position: relative; }
  .hub-strips .chapter + .chapter { margin-top: 80px; }
  .ch-head { display: grid; grid-template-columns: auto 1fr auto; gap: 32px; align-items: baseline; margin-bottom: 22px; }
  .next-chapter .ch-head { align-items: last baseline; }   /* lead and count sit on the title's line, not the kicker's */
  .ch-head h2 { font: 600 32px/1 var(--font-display); letter-spacing: 3px; text-transform: uppercase; color: var(--bone); }
  .ch-link { text-decoration: none; }
  .ch-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
  .chapter:hover .ch-link, .ch-link:focus-visible { color: var(--brass-hi); }
  .chapter:hover .ch-name, .ch-link:focus-visible .ch-name { text-decoration: underline; text-decoration-color: var(--brass); text-underline-offset: 6px; }   /* the title only, not the Next kicker */
  .chapter:focus-within { outline: 2px solid var(--brass-hi); outline-offset: 8px; }
  .ch-link:focus-visible { outline: none; }
  .ch-kicker { font: 500 16px/1 var(--font-display); letter-spacing: 2.5px; color: var(--brass-hi); margin-bottom: 10px; }
  .ch-lead { color: var(--text); max-width: 640px; }
  .ch-count { font: 500 16px/1 var(--font-display); letter-spacing: 2.5px; text-transform: uppercase; color: var(--muted); }
  .ch-row { display: flex; gap: var(--gap); }
  .ch-cell { flex: var(--r) 1 0; min-width: 0; overflow: hidden; box-shadow: 0 0 0 1px var(--line); }
  .ch-cell img { width: 100%; height: auto; transition: transform .6s ease; }
  .chapter:hover .ch-cell img { transform: scale(1.03); }

  /* End of each gallery: Book a Shoot centered, then a hairline and the next gallery's chapter */
  .next-chapter { display: block; margin-top: 96px; padding-top: 28px; border-top: 1px solid var(--line); }
  .gallery-end a.next-text-link { display: none; }   /* a.: outranks .more a:not(.btn) */
  .gallery-end .btn { margin-right: 0; }
}
@media (min-width: 1200px) and (hover: none) {
  .f-tag { opacity: 1; transform: none; }
}
@media (min-width: 1921px) {
  .f-bleed { --bleed: var(--wide); }   /* past 1920 the combine band is the frame's width (see .f-bleed above) */
}

/* Develop on scroll (1200 and up): each frame comes up out of the dark as it enters, like a print in the tray, and is
   at full light by a quarter of the way in. CSS scroll timeline only: opacity and transform on the wrappers, never
   filter and never the img, so the hover zoom and rest dim still work. Browsers without view timelines, and reduced
   motion, show the frames static and at full light. animation-timeline must follow the shorthand, which resets it. */
@keyframes develop { from { opacity: .25; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@media (min-width: 1200px) and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .f-cell, .f-bleed, .home-galleries .tile, .ch-row { animation: develop linear both; animation-timeline: view(); animation-range: entry 0% cover 25%; }
  }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; scroll-behavior: auto !important; }
  .tile-link:hover .tile-img img { transform: none; }
  .chapter:hover .ch-cell img { transform: none; }
}
