/* ==========================================================================
   Laura Garretty Photography
   Single shared stylesheet.

   Contents
   1.  Design tokens
   2.  Reset & base
   3.  Typography
   4.  Utilities (container, skip link, buttons)
   5.  Site header & navigation
   6.  Hero / page headers
   7.  Quote band
   8.  Gallery preview (home) + pager
   9.  About band (text over image)
   10. Prose (about page bio)
   11. Shop grid (product cards — pyrography page)
   12. Bundle feature blocks (bundles page)
   13. Gallery collections (gallery page)
   14. Lightbox
   15. Contact
   16. Footer
   17. Blog listing & post
   18. Home hub (book hero, bundle teaser cards, branch cards)
   19. Responsive — 768px / 1200px
   20. Reduced motion
   ========================================================================== */


/* ==========================================================================
   1. Design tokens
   ========================================================================== */

:root {
  /* Colour */
  --charcoal:          #1a1a1a;  /* header, footer, primary dark background   */
  --charcoal-soft:     #2a2a2a;  /* alternating dark section                  */
  --charcoal-line:     #383838;  /* hairline dividers on dark                 */
  --light:             #f5f5f5;  /* quote band                                */
  --white:             #ffffff;
  --ink:               #232323;  /* body text on light backgrounds            */
  --ink-soft:          #55505a;  /* secondary text on light backgrounds       */

  /* The mauve is used at two different luminances. --mauve is the exact tone
     from the original site and is only ever placed on dark backgrounds, where
     it clears AA (4.96:1 on --charcoal). --mauve-on-light is darkened so it
     also clears AA on --light (4.98:1) without shifting the header's colour. */
  --mauve:             #9b7fa6;
  --mauve-on-light:    #7d5f88;
  --mauve-bright:      #b498bd;  /* hover state on dark                       */

  /* Ember — the Pyrography section's accent, applied via body.theme-ember.
     --ember-on-light is darkened from the brand-supplied #be4d2a (same hue
     14.19° and saturation 63.79%, lightness taken from 45.49% to 42.49%)
     because #be4d2a cleared AA on --light by only ~0.004 — effectively no
     margin. This value computes to 5.0349:1, real headroom this time. */
  --ember:             #ed6035;
  --ember-on-light:    #b14827;
  --ember-bright:      #ff764d;

  /* Sage — the Blog section's accent, applied via body.theme-sage. The one
     true third hue against mauve (violet) and ember (red-orange), so the
     section reads as its own place rather than a pale echo of either.
     --sage clears AA on --charcoal at 5.59:1; --sage-on-light clears AA on
     --light/--white at 5.47:1/5.96:1 — both computed the same way as the
     ember pair above, with comparable headroom. */
  --sage:              #7a9b6e;
  --sage-on-light:     #4f6b45;
  --sage-bright:       #98c28a;  /* hover state on dark                     */

  /* Teal — the Photography page's accent, applied via body.theme-teal.
     Indigo is reserved for a future home page update, so this page gets
     its own blue-green hue instead, distinct from mauve/ember/sage. --teal
     clears AA on --charcoal at 5.35:1; --teal-on-light clears AA on
     --light/--white at 5.65:1/6.16:1 — computed the same way as the other
     accent pairs above. */
  --teal:              #4f9b93;
  --teal-on-light:     #2f6b64;
  --teal-bright:       #6ebdb4;  /* hover state on dark                     */

  /* Indigo — the home page's accent, applied via body.theme-indigo. Hue
     235° sits between mauve's violet and teal's blue-green so it reads as
     its own colour rather than a blend of the two. --indigo clears AA on
     --charcoal at 5.52:1; --indigo-on-light clears AA on --light/--white at
     6.07:1/6.61:1 — computed the same way as the other accent pairs above. */
  --indigo:            #858bd6;
  --indigo-on-light:   #4850bf;
  --indigo-bright:     #a3a8e2;  /* hover state on dark                     */

  /* Shrub — the Comfort Bundles page's accent, applied via body.theme-shrub.
     Sampled from the shrubbery visible behind both bundle flat-lay photos
     (median of ~61k green-hued pixels pooled across the two hero images,
     hue 76°). Hue is kept well clear of --sage's 104° so the two don't read
     as the same colour. --shrub clears AA on --charcoal at 5.50:1;
     --shrub-on-light clears AA on --light/--white at 5.22:1/5.69:1 —
     computed the same way as the other accent pairs above. */
  --shrub:             #869852;
  --shrub-on-light:    #5e6c37;
  --shrub-bright:      #a9be6f;  /* hover state on dark                     */

  /* Gold — the Blog section's accent, applied via body.theme-gold. Replaces
     sage there: with sage, teal and shrub all sitting in the same
     green-blue-green hue band (104°/174°/75°), the palette had a gap in
     the warm range instead. Hue 43° sits in that gap, between ember's 14°
     and shrub's 75°, tuned warm and muted (aged paper, ink, gold leaf)
     rather than a bright citrus yellow. --gold clears AA on --charcoal at
     5.38:1; --gold-on-light clears AA on --light/--white at 5.40:1/5.89:1 —
     computed the same way as the other accent pairs above. Sage itself is
     untouched; nothing references it after this swap, but it stays defined
     since it's still used conceptually elsewhere. */
  --gold:              #ab8b3c;
  --gold-on-light:     #77622a;
  --gold-bright:       #cfac55;  /* hover state on dark                     */

  /* Crimson — the Contact page's accent, applied via body.theme-crimson.
     Sampled from the red foliage in streetlamp-in-autumn-foliage.jpg
     (median of ~6.4k red-hued pixels, excluding the streetlamp and sky;
     hue 11.7°). That raw sample sits only 2.3° from --ember's 14° —
     essentially a duplicate — so it's nudged to hue 350°, a 24° gap from
     ember (comparable to gold's 29° gap from the sage/teal/shrub
     cluster), reading as true crimson rather than ember's fire-orange.
     --crimson clears AA on --charcoal at 5.41:1; --crimson-on-light
     clears AA on --light/--white at 5.41:1/5.89:1 — computed the same
     way as the other accent pairs above. Needing ~65% lightness to clear
     --charcoal pushes the on-charcoal variant toward coral-rose rather
     than deep crimson; the darker, more sample-true tone lives in
     --crimson-on-light instead — the same relationship --ember has to
     --ember-on-light. */
  --crimson:           #e4677b;
  --crimson-on-light:  #c1223d;
  --crimson-bright:    #f296a5;  /* hover state on dark                     */

  /* RGB channel triples for the accent colours, so alpha-blended uses
     (rgba(var(--x-rgb), alpha)) can follow section theming too — a plain
     var() can't be decomposed into channels inside rgba() otherwise. */
  --mauve-rgb:            155, 127, 166;
  --mauve-on-light-rgb:   125, 95, 136;
  --ember-rgb:            255, 81, 38;
  --ember-on-light-rgb:   177, 72, 39;
  --sage-rgb:             122, 155, 110;
  --sage-on-light-rgb:    79, 107, 69;
  --teal-rgb:             79, 155, 147;
  --teal-on-light-rgb:    47, 107, 100;
  --indigo-rgb:           133, 139, 214;
  --indigo-on-light-rgb:  72, 80, 191;
  --shrub-rgb:            134, 152, 82;
  --shrub-on-light-rgb:   94, 108, 55;
  --gold-rgb:             171, 139, 60;
  --gold-on-light-rgb:    119, 98, 42;
  --crimson-rgb:          228, 103, 123;
  --crimson-on-light-rgb: 193, 34, 61;

  /* Semantic accent layer. Components reference --accent/--accent-bright/
     --accent-on-light rather than a specific palette family, so a section
     can swap its whole theme by overriding these three (plus the two -rgb
     tokens) on <body> — see body.theme-ember below — without touching any
     component rule. Mauve is the default/current theme. */
  --accent:               var(--mauve);
  --accent-bright:        var(--mauve-bright);
  --accent-on-light:      var(--mauve-on-light);
  --accent-rgb:           var(--mauve-rgb);
  --accent-on-light-rgb:  var(--mauve-on-light-rgb);

  /* Type */
  --font-display: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --font-body:    'Josefin Sans', 'Helvetica Neue', Arial, sans-serif;

  /* Long-form reading (.prose, lightbox descriptions) gets its own token
     even though it resolves to the same face as --font-body today. Josefin
     Sans is a strong chrome face (nav, buttons, tracked caps) but a weaker
     one for sustained paragraphs — this token is the one-line escape hatch
     if that turns out to matter once the Blog exists. */
  --font-prose:   'Josefin Sans', 'Helvetica Neue', Arial, sans-serif;

  /* Spacing */
  --gutter:        1.5rem;
  --section-y:     5rem;
  --container-max: 1200px;
  --prose-max:     800px;

  /* Motion */
  --ease:       cubic-bezier(0.4, 0, 0.2, 1);
  --dur-fast:   180ms;
  --dur:        320ms;

  /* Chrome */
  --radius:      2px;
  --header-h:    84px;
}

/* Section theme override — swaps the semantic accent layer without
   touching any component rule. Applied via a class on <body>, e.g.
   <body class="theme-ember">. Not used on any page yet; the Pyrography
   section will be the first to carry it. */
body.theme-ember {
  --accent:               var(--ember);
  --accent-bright:        var(--ember-bright);
  --accent-on-light:      var(--ember-on-light);
  --accent-rgb:           var(--ember-rgb);
  --accent-on-light-rgb:  var(--ember-on-light-rgb);
}

/* Blog section — applied to blog.html and every individual post page. */
body.theme-sage {
  --accent:               var(--sage);
  --accent-bright:        var(--sage-bright);
  --accent-on-light:      var(--sage-on-light);
  --accent-rgb:           var(--sage-rgb);
  --accent-on-light-rgb:  var(--sage-on-light-rgb);
}

/* Photography section — applied to gallery.html. Retints the existing
   collections/lightbox along with the new "Ache of Becoming" book teaser,
   rather than scoping the accent to just the new section. */
body.theme-teal {
  --accent:               var(--teal);
  --accent-bright:        var(--teal-bright);
  --accent-on-light:      var(--teal-on-light);
  --accent-rgb:           var(--teal-rgb);
  --accent-on-light-rgb:  var(--teal-on-light-rgb);
}

/* Home page — applied to index.html only. Indigo is scoped to the hero band
   and other homepage-level chrome; the Writing branch card on this same page
   deliberately opts back into --mauve (see .branch-card--mauve below) since
   mauve is being reserved for the Writing section itself, not this page's
   own accent. Same hue-235° derivation as the other three accents: --indigo
   clears AA on --charcoal at 5.52:1; --indigo-on-light clears AA on
   --light/--white at 6.07:1/6.61:1. */
body.theme-indigo {
  --accent:               var(--indigo);
  --accent-bright:        var(--indigo-bright);
  --accent-on-light:      var(--indigo-on-light);
  --accent-rgb:           var(--indigo-rgb);
  --accent-on-light-rgb:  var(--indigo-on-light-rgb);
}

/* Comfort Bundles page — applied to bundles.html only. */
body.theme-shrub {
  --accent:               var(--shrub);
  --accent-bright:        var(--shrub-bright);
  --accent-on-light:      var(--shrub-on-light);
  --accent-rgb:           var(--shrub-rgb);
  --accent-on-light-rgb:  var(--shrub-on-light-rgb);
}

/* Blog section — applied to blog.html and every individual post page.
   Replaces body.theme-sage there (see --gold above for why); .cta still
   used on blog.html picks up this accent automatically since it reads
   --accent-on-light rather than a specific palette family. */
body.theme-gold {
  --accent:               var(--gold);
  --accent-bright:        var(--gold-bright);
  --accent-on-light:      var(--gold-on-light);
  --accent-rgb:           var(--gold-rgb);
  --accent-on-light-rgb:  var(--gold-on-light-rgb);
}

/* Contact page — applied to contact.html only. Replaces the default mauve
   it carried with no theme-* class at all. */
body.theme-crimson {
  --accent:               var(--crimson);
  --accent-bright:        var(--crimson-bright);
  --accent-on-light:      var(--crimson-on-light);
  --accent-rgb:           var(--crimson-rgb);
  --accent-on-light-rgb:  var(--crimson-on-light-rgb);
}


/* ==========================================================================
   2. Reset & base
   ========================================================================== */

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

html {
  scroll-behavior: smooth;
  /* Anchored targets clear the sticky header. */
  scroll-padding-top: var(--header-h);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--charcoal);
  color: var(--white);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Stops a long word or URL forcing a horizontal scrollbar on narrow screens. */
body,
h1, h2, h3, h4,
p, li, figcaption {
  overflow-wrap: break-word;
}

img,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

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

a:hover,
a:focus-visible {
  color: var(--accent-bright);
}

/* A single, visible focus ring everywhere. Never removed. */
:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 3px;
}

/* On light backgrounds the bright accent ring is too faint — darken it. */
.quote-band :focus-visible,
.prose :focus-visible,
.contact-grid :focus-visible {
  outline-color: var(--accent-on-light);
}


/* ==========================================================================
   3. Typography
   ========================================================================== */

h1, h2, h3, h4 {
  margin: 0 0 0.6em;
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.2;
}

p {
  margin: 0 0 1.2em;
}

p:last-child {
  margin-bottom: 0;
}

/* Tracked-out, all-caps display heading. The trailing letter-space is
   trimmed with a negative margin so centred text stays optically centred. */
.h-display {
  text-transform: uppercase;
  letter-spacing: 0.18em;
  margin-right: -0.18em;
}

.section-heading {
  text-align: center;
  font-size: clamp(1.8rem, 1.2rem + 2.1vw, 2.7rem);
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  margin-right: -0.14em;
  margin-bottom: 2.5rem;
}


/* ==========================================================================
   4. Utilities
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

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

.section--dark  { background: var(--charcoal); }
.section--soft  { background: var(--charcoal-soft); }
.section--light { background: var(--light); color: var(--ink); }
.section--white { background: var(--white); color: var(--ink); }

.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--accent);
  color: var(--white);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transform: translateY(-120%);
  transition: transform var(--dur-fast) var(--ease);
}

.skip-link:focus {
  transform: translateY(0);
  color: var(--white);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Buttons ------------------------------------------------------------ */

.btn {
  display: inline-block;
  padding: 0.85rem 2.2rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: transparent;
  color: var(--accent);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 0.82rem;
  letter-spacing: 0.13em;
  margin-right: -0.13em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}

.btn:hover,
.btn:focus-visible {
  background: var(--accent);
  color: var(--white);
}

/* Button sitting on a light background needs the darker mauve for contrast. */
.btn--on-light {
  border-color: var(--accent-on-light);
  color: var(--accent-on-light);
}

.btn--on-light:hover,
.btn--on-light:focus-visible {
  background: var(--accent-on-light);
  color: var(--white);
}

/* The home page's Featured Bundles teaser CTA is pinned to ember regardless
   of the page's own indigo accent, so it still reads as the same "buy"
   colour a visitor will meet again on the Bundles page itself. */
.btn--ember {
  border-color: var(--ember);
  color: var(--ember);
}

.btn--ember:hover,
.btn--ember:focus-visible {
  background: var(--ember);
  color: var(--white);
}

/* Bundles page CTA is pinned to shrub, the same green as the bundle
   headings and the page's own accent — one consistent "buy" signal down
   the page. */
.btn--shrub {
  border-color: var(--shrub);
  color: var(--shrub);
}

.btn--shrub:hover,
.btn--shrub:focus-visible {
  background: var(--shrub);
  color: var(--white);
}


/* ==========================================================================
   5. Site header & navigation
   ========================================================================== */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  background: transparent;
  transition: background-color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}

/* Added by js/main.js once the page scrolls past the hero lip. */
.site-header.scrolled {
  background: var(--charcoal);
  box-shadow: 0 1px 0 var(--charcoal-line);
}

.nav-wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  max-width: var(--container-max);
  min-height: var(--header-h);
  margin-inline: auto;
  padding: 0.75rem var(--gutter);
}

.brand {
  display: block;
  flex-shrink: 0;
  line-height: 0;
}

.brand-logo {
  width: auto;
  height: 54px;
  color: var(--accent);
}

/* --- Hamburger ---------------------------------------------------------- */

.nav-toggle {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 10px;
  margin-right: -10px;
}

.nav-toggle span {
  display: block;
  height: 2px;
  background: var(--accent);
  transition: transform var(--dur-fast) var(--ease),
              opacity var(--dur-fast) var(--ease);
}

.nav-toggle[aria-expanded='true'] span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded='true'] span:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded='true'] span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* --- Menu --------------------------------------------------------------- */

.nav-menu {
  display: flex;
  gap: 2.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-menu a {
  display: inline-block;
  padding: 0.35rem 0;
  color: var(--accent);
  font-size: 0.86rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  margin-right: -0.12em;
  text-transform: uppercase;
  border-bottom: 1px solid transparent;
  transition: color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}

.nav-menu a:hover,
.nav-menu a:focus-visible,
.nav-menu a[aria-current='page'] {
  color: var(--accent-bright);
  border-bottom-color: var(--accent-bright);
}

/* --- Submenu (Work) ------------------------------------------------------
   A disclosure button + a plain list of links, not a full ARIA menu — the
   links are Tab-navigable, not arrow-key menuitems, so no aria-haspopup is
   set (it would promise arrow-key roving the markup doesn't provide). See
   js/main.js initNavSubmenu() for the open/close/Escape/outside-click
   behaviour this markup pairs with. */

.nav-submenu-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0;
  color: var(--accent);
  font-size: 0.86rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  margin-right: -0.12em;
  text-transform: uppercase;
  border-bottom: 1px solid transparent;
  transition: color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}

.nav-submenu-toggle:hover,
.nav-submenu-toggle:focus-visible,
.nav-submenu-toggle[aria-expanded='true'],
.nav-submenu-toggle.is-current {
  color: var(--accent-bright);
  border-bottom-color: var(--accent-bright);
}

.nav-submenu-caret {
  width: 8px;
  height: 8px;
  transition: transform var(--dur-fast) var(--ease);
}

.nav-submenu-toggle[aria-expanded='true'] .nav-submenu-caret {
  transform: rotate(180deg);
}

/* Closed by default in both breakpoints; js/main.js toggles .is-open.
   Requires JS to open — consistent with the rest of .nav-menu, which
   already requires JS to open on mobile. */
.nav-submenu {
  display: none;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-submenu.is-open {
  display: block;
}


/* ==========================================================================
   6. Hero / page headers
   ========================================================================== */

.hero {
  display: grid;
  place-items: center;
  position: relative;
  min-height: 100vh;
  min-height: 100svh;   /* avoids the mobile URL-bar jump */
  padding: calc(var(--header-h) + 2rem) var(--gutter) 4rem;
  background-color: var(--charcoal);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  text-align: center;
}

/* Gradient placeholder — the base layer for any hero without a photo, and
   the fallback tone behind one that is still loading. */
.hero--placeholder {
  background-image: linear-gradient(160deg, #1e2a22 0%, #16201b 45%, #101512 100%);
}

.hero--placeholder-blue {
  background-image: linear-gradient(160deg, #1d2730 0%, #172029 48%, #0f1418 100%);
}

/* Warm, charred-wood tone for the Pyrography hero — used behind
   rock-and-roll.jpg while it loads, or if the path ever breaks. */
.hero--placeholder-ember {
  background-image: linear-gradient(160deg, #2a1a12 0%, #1f140d 45%, #120b07 100%);
}

/* Fallback/loading tone behind wrapped-with-care.jpg: a muted plum
   drifting into a charred rust, pulled dark and desaturated to sit
   alongside the site's other hero placeholders. Predates the bundle
   headings' move to a single shrub green below — kept as its own blend
   rather than switched to shrub, since it only ever shows briefly while
   the photo loads. */
.hero--placeholder-bundles {
  background-image: linear-gradient(160deg, #241a26 0%, #201419 45%, #1c130f 100%);
}

/* Muted, desaturated sage-to-charcoal gradient for the Blog section —
   same treatment as the other placeholder heroes above, used until a
   photo exists for the listing page or an individual post. */
.hero--placeholder-sage {
  background-image: linear-gradient(160deg, #1b2419 0%, #161e15 45%, #10150f 100%);
}

/* Dark, desaturated mauve-to-charcoal gradient for the Writing section —
   same treatment as the other placeholder heroes above. Stays purely
   mauve/violet in hue throughout (unlike .hero--placeholder-bundles,
   which deliberately drifts toward rust) since this page doesn't need to
   evoke a second discipline. */
.hero--placeholder-mauve {
  background-image: linear-gradient(160deg, #241b28 0%, #1c1420 45%, #120e16 100%);
}

/* Scrim: keeps white text legible over any photograph. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
              rgba(10, 10, 10, 0.55) 0%,
              rgba(10, 10, 10, 0.4)  45%,
              rgba(10, 10, 10, 0.65) 100%);
}

/* Stronger scrim for one hero only: rock-and-roll.jpg (Pyrography) is a
   light wood tone with dense linework edge-to-edge, no empty zone for
   centred text to sit in, and the standard scrim above is lightest (40%)
   right where centred .hero-content falls. Scoped to this modifier class
   rather than changed on .hero::after itself, so no other page's hero is
   affected. */
.hero--strong-scrim::after {
  background: linear-gradient(180deg,
              rgba(10, 10, 10, 0.72) 0%,
              rgba(10, 10, 10, 0.6)  45%,
              rgba(10, 10, 10, 0.78) 100%);
}

.hero-content {
  position: relative;
  z-index: 1;
  max-width: 900px;
}

.hero-content h1 {
  font-size: clamp(2.1rem, 1.1rem + 4.4vw, 4.5rem);
  color: var(--white);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  margin-right: -0.16em;
  margin-bottom: 1.25rem;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.5);
}

.hero-content p {
  max-width: 40ch;
  margin-inline: auto;
  font-size: clamp(0.95rem, 0.85rem + 0.4vw, 1.15rem);
  font-weight: 300;
  color: rgba(255, 255, 255, 0.92);
  letter-spacing: 0.03em;
  text-shadow: 0 1px 16px rgba(0, 0, 0, 0.5);
}


/* ==========================================================================
   7. Quote band
   ========================================================================== */

.quote-band {
  background: var(--light);
  color: var(--ink);
  padding-block: var(--section-y);
}

.quote-band blockquote {
  position: relative;
  max-width: var(--prose-max);
  margin: 0 auto;
  padding-top: 2.5rem;
  text-align: center;
}

.quote-mark {
  position: absolute;
  top: 0;
  left: 0;
  width: 58px;
  height: auto;
  color: var(--accent-on-light);
  opacity: 0.32;
}

.quote-band q,
.quote-band .quote-text {
  display: block;
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.15rem, 0.9rem + 1.1vw, 1.65rem);
  line-height: 1.6;
  color: var(--ink);
  quotes: none;
}

.quote-band cite {
  display: block;
  margin-top: 1.5rem;
  font-family: var(--font-body);
  font-style: normal;
  font-size: 0.82rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  margin-right: -0.2em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}


/* ==========================================================================
   8. Gallery preview (home) + pager
   ========================================================================== */

/* Masonry *feel* via CSS Grid row spans rather than true masonry: DOM order
   is preserved (so pagination and tab order stay sane) and the layout is
   deterministic. `dense` backfills the gaps that varied spans would leave. */
.preview-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 84px;
  grid-auto-flow: row dense;
  gap: 12px;
}

.preview-item {
  grid-row: span 2;
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
}

/* Every third tile is taller, giving the staggered masonry rhythm. */
.preview-item:nth-child(3n + 1) {
  grid-row: span 3;
}

/* A page the pager has switched away from. */
.preview-item[hidden] {
  display: none;
}

.preview-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur) var(--ease);
}

.preview-item:hover img {
  transform: scale(1.06);
}

/* --- Pager dots --------------------------------------------------------- */

.pager {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 2.5rem;
}

.pager__dot {
  width: 24px;
  height: 24px;
  padding: 7px;      /* keeps the 10px dot inside a 24px touch target */
  border-radius: 50%;
}

.pager__dot::before {
  content: '';
  display: block;
  width: 10px;
  height: 10px;
  border: 1px solid var(--accent);
  border-radius: 50%;
  background: transparent;
  transition: background-color var(--dur-fast) var(--ease);
}

.pager__dot[aria-current='true']::before,
.pager__dot:hover::before {
  background: var(--accent);
}


/* ==========================================================================
   9. About band (text over image)
   ========================================================================== */

.about-band {
  display: grid;
  place-items: center;
  position: relative;
  padding-block: calc(var(--section-y) + 1rem);
  padding-inline: var(--gutter);
  background-color: var(--charcoal);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.about-band--placeholder {
  background-image: linear-gradient(140deg, #1d2a21 0%, #15201a 50%, #0e1411 100%);
}

/* The 60% overlay called for in the brief. */
.about-band::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(12, 12, 12, 0.6);
}

.about-band__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--container-max);
}

.about-band__content {
  max-width: 620px;
  margin-left: auto;   /* right-aligned block, as in the original */
  text-align: left;
}

.about-band__content h2 {
  font-size: clamp(1.8rem, 1.2rem + 2.1vw, 2.7rem);
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  margin-right: -0.2em;
}

.about-band__content p {
  margin-bottom: 2rem;
  color: rgba(255, 255, 255, 0.93);
}

/* --- Centred prose CTA (blog page) --------------------------------------- */

.cta {
  max-width: 620px;
  margin-inline: auto;
  text-align: center;
}

.cta p {
  margin-bottom: 2rem;
}

/* --- Commission feature: image + copy split (Commission a Piece, pyrography
   page). Same media/copy split as .bundle-feature, but simpler — no thumb
   strip, included-list or price — and tuned for a light section background
   (.bundle-feature assumes it sits on the dark body background). --------- */

.commission-feature {
  display: grid;
  gap: 2rem;
  align-items: center;
}

.commission-feature__media img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
}

.commission-feature__copy h2 {
  font-size: clamp(1.6rem, 1.1rem + 1.8vw, 2.3rem);
  color: var(--accent-on-light);
  margin-bottom: 1.25rem;
}

.commission-feature__copy p {
  margin-bottom: 1.5rem;
  color: var(--ink-soft);
  line-height: 1.85;
}

.commission-feature__prompt {
  padding-left: 1rem;
  border-left: 2px solid var(--accent-on-light);
  font-style: italic;
  color: var(--ink);
}

@media (min-width: 768px) {
  .commission-feature {
    grid-template-columns: 1fr 1fr;
    gap: 3rem;
  }
}

/* --- Full-width centred banner (Shop on Etsy, pyrography page) ---------- */

.etsy-banner {
  text-align: center;
}


/* ==========================================================================
   10. Prose (about page bio)
   ========================================================================== */

.prose {
  max-width: var(--prose-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
  color: var(--ink);
  font-family: var(--font-prose);
}

/* Portrait at the top of the about page bio, above the heading. */
.about-photo {
  max-width: 340px;
  margin: 0 auto 3rem;
}

.about-photo img {
  width: 100%;
  border-radius: var(--radius);
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.15);
}

.prose h2 {
  font-size: clamp(1.9rem, 1.3rem + 2.2vw, 2.8rem);
  color: var(--ink);
  margin-bottom: 1.5rem;
}

/* Chapter subheadings within a longer bio (about page) — one per
   narrative beat, lighter than h2 so the page keeps a single clear
   top-level heading. */
.prose h3 {
  font-size: clamp(1.3rem, 1rem + 1.1vw, 1.6rem);
  color: var(--accent-on-light);
  margin-top: 2.75rem;
  margin-bottom: 1rem;
}

.prose p {
  margin-bottom: 1.5rem;
  color: var(--ink-soft);
  font-size: 1.05rem;
  line-height: 1.85;
}

/* Short accent rule under the bio heading. */
.prose h2::after {
  content: '';
  display: block;
  width: 64px;
  height: 2px;
  margin-top: 1.1rem;
  background: var(--accent-on-light);
}


/* ==========================================================================
   11. Shop grid (product cards — pyrography page)

   Distinct from .gallery-item: a shop card needs its title and price
   readable without hovering — a shopper checking a price shouldn't have to
   guess it's hidden behind a hover state, especially on touch. Same grid
   rhythm, spacing and image treatment as the gallery, different caption.
   ========================================================================== */

.shop-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.shop-card__link {
  display: block;
  color: inherit;
}

.shop-card__image {
  display: grid;
  place-items: center;
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--charcoal-soft);
}

.shop-card__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur) var(--ease);
}

.shop-card__link:hover .shop-card__image img,
.shop-card__link:focus-visible .shop-card__image img {
  transform: scale(1.06);
}

.shop-card__title {
  display: block;
  margin-top: 0.85rem;
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: var(--white);
  transition: color var(--dur-fast) var(--ease);
}

.shop-card__price {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}

.shop-card__link:hover .shop-card__title,
.shop-card__link:focus-visible .shop-card__title {
  color: var(--accent-bright);
}

@media (min-width: 768px) {
  .shop-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}


/* ==========================================================================
   12. Bundle feature blocks (bundles page)

   One block per bundle, stacked on the page. Headings are pinned to
   --shrub directly, same as the .btn--shrub CTA (see Utilities) — one
   consistent green identity down the page, rather than the mauve/ember
   per-block distinction this used to carry.
   ========================================================================== */

.bundle-feature {
  display: grid;
  gap: 2rem;
}

.bundle-feature + .bundle-feature {
  margin-top: 4.5rem;
}

.bundle-feature__gallery {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.bundle-feature__hero-img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
}

/* Static, like the home page's .preview-item tiles — a supplementary look
   at what's in the box, not a second interactive lightbox gallery.
   Fixed at 4 columns, matching Seeds of Trust's 4 thumbnails at every
   viewport width — this is the layout that was actually screenshotted and
   verified. A prior attempt at repeat(auto-fit, minmax(0, 1fr)), meant to
   adapt to a future bundle with a different photo count, collapsed to a
   single column instead (auto-fit can't size tracks sensibly with a 0
   minimum, since grid items default to min-width: auto and won't shrink
   below an unconstrained image's intrinsic size) and also changed this
   bundle's own mobile layout to a 2x2 grid instead of one row. If a future
   bundle needs a different thumbnail count, revisit this with a non-zero
   minmax() minimum and verify across viewports before shipping — don't
   swap it back to auto-fit/minmax(0, ...) blind. */
.bundle-feature__thumbs {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.bundle-feature__thumbs img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
}

.bundle-feature__copy {
  display: flex;
  flex-direction: column;
}

.bundle-feature__copy .btn {
  align-self: flex-start;
}

.bundle-feature__heading {
  font-size: clamp(1.6rem, 1.1rem + 1.8vw, 2.3rem);
  color: var(--shrub);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin-right: -0.12em;
  margin-bottom: 0.9rem;
}

.bundle-feature__story {
  color: rgba(255, 255, 255, 0.88);
  margin-bottom: 1.5rem;
}

.bundle-feature__included-label {
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
  margin-bottom: 0.75rem;
}

.bundle-feature__included {
  margin: 0 0 1.75rem;
  padding-left: 1.15rem;
  color: rgba(255, 255, 255, 0.88);
}

.bundle-feature__included li {
  margin-bottom: 0.5rem;
}

.bundle-feature__price {
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
  margin-bottom: 1.5rem;
}

@media (min-width: 768px) {
  .bundle-feature {
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: 3rem;
  }
}


/* ==========================================================================
   13. Gallery collections (gallery page)
   ========================================================================== */

.collection + .collection {
  margin-top: 4.5rem;
}

.collection__title {
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.1rem);
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  margin-right: -0.16em;
  margin-bottom: 0.4rem;
}

.collection__count {
  margin-bottom: 1.75rem;
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.gallery-item {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;   /* square thumbnails */
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--charcoal-soft);
}

.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur) var(--ease);
}

/* Hover: gentle zoom plus a mauve wash. */
.gallery-item::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(var(--accent-rgb), 0.28);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
  pointer-events: none;
}

.gallery-item:hover img,
.gallery-item:focus-visible img {
  transform: scale(1.06);
}

.gallery-item:hover::after,
.gallery-item:focus-visible::after {
  opacity: 1;
}

/* Hover/focus title: the tile names the photograph before it is opened.
   Read from the same data-title the lightbox uses, so a title can never
   drift between the grid and the viewer. z-index lifts it above the mauve
   wash in ::after, which would otherwise paint over it. */
.gallery-item[data-title]::before {
  content: attr(data-title);
  position: absolute;
  z-index: 1;
  inset: auto 0 0 0;
  padding: 2.25rem 0.75rem 0.7rem;
  background: linear-gradient(to top,
                              rgba(0, 0, 0, 0.82) 0%,
                              rgba(0, 0, 0, 0.55) 45%,
                              rgba(0, 0, 0, 0) 100%);
  color: var(--white);
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: 0.04em;
  text-align: center;
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
  pointer-events: none;
}

.gallery-item[data-title]:hover::before,
.gallery-item[data-title]:focus-visible::before {
  opacity: 1;
  transform: translateY(0);
}

/* --- Labelled placeholders ---------------------------------------------- */

/* A placeholder is a non-interactive tile that names the slot it fills, so
   real photographs can be dropped in without guesswork. Removing the
   `placeholder` class and adding a data-full attribute activates it. */
.placeholder {
  display: grid;
  place-items: center;
  cursor: default;
  color: rgba(255, 255, 255, 0.55);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  margin-right: -0.14em;
  text-transform: uppercase;
  border: 1px solid var(--charcoal-line);
}

.placeholder::after {
  content: none;   /* no mauve hover wash on an empty slot */
}

/* Varied greys so a wall of placeholders reads as variety, not one flat block.
   The shade is set on the grid *slot* and inherited down, so it works whether
   the placeholder is the slot itself (preview grid) or nested inside an <li>
   (gallery grid). */
.preview-grid > :nth-child(6n + 1),
.gallery-grid > :nth-child(6n + 1) { --slot-grey: #2f2f2f; }

.preview-grid > :nth-child(6n + 2),
.gallery-grid > :nth-child(6n + 2) { --slot-grey: #383838; }

.preview-grid > :nth-child(6n + 3),
.gallery-grid > :nth-child(6n + 3) { --slot-grey: #262626; }

.preview-grid > :nth-child(6n + 4),
.gallery-grid > :nth-child(6n + 4) { --slot-grey: #414141; }

.preview-grid > :nth-child(6n + 5),
.gallery-grid > :nth-child(6n + 5) { --slot-grey: #2b2b2b; }

.preview-grid > :nth-child(6n),
.gallery-grid > :nth-child(6n)     { --slot-grey: #353535; }

.placeholder {
  background: var(--slot-grey, #2f2f2f);
}

/* Monochrome collection: desaturated, per the brief. */
.collection--mono .placeholder {
  filter: grayscale(1);
}

.collection--mono .gallery-item img {
  filter: grayscale(1);
  transition: transform var(--dur) var(--ease),
              filter var(--dur) var(--ease);
}

.collection--mono .gallery-item:hover img,
.collection--mono .gallery-item:focus-visible img {
  filter: grayscale(0);
}


/* ==========================================================================
   14. Lightbox
   ========================================================================== */

/* Built by js/main.js and appended to <body>, so it exists only on pages
   that actually have activated gallery items. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(8, 8, 8, 0.94);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) var(--ease),
              visibility 0s linear var(--dur);
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur) var(--ease),
              visibility 0s;
}

/* Column layout: the photograph takes the space the caption doesn't need,
   so a 90-word description never pushes the image out of view.

   `height` — not `max-height` — is deliberate. A percentage max-height here
   resolves against a grid area with no definite height, which leaves the
   column free to grow to the image's natural size; the caption then lands
   below the fold. A definite height gives flex-shrink something to work
   against, so the image yields space instead of the caption losing it. */
.lightbox__figure {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  max-width: min(1100px, 100%);
  height: 100%;
  min-height: 0;
  margin: 0;
  text-align: center;
  pointer-events: none;   /* clicks fall through to the backdrop… */
}

/* max-height is what keeps a portrait photograph inside the viewport: capped
   on width alone, an 800x1200 image renders 1200px tall whatever the window
   is. Width stays auto so the box tracks the aspect ratio as height shrinks,
   and the backdrop stays clickable either side of a portrait frame. */
.lightbox__img {
  flex: 0 1 auto;
  min-height: 0;          /* lets the image shrink inside the flex column */
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--radius);
  pointer-events: auto;   /* …but not through the photograph itself */
}

/* Capped and scrollable: long descriptions stay readable without ever
   crowding out the photograph they describe.

   `0 0 auto` keeps the caption at its full height while the image absorbs
   the shrinking above — the reverse starved the text on short viewports.
   Anything past the cap is reachable through the Read more toggle, since a
   zero-width overlay scrollbar is no signal that text has been clipped. */
.lightbox__caption {
  flex: 0 0 auto;
  overflow-y: auto;
  max-width: 70ch;
  max-height: 32vh;
  padding-inline: 0.5rem;
  pointer-events: auto;
  color: rgba(255, 255, 255, 0.85);
  overscroll-behavior: contain;
  transition: max-height var(--dur) var(--ease);
}

/* Expanded, the caption takes the room it needs and the photograph gives
   way — the visitor has asked to read, not to look. */
.lightbox__caption.is-expanded {
  max-height: 70vh;
}

.lightbox__title {
  margin: 0 0 0.5rem;
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 1rem + 0.7vw, 1.5rem);
  font-weight: 400;
  color: var(--white);
  letter-spacing: 0.06em;
}

.lightbox__desc {
  margin: 0 0 0.75rem;
  font-family: var(--font-prose);
  font-size: 0.94rem;
  font-weight: 300;
  line-height: 1.65;
  color: rgba(255, 255, 255, 0.78);
  text-align: left;
}

.lightbox__desc[hidden] {
  display: none;
}

/* Shown by js/main.js only when the description is actually taller than the
   cap, so it never appears on text that already fits. */
.lightbox__more {
  display: inline-block;
  margin: 0 0 0.75rem;
  padding: 0.2rem 0;
  border: 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.45);
  background: none;
  color: rgba(255, 255, 255, 0.85);
  font-family: inherit;
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}

.lightbox__more:hover,
.lightbox__more:focus-visible {
  color: var(--white);
  border-color: var(--accent);
}

.lightbox__more[hidden] {
  display: none;
}

/* Camera body and position indicator share one muted metadata line. */
.lightbox__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 1.1rem;
  margin: 0;
  color: rgba(255, 255, 255, 0.5);
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.lightbox__meta > [hidden] {
  display: none;
}

.lightbox__counter {
  color: rgba(255, 255, 255, 0.5);
}

/* --- Controls ----------------------------------------------------------- */

.lightbox__btn {
  position: absolute;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.4);
  color: var(--white);
  line-height: 1;
  transition: background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}

.lightbox__btn:hover,
.lightbox__btn:focus-visible {
  background: var(--accent);
  border-color: var(--accent);
}

.lightbox__btn svg {
  width: 22px;
  height: 22px;
}

.lightbox__close {
  top: clamp(1rem, 3vw, 2rem);
  right: clamp(1rem, 3vw, 2rem);
  font-size: 1.6rem;
}

.lightbox__prev { left:  clamp(0.5rem, 2vw, 2rem); top: 50%; transform: translateY(-50%); }
.lightbox__next { right: clamp(0.5rem, 2vw, 2rem); top: 50%; transform: translateY(-50%); }

/* Locks the page behind the open lightbox. */
body.is-locked {
  overflow: hidden;
}


/* ==========================================================================
   15. Contact
   ========================================================================== */

.contact-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3.5rem;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
  color: var(--ink);
}

.contact-grid h2 {
  font-size: clamp(1.7rem, 1.2rem + 1.8vw, 2.4rem);
  color: var(--ink);
  margin-bottom: 1.5rem;
}

/* --- Form --------------------------------------------------------------- */

.field {
  margin-bottom: 1.4rem;
}

.field label {
  display: block;
  margin-bottom: 0.45rem;
  font-size: 0.76rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  margin-right: -0.16em;
  text-transform: uppercase;
  color: var(--ink);
}

.field input,
.field textarea {
  width: 100%;
  padding: 0.8rem 0.95rem;
  border: 1px solid #d3cdd6;
  border-radius: var(--radius);
  background: var(--white);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 300;
  transition: border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}

.field textarea {
  min-height: 170px;
  resize: vertical;
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent-on-light);
  box-shadow: 0 0 0 3px rgba(var(--accent-on-light-rgb), 0.18);
}

/* Invalid state is announced by the error text, not colour alone. */
.field input[aria-invalid='true'],
.field textarea[aria-invalid='true'] {
  border-color: #b3261e;
}

.field__error {
  display: block;
  min-height: 1.2em;
  margin-top: 0.35rem;
  color: #b3261e;
  font-size: 0.82rem;
}

.field__error:empty {
  min-height: 0;
}

.form-status {
  margin-top: 1.25rem;
  padding: 0.9rem 1.1rem;
  border-left: 3px solid var(--accent-on-light);
  background: #efe9f1;
  color: var(--ink);
  font-size: 0.95rem;
}

.form-status:empty {
  display: none;
}

/* --- Contact details ---------------------------------------------------- */

.contact-info dl {
  margin: 0;
}

.contact-info dt {
  margin-bottom: 0.3rem;
  font-size: 0.74rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  margin-right: -0.18em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}

.contact-info dd {
  margin: 0 0 1.75rem;
  font-size: 1.08rem;
  color: var(--ink);
}

.contact-info dd a {
  color: var(--ink);
  border-bottom: 1px solid var(--accent-on-light);
  transition: color var(--dur-fast) var(--ease);
}

.contact-info dd a:hover,
.contact-info dd a:focus-visible {
  color: var(--accent-on-light);
}


/* ==========================================================================
   16. Footer
   ========================================================================== */

.site-footer {
  padding: 3.5rem var(--gutter);
  background: var(--charcoal);
  color: var(--white);
  text-align: center;
}

.footer-logo {
  height: 48px;
  width: auto;
  margin: 0 auto 1.75rem;
  opacity: 0.9;
  color: var(--accent);
}

.footer-copy {
  margin-bottom: 0.5rem;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.9);
}

.footer-contact {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1.25rem;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.7);
}

.footer-contact a {
  color: rgba(255, 255, 255, 0.7);
}

.footer-contact a:hover,
.footer-contact a:focus-visible {
  color: var(--accent-bright);
}


/* ==========================================================================
   17. Blog listing & post
   ========================================================================== */

/* --- Listing page (blog.html) ------------------------------------------- */

.blog-list {
  max-width: var(--prose-max);
  margin: 0 auto;
  padding: 0;
  list-style: none;
}

.blog-card + .blog-card {
  margin-top: 2.5rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--charcoal-line);
}

.blog-card__link {
  display: block;
  color: inherit;
}

.blog-card__date {
  display: block;
  margin-bottom: 0.6rem;
  font-size: 0.76rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  margin-right: -0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.blog-card__title {
  font-size: clamp(1.4rem, 1.1rem + 1.2vw, 1.9rem);
  color: var(--white);
  margin-bottom: 0.75rem;
  transition: color var(--dur-fast) var(--ease);
}

.blog-card__link:hover .blog-card__title,
.blog-card__link:focus-visible .blog-card__title {
  color: var(--accent-bright);
}

.blog-card__excerpt {
  color: rgba(255, 255, 255, 0.85);
  margin-bottom: 1rem;
}

.blog-card__cta {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.13em;
  margin-right: -0.13em;
  text-transform: uppercase;
  color: var(--accent);
}

/* --- Individual post page ------------------------------------------------ */

.blog-post__back {
  display: inline-block;
  margin-bottom: 2rem;
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.13em;
  margin-right: -0.13em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}

.blog-post__meta {
  display: block;
  margin-bottom: 2rem;
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  margin-right: -0.16em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}

/* --- Poem (verse, not prose — line and stanza breaks preserved) --------- */

.poem {
  margin: 2.5rem 0;
  padding: 2rem clamp(1rem, 4vw, 2.5rem);
  background: var(--light);
  border-left: 3px solid var(--accent-on-light);
}

.poem__title {
  font-size: clamp(1.3rem, 1rem + 1vw, 1.7rem);
  color: var(--accent-on-light);
  margin-bottom: 0.3rem;
}

.poem__byline {
  display: block;
  margin-bottom: 1.5rem;
  font-family: var(--font-body);
  font-size: 0.76rem;
  letter-spacing: 0.12em;
  margin-right: -0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.poem__stanza {
  margin-bottom: 1.4rem;
  color: var(--ink);
  line-height: 1.85;
}

.poem__stanza:last-child {
  margin-bottom: 0;
}

/* --- Embedded video (e.g. a post's original YouTube upload) ------------- */

/* aspect-ratio is set inline per embed, from that video's own iframe
   dimensions, rather than assumed as 16:9 — home video from this era is
   rarely widescreen. */
.video-embed {
  position: relative;
  width: 100%;
  margin: 2.5rem 0;
  border-radius: var(--radius);
  overflow: hidden;
}

.video-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* --- Inline photo within a post (e.g. a photographed artefact) ---------- */

.blog-post__figure {
  max-width: 320px;
  margin: 2.5rem auto;
}

.blog-post__figure img {
  width: 100%;
  border-radius: var(--radius);
}

.blog-post__figure figcaption {
  margin-top: 0.75rem;
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  text-align: center;
}


/* ==========================================================================
   18. Home hub (book hero, bundle teaser cards, branch cards)
   ========================================================================== */

/* --- Book hero: a contained band, not the full-viewport .hero used
   elsewhere — the brief calls for restraint here, not a splash screen. --- */

.book-hero {
  padding-top: calc(var(--header-h) + 3rem);
}

.book-hero__inner {
  display: grid;
  gap: 2.5rem;
  align-items: center;
}

.book-hero__cover {
  max-width: 260px;
  margin-inline: auto;
}

.book-hero__cover img {
  width: 100%;
  border-radius: var(--radius);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4);
}

.book-hero__content {
  text-align: center;
}

.book-hero__eyebrow {
  margin-bottom: 0.75rem;
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  margin-right: -0.18em;
  text-transform: uppercase;
  color: var(--accent);
}

.book-hero__content h1 {
  font-size: clamp(2rem, 1.5rem + 2.2vw, 3.2rem);
  color: var(--white);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-right: -0.1em;
  margin-bottom: 0.6rem;
}

.book-hero__subhead {
  margin-bottom: 1rem;
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.05rem, 0.9rem + 0.6vw, 1.3rem);
  color: rgba(255, 255, 255, 0.9);
}

.book-hero__body {
  max-width: 46ch;
  margin-inline: auto;
  color: rgba(255, 255, 255, 0.78);
  font-weight: 300;
}

/* Decorative-but-functional: skips straight to the next section. Sized and
   spaced independently of .lightbox__btn — that one sits over a photograph
   and needs a backdrop, this one sits in open space and doesn't. */
.book-hero__scroll {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin: 2.5rem auto 0;
  border: 1px solid var(--charcoal-line);
  border-radius: 50%;
  color: var(--accent);
  animation: book-hero-scroll-bounce 2.2s var(--ease) infinite;
}

.book-hero__scroll:hover,
.book-hero__scroll:focus-visible {
  color: var(--accent-bright);
  border-color: var(--accent);
}

.book-hero__scroll svg {
  width: 16px;
  height: 16px;
}

@keyframes book-hero-scroll-bounce {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(6px); }
}

/* --- Bundle teaser cards ---
   A lighter sibling to .bundle-feature (bundles.html) — a homepage teaser,
   not the full included-items breakdown. The media block and the CTA button
   are deliberately sibling <a> elements, not nested — a link inside a link
   is invalid HTML and breaks screen readers. */

.bundle-teaser-intro {
  max-width: var(--prose-max);
  margin: 0 auto 3rem;
  text-align: center;
  color: rgba(255, 255, 255, 0.85);
}

.bundle-teaser-grid {
  display: grid;
  gap: 2.5rem;
}

.bundle-teaser-card {
  display: flex;
  flex-direction: column;
}

.bundle-teaser-card__media {
  display: block;
  color: inherit;
}

.bundle-teaser-card__media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
  margin-bottom: 1.1rem;
  transition: transform var(--dur) var(--ease);
}

.bundle-teaser-card__media:hover img,
.bundle-teaser-card__media:focus-visible img {
  transform: scale(1.03);
}

.bundle-teaser-card__title {
  font-size: clamp(1.3rem, 1.05rem + 1vw, 1.7rem);
  color: var(--accent);
  transition: color var(--dur-fast) var(--ease);
}

.bundle-teaser-card__media:hover .bundle-teaser-card__title,
.bundle-teaser-card__media:focus-visible .bundle-teaser-card__title {
  color: var(--accent-bright);
}

.bundle-teaser-card__tagline {
  margin-top: 0.6rem;
  color: rgba(255, 255, 255, 0.88);
}

.bundle-teaser-card__desc {
  margin-top: 0.6rem;
  color: rgba(255, 255, 255, 0.75);
  font-size: 0.95rem;
}

.bundle-teaser-card__price {
  margin-top: 1rem;
  margin-bottom: 1.5rem;
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}

.bundle-teaser-card .btn {
  align-self: flex-start;
}

/* --- Creative branches --- */

.branches {
  display: grid;
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Local accent overrides, scoped to the card rather than <body> — same
   technique body.theme-ember uses, extended to the two accents that
   don't otherwise appear on this page. */
.branch-card--mauve {
  --accent:               var(--mauve);
  --accent-bright:        var(--mauve-bright);
  --accent-on-light:      var(--mauve-on-light);
  --accent-rgb:           var(--mauve-rgb);
  --accent-on-light-rgb:  var(--mauve-on-light-rgb);
}

.branch-card--teal {
  --accent:               var(--teal);
  --accent-bright:        var(--teal-bright);
  --accent-on-light:      var(--teal-on-light);
  --accent-rgb:           var(--teal-rgb);
  --accent-on-light-rgb:  var(--teal-on-light-rgb);
}

.branch-card--ember {
  --accent:               var(--ember);
  --accent-bright:        var(--ember-bright);
  --accent-on-light:      var(--ember-on-light);
  --accent-rgb:           var(--ember-rgb);
  --accent-on-light-rgb:  var(--ember-on-light-rgb);
}

.branch-card--sage {
  --accent:               var(--sage);
  --accent-bright:        var(--sage-bright);
  --accent-on-light:      var(--sage-on-light);
  --accent-rgb:           var(--sage-rgb);
  --accent-on-light-rgb:  var(--sage-on-light-rgb);
}

.branch-card {
  display: block;
  height: 100%;
  padding: 2rem 1.5rem;
  border: 1px solid var(--charcoal-line);
  border-radius: var(--radius);
  color: inherit;
  text-align: center;
  transition: border-color var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease);
}

a.branch-card:hover,
a.branch-card:focus-visible {
  border-color: var(--accent);
  background: var(--charcoal-soft);
}

.branch-card__status {
  margin-bottom: 0.5rem;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  margin-right: -0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
}

.branch-card__title {
  font-size: 1.4rem;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-right: -0.08em;
  margin-bottom: 0.6rem;
}

.branch-card__desc {
  color: rgba(255, 255, 255, 0.75);
  font-size: 0.92rem;
}

/* General-purpose "disabled tile" treatment for any branch-card that
   isn't a live link yet — muted to read as inactive rather than
   clickable. Not currently used by Writing (now a live link); kept
   available for a future placeholder card. */
.branch-card.is-disabled {
  opacity: 0.55;
}

/* --- Writing page: Ache of Becoming book teaser ---
   Same cover-image-plus-copy idea as the homepage's .book-hero, but
   contained inside a normal .section rather than a full-bleed band, and
   built as its own small component (not a reuse of .book-hero__content)
   because that class's h1 styling doesn't fit this section's h2.
   writing.html's .writing-book__content also reuses three standalone
   classes from the homepage's book-hero component directly —
   .book-hero__eyebrow, .book-hero__subhead and .book-hero__body — which
   works only because those selectors aren't scoped under .book-hero as a
   descendant combinator. */

.writing-book__inner {
  display: grid;
  gap: 2.5rem;
  align-items: start;
}

.writing-book__cover {
  max-width: 260px;
  margin-inline: auto;
}

.writing-book__cover img {
  width: 100%;
  border-radius: var(--radius);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4);
}

.writing-book__content {
  text-align: center;
}

.writing-book__content h2 {
  font-size: clamp(1.8rem, 1.2rem + 2.1vw, 2.7rem);
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-right: -0.1em;
  margin-bottom: 0.6rem;
}

/* ==========================================================================
   19. Responsive
   ========================================================================== */

/* --- Below 768px: mobile nav ------------------------------------------- */

@media (max-width: 767px) {
  .nav-menu {
    position: fixed;
    inset: var(--header-h) 0 auto 0;
    flex-direction: column;
    gap: 0;
    padding: 0.5rem var(--gutter) 1.5rem;
    background: var(--charcoal);
    border-top: 1px solid var(--charcoal-line);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.35);

    /* Collapsed by default; .is-open is toggled by js/main.js. */
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--dur-fast) var(--ease),
                transform var(--dur-fast) var(--ease),
                visibility 0s linear var(--dur-fast);
  }

  .nav-menu.is-open {
    transform: translateY(0);
    opacity: 1;
    visibility: visible;
    transition: opacity var(--dur-fast) var(--ease),
                transform var(--dur-fast) var(--ease),
                visibility 0s;
  }

  .nav-menu li + li {
    border-top: 1px solid var(--charcoal-line);
  }

  .nav-menu a,
  .nav-submenu-toggle {
    padding: 0.95rem 0;
    border-bottom: none;
  }

  .nav-menu a[aria-current='page'] {
    border-bottom: none;
  }

  /* On mobile the submenu is inline content within the same sliding panel
     as the rest of .nav-menu, not a dropdown — just indented. */
  .nav-submenu-toggle {
    width: 100%;
    justify-content: space-between;
  }

  .nav-submenu {
    padding-left: 1rem;
  }

  .nav-submenu a {
    padding: 0.8rem 0;
  }

  /* The header must be solid whenever the menu is open, or the links land
     on top of the hero photograph. `.nav-open` is set by js/main.js; the
     :has() rule is a no-JS equivalent for browsers that support it. */
  .site-header.nav-open,
  .site-header:has(.nav-menu.is-open) {
    background: var(--charcoal);
  }

  .lightbox__prev,
  .lightbox__next {
    top: auto;
    bottom: clamp(0.5rem, 2vw, 1.5rem);
    transform: none;
  }
}

/* --- 768px and up ------------------------------------------------------- */

@media (min-width: 768px) {
  :root {
    --gutter: 2rem;
    --section-y: 6rem;
  }

  .nav-toggle {
    display: none;
  }

  /* On desktop the submenu is a dropdown panel anchored under "Work". */
  .nav-item--submenu {
    position: relative;
  }

  .nav-submenu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 10;
    min-width: 190px;
    margin-top: 0.65rem;
    padding: 0.5rem 0;
    background: var(--charcoal);
    border: 1px solid var(--charcoal-line);
    border-radius: var(--radius);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.35);
  }

  .nav-submenu a {
    padding: 0.6rem 1.1rem;
    white-space: nowrap;
  }

  .nav-submenu a:hover,
  .nav-submenu a:focus-visible {
    background: var(--charcoal-soft);
  }

  .preview-grid {
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: 96px;
  }

  .gallery-grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .contact-grid {
    grid-template-columns: 1.35fr 1fr;
    gap: 4.5rem;
  }

  .about-band__content {
    text-align: left;
  }

  .book-hero__inner {
    grid-template-columns: minmax(240px, 320px) 1fr;
    gap: 4rem;
  }

  .book-hero__cover {
    margin-inline: 0;
  }

  .book-hero__content {
    text-align: left;
  }

  .book-hero__body {
    margin-inline: 0;
  }

  .writing-book__inner {
    grid-template-columns: minmax(240px, 320px) 1fr;
    gap: 4rem;
  }

  .writing-book__cover {
    margin-inline: 0;
  }

  .writing-book__content {
    text-align: left;
  }

  .bundle-teaser-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .branches {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* --- 1200px and up ------------------------------------------------------ */

@media (min-width: 1200px) {
  :root {
    --section-y: 7rem;
  }

  .preview-grid {
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: 104px;
  }

  .gallery-grid {
    grid-template-columns: repeat(4, 1fr);
  }

  .branches {
    grid-template-columns: repeat(4, 1fr);
  }
}


/* ==========================================================================
   20. Reduced motion
   ========================================================================== */

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

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Zoom-on-hover is the one effect worth removing outright rather than
     just shortening — it is movement for its own sake. */
  .preview-item:hover img,
  .gallery-item:hover img,
  .gallery-item:focus-visible img {
    transform: none;
  }
}
